From ec376f73d5c39cf04080a167a017a840e0abefe9 Mon Sep 17 00:00:00 2001 From: Mother Seara Date: Wed, 5 Aug 2026 11:19:54 +0900 Subject: [PATCH 1/2] chore: point pins at the commits their version labels claim (0.2.10) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by a logic ↔ documentation consistency audit across the mirror family. The `action-mirror` and `provenance-mirror` pins were both commented `# v0.2.0` while sitting TWO commits before that tag. The two missing commits were: docs: update self-references bhyi4/ -> mirror-stack/ after org migration docs: point SPEC references to v1.1 (seal-width amendment) So anyone installing this package received pre-org-migration docs — stale `bhyi4/` self-references and SPEC v1.0 — under a "v0.2.0" label. A pin whose comment names a release it does not point at is a claim the installer cannot check, which is the defect class this stack exists to catch. Also bumps `measure-mirror` v0.28.1 → v0.29.0, which adds ㉘ `subspace_claim_check` and fixes a latent KeyError in the finding formatters on INFO/N-A levels. `tests/test_pins_are_releases.py` checks each pin's SHA against the GitHub tag its comment names, and offline that every pin is a full 40-hex lowercase SHA with a version label. It skips rather than fails when the API is unreachable. Reverse-verified: restoring the old action-mirror pin makes it fail, so the guard has real discriminative power rather than passing on everything. No new tool: this server exposes a curated 19, not all 28 probes — `mm_verify` is the umbrella for the rest, and ㉘ is reachable through it by design. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 28 +++++++++++++++ mirror_stack_mcp/__init__.py | 2 +- pyproject.toml | 23 ++++++++----- tests/test_pins_are_releases.py | 61 +++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 tests/test_pins_are_releases.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb539e..4eac2f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,34 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- +## [0.2.10] — 2026-08-05 + +### Changed +- **Pins now point at the commits their version labels claim.** The + `action-mirror` and `provenance-mirror` pins were both commented `# v0.2.0` + while sitting **two commits before** that tag. The two missing commits were + the org migration (`bhyi4/` → `mirror-stack/`) and the SPEC v1.1 reference + update, so an install got pre-migration docs under a v0.2.0 label — a claim + the installer had no way to see was false. +- `measure-mirror` pin bumped **v0.28.1 → v0.29.0**: adds ㉘ + `subspace_claim_check` (a declaration auditor, holdout PASS 22/22 after two + sealed kills), `Finding.data`, and a fix for a latent `KeyError` in the + finding formatters on `INFO`/`N/A` levels. + +### Added +- `tests/test_pins_are_releases.py` — each pin's SHA is checked against the + GitHub tag its comment names, plus offline checks that every pin is a full + 40-hex lowercase SHA and carries a version label. Skips when the API is + unreachable rather than failing offline. Reverse-verified: restoring the old + `action-mirror` pin makes it fail. + +### Note +This server exposes a curated 19 tools, not all 28 measure-mirror probes — +`mm_verify` is the umbrella for the rest. ㉘ is reachable through it; no new +tool was added, by design. + +--- + ## [0.2.9] — 2026-07-21 ### Changed diff --git a/mirror_stack_mcp/__init__.py b/mirror_stack_mcp/__init__.py index 8c661ad..1845120 100644 --- a/mirror_stack_mcp/__init__.py +++ b/mirror_stack_mcp/__init__.py @@ -1,2 +1,2 @@ """🪞🔎🪪 Mirror Stack unified MCP server.""" -__version__ = "0.2.9" +__version__ = "0.2.10" diff --git a/pyproject.toml b/pyproject.toml index 6e8fe70..7d98a75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "mirror-stack-mcp" -version = "0.2.9" +version = "0.2.10" description = "Unified MCP server for the Mirror Stack — claims, actions, provenance + verify-all in one server" readme = "README.md" requires-python = ">=3.10" @@ -12,13 +12,20 @@ license = { text = "Apache-2.0" } authors = [{ name = "Mother Seara", email = "ruinbl82@gmail.com" }] dependencies = [ "mcp>=1.0", - # Pinned to exact commits for reproducible installs. An unpinned git dep silently - # tracks each mirror's default branch, so an install made before a mirror's release - # freezes on whatever was HEAD then and never refreshes — that is how a local install - # ran stale measure-mirror 0.14.3 long after 0.15.1 landed. Bump these on purpose. - "measure-mirror @ git+https://github.com/mirror-stack/measure-mirror@abe0c19d3894c1278a9bf5281a45946ef0e1eea4", # v0.28.1 — power_check honors alpha/target_power (was hardcoded 1.96/0.842: text-vs-number lie); v0.28.0 SECURITY verify_chain prev_seal (SPEC §4 rule 3); v0.27.0 full 64-hex seals; v0.26 ㉗ prereg_lint - "action-mirror @ git+https://github.com/mirror-stack/action-mirror@fa1fc4998936e6bf179b5c14825fb09e78a36087", # v0.2.0 — full 64-hex SHA-256 seals (security; legacy 16-hex verify via prefix match); v0.1.0 ledgers conform to MIRROR-SPEC v1.0 - "provenance-mirror @ git+https://github.com/mirror-stack/provenance-mirror@321f84abc4ffd91da43a5ebc866b5ce02cf3c276", # v0.2.0 — full 64-hex SHA-256 seals (security; legacy 16-hex verify via prefix match); v0.1.0 ledgers conform to MIRROR-SPEC v1.0 + # Pinned to exact RELEASE commits for reproducible installs. An unpinned git + # dep silently tracks each mirror's default branch, so an install made before + # a mirror's release freezes on whatever was HEAD then and never refreshes — + # that is how a local install ran stale measure-mirror 0.14.3 long after + # 0.15.1 landed. Bump these on purpose. + # + # Each SHA below is the commit its version TAG points at, verified against + # the GitHub tag API by tests/test_pins_are_releases.py. The previous + # 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@b3b6dec8893c8e645ad0c9d50d08fc3c9417eee1", # v0.29.0 — ㉘ subspace_claim_check (declaration auditor, holdout PASS 22/22); Finding.data; INFO/N-A formatter crash fixed; CHANGELOG + catalog-count sync guards + "action-mirror @ git+https://github.com/mirror-stack/action-mirror@15b0c5b775e916a22d837ddc0714e85aef7ec74e", # v0.2.0 — 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@2d1d52d280352567410d140270f7714571bf784f", # v0.2.0 — full 64-hex SHA-256 seals (security; legacy 16-hex verify via prefix match); org migration + SPEC v1.1 references ] [project.optional-dependencies] diff --git a/tests/test_pins_are_releases.py b/tests/test_pins_are_releases.py new file mode 100644 index 0000000..b8d0214 --- /dev/null +++ b/tests/test_pins_are_releases.py @@ -0,0 +1,61 @@ +"""Every git pin must point at the commit its version label claims. + +Found by a family-wide consistency audit: the `action-mirror` and +`provenance-mirror` pins were both commented `# v0.2.0` while sitting TWO +commits *before* the v0.2.0 tag. The two missing commits were the org migration +(`bhyi4/` → `mirror-stack/`) and the SPEC v1.1 reference update — so anyone +installing this package got pre-migration docs under a v0.2.0 label. + +A pin whose comment names a release it does not point to is a lie the installer +cannot see, which is exactly the defect class this stack exists to catch. +""" +import json +import re +import urllib.error +import urllib.request +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +PIN_RE = re.compile( + r'"(?P[a-z-]+) @ git\+https://github\.com/(?P[\w-]+)/' + r'(?P[\w-]+)@(?P[0-9a-f]{40})",\s*#\s*(?Pv?[\d.]+)') + + +def _pins(): + text = (ROOT / "pyproject.toml").read_text(encoding="utf-8") + pins = [m.groupdict() for m in PIN_RE.finditer(text)] + assert pins, "no git pins parsed from pyproject.toml — did the format change?" + return pins + + +def test_every_pin_declares_a_version(): + for pin in _pins(): + assert pin["ver"], f"{pin['pkg']} pin has no version comment" + + +def test_pin_shas_are_full_length_and_lowercase(): + """A short SHA is ambiguous and an uppercase one breaks string comparison.""" + text = (ROOT / "pyproject.toml").read_text(encoding="utf-8") + for sha in re.findall(r'git\+https://github\.com/[\w-]+/[\w-]+@([0-9a-fA-F]+)', text): + assert len(sha) == 40, f"pin {sha} is not a full 40-hex commit SHA" + assert sha == sha.lower(), f"pin {sha} is not lowercase" + + +@pytest.mark.parametrize("pin", _pins(), ids=lambda p: p["pkg"]) +def test_pin_matches_its_tagged_release(pin): + url = f"https://api.github.com/repos/{pin['owner']}/{pin['repo']}/tags" + try: + with urllib.request.urlopen(url, timeout=15) as r: + tags = json.load(r) + except (urllib.error.URLError, TimeoutError) as e: # offline / rate limited + pytest.skip(f"GitHub tags unreachable for {pin['repo']}: {e}") + want = pin["ver"] if pin["ver"].startswith("v") else "v" + pin["ver"] + match = [t for t in tags if t["name"] == want] + assert match, ( + f"{pin['pkg']} pin claims {want} but that tag does not exist " + f"(tags: {[t['name'] for t in tags][:5]})") + assert match[0]["commit"]["sha"] == pin["sha"], ( + f"{pin['pkg']} pin is commented {want} but points at {pin['sha'][:8]}, " + f"while {want} is {match[0]['commit']['sha'][:8]}") From e74425dff582638a12c84e0dce9afebf9e83b3d8 Mon Sep 17 00:00:00 2001 From: bhyi4 Date: Wed, 5 Aug 2026 15:14:56 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(deps):=20pin=20mcp<2=20=E2=80=94=202.x?= =?UTF-8?q?=20removed=20mcp.server.fastmcp=20(unblocks=20CI;=20same=20fix?= =?UTF-8?q?=20as=20yeoul#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7d98a75..b09f354 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10" license = { text = "Apache-2.0" } authors = [{ name = "Mother Seara", email = "ruinbl82@gmail.com" }] dependencies = [ - "mcp>=1.0", + "mcp>=1.0,<2", # upper bound: mcp 2.x removed mcp.server.fastmcp (same fix as yeoul) # Pinned to exact RELEASE commits for reproducible installs. An unpinned git # dep silently tracks each mirror's default branch, so an install made before # a mirror's release freezes on whatever was HEAD then and never refreshes —