From a9125b6306c67be15a77495eb8eba581aa0ca176 Mon Sep 17 00:00:00 2001 From: Mother Seara Date: Wed, 9 Sep 2026 22:35:25 +0900 Subject: [PATCH] release: align tagged mirror dependencies and current documentation --- CHANGELOG.md | 5 +++++ README.md | 10 ++++++++-- docs/ANCHORING.md | 9 +++++++-- docs/STACK_CANONICAL.md | 6 ++++-- pyproject.toml | 6 +++--- tests/test_provenance_release_contract.py | 11 +++++++++++ 6 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 tests/test_provenance_release_contract.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 65e95fd..702f2b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [0.2.14] — 2026-09-09 +- Pin measure-mirror v0.41.2 and provenance-mirror v0.3.1 to their exact tagged + commits; test the corrected provenance contract through the MCP wrapper. +- Align README/tool tables and canonical/anchoring guides with the actual verification + paths, release pins and installation/reconnect boundary. + - Gate and outsider CLI recompute MIRROR-SPEC content hashes and links from a single snapshot. Missing, empty, malformed, duplicate-key and tampered ledgers fail closed. - Publish requires a reasoned retraction or explicit `action=result` with diff --git a/README.md b/README.md index 92b735c..5131011 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,12 @@ Windsurf, any MCP client. ### Verification depth and gate migration (0.2.14) +Release pins: measure-mirror **v0.41.2**, action-mirror **v0.4.0**, and +provenance-mirror **v0.3.1**. Exact tag commits are recorded in +[`pyproject.toml`](pyproject.toml) and checked by CI. Updating the checkout alone +does not refresh an already installed dependency or a running MCP process. +Reinstall the package and reconnect the client after an upgrade; do not rewrite ledgers. + `mirror-stack-verify` now recomputes both content hashes and chain links; pointer-only fixtures do not certify integrity. Legacy 16-hex seals are accepted with a warning. `stack_verify_all` labels checks `HASH_RECOMPUTED`, `LOCAL_SNAPSHOT`, or `HEAD_WITNESS`. @@ -79,8 +85,8 @@ reporting a resolved result, including a failure; it does not certify scientific | `am_record` | 🪪 actions | seal an action; `target=` ties it to a claim | | `am_witness` | 🪪 | pin a peer's ledger head (catches whole-file replacement) | | `am_verify` | 🪪 | verify an action ledger's hash chain | -| `pm_verify` | 🔎 provenance | verify a file's provenance across 5 signals | -| `stack_verify_all` | 🪞🔎🪪 | whole stack in one call: chain (L1) + anchors (L3) + witness (L2) | +| `pm_verify` | 🔎 provenance | inspect 5 provenance/integrity signals; marker-only results are PROVENANCE-UNVERIFIED, never signature verification | +| `stack_verify_all` | 🪞🔎🪪 | supplied ledgers only: hash integrity (L1), optional local snapshots (L3) and pinned-head witness comparisons (L2); scope is reported | (More granular `measure-mirror` probes are reachable via `mm_verify` — it dispatches by data key.) diff --git a/docs/ANCHORING.md b/docs/ANCHORING.md index 28a33f1..8c6d585 100644 --- a/docs/ANCHORING.md +++ b/docs/ANCHORING.md @@ -107,8 +107,13 @@ ots upgrade manifest.json.ots ots info manifest.json.ots # shows BitcoinBlockHeaderAttestation() + merkle root ``` -A self-contained re-runnable script (`ots_anchor.sh`) lives alongside the standard ledgers in the -[Mirror Stack conventions](https://github.com/mirror-stack/measure-mirror/tree/main/stack). +The packaged implementation is +[`mirror_stack_mcp/ots_anchor.py`](../mirror_stack_mcp/ots_anchor.py). +Machine-local cron scripts are deployment-specific and are not shipped in the conventions directory. + +The outsider `mirror-stack-verify` CLI recomputes ledger hashes but checks a supplied +OTS proof separately. It does not currently verify ledger-to-proof binding, so its +output correctly leaves this ledger's external-clock precedence unverified. ## Notes diff --git a/docs/STACK_CANONICAL.md b/docs/STACK_CANONICAL.md index cb8589f..0784b4a 100644 --- a/docs/STACK_CANONICAL.md +++ b/docs/STACK_CANONICAL.md @@ -50,5 +50,7 @@ measure_mirror.mm.linkage_check(path) -> (ok, message, entries) ← CANONICAL measure-mirror's own SHA-256 seal. Not duplicated — a different, mm-specific check used by `verify_self`'s L1 seal step. -Because `linkage_check` is the single source, the two verifiers cannot diverge; -a conformance/regression test on each side asserts they agree. +Because `linkage_check` is the single source, its two adapters cannot diverge; +a conformance/regression test on each side asserts they agree. This equivalence +does not mean the outsider CLI still performs linkage-only verification: since +0.2.14 its entry point uses `integrity.read_verified()` and recomputes hashes too. diff --git a/pyproject.toml b/pyproject.toml index 81644bb..8e32d5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,9 +23,9 @@ dependencies = [ # action-mirror and provenance-mirror pins were labelled "v0.2.0" while # sitting TWO commits before that tag, so an install got the pre-org-migration # docs (stale `bhyi4/` self-references, SPEC v1.0) under a v0.2.0 label. - "measure-mirror @ git+https://github.com/mirror-stack/measure-mirror@7f8259bd3f424c5091a37be953dca669884ee7e0", # v0.41.1 — (auto-pin: was v0.41.0 11f1d768; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.40.0 3d9b007e; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.39.0 9784bce4; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.38.1 aa850516; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.38.0 815e6184; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.37.0 989da84e; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.36.0 bce68bbd; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.35.0 183c7259; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.34.0 c6965151; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.33.0 895ad803; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.32.0 21ca2893; verify via CI test_pins_are_releases + fixtures) — ㉘ vacuous both-directions on real runs (computed matched-null certificate); catalog count sync 72 + KO count guards - "action-mirror @ git+https://github.com/mirror-stack/action-mirror@22eb4c5b09578f443b59d12a8455c5493b6064ed", # v0.4.0 — (auto-pin: was v0.3.0 d59ea1df; verify via CI test_pins_are_releases + fixtures) — (auto-pin: was v0.2.0 15b0c5b7; verify via CI test_pins_are_releases + fixtures) — full 64-hex SHA-256 seals (security; legacy 16-hex verify via prefix match); org migration + SPEC v1.1 references - "provenance-mirror @ git+https://github.com/mirror-stack/provenance-mirror@92b8e6ebf948bbb671d20282de99ea9886b8607c", # v0.3.0 — (auto-pin: was v0.2.0 2d1d52d2; verify via CI test_pins_are_releases + fixtures) — full 64-hex SHA-256 seals (security; legacy 16-hex verify via prefix match); org migration + SPEC v1.1 references + "measure-mirror @ git+https://github.com/mirror-stack/measure-mirror@219058aff61f2e6c0ea84041fd47a3b616ba3d85", # v0.41.2 — explicit verification depth + "action-mirror @ git+https://github.com/mirror-stack/action-mirror@22eb4c5b09578f443b59d12a8455c5493b6064ed", # v0.4.0 — unchanged released action core + "provenance-mirror @ git+https://github.com/mirror-stack/provenance-mirror@d41df098979e84a81469eeec1a3e3b1d471c90ef", # v0.3.1 — unverified hints and synchronized guides ] [project.optional-dependencies] diff --git a/tests/test_provenance_release_contract.py b/tests/test_provenance_release_contract.py new file mode 100644 index 0000000..328000e --- /dev/null +++ b/tests/test_provenance_release_contract.py @@ -0,0 +1,11 @@ +"""The installed MCP dependency must emit the corrected provenance contract.""" +from mirror_stack_mcp import server + + +def test_mcp_uses_unverified_provenance_dependency(tmp_path): + path = tmp_path / "marker.txt" + path.write_bytes(b"ordinary text c2pa, no manifest or signature") + result = server.pm_verify(str(path), str(tmp_path / "pm.jsonl")) + assert result["verdict"] == "PROVENANCE-UNVERIFIED" + assert result["verification"]["signature_verified"] is False + assert result["ledger_entry"]["verdict"] == result["verdict"]