diff --git a/README.md b/README.md index 9fd7e09..5669c08 100644 --- a/README.md +++ b/README.md @@ -22,18 +22,21 @@ same exact release bytes. ## Spacecraft finite-burn certificate -**Commit-scoped status:** this source snapshot was prepared as the **v1.7.5 -corrective release candidate** before publication. A tag or source snapshot does -not itself establish current GitHub publication state; consult the -[releases index](https://github.com/AnubisQuantumCipher/jackal/releases) and -the postpublication readback on `master`. The v1.7.5 tag page exists only after -publication. At this candidate commit, the -historical v1.7.4 release remained published and its 11 public assets had passed -download readback, but **v1.7.4 should not be used as the publication-grade -verifier bundle**. Its tag full-certificate campaign was cancelled at the -60-minute ceiling. The v1.7.5 candidate was prepared to close gaps in the -structured verdict, claim surfaces, executable archive, verification -instructions, and tag campaign before independent review and publication. +**Published state:** [JACKAL v1.7.5](https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5) +is the observed public **Latest** release and is neither a draft nor a +prerelease. Its qualified verdict is **CERTIFIED SAFE under the stated +finite-burn ODE model, supplied input bounds, and machine-checked +interval-certificate assumptions**. Fresh downloads reproduced all 12 uploaded +release asset byte identities and all 11 `SHA256SUMS` payload rows; the committed +[v1.7.5 readback receipt](release/evidence/spacecraft_burn_release_readback_v175.json) +binds the PR, merge, annotated tag, release metadata, asset sizes and hashes, +proof/checker/source/request/witness/review identities, hosted checks, plugin +identity, protected checkout, and explicit non-claims. + +The v1.7.4 release, tag, assets, and +[historical readback](release/evidence/spacecraft_burn_release_readback_v174.json) +remain immutable historical evidence. v1.7.4 is not the publication-grade +verifier bundle; v1.7.5 is the corrective published epoch. The published historical [v1.7.4 release](https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.4) added a repository/release formal certificate for the spacecraft finite-burn @@ -52,8 +55,9 @@ request, model, epoch, nonce, and receipt. See assurance boundary and physical-model non-claims. This lane does not add an MCP command. The ordered agent catalog remains 41 -tools; use the repo-local CLI now, and use v1.7.5 release assets only after the -fresh public-download readback is committed. +tools. Use either the repo-local CLI or the exact published v1.7.5 assets; the +[public-download readback](release/evidence/spacecraft_burn_release_readback_v175.json) +binds the release bytes without changing the plugin surface. JACKAL is written in **Anubis Safe mode**. It does not try to win by adding another wall of buttons. It treats a serious calculation as a bounded scientific claim: value, units, diff --git a/docs/superpowers/plans/2026-08-24-spacecraft-burn-formal-certification-v2.md b/docs/superpowers/plans/2026-08-24-spacecraft-burn-formal-certification-v2.md index 1a266ad..d77d5ca 100644 --- a/docs/superpowers/plans/2026-08-24-spacecraft-burn-formal-certification-v2.md +++ b/docs/superpowers/plans/2026-08-24-spacecraft-burn-formal-certification-v2.md @@ -939,38 +939,75 @@ binds its live Python/Git runtime to the proof identity, builds a deterministic safe-entry archive, and reproduces the checker and outer-verifier procedure. The v1.7.4 packager remains byte-for-byte unchanged. -- [ ] **Step 4: Complete a new independent review** +- [x] **Step 4: Complete a new independent review** Review the exact v1.7.5 candidate, including the Picard enclosure producer, formal checker, source binding, structured claims, and executable package. Record an internal independent-review report and clearance with zero unresolved release blockers; do not call it external peer review. -- [ ] **Step 5: Run every full release gate on the final reviewed candidate** +Completion evidence: reviewed commit +`54c9af66405c445d17735c92ee177cd652fc34b9` received 37 independent-review +passes; 17 findings were resolved, 1 was classified invalid, and 0 unresolved +release blockers remained. The review report and clearance bind the exact +reviewed candidate and preserve the internal-review/non-peer-review boundary. + +- [x] **Step 5: Run every full release gate on the final reviewed candidate** Run the full Lean build, axiom and admission audit, evidence reproduction, checker/verifier replay, mutation campaign, claim gate, package extraction replay, capability drift, all 41-tool plugin checks, skill validation, repository tests, and clean-diff checks from fresh state. -- [ ] **Step 6: Commit, push, review, merge, and verify the merge SHA** +Completion evidence: the full Lean build, admission/axiom audit, proof identity, +checker and outer-verifier replay, evidence reproduction, mutation campaign, +claim gate, capability/plugin checks, repository tests, and clean extraction +replay passed. Two complete campaigns were byte-identical across the five +decisive outputs; two deterministic package builds matched as 12-asset +directories, and `SHA256SUMS` verified all 11 payload rows. + +- [x] **Step 6: Commit, push, review, merge, and verify the merge SHA** Push the corrective branch, open a PR with exact proof and non-claim evidence, wait for every required check and review disposition, merge through repository convention, and then require every relevant workflow to pass on the exact remote `master` merge commit. -- [ ] **Step 7: Tag and publish v1.7.5 from the verified merge** +Completion evidence: PR +[17](https://github.com/AnubisQuantumCipher/jackal/pull/17) bound head +`eb69713918798f5828950d92f1003c66d2eb26ca` and merged as +`9a49f70b65b20907df40be99ee83e61e18adc7c5`. The required PR workflows and +the exact-merge `master` workflows completed successfully. + +- [x] **Step 7: Tag and publish v1.7.5 from the verified merge** Build and compare the release assets from the exact merge commit, create and push an annotated v1.7.5 tag, wait for all tag-triggered workflows, validate a draft with the explicit asset roster and checksums, and publish it as Latest only after every gate is green. -- [ ] **Step 8: Read back the public release and merge the closure receipt** +Completion evidence: annotated tag object +`1369dacf60101c2d196d577b0319b6d5c0a72aa8` peels to merge +`9a49f70b65b20907df40be99ee83e61e18adc7c5`; all three tag-triggered +workflows completed successfully. Public release +[377032844](https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5) +was published as Latest with 12 uploaded release assets and is neither a draft +nor a prerelease. + +- [x] **Step 8: Read back the public release and merge the closure receipt** Download every public asset into fresh storage, verify the tag target, sizes, hashes, `SHA256SUMS`, metadata, and the extracted verification procedure. Commit the v1.7.5 publication-readback receipt and final README state in a separate closure PR, merge it, and audit remote refs, plugin identity, and the untouched protected checkout one final time. + +Completion evidence: fresh public downloads reproduced all 12 uploaded release +asset sizes and SHA-256 identities, all 11 `SHA256SUMS` rows, the canonical +checker `ACCEPT`, the authoritative outer-verifier `ACCEPT`, and the public +Latest metadata. The +new `release/evidence/spacecraft_burn_release_readback_v175.json` records those +observations, the unchanged plugin/protected-checkout identities, and the +explicit non-claims. The closure commit containing that receipt and this final +prose is landed through this closure PR before terminal declaration; no PR +number is invented here. diff --git a/release/evidence/spacecraft_burn_release_readback_v175.json b/release/evidence/spacecraft_burn_release_readback_v175.json new file mode 100644 index 0000000..5645960 --- /dev/null +++ b/release/evidence/spacecraft_burn_release_readback_v175.json @@ -0,0 +1,330 @@ +{ + "schema": "jackal-spacecraft-burn-release-readback-v1", + "observed_at": "2026-08-26T10:16:27Z", + "terminal_state": "PUBLISHED_READBACK_VERIFIED", + "terminal_reason": "The public v1.7.5 release, annotated tag, all twelve uploaded release asset identities downloaded into fresh storage, eleven checksum rows, extracted checker, authoritative outer replay, PR gates, exact-master workflows, and exact-tag workflows were independently read back and matched.", + "repository": "https://github.com/AnubisQuantumCipher/jackal", + "pull_request": { + "number": 17, + "url": "https://github.com/AnubisQuantumCipher/jackal/pull/17", + "title": "fix(spacecraft): publish review-cleared v1.7.5 certification", + "base": "9a0aaca36956d1f85540888c02c879d4480fd840", + "head": "eb69713918798f5828950d92f1003c66d2eb26ca", + "reviewed_commit": "54c9af66405c445d17735c92ee177cd652fc34b9", + "merge_commit": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "merged_at": "2026-08-26T00:53:44Z", + "state": "merged", + "hosted_contexts": { + "observed": 5, + "passed": 5, + "failed": 0, + "contexts": [ + { + "name": "CodeRabbit", + "workflow": "CodeRabbit", + "event": "pull_request", + "state": "success", + "run_id": null, + "url": "", + "completed_at": null + }, + { + "name": "Gaussian/range source closures and axiom audits", + "workflow": "Formal proof identity gate", + "event": "pull_request", + "state": "success", + "run_id": 32895064449, + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32895064449/job/97955699232", + "completed_at": "2026-08-25T20:32:46Z" + }, + { + "name": "claim-kernel admission and surface locks (engine-free)", + "workflow": "Formal proof identity gate", + "event": "pull_request", + "state": "success", + "run_id": 32895064449, + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32895064449/job/97955699352", + "completed_at": "2026-08-25T20:23:43Z" + }, + { + "name": "macOS arm64 plugin gates", + "workflow": "JACKAL Codex plugin", + "event": "pull_request", + "state": "success", + "run_id": 32895064437, + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32895064437/job/97955699144", + "completed_at": "2026-08-25T20:23:58Z" + }, + { + "name": "full-certificate-campaign", + "workflow": "Spacecraft burn formal certificate gate", + "event": "pull_request", + "state": "success", + "run_id": 32895064617, + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32895064617/job/97955699372", + "completed_at": "2026-08-26T00:52:18Z", + "job_id": 97955699372, + "started_at": "2026-08-25T20:23:37Z", + "conclusion": "success" + } + ] + } + }, + "release": { + "id": 377032844, + "name": "JACKAL v1.7.5 - Spacecraft finite-burn certification", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5", + "tag": "v1.7.5", + "tag_object": "1369dacf60101c2d196d577b0319b6d5c0a72aa8", + "tag_commit": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "target_commitish": "master", + "created_at": "2026-08-26T05:28:03Z", + "published_at": "2026-08-26T09:57:14Z", + "latest": true, + "draft": false, + "prerelease": false, + "github_immutable_release_enabled": false, + "title_and_notes_byte_match": true, + "notes_sha256": "ae27adbb2447455326230682cf7c072e279036004bb67559a9532744a2522160", + "fresh_download_byte_matches": 12, + "fresh_download_checksum_rows_passed": 11, + "assets": [ + { + "name": "SHA256SUMS", + "bytes": 1075, + "sha256": "c177a260d5cecf5cf9341cab658f234b619cb2b81caed0f081ca592aecc65ba1", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/SHA256SUMS" + }, + { + "name": "VERIFICATION.md", + "bytes": 3429, + "sha256": "8e2ce70e223387ec297777e8e810d058a32cad4c6f94b44f9f595239b6b69c7a", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/VERIFICATION.md" + }, + { + "name": "baseline_receipt_v2.json", + "bytes": 14299, + "sha256": "489eaffcdb5445262a07443c7d02421d2363f9a7e52fbc081e21a1ed29d5a8ed", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/baseline_receipt_v2.json" + }, + { + "name": "baseline_witness_v2.cert", + "bytes": 35939138, + "sha256": "27d5b16e08dd9f1b39774adb455a43e129bb390b9c7462f87ba93cdade87204c", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/baseline_witness_v2.cert" + }, + { + "name": "independent_verification_v2.json", + "bytes": 1960, + "sha256": "de716e84319e63ee2971e06586414df692e7f1d69da802917e7aa28895876246", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/independent_verification_v2.json" + }, + { + "name": "instrument_validation_v2.json", + "bytes": 5937, + "sha256": "8cb4496d33b63123b4c5cc4ee8d8956a3ff767456f45aaf1299422fdd474628a", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/instrument_validation_v2.json" + }, + { + "name": "jackal-spacecraft-burn-v1.7.5-verifier-macos-arm64.tar.gz", + "bytes": 39423959, + "sha256": "7eae30a674c0d82f52644125d17025ae8aad82a7eeaa5801afbee49c220f1abf", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/jackal-spacecraft-burn-v1.7.5-verifier-macos-arm64.tar.gz" + }, + { + "name": "mutation_aba_v2.json", + "bytes": 13626, + "sha256": "542d0bb66359bb4960255c16bb9d8bf160f1d681e5960e630456d3995535ab35", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/mutation_aba_v2.json" + }, + { + "name": "request_v2.json", + "bytes": 533, + "sha256": "03bcad618ad60114007c74a384eb8c9432e3755b817e74bd5bdc9bd1ba6df3e7", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/request_v2.json" + }, + { + "name": "spacecraft_burn_independent_review_v175.md", + "bytes": 15026, + "sha256": "f7700a20d4ff86f010667e019de0dc62b39976e6290f76209bdedcc385144a51", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/spacecraft_burn_independent_review_v175.md" + }, + { + "name": "spacecraft_burn_proof_identity_v1.json", + "bytes": 31944, + "sha256": "dc786a6e73a01278b09b899abd54555a5d268a305d745f66c4bf5480527bf876", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/spacecraft_burn_proof_identity_v1.json" + }, + { + "name": "spacecraft_burn_review_clearance_v175.json", + "bytes": 358, + "sha256": "c65e33f86e60200643972e8b4f70a81ced214affe23c9049e029e91ee928c51b", + "url": "https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.5/spacecraft_burn_review_clearance_v175.json" + } + ] + }, + "hosted_checks": { + "post_merge_and_tag": [ + { + "run_id": 32916885112, + "workflow": "Formal proof identity gate", + "event": "push", + "ref": "master", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T00:53:47Z", + "completed_at": "2026-08-26T01:18:27Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32916885112" + }, + { + "run_id": 32916885108, + "workflow": "JACKAL Codex plugin", + "event": "push", + "ref": "master", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T00:53:47Z", + "completed_at": "2026-08-26T00:54:13Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32916885108" + }, + { + "run_id": 32916885129, + "workflow": "Spacecraft burn formal certificate gate", + "event": "push", + "ref": "master", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T00:53:47Z", + "completed_at": "2026-08-26T05:26:38Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32916885129", + "job_id": 98022337805, + "started_at": "2026-08-26T00:53:51Z" + }, + { + "run_id": 32934182467, + "workflow": "Formal proof identity gate", + "event": "push", + "ref": "v1.7.5", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T05:28:36Z", + "completed_at": "2026-08-26T05:37:39Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32934182467" + }, + { + "run_id": 32934182499, + "workflow": "JACKAL Codex plugin", + "event": "push", + "ref": "v1.7.5", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T05:28:36Z", + "completed_at": "2026-08-26T05:28:59Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32934182499" + }, + { + "run_id": 32934182495, + "workflow": "Spacecraft burn formal certificate gate", + "event": "push", + "ref": "v1.7.5", + "head_sha": "9a49f70b65b20907df40be99ee83e61e18adc7c5", + "conclusion": "success", + "created_at": "2026-08-26T05:28:36Z", + "completed_at": "2026-08-26T09:53:10Z", + "url": "https://github.com/AnubisQuantumCipher/jackal/actions/runs/32934182495", + "job_id": 98072135748, + "started_at": "2026-08-26T05:28:38Z" + } + ], + "all_master_push_runs_successful": true, + "all_tag_push_runs_successful": true + }, + "public_replay": { + "checksum_manifest_sha256": "c177a260d5cecf5cf9341cab658f234b619cb2b81caed0f081ca592aecc65ba1", + "checksum_rows_passed": 11, + "asset_byte_matches": 12, + "archive_safe_extraction_completed": true, + "checker_result_line": "ACCEPT theorem=spacecraft_burn_certified_safe status=formal-bounded margin_lo=51450379597827184853505075 margin_hi=97148190212754394888777802 model=jackal-spacecraft-finite-burn-ode-v2 epoch=v1.7.5", + "outer_verifier_status": "ACCEPT", + "outer_verifier_reasons": [], + "outer_verifier_output_sha256": "de716e84319e63ee2971e06586414df692e7f1d69da802917e7aa28895876246", + "structured_claim_gate": "PASS" + }, + "proof": { + "qualified_verdict": "CERTIFIED SAFE under the stated finite-burn ODE model, supplied input bounds, and machine-checked interval-certificate assumptions", + "assurance_class": "formal-bounded", + "model_id": "jackal-spacecraft-finite-burn-ode-v2", + "release_epoch": "v1.7.5", + "soundness_theorem": "JackalIv.Spacecraft.spacecraft_burn_certified_safe", + "observed_theorem_axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "tracked_lean_files": 57, + "source_closure_files": 23, + "named_theorems": 29, + "logical_admissions": 0, + "checker_sha256": "2e08149b735ff70a1f1b6606aeca46c9e4dbf2a7d12db2cdc0e80d37f325fa59", + "proof_identity_file_sha256": "dc786a6e73a01278b09b899abd54555a5d268a305d745f66c4bf5480527bf876", + "proof_identity_digest_sha256": "418854abbb009a25b020be6cb3799dfd3ae75d6619ad4f26032cc64fead924be", + "receipt_sha256": "489eaffcdb5445262a07443c7d02421d2363f9a7e52fbc081e21a1ed29d5a8ed", + "request_digest": "03bcad618ad60114007c74a384eb8c9432e3755b817e74bd5bdc9bd1ba6df3e7", + "witness_sha256": "27d5b16e08dd9f1b39774adb455a43e129bb390b9c7462f87ba93cdade87204c", + "producer_source_sha256": "d6e98c03e74847b8aea05600c3bae3681e59579506f2a0661504f6ea96e1c38a", + "independent_review": { + "method": "internal independent code review with adversarial security, proof, packaging, claims, integration, and CodeRabbit passes; not external academic peer review", + "completed_passes": 37, + "resolved_findings": 17, + "invalid_findings": 1, + "unresolved_release_blocking": 0, + "asset_sha256": "f7700a20d4ff86f010667e019de0dc62b39976e6290f76209bdedcc385144a51", + "clearance_sha256": "c65e33f86e60200643972e8b4f70a81ced214affe23c9049e029e91ee928c51b" + } + }, + "plugin": { + "impact": "none", + "reason": "The spacecraft certification correction changes no plugins/jackel bytes and introduces no new MCP tool; the installed 41-tool plugin remains byte-aligned with its source and cache.", + "version": "0.1.0+codex.20260824183637", + "tool_count": 41, + "unique_tool_count": 41, + "ordered_tool_names_sha256": "851a50fb7b82d23e2e4dc59d3617659e7f161ed4f2f9fb0bc572f6c939c459bd", + "full_definitions_sha256": "03279ea328d028371b336fe2eb9decf3caf500a21a8d988058e51696c3975df0", + "aggregate_identity_sha256": "b2d62d374a54ffdaf090df3a6ea24ef9f6a64f9dde8c5189c29d67bd3b12ece8", + "pinned_package_sha256": "68b0e7850fcb60358633908f70ffcf405cbbef103b04d3d93dd1298789e505ae", + "plugin_tests_passed": 220, + "capability_tests_passed": 35, + "source_cache_byte_match": true, + "verification_command": "diff -r plugins/jackel $HOME/.codex/plugins/cache/anubis-quantum-cipher/jackel/0.1.0+codex.20260824183637" + }, + "protected_checkout": { + "path": "$HOME/Desktop/Projects/jackal-calc", + "branch": "feat/mathematical-evidence-kernel-v1.6.0", + "head": "57739317b24250ff62fd9b23f67c760d9066ab94", + "tracked_changes": [], + "untracked_roots": [ + "jackal_calc.anb.zip", + "jackal_calc.md", + "spacecraft_burn_cert/", + "website/" + ], + "mutation_performed_by_publication_work": false + }, + "corrective_release": { + "required": false, + "target": "v1.7.5", + "status": "published-and-readback-verified", + "preserve_v1_7_4_bytes": true, + "v1_7_4_overwritten": false + }, + "nonclaims": [ + "The qualified verdict is conditional on the stated finite-burn ODE model, supplied input bounds, and machine-checked interval-certificate assumptions; it is not a certification of physical spacecraft hardware, sensors, actuators, model fidelity, or mission operations.", + "The system does not establish that the supplied input bounds are true for any real mission.", + "The theorem and checker do not establish the correctness of the Lean compiler, linker, operating system, hardware, or software supply chain.", + "The Python Picard witness generator and its source are not formally verified; they remain outside the Lean mathematical soundness base.", + "The review is an internal independent engineering review, not external academic peer review or third-party certification.", + "The proof identity and release checksums are unsigned SHA-256 bindings, not signatures or builder authentication.", + "This spacecraft release adds no new JACKEL tool and changes no plugin byte; the plugin remains the same 41-tool v1.7.3 runtime surface.", + "The v1.7.4 tag, release, assets, and historical readback remain immutable history and were not overwritten." + ] +} diff --git a/spacecraft_burn_cert/README.md b/spacecraft_burn_cert/README.md index 3dd5386..84e39dc 100644 --- a/spacecraft_burn_cert/README.md +++ b/spacecraft_burn_cert/README.md @@ -1,12 +1,12 @@ # Spacecraft finite-burn formal certificate -Commit-scoped publication state: this source snapshot is the v1.7.5 candidate -prepared before publication. It does not by itself establish current GitHub -release state. Consult the -[releases index](https://github.com/AnubisQuantumCipher/jackal/releases) and -the postpublication readback on `master`; the v1.7.5 tag page exists only after -publication. Use release assets only when those current checks bind their exact -bytes. +Published state: [JACKAL v1.7.5](https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5) +is the observed public Latest release and is neither a draft nor a prerelease. +Fresh downloads reproduced all 12 uploaded release assets and all 11 checksum +payload rows. The committed +[v1.7.5 readback](../release/evidence/spacecraft_burn_release_readback_v175.json) +binds the exact released bytes and publication metadata. The v1.7.4 release, +tag, assets, and readback remain immutable historical evidence. This lane certifies a universal lower bound for the finite-duration periapsis burn challenge. The publication verdict is: diff --git a/spacecraft_burn_cert/REPORT.md b/spacecraft_burn_cert/REPORT.md index 0928345..1b13e76 100644 --- a/spacecraft_burn_cert/REPORT.md +++ b/spacecraft_burn_cert/REPORT.md @@ -1,12 +1,13 @@ # Finite-duration periapsis burn certification report -Commit-scoped publication state: this source snapshot records the v1.7.5 -candidate prepared before publication. Neither this source snapshot nor a tag -alone proves the current GitHub release state. Consult the -[releases index](https://github.com/AnubisQuantumCipher/jackal/releases) and -the postpublication readback committed on `master`; the v1.7.5 tag page exists -only after publication. Only those current checks establish publication and -bind the released bytes. +Published state: [JACKAL v1.7.5](https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5) +is the observed public Latest release and is neither a draft nor a prerelease. +Fresh downloads reproduced all 12 uploaded release assets and all 11 checksum +payload rows. The committed +[v1.7.5 publication readback](../release/evidence/spacecraft_burn_release_readback_v175.json) +binds the PR, merge, annotated tag, release metadata, proof identities, and +released bytes. The v1.7.4 release, tag, assets, and readback remain immutable +historical evidence. ## Decisive result diff --git a/tests/spacecraft_burn_publication_state_test.py b/tests/spacecraft_burn_publication_state_test.py index a92c5fb..ce5f957 100644 --- a/tests/spacecraft_burn_publication_state_test.py +++ b/tests/spacecraft_burn_publication_state_test.py @@ -1,5 +1,6 @@ from __future__ import annotations +import copy import json import re import unittest @@ -10,11 +11,20 @@ README = ROOT / "README.md" PLAN = ROOT / "docs/superpowers/plans/2026-08-24-spacecraft-burn-formal-certification-v2.md" READBACK = ROOT / "release/evidence/spacecraft_burn_release_readback_v174.json" +READBACK_V175 = ( + ROOT / "release/evidence/spacecraft_burn_release_readback_v175.json" +) +SPACECRAFT_README = ROOT / "spacecraft_burn_cert/README.md" +REPORT = ROOT / "spacecraft_burn_cert/REPORT.md" MERGE_COMMIT = "9a0aaca36956d1f85540888c02c879d4480fd840" BRANCH_HEAD = "db1360be09be3cdfb259c251f8d914dc36450641" TAG_OBJECT = "b5cdf93e993aad0f9b735c644c91fe38eacad094" PLUGIN_VERSION = "0.1.0+codex.20260824183637" +V175_PR_HEAD = "eb69713918798f5828950d92f1003c66d2eb26ca" +V175_MERGE_COMMIT = "9a49f70b65b20907df40be99ee83e61e18adc7c5" +V175_TAG_OBJECT = "1369dacf60101c2d196d577b0319b6d5c0a72aa8" +V175_RELEASE_ID = 377032844 QUALIFIED_VERDICT = ( "CERTIFIED SAFE under the stated finite-burn ODE model, supplied input bounds, " "and machine-checked interval-certificate assumptions" @@ -46,6 +56,184 @@ "spacecraft_burn_proof_identity_v1.json": 20261, } +EXPECTED_V175_ASSETS = { + "SHA256SUMS": ( + 1075, + "c177a260d5cecf5cf9341cab658f234b619cb2b81caed0f081ca592aecc65ba1", + ), + "VERIFICATION.md": ( + 3429, + "8e2ce70e223387ec297777e8e810d058a32cad4c6f94b44f9f595239b6b69c7a", + ), + "baseline_receipt_v2.json": ( + 14299, + "489eaffcdb5445262a07443c7d02421d2363f9a7e52fbc081e21a1ed29d5a8ed", + ), + "baseline_witness_v2.cert": ( + 35939138, + "27d5b16e08dd9f1b39774adb455a43e129bb390b9c7462f87ba93cdade87204c", + ), + "independent_verification_v2.json": ( + 1960, + "de716e84319e63ee2971e06586414df692e7f1d69da802917e7aa28895876246", + ), + "instrument_validation_v2.json": ( + 5937, + "8cb4496d33b63123b4c5cc4ee8d8956a3ff767456f45aaf1299422fdd474628a", + ), + "jackal-spacecraft-burn-v1.7.5-verifier-macos-arm64.tar.gz": ( + 39423959, + "7eae30a674c0d82f52644125d17025ae8aad82a7eeaa5801afbee49c220f1abf", + ), + "mutation_aba_v2.json": ( + 13626, + "542d0bb66359bb4960255c16bb9d8bf160f1d681e5960e630456d3995535ab35", + ), + "request_v2.json": ( + 533, + "03bcad618ad60114007c74a384eb8c9432e3755b817e74bd5bdc9bd1ba6df3e7", + ), + "spacecraft_burn_independent_review_v175.md": ( + 15026, + "f7700a20d4ff86f010667e019de0dc62b39976e6290f76209bdedcc385144a51", + ), + "spacecraft_burn_proof_identity_v1.json": ( + 31944, + "dc786a6e73a01278b09b899abd54555a5d268a305d745f66c4bf5480527bf876", + ), + "spacecraft_burn_review_clearance_v175.json": ( + 358, + "c65e33f86e60200643972e8b4f70a81ced214affe23c9049e029e91ee928c51b", + ), +} + +V175_PROOF_IDENTITIES = { + "checker_sha256": "2e08149b735ff70a1f1b6606aeca46c9e4dbf2a7d12db2cdc0e80d37f325fa59", + "proof_identity_file_sha256": ( + "dc786a6e73a01278b09b899abd54555a5d268a305d745f66c4bf5480527bf876" + ), + "proof_identity_digest_sha256": ( + "418854abbb009a25b020be6cb3799dfd3ae75d6619ad4f26032cc64fead924be" + ), + "request_digest": "03bcad618ad60114007c74a384eb8c9432e3755b817e74bd5bdc9bd1ba6df3e7", + "witness_sha256": "27d5b16e08dd9f1b39774adb455a43e129bb390b9c7462f87ba93cdade87204c", + "producer_source_sha256": ( + "d6e98c03e74847b8aea05600c3bae3681e59579506f2a0661504f6ea96e1c38a" + ), +} + +CANONICAL_CHECKER_ACCEPT = ( + "ACCEPT theorem=spacecraft_burn_certified_safe status=formal-bounded " + "margin_lo=51450379597827184853505075 " + "margin_hi=97148190212754394888777802 " + "model=jackal-spacecraft-finite-burn-ode-v2 epoch=v1.7.5" +) +EXPECTED_PR_CONTEXTS = { + ("Spacecraft burn formal certificate gate", "full-certificate-campaign"), + ( + "Formal proof identity gate", + "Gaussian/range source closures and axiom audits", + ), + ( + "Formal proof identity gate", + "claim-kernel admission and surface locks (engine-free)", + ), + ("JACKAL Codex plugin", "macOS arm64 plugin gates"), + ("CodeRabbit", "CodeRabbit"), +} +EXPECTED_POST_MERGE_RUNS = { + 32916885108: ("JACKAL Codex plugin", "master"), + 32916885112: ("Formal proof identity gate", "master"), + 32916885129: ("Spacecraft burn formal certificate gate", "master"), + 32934182499: ("JACKAL Codex plugin", "v1.7.5"), + 32934182467: ("Formal proof identity gate", "v1.7.5"), + 32934182495: ("Spacecraft burn formal certificate gate", "v1.7.5"), +} + + +def assert_v175_security_contract( + testcase: unittest.TestCase, + receipt: dict, +) -> None: + release = receipt["release"] + assets = release["assets"] + names = [asset["name"] for asset in assets] + testcase.assertEqual(len(assets), 12) + testcase.assertEqual(len(set(names)), 12) + testcase.assertEqual( + { + asset["name"]: (asset["bytes"], asset["sha256"]) + for asset in assets + }, + EXPECTED_V175_ASSETS, + ) + testcase.assertTrue(release["title_and_notes_byte_match"]) + testcase.assertEqual( + release["notes_sha256"], + "ae27adbb2447455326230682cf7c072e279036004bb67559a9532744a2522160", + ) + testcase.assertEqual( + receipt["public_replay"], + { + "checksum_manifest_sha256": ( + "c177a260d5cecf5cf9341cab658f234b619cb2b81caed0f081ca592aecc65ba1" + ), + "checksum_rows_passed": 11, + "asset_byte_matches": 12, + "archive_safe_extraction_completed": True, + "checker_result_line": CANONICAL_CHECKER_ACCEPT, + "outer_verifier_status": "ACCEPT", + "outer_verifier_reasons": [], + "outer_verifier_output_sha256": ( + "de716e84319e63ee2971e06586414df692e7f1d69da802917e7aa28895876246" + ), + "structured_claim_gate": "PASS", + }, + ) + + hosted = receipt["pull_request"]["hosted_contexts"] + testcase.assertEqual( + (hosted["observed"], hosted["passed"], hosted["failed"]), + (5, 5, 0), + ) + contexts = hosted["contexts"] + testcase.assertEqual(len(contexts), 5) + testcase.assertEqual( + {(context["workflow"], context["name"]) for context in contexts}, + EXPECTED_PR_CONTEXTS, + ) + testcase.assertEqual({context["state"] for context in contexts}, {"success"}) + + runs = receipt["hosted_checks"]["post_merge_and_tag"] + testcase.assertEqual(len(runs), 6) + testcase.assertEqual( + { + run["run_id"]: (run["workflow"], run["ref"]) + for run in runs + }, + EXPECTED_POST_MERGE_RUNS, + ) + testcase.assertEqual({run["event"] for run in runs}, {"push"}) + testcase.assertEqual({run["head_sha"] for run in runs}, {V175_MERGE_COMMIT}) + testcase.assertEqual({run["conclusion"] for run in runs}, {"success"}) + + plugin = receipt["plugin"] + testcase.assertEqual( + plugin["ordered_tool_names_sha256"], + "851a50fb7b82d23e2e4dc59d3617659e7f161ed4f2f9fb0bc572f6c939c459bd", + ) + testcase.assertEqual( + plugin["full_definitions_sha256"], + "03279ea328d028371b336fe2eb9decf3caf500a21a8d988058e51696c3975df0", + ) + testcase.assertEqual( + plugin["pinned_package_sha256"], + "68b0e7850fcb60358633908f70ffcf405cbbef103b04d3d93dd1298789e505ae", + ) + testcase.assertTrue(plugin["source_cache_byte_match"]) + testcase.assertEqual(plugin["plugin_tests_passed"], 220) + testcase.assertEqual(plugin["capability_tests_passed"], 35) + class SpacecraftBurnPublicationStateTests(unittest.TestCase): def test_readme_reports_the_published_qualified_release(self): @@ -118,6 +306,271 @@ def test_readback_binds_remote_release_assets_plugin_and_protected_checkout(self ["jackal_calc.anb.zip", "jackal_calc.md", "spacecraft_burn_cert/", "website/"], ) + def test_v175_public_release_readback_binds_exact_remote_state(self): + self.assertTrue( + READBACK_V175.is_file(), + "published v1.7.5 release readback receipt is missing", + ) + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + self.assertEqual( + receipt["schema"], + "jackal-spacecraft-burn-release-readback-v1", + ) + self.assertEqual(receipt["terminal_state"], "PUBLISHED_READBACK_VERIFIED") + self.assertEqual(receipt["pull_request"]["number"], 17) + self.assertEqual(receipt["pull_request"]["head"], V175_PR_HEAD) + self.assertEqual( + receipt["pull_request"]["merge_commit"], + V175_MERGE_COMMIT, + ) + self.assertEqual(receipt["pull_request"]["state"], "merged") + release = receipt["release"] + self.assertEqual(release["id"], V175_RELEASE_ID) + self.assertEqual( + release["name"], + "JACKAL v1.7.5 - Spacecraft finite-burn certification", + ) + self.assertEqual( + release["url"], + "https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5", + ) + self.assertEqual(release["tag"], "v1.7.5") + self.assertEqual(release["tag_object"], V175_TAG_OBJECT) + self.assertEqual(release["tag_commit"], V175_MERGE_COMMIT) + self.assertTrue(release["latest"]) + self.assertFalse(release["draft"]) + self.assertFalse(release["prerelease"]) + self.assertEqual(release["fresh_download_byte_matches"], 12) + self.assertEqual(release["fresh_download_checksum_rows_passed"], 11) + assets = { + asset["name"]: (asset["bytes"], asset["sha256"]) + for asset in release["assets"] + } + self.assertEqual(assets, EXPECTED_V175_ASSETS) + + def test_v175_readback_binds_public_replay_and_unique_remote_rows(self): + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + assert_v175_security_contract(self, receipt) + + def test_v175_security_contract_rejects_laundered_readback_copies(self): + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + mutations = [] + + duplicate_asset = copy.deepcopy(receipt) + duplicate_asset["release"]["assets"].append( + copy.deepcopy(duplicate_asset["release"]["assets"][0]) + ) + mutations.append(("duplicate-asset", duplicate_asset)) + + missing_formal_context = copy.deepcopy(receipt) + missing_formal_context["pull_request"]["hosted_contexts"]["contexts"] = [ + context + for context in missing_formal_context["pull_request"][ + "hosted_contexts" + ]["contexts"] + if context["name"] + != "claim-kernel admission and surface locks (engine-free)" + ] + mutations.append(("missing-formal-context", missing_formal_context)) + + for label, path, replacement in ( + ( + "unsafe-extraction", + ("public_replay", "archive_safe_extraction_completed"), + False, + ), + ( + "notes-byte-drift", + ("release", "title_and_notes_byte_match"), + False, + ), + ( + "plugin-cache-drift", + ("plugin", "source_cache_byte_match"), + False, + ), + ( + "checker-refusal", + ("public_replay", "checker_result_line"), + "REJECT forged", + ), + ( + "outer-refusal", + ("public_replay", "outer_verifier_status"), + "REFUSED", + ), + ( + "outer-reasons", + ("public_replay", "outer_verifier_reasons"), + ["witness-hash-mismatch"], + ), + ( + "outer-output-drift", + ("public_replay", "outer_verifier_output_sha256"), + "0" * 64, + ), + ): + changed = copy.deepcopy(receipt) + target = changed + for component in path[:-1]: + target = target[component] + target[path[-1]] = replacement + mutations.append((label, changed)) + + for label, changed in mutations: + with self.subTest(label=label), self.assertRaises(AssertionError): + assert_v175_security_contract(self, changed) + + def test_v175_readback_binds_successful_pr_master_and_tag_workflows(self): + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + expected_pr_workflows = { + "CodeRabbit", + "Formal proof identity gate", + "JACKAL Codex plugin", + "Spacecraft burn formal certificate gate", + } + contexts = receipt["pull_request"]["hosted_contexts"]["contexts"] + self.assertTrue(contexts) + self.assertEqual( + {context["workflow"] for context in contexts}, + expected_pr_workflows, + ) + self.assertEqual({context["event"] for context in contexts}, {"pull_request"}) + self.assertEqual({context["state"] for context in contexts}, {"success"}) + + expected_push_workflows = { + "Formal proof identity gate", + "JACKAL Codex plugin", + "Spacecraft burn formal certificate gate", + } + runs = receipt["hosted_checks"]["post_merge_and_tag"] + for ref in ("master", "v1.7.5"): + selected = [run for run in runs if run["ref"] == ref] + self.assertEqual( + {run["workflow"] for run in selected}, + expected_push_workflows, + ) + self.assertEqual({run["event"] for run in selected}, {"push"}) + self.assertEqual( + {run["head_sha"] for run in selected}, + {V175_MERGE_COMMIT}, + ) + self.assertEqual({run["conclusion"] for run in selected}, {"success"}) + self.assertTrue(receipt["hosted_checks"]["all_master_push_runs_successful"]) + self.assertTrue(receipt["hosted_checks"]["all_tag_push_runs_successful"]) + + def test_v175_readback_binds_proof_review_plugin_and_checkout_identities(self): + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + proof = receipt["proof"] + self.assertEqual(proof["qualified_verdict"], QUALIFIED_VERDICT) + self.assertEqual(proof["assurance_class"], "formal-bounded") + self.assertEqual(proof["model_id"], "jackal-spacecraft-finite-burn-ode-v2") + self.assertEqual(proof["release_epoch"], "v1.7.5") + self.assertEqual( + proof["soundness_theorem"], + "JackalIv.Spacecraft.spacecraft_burn_certified_safe", + ) + self.assertEqual( + proof["observed_theorem_axioms"], + ["propext", "Classical.choice", "Quot.sound"], + ) + self.assertEqual(proof["tracked_lean_files"], 57) + self.assertEqual(proof["named_theorems"], 29) + self.assertEqual(proof["logical_admissions"], 0) + for field, expected in V175_PROOF_IDENTITIES.items(): + self.assertEqual(proof[field], expected) + review = proof["independent_review"] + self.assertEqual(review["completed_passes"], 37) + self.assertEqual(review["resolved_findings"], 17) + self.assertEqual(review["invalid_findings"], 1) + self.assertEqual(review["unresolved_release_blocking"], 0) + self.assertEqual( + review["asset_sha256"], + "f7700a20d4ff86f010667e019de0dc62b39976e6290f76209bdedcc385144a51", + ) + self.assertEqual( + review["clearance_sha256"], + "c65e33f86e60200643972e8b4f70a81ced214affe23c9049e029e91ee928c51b", + ) + + plugin = receipt["plugin"] + self.assertEqual(plugin["impact"], "none") + self.assertEqual(plugin["version"], PLUGIN_VERSION) + self.assertEqual(plugin["tool_count"], 41) + self.assertEqual(plugin["unique_tool_count"], 41) + self.assertEqual( + plugin["aggregate_identity_sha256"], + "b2d62d374a54ffdaf090df3a6ea24ef9f6a64f9dde8c5189c29d67bd3b12ece8", + ) + checkout = receipt["protected_checkout"] + self.assertEqual(checkout["path"], "$HOME/Desktop/Projects/jackal-calc") + self.assertEqual( + checkout["branch"], + "feat/mathematical-evidence-kernel-v1.6.0", + ) + self.assertEqual( + checkout["head"], + "57739317b24250ff62fd9b23f67c760d9066ab94", + ) + self.assertEqual(checkout["tracked_changes"], []) + self.assertEqual( + checkout["untracked_roots"], + [ + "jackal_calc.anb.zip", + "jackal_calc.md", + "spacecraft_burn_cert/", + "website/", + ], + ) + self.assertFalse(checkout["mutation_performed_by_publication_work"]) + + def test_v175_readback_keeps_all_release_nonclaims_explicit(self): + receipt = json.loads(READBACK_V175.read_text(encoding="utf-8")) + text = " ".join(receipt["nonclaims"]).lower() + for required in ( + "physical", + "supplied input", + "lean compiler", + "not formally verified", + "not external academic peer review", + "unsigned", + "no new jackel tool", + "v1.7.4", + ): + self.assertIn(required, text) + + def test_v175_docs_link_published_release_and_readback_not_candidate_state(self): + release_url = ( + "https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5" + ) + for path in (README, SPACECRAFT_README, REPORT): + with self.subTest(path=str(path)): + text = path.read_text(encoding="utf-8") + normalized = " ".join(text.split()) + self.assertIn(release_url, text) + self.assertIn( + "spacecraft_burn_release_readback_v175.json", + text, + ) + self.assertIn(QUALIFIED_VERDICT, normalized) + self.assertNotIn("v1.7.5 candidate", normalized.lower()) + self.assertNotIn("exists only after publication", normalized.lower()) + self.assertNotIn("only after the fresh public-download", normalized.lower()) + + def test_task15_steps_four_through_eight_have_concrete_completion_evidence(self): + text = PLAN.read_text(encoding="utf-8") + task = text.split("### Task 15:", 1)[1] + for step in range(4, 9): + marker = f"**Step {step}:" + self.assertRegex( + task, + rf"(?m)^- \[x\] {re.escape(marker)}", + ) + section = task.split(marker, 1)[1] + if step < 8: + section = section.split(f"**Step {step + 1}:", 1)[0] + self.assertIn("Completion evidence:", section) + if __name__ == "__main__": unittest.main() diff --git a/tests/spacecraft_burn_release_gate_test.py b/tests/spacecraft_burn_release_gate_test.py index 5315eb6..3f87910 100644 --- a/tests/spacecraft_burn_release_gate_test.py +++ b/tests/spacecraft_burn_release_gate_test.py @@ -51,6 +51,10 @@ def write_clean_surfaces(root: Path, gate) -> None: {**candidate, "step_exact": "1/48"}, ]}, })) + elif relative == gate.V175_READBACK_PATH: + destination.write_text(json.dumps({ + "schema": "jackal-spacecraft-burn-release-readback-v1" + })) else: destination.write_text("{}\n") @@ -610,6 +614,57 @@ def test_current_json_evidence_is_in_the_gated_surface(self): gate.JSON_TARGETS, ) + def test_v175_publication_readback_is_schema_aware_gated_json(self): + gate = load_gate() + target = Path( + "release/evidence/spacecraft_burn_release_readback_v175.json" + ) + self.assertIn(target, gate.JSON_TARGETS) + cases = ( + ( + "jackal-spacecraft-burn-release-readback-v1", + gate.QUALIFIED_VERDICT, + None, + ), + ( + "wrong-release-readback-schema", + gate.QUALIFIED_VERDICT, + "invalid-release-readback-schema", + ), + ( + "jackal-spacecraft-burn-release-readback-v1", + gate.QUALIFIED_VERDICT.lower(), + "unqualified-certified-safe", + ), + ) + for schema, qualified_verdict, expected_reason in cases: + with ( + self.subTest( + schema=schema, + qualified_verdict=qualified_verdict, + ), + tempfile.TemporaryDirectory() as directory, + ): + root = Path(directory) + write_clean_surfaces(root, gate) + (root / target).write_text(json.dumps({ + "schema": schema, + "proof": {"qualified_verdict": qualified_verdict}, + })) + result = gate.scan(root) + if expected_reason is None: + self.assertEqual(result["status"], "PASS", result["findings"]) + else: + self.assertEqual(result["status"], "FAIL") + self.assertTrue( + any( + finding["file"] == str(target) + and finding["reason"] == expected_reason + for finding in result["findings"] + ), + result["findings"], + ) + def test_frozen_github_release_metadata_and_notes_are_gated(self): gate = load_gate() expected = ( diff --git a/tests/spacecraft_burn_v175_epoch_test.py b/tests/spacecraft_burn_v175_epoch_test.py index d50f7c4..92c9492 100644 --- a/tests/spacecraft_burn_v175_epoch_test.py +++ b/tests/spacecraft_burn_v175_epoch_test.py @@ -27,31 +27,83 @@ def load_module(path: Path, name: str): class SpacecraftBurnV175EpochTests(unittest.TestCase): - def test_readme_marks_v175_as_commit_scoped_corrective_candidate(self): + def test_readme_marks_v175_as_published_latest_corrective_release(self): readme = (ROOT / "README.md").read_text() rendered = " ".join(readme.split()) - self.assertIn("v1.7.5 corrective release candidate", rendered) - self.assertIn("Commit-scoped status", rendered) - self.assertIn("source snapshot was prepared", rendered) - self.assertIn("current GitHub publication state", rendered) + self.assertIn("**Published state:**", rendered) + self.assertIn("observed public **Latest** release", rendered) self.assertIn( - "v1.7.4 should not be used as the publication-grade verifier bundle", - rendered, + "https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5", + readme, + ) + self.assertIn( + "release/evidence/spacecraft_burn_release_readback_v175.json", + readme, + ) + self.assertIn("12 uploaded release asset byte identities", rendered) + self.assertIn("11 `SHA256SUMS` payload rows", rendered) + self.assertIn("v1.7.4 release, tag, assets", rendered) + self.assertIn("remain immutable historical evidence", rendered) + for stale in ( + "v1.7.5 corrective release candidate", + "Commit-scoped status", + "source snapshot was prepared", + "exists only after publication", + "only after the fresh public-download", + ): + self.assertNotIn(stale, rendered) + + def test_published_docs_and_immutable_tag_surfaces_are_consistent(self): + surfaces = ( + ( + ROOT / "spacecraft_burn_cert/README.md", + "../release/evidence/spacecraft_burn_release_readback_v175.json", + ), + ( + ROOT / "spacecraft_burn_cert/REPORT.md", + "../release/evidence/spacecraft_burn_release_readback_v175.json", + ), + ) + release_url = ( + "https://github.com/AnubisQuantumCipher/jackal/releases/tag/v1.7.5" + ) + for path, readback_link in surfaces: + with self.subTest(path=str(path)): + text = path.read_text() + rendered = " ".join(text.split()) + self.assertIn("Published state:", rendered) + self.assertIn("observed public Latest release", rendered) + self.assertIn(release_url, text) + self.assertIn(readback_link, text) + self.assertIn( + "v1.7.4 release, tag, assets, and readback remain immutable " + "historical evidence", + rendered, + ) + for stale in ( + "Commit-scoped publication state", + "v1.7.5 candidate", + "current GitHub release state", + "exists only after publication", + ): + self.assertNotIn(stale, rendered) + + notes = (ROOT / "release/spacecraft_burn_v175_release_notes.md").read_text() + metadata = json.loads( + (ROOT / "release/evidence/spacecraft_burn_release_metadata_v175.json") + .read_text() + ) + self.assertTrue( + notes.startswith( + "# JACKAL v1.7.5 - Spacecraft finite-burn certification\n" + ) + ) + self.assertNotIn("candidate; not published", notes) + self.assertEqual(metadata["tag"], EPOCH) + self.assertEqual( + metadata["title"], + "JACKAL v1.7.5 - Spacecraft finite-burn certification", ) - self.assertIn("v1.7.4 tag full-certificate campaign was cancelled", rendered) - self.assertIn("PR and master-branch hosted gates passed", rendered) - - def test_immutable_tag_surfaces_do_not_encode_mutable_unpublished_state(self): - root_readme = (ROOT / "README.md").read_text() - certificate_readme = (ROOT / "spacecraft_burn_cert/README.md").read_text() - report = (ROOT / "spacecraft_burn_cert/REPORT.md").read_text() - self.assertNotIn("not yet published", root_readme) - for surface in (certificate_readme, report): - with self.subTest(surface=surface[:40]): - rendered = " ".join(surface.split()) - self.assertIn("Commit-scoped publication state", rendered) - self.assertIn("current GitHub release state", rendered) - self.assertNotIn("candidate; not published", rendered) def test_checker_proof_identity_and_workflow_use_v175_epoch(self): checker = (ROOT / "proofs/lean/JackalIv/Spacecraft/CertCheck.lean").read_text() diff --git a/tools/spacecraft_burn_release_gate.py b/tools/spacecraft_burn_release_gate.py index 2fe98b1..1b115d8 100644 --- a/tools/spacecraft_burn_release_gate.py +++ b/tools/spacecraft_burn_release_gate.py @@ -23,6 +23,9 @@ INSTRUMENT_VALIDATION_PATH = Path( "spacecraft_burn_cert/evidence/instrument_validation_v2.json" ) +V175_READBACK_PATH = Path( + "release/evidence/spacecraft_burn_release_readback_v175.json" +) QUALIFIED_PATTERN = re.compile( r"\s+".join(map(re.escape, QUALIFIED_VERDICT.split())) + r"(?=(?:[.!?](?:[*_`]+)?|(?:[*_`]+)[.!?])(?:\s|$)|(?:[*_`]+)?\s*$)" @@ -44,6 +47,7 @@ Path("release/evidence/spacecraft_burn_proof_identity_v1.json"), Path("release/evidence/spacecraft_burn_review_clearance_v1.json"), Path("release/evidence/spacecraft_burn_release_readback_v174.json"), + V175_READBACK_PATH, Path("release/evidence/spacecraft_burn_review_clearance_v175.json"), Path("release/evidence/spacecraft_burn_release_metadata_v175.json"), ) @@ -404,10 +408,28 @@ def instrument_assurance_findings(value: object, relative: Path) -> list[dict]: }] +def release_readback_findings(value: object, relative: Path) -> list[dict]: + if relative != V175_READBACK_PATH: + return [] + if ( + isinstance(value, dict) + and value.get("schema") + == "jackal-spacecraft-burn-release-readback-v1" + ): + return [] + return [{ + "file": str(relative), + "json_path": "$.schema", + "reason": "invalid-release-readback-schema", + }] + + def document_findings(value: object, relative: Path) -> list[dict]: schema = value.get("schema") if isinstance(value, dict) else None - return json_findings(value, relative, document_schema=schema) + instrument_assurance_findings( - value, relative + return ( + json_findings(value, relative, document_schema=schema) + + instrument_assurance_findings(value, relative) + + release_readback_findings(value, relative) )