From 3e267a856c6a3486d416638bd109faf383bf81fe Mon Sep 17 00:00:00 2001 From: Andrew Peris Date: Thu, 17 Sep 2026 12:38:57 -0400 Subject: [PATCH] Verify Comic Manifest candidate against released SDK (#89) --- README.md | 4 + docs/comic-manifest-contracts.md | 53 + .../comic-manifest-contract-lock.json | 28 + tests/fixtures/comic-manifest-v1.json | 671 +++++++++ tests/fixtures/comic-manifest-v1.schema.json | 1315 +++++++++++++++++ .../comic-manifest-contract.test.js | 98 ++ 6 files changed, 2169 insertions(+) create mode 100644 docs/comic-manifest-contracts.md create mode 100644 tests/fixtures/comic-manifest-contract-lock.json create mode 100644 tests/fixtures/comic-manifest-v1.json create mode 100644 tests/fixtures/comic-manifest-v1.schema.json create mode 100644 tests/prompt-sdk/comic-manifest-contract.test.js diff --git a/README.md b/README.md index 393e2d5..98d39d7 100644 --- a/README.md +++ b/README.md @@ -128,3 +128,7 @@ The license does not grant rights to Definitely Secure Studio names, the Prompt Mark, wordmarks, logos, other brand assets, or proprietary creative material. Third-party material remains subject to its own terms. Examples and fixtures must be synthetic, properly licensed, or already public. + +The [Comic Manifest contract consumer proof](docs/comic-manifest-contracts.md) +checks the unreleased Codex candidate against the released SDK using offline +synthetic fixtures; it does not add a Manifest runtime or production dependency. diff --git a/docs/comic-manifest-contracts.md b/docs/comic-manifest-contracts.md new file mode 100644 index 0000000..b048430 --- /dev/null +++ b/docs/comic-manifest-contracts.md @@ -0,0 +1,53 @@ +# Comic Manifest contract consumer proof (Studio #89) + +This is a **test-only consumer of an unreleased Codex 1.0.0 candidate**. It adds no +Manifest runtime, orchestration, source retrieval, trust issuer or publication API. +Codex owns the schema and semantics; public creative authority remains in Universe. + +The [fixture lock](../tests/fixtures/comic-manifest-contract-lock.json) pins Codex +commit `53e4bd7738ae33c928bf72864d69d413168cc5b4` by full source paths, sizes and +SHA-256 digests. The schema and scenario are verbatim test artifacts, not local +normative schema forks or production dependencies. The existing Context Builder +fixture is identical to the pinned Codex bytes and is reused unchanged. All apparent +private context, grants, IDs, publication numbers and URLs are synthetic. A fixed +fixture UUID is not a production attestation or evidence of secure issuance. + +The [Codex specification](https://github.com/DefinitelySecureStudio/codex/blob/53e4bd7738ae33c928bf72864d69d413168cc5b4/specs/manifests/comic-manifest-v1.md) +and RFC 0007 define three immutable payloads, exact-version support, relational +invariants, detached approvals and public projection. Schema validity proves only +structure. No matching hash, stored preparation result or supplied decision object +can authorize access, renew an expired grant, declassify output or promote canon. + +## Verification + +`node --test tests/prompt-sdk/comic-manifest-contract.test.js` checks exact artifact +pins; the three records and detached approval schema; SDK canonical identity +agreement; exact package/prompt/Builder linkage; and public-byte verification without +private record access. It renders the referenced prepared package through the +released SDK API at an explicit historical fixture time. Negative cases reject +unknown fields/versions, public private IDs, rehashed package/prompt substitutions, +expired/denied/wrong-purpose use and preparation evidence substituted for a grant. +No provider, external URL or real source is invoked. `npm test` includes this proof. + +This is not a Manifest validator or full synthetic build execution. Codex's separate +fixture oracle tests candidate relational semantics. Production raw JSON hardening, +current trusted verifier/revocation adapters, media/rights inspection, approval +verification and safe projection remain #90–#98 responsibilities. Human disclosure +review must inspect free text and output bytes; sentinel checks do not prove safety. + +## Adoption and constitutional scope + +Merge the coordinated Codex contract PR before this proof. Refresh test pins only +from reviewed exact Codex blobs and verify bytes; do not edit the copies by hand. +Production adoption waits for #99's immutable contract and implementation releases +and full verified artifact tuples. Source commit URLs are not release assets. +Released Prompt SDK/Context Package/Context Builder code, schemas, lockfiles and +artifacts remain unchanged. Rollback removes this test-only consumer. + +Constitution: v1.0.0, `constitution/v1.0.0`, Studio commit +`a9cc8a503aa30e17820edc62ac95f7cbe10e0564`; Studio ADR 0018 at +`7b5065cef76bea9580609caba356b0d8fe7cc17c` governs the boundary. Owner @andrewperis; +Codex and Platform maintainers review the exact PR revisions. Universal, +repository/production-system and automated-workflow design profiles apply to the +consumer seam; this bounded offline proof grants no real access, disclosure, +publication or canon authority. Runtime/release conformance is not claimed. diff --git a/tests/fixtures/comic-manifest-contract-lock.json b/tests/fixtures/comic-manifest-contract-lock.json new file mode 100644 index 0000000..f51feb8 --- /dev/null +++ b/tests/fixtures/comic-manifest-contract-lock.json @@ -0,0 +1,28 @@ +{ + "repository": "DefinitelySecureStudio/codex", + "commit": "53e4bd7738ae33c928bf72864d69d413168cc5b4", + "status": "unreleased-test-only", + "artifacts": [ + { + "source_path": "schemas/json/comic-manifest/v1/comic-manifest.schema.json", + "path": "tests/fixtures/comic-manifest-v1.schema.json", + "artifact_uri": "https://github.com/DefinitelySecureStudio/codex/blob/53e4bd7738ae33c928bf72864d69d413168cc5b4/schemas/json/comic-manifest/v1/comic-manifest.schema.json", + "byte_size": 29711, + "sha256": "sha256:c9e7d3ee3a9593ec7e85504f680d0cd9b5ece7a6c0db22f4a7152d08b6db2f5c" + }, + { + "source_path": "fixtures/comic-manifest-v1.json", + "path": "tests/fixtures/comic-manifest-v1.json", + "artifact_uri": "https://github.com/DefinitelySecureStudio/codex/blob/53e4bd7738ae33c928bf72864d69d413168cc5b4/fixtures/comic-manifest-v1.json", + "byte_size": 27425, + "sha256": "sha256:bc0a33418a57446953d917ffab1f77c9f39911bef7ef27b70d108ffa32e8aca7" + }, + { + "source_path": "fixtures/context-builder-v1.json", + "path": "tests/fixtures/context-builder-v1.json", + "artifact_uri": "https://github.com/DefinitelySecureStudio/codex/blob/53e4bd7738ae33c928bf72864d69d413168cc5b4/fixtures/context-builder-v1.json", + "byte_size": 19808, + "sha256": "sha256:b1fe9076bd0d9637bdc638436de1cbab0a9d11916a9eb5e279fe60191c2aa743" + } + ] +} diff --git a/tests/fixtures/comic-manifest-v1.json b/tests/fixtures/comic-manifest-v1.json new file mode 100644 index 0000000..2f03519 --- /dev/null +++ b/tests/fixtures/comic-manifest-v1.json @@ -0,0 +1,671 @@ +{ + "production": { + "kind": "comic-production", + "spec_version": "1.0.0", + "production_id": "urn:uuid:10000000-0000-4000-8000-000000000001", + "revision": 1, + "previous": null, + "classification": "internal", + "title": "Synthetic Shapes", + "intent": "Offline conformance only; no Studio canon.", + "inputs": { + "canon": { + "repository": "synthetic/canon", + "version": "1.0.0", + "tag": "canon/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/canon", + "media_type": "application/json", + "byte_size": 18, + "sha256": "sha256:a8198524f58e72b56283ab71ebddada22840f108b46ef7165bb3fca9919c5558" + } + }, + "dependencies": [ + { + "repository": "synthetic/mock-tool", + "version": "1.0.0", + "tag": "mock-tool/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/mock-tool", + "media_type": "application/json", + "byte_size": 22, + "sha256": "sha256:b5b94381f12f81d18bc1fc6fed0b04254162f21361e4d999ab356cc14cc464cf" + } + }, + { + "repository": "synthetic/comic-manifest", + "version": "1.0.0", + "tag": "comic-manifest/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/comic-manifest", + "media_type": "application/json", + "byte_size": 29, + "sha256": "sha256:836b922aa06e1e4759a9ee86412b96b8502bfe992092a10bfc08d97e390ffa47" + } + } + ], + "prompts": [ + { + "binding_id": "description", + "definition": { + "repository": "synthetic/prompt", + "version": "1.0.0", + "tag": "prompt/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/prompt", + "media_type": "application/json", + "byte_size": 2629, + "sha256": "sha256:7d127a76b06a3db563f2935dc0f0d03efa2fcb5d8fe4a13492860497ee6b9064" + } + }, + "prompt_id": "prompt.reference.context-builder", + "prompt_version": "1.0.0", + "identity": { + "canonicalization": "studio-json-v1", + "byte_size": 2629, + "sha256": "sha256:7d127a76b06a3db563f2935dc0f0d03efa2fcb5d8fe4a13492860497ee6b9064" + }, + "context": { + "contract_version": "1.0.0", + "package_id": "context-package.reference.builder", + "package_version": "1.0.0", + "instance_id": "urn:uuid:00000000-0000-4000-8000-000000000064", + "manifest_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 1769, + "sha256": "sha256:a287bcbe601550c2a4df68b296c64d622591fc91aa5713e8ea6e2e6119f04eab" + }, + "classification": "internal", + "purpose": "Prepare synthetic context for contract conformance.", + "sections": [ + "approved_notes", + "context_facts" + ], + "builder_result_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 2848, + "sha256": "sha256:729ce7ad380821185cecb4166e6bdd681048097450aa9256505f18c3dafa48b4" + }, + "preparation_reference": "urn:uuid:00000000-0000-4000-8000-000000000063", + "use_authorization_reference": "urn:uuid:00000000-0000-4000-8000-000000000071" + } + } + ], + "assets": [] + }, + "panels": [ + { + "panel_id": "first", + "description": "A synthetic blue cube.", + "text": [ + { + "text_id": "caption-one", + "kind": "caption", + "speaker": null, + "text": "A cube." + } + ], + "asset_ids": [], + "prompt_bindings": [ + "description" + ] + }, + { + "panel_id": "second", + "description": "A synthetic red sphere.", + "text": [ + { + "text_id": "caption-two", + "kind": "caption", + "speaker": null, + "text": "A sphere." + } + ], + "asset_ids": [], + "prompt_bindings": [] + } + ], + "renditions": [ + { + "rendition_id": "transcript", + "required": true, + "media_type": "text/plain", + "dimensions": null, + "alt_text": "A blue cube, followed by a red sphere.", + "transcript": "Panel 1: A cube.\nPanel 2: A sphere.", + "rights_notice": "Synthetic conformance fixture; Apache-2.0." + } + ] + }, + "result": { + "kind": "comic-build-result", + "spec_version": "1.0.0", + "result_id": "urn:uuid:10000000-0000-4000-8000-000000000002", + "attempt_id": "urn:uuid:10000000-0000-4000-8000-000000000003", + "production": { + "production_id": "urn:uuid:10000000-0000-4000-8000-000000000001", + "revision": 1, + "identity": { + "canonicalization": "studio-json-v1", + "byte_size": 3359, + "sha256": "sha256:9447b652a4ab121bf5355e5faa21a224b2d6d4259d403c005580b757511d1e19" + } + }, + "classification": "internal", + "inputs": { + "canon": { + "repository": "synthetic/canon", + "version": "1.0.0", + "tag": "canon/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/canon", + "media_type": "application/json", + "byte_size": 18, + "sha256": "sha256:a8198524f58e72b56283ab71ebddada22840f108b46ef7165bb3fca9919c5558" + } + }, + "dependencies": [ + { + "repository": "synthetic/mock-tool", + "version": "1.0.0", + "tag": "mock-tool/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/mock-tool", + "media_type": "application/json", + "byte_size": 22, + "sha256": "sha256:b5b94381f12f81d18bc1fc6fed0b04254162f21361e4d999ab356cc14cc464cf" + } + }, + { + "repository": "synthetic/comic-manifest", + "version": "1.0.0", + "tag": "comic-manifest/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/comic-manifest", + "media_type": "application/json", + "byte_size": 29, + "sha256": "sha256:836b922aa06e1e4759a9ee86412b96b8502bfe992092a10bfc08d97e390ffa47" + } + } + ], + "prompts": [ + { + "binding_id": "description", + "definition": { + "repository": "synthetic/prompt", + "version": "1.0.0", + "tag": "prompt/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/prompt", + "media_type": "application/json", + "byte_size": 2629, + "sha256": "sha256:7d127a76b06a3db563f2935dc0f0d03efa2fcb5d8fe4a13492860497ee6b9064" + } + }, + "prompt_id": "prompt.reference.context-builder", + "prompt_version": "1.0.0", + "identity": { + "canonicalization": "studio-json-v1", + "byte_size": 2629, + "sha256": "sha256:7d127a76b06a3db563f2935dc0f0d03efa2fcb5d8fe4a13492860497ee6b9064" + }, + "context": { + "contract_version": "1.0.0", + "package_id": "context-package.reference.builder", + "package_version": "1.0.0", + "instance_id": "urn:uuid:00000000-0000-4000-8000-000000000064", + "manifest_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 1769, + "sha256": "sha256:a287bcbe601550c2a4df68b296c64d622591fc91aa5713e8ea6e2e6119f04eab" + }, + "classification": "internal", + "purpose": "Prepare synthetic context for contract conformance.", + "sections": [ + "approved_notes", + "context_facts" + ], + "builder_result_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 2848, + "sha256": "sha256:729ce7ad380821185cecb4166e6bdd681048097450aa9256505f18c3dafa48b4" + }, + "preparation_reference": "urn:uuid:00000000-0000-4000-8000-000000000063", + "use_authorization_reference": "urn:uuid:00000000-0000-4000-8000-000000000071" + } + } + ], + "assets": [] + }, + "status": "complete", + "outputs": [ + { + "rendition_id": "transcript", + "artifact": { + "artifact_uri": "urn:uuid:10000000-0000-4000-8000-000000000010", + "media_type": "text/plain", + "byte_size": 36, + "sha256": "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + }, + "dimensions": null, + "rights_notice": "Synthetic conformance fixture; Apache-2.0.", + "alt_text": "A blue cube, followed by a red sphere.", + "transcript": "Panel 1: A cube.\nPanel 2: A sphere." + } + ], + "gates": [ + { + "gate": "integrity", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000020", + "rationale": "Synthetic bytes verified." + } + ], + "execution": { + "tool": { + "repository": "synthetic/mock-tool", + "version": "1.0.0", + "tag": "mock-tool/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/mock-tool", + "media_type": "application/json", + "byte_size": 22, + "sha256": "sha256:b5b94381f12f81d18bc1fc6fed0b04254162f21361e4d999ab356cc14cc464cf" + } + }, + "workflow_id": "synthetic-offline", + "run_uri": null, + "started_at": "2026-09-15T12:00:00Z", + "finished_at": "2026-09-15T12:00:01Z", + "transformations": [ + { + "step_id": "mock", + "input_digests": [ + "sha256:a8198524f58e72b56283ab71ebddada22840f108b46ef7165bb3fca9919c5558", + "sha256:9447b652a4ab121bf5355e5faa21a224b2d6d4259d403c005580b757511d1e19" + ], + "output_digests": [ + "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + ], + "private_inputs_withheld": false, + "private_outputs_withheld": false + } + ], + "generation": [], + "reproducibility": "exact", + "limitations": "Fixed synthetic text only; no external generation." + }, + "diagnostics": [] + }, + "release": { + "kind": "comic-public-release", + "spec_version": "1.0.0", + "release_id": "urn:uuid:10000000-0000-4000-8000-000000000004", + "episode_id": "DS-0001", + "revision": 1, + "previous": null, + "classification": "public", + "title": "Synthetic Shapes", + "production_credit": "A Definitely Secure Studio production.", + "canon_scope": "None; synthetic test identity does not reserve a real publication number.", + "scope": { + "destination": "https://example.invalid/synthetic/archive", + "audience": "synthetic-test", + "purpose": "Offline conformance only.", + "publication_time": "2026-09-15T12:10:00Z" + }, + "input_canon": { + "repository": "synthetic/canon", + "version": "1.0.0", + "tag": "canon/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/canon", + "media_type": "application/json", + "byte_size": 18, + "sha256": "sha256:a8198524f58e72b56283ab71ebddada22840f108b46ef7165bb3fca9919c5558" + } + }, + "dependencies": [ + { + "repository": "synthetic/mock-tool", + "version": "1.0.0", + "tag": "mock-tool/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/mock-tool", + "media_type": "application/json", + "byte_size": 22, + "sha256": "sha256:b5b94381f12f81d18bc1fc6fed0b04254162f21361e4d999ab356cc14cc464cf" + } + }, + { + "repository": "synthetic/comic-manifest", + "version": "1.0.0", + "tag": "comic-manifest/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/comic-manifest", + "media_type": "application/json", + "byte_size": 29, + "sha256": "sha256:836b922aa06e1e4759a9ee86412b96b8502bfe992092a10bfc08d97e390ffa47" + } + }, + { + "repository": "synthetic/prompt", + "version": "1.0.0", + "tag": "prompt/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/prompt", + "media_type": "application/json", + "byte_size": 2629, + "sha256": "sha256:7d127a76b06a3db563f2935dc0f0d03efa2fcb5d8fe4a13492860497ee6b9064" + } + } + ], + "outputs": [ + { + "rendition_id": "transcript", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/transcript.txt", + "media_type": "text/plain", + "byte_size": 36, + "sha256": "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + }, + "dimensions": null, + "rights_notice": "Synthetic conformance fixture; Apache-2.0.", + "alt_text": "A blue cube, followed by a red sphere.", + "transcript": "Panel 1: A cube.\nPanel 2: A sphere." + } + ], + "gates": [ + { + "gate": "editorial", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000100", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "canon-continuity", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000101", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "visual-text", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000102", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "integrity", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000103", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "provenance", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000104", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "security-privacy", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000105", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "rights", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000106", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "accessibility", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000107", + "rationale": "Synthetic reviewed fixture only." + }, + { + "gate": "packaging", + "disposition": "pass", + "evidence_reference": "urn:uuid:10000000-0000-4000-8000-000000000108", + "rationale": "Synthetic reviewed fixture only." + } + ], + "execution": { + "tool": { + "repository": "synthetic/mock-tool", + "version": "1.0.0", + "tag": "mock-tool/v1.0.0", + "commit": "1111111111111111111111111111111111111111", + "artifact": { + "artifact_uri": "https://example.invalid/synthetic/mock-tool", + "media_type": "application/json", + "byte_size": 22, + "sha256": "sha256:b5b94381f12f81d18bc1fc6fed0b04254162f21361e4d999ab356cc14cc464cf" + } + }, + "workflow_id": "synthetic-offline", + "run_uri": null, + "started_at": "2026-09-15T12:00:00Z", + "finished_at": "2026-09-15T12:00:01Z", + "transformations": [ + { + "step_id": "mock", + "input_digests": [ + "sha256:a8198524f58e72b56283ab71ebddada22840f108b46ef7165bb3fca9919c5558" + ], + "output_digests": [ + "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + ], + "private_inputs_withheld": true, + "private_outputs_withheld": false + } + ], + "generation": [], + "reproducibility": "exact", + "limitations": "Fixed synthetic text only; no external generation." + }, + "approvers": [ + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000200", + "role": "publisher", + "actor": "synthetic-publisher", + "decided_at": "2026-09-15T12:02:00Z" + }, + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000201", + "role": "canon-editor", + "actor": "synthetic-canon-editor", + "decided_at": "2026-09-15T12:02:00Z" + }, + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000202", + "role": "disclosure-reviewer", + "actor": "synthetic-disclosure-reviewer", + "decided_at": "2026-09-15T12:02:00Z" + } + ], + "private_context": { + "influenced": true, + "attestation_reference": "urn:uuid:10000000-0000-4000-8000-000000000300" + } + }, + "approvals": [ + { + "kind": "comic-approval-binding", + "spec_version": "1.0.0", + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000199", + "role": "production-reviewer", + "actor": "synthetic-production-reviewer", + "decided_at": "2026-09-15T12:02:00Z", + "subject": { + "canonicalization": "studio-json-v1", + "byte_size": 3359, + "sha256": "sha256:9447b652a4ab121bf5355e5faa21a224b2d6d4259d403c005580b757511d1e19" + }, + "artifact_digests": [], + "scope": { + "destination": "https://example.invalid/synthetic/archive", + "audience": "synthetic-test", + "purpose": "Offline conformance only.", + "publication_time": "2026-09-15T12:10:00Z" + }, + "expires_at": "2026-09-16T00:00:00Z", + "authority_reference": "urn:uuid:10000000-0000-4000-8000-000000000400" + }, + { + "kind": "comic-approval-binding", + "spec_version": "1.0.0", + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000200", + "role": "publisher", + "actor": "synthetic-publisher", + "decided_at": "2026-09-15T12:02:00Z", + "subject": { + "canonicalization": "studio-json-v1", + "byte_size": 5269, + "sha256": "sha256:1d2b5e1bfc49f40ceea1662b04d7380735b82f730f55a61cc71f5a6696b750c2" + }, + "artifact_digests": [ + "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + ], + "scope": { + "destination": "https://example.invalid/synthetic/archive", + "audience": "synthetic-test", + "purpose": "Offline conformance only.", + "publication_time": "2026-09-15T12:10:00Z" + }, + "expires_at": "2026-09-16T00:00:00Z", + "authority_reference": "urn:uuid:10000000-0000-4000-8000-000000000400" + }, + { + "kind": "comic-approval-binding", + "spec_version": "1.0.0", + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000201", + "role": "canon-editor", + "actor": "synthetic-canon-editor", + "decided_at": "2026-09-15T12:02:00Z", + "subject": { + "canonicalization": "studio-json-v1", + "byte_size": 5269, + "sha256": "sha256:1d2b5e1bfc49f40ceea1662b04d7380735b82f730f55a61cc71f5a6696b750c2" + }, + "artifact_digests": [ + "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + ], + "scope": { + "destination": "https://example.invalid/synthetic/archive", + "audience": "synthetic-test", + "purpose": "Offline conformance only.", + "publication_time": "2026-09-15T12:10:00Z" + }, + "expires_at": "2026-09-16T00:00:00Z", + "authority_reference": "urn:uuid:10000000-0000-4000-8000-000000000400" + }, + { + "kind": "comic-approval-binding", + "spec_version": "1.0.0", + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000202", + "role": "disclosure-reviewer", + "actor": "synthetic-disclosure-reviewer", + "decided_at": "2026-09-15T12:02:00Z", + "subject": { + "canonicalization": "studio-json-v1", + "byte_size": 5269, + "sha256": "sha256:1d2b5e1bfc49f40ceea1662b04d7380735b82f730f55a61cc71f5a6696b750c2" + }, + "artifact_digests": [ + "sha256:5aa128a0dd0945b00ba3d71a5f7b5916e06f40c53048c31d74432eb03f4e764d" + ], + "scope": { + "destination": "https://example.invalid/synthetic/archive", + "audience": "synthetic-test", + "purpose": "Offline conformance only.", + "publication_time": "2026-09-15T12:10:00Z" + }, + "expires_at": "2026-09-16T00:00:00Z", + "authority_reference": "urn:uuid:10000000-0000-4000-8000-000000000400" + } + ], + "linkage": { + "production": { + "production_id": "urn:uuid:10000000-0000-4000-8000-000000000001", + "revision": 1, + "identity": { + "canonicalization": "studio-json-v1", + "byte_size": 3359, + "sha256": "sha256:9447b652a4ab121bf5355e5faa21a224b2d6d4259d403c005580b757511d1e19" + } + }, + "result_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 4465, + "sha256": "sha256:871cb595c8d3b44d6245fd9c86daf9aa9185b76081f918b5a44c4568062f1dcf" + }, + "release_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 5269, + "sha256": "sha256:1d2b5e1bfc49f40ceea1662b04d7380735b82f730f55a61cc71f5a6696b750c2" + }, + "attestation_reference": "urn:uuid:10000000-0000-4000-8000-000000000300" + }, + "at": "2026-09-15T12:10:00Z", + "output_bytes": { + "transcript": "Panel 1: A cube.\nPanel 2: A sphere.\n" + }, + "dependency_bytes": { + "https://example.invalid/synthetic/canon": "{\"synthetic\":true}", + "https://example.invalid/synthetic/mock-tool": "synthetic offline tool", + "https://example.invalid/synthetic/comic-manifest": "synthetic contract descriptor", + "https://example.invalid/synthetic/prompt": "{\"capabilities\":{\"optional\":[],\"required\":[\"text-generation\"]},\"context_slots\":[{\"accepted_classifications\":[\"public\",\"internal\"],\"accepted_media_types\":[\"text/plain\"],\"description\":\"Explicit synthetic notes.\",\"max_bytes\":100,\"name\":\"approved_notes\",\"required\":true},{\"accepted_classifications\":[\"internal\"],\"accepted_media_types\":[\"application/json\"],\"description\":\"Synthetic facts.\",\"max_bytes\":100,\"name\":\"context_facts\",\"required\":true},{\"accepted_classifications\":[\"public\"],\"accepted_media_types\":[\"text/plain\"],\"description\":\"Optional synthetic footer.\",\"max_bytes\":100,\"name\":\"optional_footer\",\"required\":false}],\"description\":\"Synthetic renderer fixture for an explicitly supplied public item.\",\"governance\":{\"constitution\":{\"commit\":\"a9cc8a503aa30e17820edc62ac95f7cbe10e0564\",\"tag\":\"constitution/v1.0.0\",\"version\":\"1.0.0\"},\"decision_owner\":\"@andrewperis\",\"evidence\":[\"https://github.com/DefinitelySecureStudio/studio/issues/63\"]},\"id\":\"prompt.reference.context-builder\",\"inputs\":[{\"classification\":\"public\",\"constraints\":{\"min_length\":1},\"description\":\"Synthetic public item name.\",\"name\":\"item\",\"required\":true,\"type\":\"string\"},{\"classification\":\"public\",\"description\":\"Synthetic attributes.\",\"name\":\"attributes\",\"required\":true,\"type\":\"object\"},{\"classification\":\"public\",\"default\":true,\"description\":\"Request concise output.\",\"name\":\"concise\",\"required\":false,\"type\":\"boolean\"}],\"lifecycle\":{\"status\":\"draft\"},\"name\":\"Describe a public item\",\"output\":{\"description\":\"A synthetic plain-text description for human review.\",\"kind\":\"text\",\"media_type\":\"text/plain\"},\"owners\":[\"@andrewperis\"],\"provenance\":{\"created_at\":\"2026-08-17T00:00:00Z\",\"created_by\":\"@andrewperis\",\"origin\":\"studio-original\",\"rights\":{\"basis\":\"studio-original\",\"notices\":[],\"reviewed_at\":\"2026-08-17T00:00:00Z\",\"reviewed_by\":\"@andrewperis\"},\"source_references\":[]},\"purpose\":\"Exercise provider-neutral rendering; it does not retrieve data, approve output, or establish Canon.\",\"spec_version\":\"1.0.0\",\"template\":{\"format\":\"studio-messages-v1\",\"messages\":[{\"parts\":[{\"text\":\"Describe the explicit item using only supplied inputs and context.\",\"type\":\"text\"}],\"role\":\"instruction\"},{\"parts\":[{\"text\":\"Item: \",\"type\":\"text\"},{\"name\":\"item\",\"type\":\"input\"},{\"text\":\"\\nAttributes: \",\"type\":\"text\"},{\"format\":\"json\",\"name\":\"attributes\",\"type\":\"input\"},{\"text\":\"\\nConcise: \",\"type\":\"text\"},{\"format\":\"text\",\"name\":\"concise\",\"type\":\"input\"},{\"text\":\"\\nNotes: \",\"type\":\"text\"},{\"slot\":\"approved_notes\",\"type\":\"context\"},{\"format\":\"json\",\"slot\":\"context_facts\",\"type\":\"context\"},{\"slot\":\"optional_footer\",\"type\":\"context\"}],\"role\":\"user\"}]},\"version\":\"1.0.0\"}" + }, + "protected_sentinels": [ + "SYNTHETIC-PROTECTED-SENTINEL" + ], + "trust": { + "approvals": [ + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000199", + "sha256": "sha256:21cf0df439e7d871bb1af47e40b9a8b65e87c3d0e0d1b347612cc5a6c3ec09d5" + }, + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000200", + "sha256": "sha256:9b08c55b7da322ba912971c7a04c66518b62972acfc9a01e76e52c765f397603" + }, + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000201", + "sha256": "sha256:ec2b4192b3c31f50be3ec5628a97d181090530d30baa1fe56c5a4295c67740c8" + }, + { + "decision_id": "urn:uuid:10000000-0000-4000-8000-000000000202", + "sha256": "sha256:310efb68d2464edebedc0505456c402e04770c26e3f782c1d89104a7b2fffc94" + } + ], + "revoked": [], + "not_applicable": [], + "assignment": { + "production_id": "urn:uuid:10000000-0000-4000-8000-000000000001", + "episode_id": "DS-0001" + }, + "attestation": { + "reference": "urn:uuid:10000000-0000-4000-8000-000000000300", + "linkage_identity": { + "canonicalization": "studio-json-v1", + "byte_size": 627, + "sha256": "sha256:0fa52c096dcc5e041979fd5887bf0938abc0a486b4b659c19b6414ae43b43e0b" + } + } + } +} diff --git a/tests/fixtures/comic-manifest-v1.schema.json b/tests/fixtures/comic-manifest-v1.schema.json new file mode 100644 index 0000000..c340b02 --- /dev/null +++ b/tests/fixtures/comic-manifest-v1.schema.json @@ -0,0 +1,1315 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:definitely-secure:contract:comic-manifest:1.0.0:comic-manifest", + "title": "Comic Manifest v1 candidate \u2014 three records; detached approval via $defs/approval", + "oneOf": [ + { + "$ref": "#/$defs/production" + }, + { + "$ref": "#/$defs/result" + }, + { + "$ref": "#/$defs/release" + } + ], + "$defs": { + "uuid": { + "type": "string", + "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" + }, + "digest": { + "type": "string", + "pattern": "^sha256:[0-9a-f]{64}$" + }, + "name": { + "type": "string", + "pattern": "^[a-z][a-z0-9-]{0,63}$" + }, + "time": { + "type": "string", + "format": "date-time", + "pattern": "Z$", + "maxLength": 32 + }, + "size": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "revision": { + "type": "integer", + "minimum": 1, + "maximum": 9007199254740991 + }, + "classification": { + "enum": [ + "public", + "internal", + "confidential", + "restricted" + ] + }, + "uri": { + "type": "string", + "format": "uri", + "pattern": "^https://", + "maxLength": 2048 + }, + "identity": { + "type": "object", + "additionalProperties": false, + "required": [ + "canonicalization", + "byte_size", + "sha256" + ], + "properties": { + "canonicalization": { + "const": "studio-json-v1" + }, + "byte_size": { + "$ref": "#/$defs/size" + }, + "sha256": { + "$ref": "#/$defs/digest" + } + } + }, + "artifact": { + "type": "object", + "additionalProperties": false, + "required": [ + "artifact_uri", + "media_type", + "byte_size", + "sha256" + ], + "properties": { + "artifact_uri": { + "$ref": "#/$defs/uri" + }, + "media_type": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "byte_size": { + "$ref": "#/$defs/size" + }, + "sha256": { + "$ref": "#/$defs/digest" + } + } + }, + "dependency": { + "type": "object", + "additionalProperties": false, + "required": [ + "repository", + "version", + "tag", + "commit", + "artifact" + ], + "properties": { + "repository": { + "type": "string", + "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$", + "maxLength": 200 + }, + "version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" + }, + "tag": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "commit": { + "type": "string", + "pattern": "^[0-9a-f]{40}$" + }, + "artifact": { + "$ref": "#/$defs/artifact" + } + } + }, + "productionRef": { + "type": "object", + "additionalProperties": false, + "required": [ + "production_id", + "revision", + "identity" + ], + "properties": { + "production_id": { + "$ref": "#/$defs/uuid" + }, + "revision": { + "$ref": "#/$defs/revision" + }, + "identity": { + "$ref": "#/$defs/identity" + } + } + }, + "releaseRef": { + "type": "object", + "additionalProperties": false, + "required": [ + "release_id", + "episode_id", + "revision", + "identity" + ], + "properties": { + "release_id": { + "$ref": "#/$defs/uuid" + }, + "episode_id": { + "type": "string", + "pattern": "^DS-(?!0000)[0-9]{4}$" + }, + "revision": { + "$ref": "#/$defs/revision" + }, + "identity": { + "$ref": "#/$defs/identity" + } + } + }, + "context": { + "type": "object", + "additionalProperties": false, + "required": [ + "contract_version", + "package_id", + "package_version", + "instance_id", + "manifest_identity", + "classification", + "purpose", + "sections", + "builder_result_identity", + "preparation_reference", + "use_authorization_reference" + ], + "properties": { + "contract_version": { + "const": "1.0.0" + }, + "package_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "package_version": { + "type": "string", + "minLength": 1, + "maxLength": 32 + }, + "instance_id": { + "$ref": "#/$defs/uuid" + }, + "manifest_identity": { + "$ref": "#/$defs/identity" + }, + "classification": { + "$ref": "#/$defs/classification" + }, + "purpose": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "sections": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "minItems": 1, + "maxItems": 256 + }, + "builder_result_identity": { + "$ref": "#/$defs/identity" + }, + "preparation_reference": { + "$ref": "#/$defs/uuid" + }, + "use_authorization_reference": { + "$ref": "#/$defs/uuid" + } + } + }, + "prompt": { + "type": "object", + "additionalProperties": false, + "required": [ + "binding_id", + "definition", + "prompt_id", + "prompt_version", + "identity", + "context" + ], + "properties": { + "binding_id": { + "$ref": "#/$defs/name" + }, + "definition": { + "$ref": "#/$defs/dependency" + }, + "prompt_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "prompt_version": { + "type": "string", + "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" + }, + "identity": { + "$ref": "#/$defs/identity" + }, + "context": { + "anyOf": [ + { + "$ref": "#/$defs/context" + }, + { + "type": "null" + } + ] + } + } + }, + "asset": { + "type": "object", + "additionalProperties": false, + "required": [ + "asset_id", + "classification", + "reference", + "rights_notice" + ], + "properties": { + "asset_id": { + "$ref": "#/$defs/name" + }, + "classification": { + "$ref": "#/$defs/classification" + }, + "reference": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "dependency" + ], + "properties": { + "kind": { + "const": "public" + }, + "dependency": { + "$ref": "#/$defs/dependency" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "handle", + "media_type", + "byte_size", + "sha256" + ], + "properties": { + "kind": { + "const": "protected" + }, + "handle": { + "$ref": "#/$defs/uuid" + }, + "media_type": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "byte_size": { + "$ref": "#/$defs/size" + }, + "sha256": { + "$ref": "#/$defs/digest" + } + } + } + ] + }, + "rights_notice": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "inputs": { + "type": "object", + "additionalProperties": false, + "required": [ + "canon", + "dependencies", + "prompts", + "assets" + ], + "properties": { + "canon": { + "$ref": "#/$defs/dependency" + }, + "dependencies": { + "type": "array", + "items": { + "$ref": "#/$defs/dependency" + }, + "minItems": 1, + "maxItems": 256 + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/$defs/prompt" + }, + "minItems": 0, + "maxItems": 256 + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/$defs/asset" + }, + "minItems": 0, + "maxItems": 256 + } + } + }, + "panel": { + "type": "object", + "additionalProperties": false, + "required": [ + "panel_id", + "description", + "text", + "asset_ids", + "prompt_bindings" + ], + "properties": { + "panel_id": { + "$ref": "#/$defs/name" + }, + "description": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "text": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "text_id", + "kind", + "speaker", + "text" + ], + "properties": { + "text_id": { + "$ref": "#/$defs/name" + }, + "kind": { + "enum": [ + "dialogue", + "caption" + ] + }, + "speaker": { + "anyOf": [ + { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + { + "type": "null" + } + ] + }, + "text": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "minItems": 0, + "maxItems": 256 + }, + "asset_ids": { + "type": "array", + "items": { + "$ref": "#/$defs/name" + }, + "minItems": 0, + "maxItems": 256 + }, + "prompt_bindings": { + "type": "array", + "items": { + "$ref": "#/$defs/name" + }, + "minItems": 0, + "maxItems": 256 + } + } + }, + "dimensions": { + "anyOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "width", + "height" + ], + "properties": { + "width": { + "type": "integer", + "minimum": 1, + "maximum": 32768 + }, + "height": { + "type": "integer", + "minimum": 1, + "maximum": 32768 + } + } + }, + { + "type": "null" + } + ] + }, + "rendition": { + "type": "object", + "additionalProperties": false, + "required": [ + "rendition_id", + "required", + "media_type", + "dimensions", + "alt_text", + "transcript", + "rights_notice" + ], + "properties": { + "rendition_id": { + "$ref": "#/$defs/name" + }, + "required": { + "type": "boolean" + }, + "media_type": { + "enum": [ + "image/png", + "image/jpeg", + "image/webp", + "application/pdf", + "text/plain" + ] + }, + "dimensions": { + "$ref": "#/$defs/dimensions" + }, + "alt_text": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "transcript": { + "type": "string", + "minLength": 1, + "maxLength": 32768 + }, + "rights_notice": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "production": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "spec_version", + "production_id", + "revision", + "previous", + "classification", + "title", + "intent", + "inputs", + "panels", + "renditions" + ], + "properties": { + "kind": { + "const": "comic-production" + }, + "spec_version": { + "const": "1.0.0" + }, + "production_id": { + "$ref": "#/$defs/uuid" + }, + "revision": { + "$ref": "#/$defs/revision" + }, + "previous": { + "anyOf": [ + { + "$ref": "#/$defs/productionRef" + }, + { + "type": "null" + } + ] + }, + "classification": { + "$ref": "#/$defs/classification" + }, + "title": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "intent": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "inputs": { + "$ref": "#/$defs/inputs" + }, + "panels": { + "type": "array", + "items": { + "$ref": "#/$defs/panel" + }, + "minItems": 1, + "maxItems": 256 + }, + "renditions": { + "type": "array", + "items": { + "$ref": "#/$defs/rendition" + }, + "minItems": 1, + "maxItems": 32 + } + } + }, + "output": { + "type": "object", + "additionalProperties": false, + "required": [ + "rendition_id", + "artifact", + "dimensions", + "rights_notice", + "alt_text", + "transcript" + ], + "properties": { + "rendition_id": { + "$ref": "#/$defs/name" + }, + "artifact": { + "$ref": "#/$defs/artifact" + }, + "dimensions": { + "$ref": "#/$defs/dimensions" + }, + "rights_notice": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "alt_text": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "transcript": { + "type": "string", + "minLength": 1, + "maxLength": 32768 + } + } + }, + "buildOutput": { + "type": "object", + "additionalProperties": false, + "required": [ + "rendition_id", + "artifact", + "dimensions", + "rights_notice", + "alt_text", + "transcript" + ], + "properties": { + "rendition_id": { + "$ref": "#/$defs/name" + }, + "artifact": { + "type": "object", + "additionalProperties": false, + "required": [ + "artifact_uri", + "media_type", + "byte_size", + "sha256" + ], + "properties": { + "artifact_uri": { + "oneOf": [ + { + "$ref": "#/$defs/uri" + }, + { + "$ref": "#/$defs/uuid" + } + ] + }, + "media_type": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "byte_size": { + "$ref": "#/$defs/size" + }, + "sha256": { + "$ref": "#/$defs/digest" + } + } + }, + "dimensions": { + "$ref": "#/$defs/dimensions" + }, + "rights_notice": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "alt_text": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "transcript": { + "type": "string", + "minLength": 1, + "maxLength": 32768 + } + } + }, + "gate": { + "type": "object", + "additionalProperties": false, + "required": [ + "gate", + "disposition", + "evidence_reference", + "rationale" + ], + "properties": { + "gate": { + "enum": [ + "editorial", + "canon-continuity", + "visual-text", + "integrity", + "provenance", + "security-privacy", + "rights", + "accessibility", + "packaging" + ] + }, + "disposition": { + "enum": [ + "pass", + "fail", + "inconclusive", + "not-run", + "not-applicable" + ] + }, + "evidence_reference": { + "$ref": "#/$defs/uuid" + }, + "rationale": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "generation": { + "type": "object", + "additionalProperties": false, + "required": [ + "provider", + "model", + "parameters", + "evidence_state", + "limitations" + ], + "properties": { + "provider": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "model": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "parameters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "$ref": "#/$defs/name" + }, + "value": { + "type": "string", + "minLength": 1, + "maxLength": 1024 + } + } + }, + "minItems": 0, + "maxItems": 256 + }, + "evidence_state": { + "enum": [ + "recorded", + "unavailable", + "withheld" + ] + }, + "limitations": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "execution": { + "type": "object", + "additionalProperties": false, + "required": [ + "tool", + "workflow_id", + "run_uri", + "started_at", + "finished_at", + "transformations", + "generation", + "reproducibility", + "limitations" + ], + "properties": { + "tool": { + "$ref": "#/$defs/dependency" + }, + "workflow_id": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "run_uri": { + "anyOf": [ + { + "$ref": "#/$defs/uri" + }, + { + "type": "null" + } + ] + }, + "started_at": { + "$ref": "#/$defs/time" + }, + "finished_at": { + "$ref": "#/$defs/time" + }, + "transformations": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "step_id", + "input_digests", + "output_digests", + "private_inputs_withheld", + "private_outputs_withheld" + ], + "properties": { + "step_id": { + "$ref": "#/$defs/name" + }, + "input_digests": { + "type": "array", + "items": { + "$ref": "#/$defs/digest" + }, + "minItems": 0, + "maxItems": 256 + }, + "output_digests": { + "type": "array", + "items": { + "$ref": "#/$defs/digest" + }, + "minItems": 0, + "maxItems": 256 + }, + "private_inputs_withheld": { + "type": "boolean" + }, + "private_outputs_withheld": { + "type": "boolean" + } + } + }, + "minItems": 1, + "maxItems": 256 + }, + "generation": { + "type": "array", + "items": { + "$ref": "#/$defs/generation" + }, + "minItems": 0, + "maxItems": 256 + }, + "reproducibility": { + "enum": [ + "exact", + "partial", + "audit-only" + ] + }, + "limitations": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + } + } + }, + "result": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "spec_version", + "result_id", + "attempt_id", + "production", + "classification", + "inputs", + "status", + "outputs", + "gates", + "execution", + "diagnostics" + ], + "properties": { + "kind": { + "const": "comic-build-result" + }, + "spec_version": { + "const": "1.0.0" + }, + "result_id": { + "$ref": "#/$defs/uuid" + }, + "attempt_id": { + "$ref": "#/$defs/uuid" + }, + "production": { + "$ref": "#/$defs/productionRef" + }, + "classification": { + "$ref": "#/$defs/classification" + }, + "inputs": { + "$ref": "#/$defs/inputs" + }, + "status": { + "enum": [ + "complete", + "partial", + "failed" + ] + }, + "outputs": { + "type": "array", + "items": { + "$ref": "#/$defs/buildOutput" + }, + "minItems": 0, + "maxItems": 32 + }, + "gates": { + "type": "array", + "items": { + "$ref": "#/$defs/gate" + }, + "minItems": 0, + "maxItems": 9 + }, + "execution": { + "$ref": "#/$defs/execution" + }, + "diagnostics": { + "type": "array", + "items": { + "enum": [ + "INPUT_MISMATCH", + "OUTPUT_MISSING", + "OUTPUT_INTEGRITY", + "AUTHORITY_DENIED", + "VALIDATION_FAILED", + "CANCELLED" + ] + }, + "minItems": 0, + "maxItems": 32 + } + }, + "allOf": [ + { + "if": { + "properties": { + "status": { + "const": "complete" + } + } + }, + "then": { + "properties": { + "outputs": { + "minItems": 1 + }, + "diagnostics": { + "maxItems": 0 + } + } + }, + "else": { + "properties": { + "diagnostics": { + "minItems": 1 + } + } + } + } + ] + }, + "scope": { + "type": "object", + "additionalProperties": false, + "required": [ + "destination", + "audience", + "purpose", + "publication_time" + ], + "properties": { + "destination": { + "$ref": "#/$defs/uri" + }, + "audience": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "purpose": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "publication_time": { + "$ref": "#/$defs/time" + } + } + }, + "approver": { + "type": "object", + "additionalProperties": false, + "required": [ + "decision_id", + "role", + "actor", + "decided_at" + ], + "properties": { + "decision_id": { + "$ref": "#/$defs/uuid" + }, + "role": { + "enum": [ + "publisher", + "canon-editor", + "disclosure-reviewer" + ] + }, + "actor": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "decided_at": { + "$ref": "#/$defs/time" + } + } + }, + "release": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "spec_version", + "release_id", + "episode_id", + "revision", + "previous", + "classification", + "title", + "production_credit", + "canon_scope", + "scope", + "input_canon", + "dependencies", + "outputs", + "gates", + "execution", + "approvers", + "private_context" + ], + "properties": { + "kind": { + "const": "comic-public-release" + }, + "spec_version": { + "const": "1.0.0" + }, + "release_id": { + "$ref": "#/$defs/uuid" + }, + "episode_id": { + "type": "string", + "pattern": "^DS-(?!0000)[0-9]{4}$" + }, + "revision": { + "$ref": "#/$defs/revision" + }, + "previous": { + "anyOf": [ + { + "$ref": "#/$defs/releaseRef" + }, + { + "type": "null" + } + ] + }, + "classification": { + "const": "public" + }, + "title": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "production_credit": { + "const": "A Definitely Secure Studio production." + }, + "canon_scope": { + "type": "string", + "minLength": 1, + "maxLength": 4096 + }, + "scope": { + "$ref": "#/$defs/scope" + }, + "input_canon": { + "$ref": "#/$defs/dependency" + }, + "dependencies": { + "type": "array", + "items": { + "$ref": "#/$defs/dependency" + }, + "minItems": 1, + "maxItems": 256 + }, + "outputs": { + "type": "array", + "items": { + "$ref": "#/$defs/output" + }, + "minItems": 1, + "maxItems": 32 + }, + "gates": { + "type": "array", + "items": { + "$ref": "#/$defs/gate" + }, + "minItems": 9, + "maxItems": 9 + }, + "execution": { + "$ref": "#/$defs/execution" + }, + "approvers": { + "type": "array", + "items": { + "$ref": "#/$defs/approver" + }, + "minItems": 2, + "maxItems": 16 + }, + "private_context": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": [ + "influenced" + ], + "properties": { + "influenced": { + "const": false + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "influenced", + "attestation_reference" + ], + "properties": { + "influenced": { + "const": true + }, + "attestation_reference": { + "$ref": "#/$defs/uuid" + } + } + } + ] + } + } + }, + "approval": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "spec_version", + "decision_id", + "role", + "actor", + "subject", + "artifact_digests", + "scope", + "decided_at", + "expires_at", + "authority_reference" + ], + "properties": { + "kind": { + "const": "comic-approval-binding" + }, + "spec_version": { + "const": "1.0.0" + }, + "decision_id": { + "$ref": "#/$defs/uuid" + }, + "role": { + "enum": [ + "production-reviewer", + "publisher", + "canon-editor", + "disclosure-reviewer" + ] + }, + "actor": { + "type": "string", + "minLength": 1, + "maxLength": 200 + }, + "subject": { + "$ref": "#/$defs/identity" + }, + "artifact_digests": { + "type": "array", + "items": { + "$ref": "#/$defs/digest" + }, + "minItems": 0, + "maxItems": 256 + }, + "scope": { + "$ref": "#/$defs/scope" + }, + "decided_at": { + "$ref": "#/$defs/time" + }, + "expires_at": { + "$ref": "#/$defs/time" + }, + "authority_reference": { + "$ref": "#/$defs/uuid" + } + } + } + } +} diff --git a/tests/prompt-sdk/comic-manifest-contract.test.js b/tests/prompt-sdk/comic-manifest-contract.test.js new file mode 100644 index 0000000..6755151 --- /dev/null +++ b/tests/prompt-sdk/comic-manifest-contract.test.js @@ -0,0 +1,98 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { readFile } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import Ajv from 'ajv/dist/2020.js'; +import addFormats from 'ajv-formats'; +import { canonicalJson, validateContextDocument, validateContextBinding, renderPromptWithContextPackage, CONTEXT_PACKAGE_CONTRACT } from '../../src/prompt-sdk/index.js'; +const read = async path => JSON.parse(await readFile(new URL(path,import.meta.url))); +const lock = await read('../fixtures/comic-manifest-contract-lock.json'); +const schema = await read('../fixtures/comic-manifest-v1.schema.json'); +const fixture = await read('../fixtures/comic-manifest-v1.json'); +const foundation = await read('../fixtures/context-builder-v1.json'); +const hash = b => 'sha256:'+createHash('sha256').update(b).digest('hex'); +const identity = value => ({canonicalization:'studio-json-v1',byte_size:Buffer.byteLength(canonicalJson(value)),sha256:hash(canonicalJson(value))}); +const ajv = new Ajv({strict:true,strictRequired:false,strictTypes:false,allErrors:true});addFormats(ajv); +const validate = ajv.compile(schema); +const approval = ajv.compile({$ref:schema.$id+'#/$defs/approval'}); +// Bounded test consumer only: no Manifest runtime or approval verifier is exported. +function bind(s,f=foundation,at=s.at) { + const p=s.production,r=s.result,b=p.inputs.prompts[0],pkg=f.result.package; + assert.deepEqual(r.production,{production_id:p.production_id,revision:p.revision,identity:identity(p)}); + assert.deepEqual(r.inputs,p.inputs); + assert.deepEqual(b.identity,identity(f.prompt)); + assert.equal(b.prompt_id,f.prompt.id);assert.equal(b.prompt_version,f.prompt.version); + assert.deepEqual(b.context.manifest_identity,identity(pkg.manifest)); + assert.equal(b.context.package_id,pkg.manifest.package.id);assert.equal(b.context.package_version,pkg.manifest.package.version); + assert.equal(b.context.instance_id,pkg.manifest.package.instance_id); + assert.deepEqual(b.context.builder_result_identity,identity(f.result)); + assert.equal(b.context.preparation_reference,f.request.preparation_reference); + assert.equal(b.context.use_authorization_reference,f.authorization.decision_id); + assert.equal(b.context.purpose,pkg.manifest.purpose);assert.equal(b.context.classification,pkg.manifest.classification); + assert.deepEqual(b.context.sections,pkg.manifest.sections.map(x=>x.slot)); + assert.equal(validateContextDocument(pkg).valid,true); + const validation=validateContextBinding(f.prompt,pkg,f.authorization,{at}); + assert.equal(validation.valid,true,JSON.stringify(validation.diagnostics)); + return renderPromptWithContextPackage(f.prompt,{inputValues:{item:'blue cube',attributes:{}},packageDocument:pkg,authorization:f.authorization,at}); +} +test('Comic candidate schema/fixtures are exact Codex source pins, not production locks',async()=>{ + assert.equal(lock.status,'unreleased-test-only');assert.match(lock.commit,/^[0-9a-f]{40}$/); + assert.equal(CONTEXT_PACKAGE_CONTRACT.status,'released');assert.equal(CONTEXT_PACKAGE_CONTRACT.version,'1.0.0'); + for(const a of lock.artifacts) { + const bytes=await readFile(new URL('../../'+a.path,import.meta.url)); + assert.equal(bytes.length,a.byte_size);assert.equal(hash(bytes),a.sha256); + assert.equal(a.artifact_uri,`https://github.com/${lock.repository}/blob/${lock.commit}/${a.source_path}`); + } +}); +test('Platform AJV accepts all three Codex records and detached evidence',()=>{ + for(const kind of ['production','result','release'])assert.equal(validate(fixture[kind]),true,JSON.stringify(validate.errors)); + for(const a of fixture.approvals)assert.equal(approval(a),true,JSON.stringify(approval.errors)); +}); +test('released SDK consumes the exact Manifest-bound Builder package',()=>{ + const {renderedPrompt}=bind(fixture); + assert.equal(renderedPrompt.classification,'internal'); + assert.match(renderedPrompt.messages[1].content,/Synthetic approved note\./); + assert.match(renderedPrompt.messages[1].content,/"facts":\["synthetic"\]/); +}); +test('Platform canonical identity agrees with every Codex linkage and approval subject',()=>{ + assert.deepEqual(fixture.linkage.production.identity,identity(fixture.production)); + assert.deepEqual(fixture.linkage.result_identity,identity(fixture.result)); + assert.deepEqual(fixture.linkage.release_identity,identity(fixture.release)); + for(const a of fixture.approvals)assert.deepEqual(a.subject,identity(a.role==='production-reviewer'?fixture.production:fixture.release)); +}); +test('offline public verification needs only release data and published bytes',()=>{ + const {release,output_bytes,dependency_bytes}=fixture; + for(const o of release.outputs) { + const bytes=Buffer.from(output_bytes[o.rendition_id]);assert.equal(bytes.length,o.artifact.byte_size);assert.equal(hash(bytes),o.artifact.sha256); + } + for(const d of [release.input_canon,...release.dependencies]) { + const bytes=Buffer.from(dependency_bytes[d.artifact.artifact_uri]);assert.equal(bytes.length,d.artifact.byte_size);assert.equal(hash(bytes),d.artifact.sha256); + } + // Integrity does not certify disclosure or publication authority. + const publicText=JSON.stringify(release); + for(const secret of [fixture.production.production_id,fixture.result.result_id,identity(fixture.production).sha256, + identity(fixture.result).sha256,foundation.result.package.manifest_identity.sha256,...fixture.protected_sentinels])assert.equal(publicText.includes(secret),false); +}); +test('unknown behavior and protected identifiers cannot enter the public schema',()=>{ + for(const [key,value] of [['production_id',fixture.production.production_id],['allow',true],['spec_version','1.1.0']]) + assert.equal(validate({...fixture.release,[key]:value}),false); + const bad=structuredClone(fixture.release);bad.private_context.package_id=foundation.result.package.manifest.package.id;assert.equal(validate(bad),false); +}); +test('rehashed Manifest cannot substitute the package or target prompt',()=>{ + for(const mutate of [ + s=>s.production.inputs.prompts[0].context.instance_id=s.production.production_id, + s=>s.production.inputs.prompts[0].prompt_version='9.0.0', + s=>s.production.inputs.prompts[0].context.manifest_identity.sha256='sha256:'+'0'.repeat(64), + s=>s.production.inputs.prompts[0].context.sections=['other'] + ]) { + const s=structuredClone(fixture);mutate(s); + s.result.production.identity=identity(s.production);s.result.inputs=structuredClone(s.production.inputs); + assert.equal(validate(s.production),true);assert.throws(()=>bind(s)); + } +}); +test('historical build/preparation evidence cannot replace or renew current use authority',()=>{ + assert.throws(()=>bind(fixture,foundation,foundation.authorization.expires_at)); + const f=structuredClone(foundation);f.authorization=f.result;assert.throws(()=>bind(fixture,f)); + const denied=structuredClone(foundation);denied.authorization.decision='deny';assert.throws(()=>bind(fixture,denied)); + const wrongScope=structuredClone(foundation);wrongScope.authorization.purpose='different-purpose';assert.throws(()=>bind(fixture,wrongScope)); +});