Skip to content

Authoring conversion receipts

Updated: 2026-09-09. Available in ZeoCore 0.10.0.

Receipt APIs are additive. Existing path-returning methods and legacy partial batch behavior keep their return shapes. Use the strict API for required releases.

Convert and compare

Initialize JupytextIntegration, then use script_to_notebook_with_receipt and notebook_to_script_with_receipt. Both require explicit input, output and workspace_root. The output must not exist. Relative paths resolve from the workspace root. NotebookConverter.convert_file_with_receipt also allows absolute_paths=True; portable relative paths are the default.

from zeo_core.integrations.jupytext import JupytextIntegration

integration = JupytextIntegration()
assert integration.initialize().success
clean = integration.script_to_notebook_with_receipt(
    "source.md", "lesson.ipynb", workspace_root="/path/to/git/workspace"
)
assert clean.success
diagnostic = integration.notebook_to_script_with_receipt(
    "lesson.ipynb", "diagnostic.md", workspace_root="/path/to/git/workspace"
)
assert diagnostic.success
parity = integration.compare_notebook_semantics(
    "/path/to/git/workspace/source.md", "/path/to/git/workspace/diagnostic.md"
)
assert parity.success

For strict authoring, declare the kernel and Jupytext text representation in canonical Markdown. Use md with explicit code fences, metadata regions and .noeval listings. Canonical Markdown and round-tripped diagnostic Markdown are compared; IPYNB-to-IPYNB pairs are also supported. Cross-format comparison may fail because Jupytext strips its text representation from notebook JSON. It does not silently ignore that metadata difference.

Comparison checks ordered cell type, declared ID, tags, source hash, every metadata field and attachments. Receipts carry metadata hashes, not potentially sensitive metadata contents. Named normalizations are CRLF to LF and the jupytext.text_representation.jupytext_version field. Unknown drift fails. Text readers create random nbformat IDs; these are not declared source IDs and do not enter text-pair comparison. Notebook JSON IDs are compared exactly. Receipt-bearing text-to-notebook conversion assigns deterministic IDs from ordinal, type and source. The legacy converter retains its existing behavior.

Empty input, zero cells and unsupported cell types produce separate parity errors. Conversion is not execution: a clean notebook is never execution evidence.

Required release batches

from zeo_core.integrations.jupytext import RequiredConversionTask

result = integration.convert_batch_strict(
    [
        RequiredConversionTask(
            task_id="lesson", source_path="source.md",
            output_path="lesson.ipynb", target_format="ipynb", required=True
        )
    ],
    "release-001",
    workspace_root="/path/to/git/workspace",
)
assert result.success and result.content.promoted

The destination directory must be absent, and its parent must already exist. Each output is relative to that directory. Preflight rejects empty batches, duplicate IDs and outputs, path traversal, symlinks, nested output collisions, source/output aliasing and paths outside the workspace before conversion. Missing input files remain ordered failed item results. Optional failure remains visible; any required failure prevents promotion. Failed staging is cleaned. An exclusive sibling promotion lock coordinates cooperating builds. Success renames one complete directory; rerunning into the same destination refuses. This is a caller-owned filesystem transaction, not an adversarial OS sandbox or protection against a hostile process changing filesystem paths concurrently.

Every success receipt contains full source/output SHA-256, sizes, format facts, converter version, preserved low-level ConversionDetails, structural validation and cell facts where applicable. reproducibility_digest() excludes only the named details.conversion_time diagnostic; use portable paths for comparison. Any output/source/version difference still changes that digest.

Pandoc review artifacts

PandocIntegration.markdown_to_docx_with_receipt and html_to_markdown_with_receipt expose the same explicit path/root contract. Initialize with an explicit Pandoc configuration as documented in the Pandoc integration guide. DocumentConverter.convert_file_with_receipt is available for an already validated PandocConfig.

DOCX receipt conversion independently checks archive structure even if legacy configuration disables structural checks. It always records human_visual_approval=false. A human render review is a separate receipt. HTML import creates a new REVIEW_DRAFT; existing Markdown is never overwritten. Pandoc absence is an explicit unavailable failure. Source and parser exception contents are not copied into receipt errors.

Ownership and evidence limits

ZeoCore owns generic conversion, comparison and required-item aggregation. ZeoTutorial owns objective/task/assessment manifests and release orchestration. Book repositories own the canonical content and independent learner checks. Learners consume committed artifacts without this authoring dependency. A converter success proves neither notebook execution nor learning, classroom effectiveness, publisher acceptance or visual approval. Fresh-kernel execution is a separate capability and release prerequisite.

Run make verify and .venv/bin/pytest -q tests/authoring. The real conversion tests use a child process to avoid the legacy suite's filesystem mocks; expected cell structure, metadata, output hashes and failure outcomes are asserted independently.