diff --git a/CHANGELOG.md b/CHANGELOG.md index 459bd20..bd108f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ where a real check ran; no receipt no accept; the honest null is first-class). `crucible.replay-template/1` routes Crucible→Mneme and `crucible.replay-pack/1` routes Mneme→Crucible, while retaining the existing Mneme→Crucible thesis route. +- Refresh the Mneme declarations from public main: the native Crucible export is + `mneme.crucible-export/2`, still consumable as `crucible.thesis/1`, and Mneme + also declares `mneme.local-origin-recheck/1` as a terminal read-only freshness + report capability. ## 0.2.0 diff --git a/README.md b/README.md index 4838b3e..bb3c152 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ $ plexus wiring --builtin The Mneme/Crucible replay loop is bidirectional and schema-exact: Crucible emits `crucible.replay-template/1` for Mneme to consume, and Mneme emits `crucible.replay-pack/1` for Crucible to consume. The existing -`crucible.thesis/1` Mneme→Crucible route remains a separate declared edge. +`crucible.thesis/1` Mneme→Crucible route remains a separate declared edge, +satisfied by Mneme's native `mneme.crucible-export/2` export. **Plan a pipeline.** "I want to feed `crucible`. What produces its inputs?" @@ -166,9 +167,11 @@ Every edge is tagged `evidence: "declared"` and cites the **module** its produce names as the source (`file:function`). plexus does not import, resolve, or run that pointer, so the citation is a self-reported claim to check, not a verified receipt. The built-in manifests for the five flagships (gather, crucible, forum, -index, mneme) were transcribed by hand from a one-time source survey (2026-07-07); -the running tool re-checks none of it, so treat every edge as declared until you -follow the pointer yourself. +index, mneme) began as a hand transcription from a source survey; the running +tool re-checks none of it, so treat every edge as declared until you follow the +pointer yourself. Mneme's contract was refreshed from public main on +2026-09-14, including `mneme.crucible-export/2` and +`mneme.local-origin-recheck/1`. plexus is also honest about what does **not** connect: diff --git a/manifests/mneme.interop.json b/manifests/mneme.interop.json index e3cdd34..3aec648 100644 --- a/manifests/mneme.interop.json +++ b/manifests/mneme.interop.json @@ -7,19 +7,33 @@ }, "emits": [ { - "capability": "mneme.crucible-export/1", + "capability": "mneme.crucible-export/2", "title": "memory as crucible thesis", "module": "src/mneme/compose.py:to_crucible_thesis", - "summary": "", + "summary": "claims, drift measurements, and declarative mneme.recheck/1 descriptors", "consumable_as": [ "crucible.thesis/1" ] }, + { + "capability": "crucible.replay-pack/1", + "title": "assessment-bound Mneme drift replay", + "module": "src/mneme/replay.py:replay_crucible", + "summary": "replays descriptor-bound measurements without importing Crucible or executing commands", + "consumable_as": [] + }, + { + "capability": "mneme.local-origin-recheck/1", + "title": "supported local origin freshness report", + "module": "src/mneme/origin.py:recheck_local_origins", + "summary": "explicit read-only local docs/file-read freshness checks under a caller-approved root", + "consumable_as": [] + }, { "capability": "mneme.provenance-chain/1", "title": "memory -> source origin", "module": "src/mneme/ingest.py:provenance_chain", - "summary": "", + "summary": "memory-to-origin receipt chain; external freshness is checked separately when supported", "consumable_as": [] }, { @@ -35,13 +49,6 @@ "module": "src/mneme/drift.py:drift_report", "summary": "", "consumable_as": [] - }, - { - "capability": "crucible.replay-pack/1", - "title": "assessment-bound replay pack", - "module": "src/mneme/replay.py:replay_crucible", - "summary": "", - "consumable_as": [] } ], "consumes": [ @@ -61,17 +68,19 @@ }, { "capability": "crucible.replay-template/1", - "title": "oracle replay template", + "title": "assessment-bound measurement replay template", "module": "src/mneme/replay.py:replay_crucible", - "summary": "", + "summary": "decoded Crucible template plus an explicitly supplied Mneme state", "consumable_as": [] } ], "evidence": [ "src/mneme/compose.py", "src/mneme/ingest.py", + "src/mneme/origin.py", "src/mneme/receipt.py", "src/mneme/drift.py", - "src/mneme/replay.py" + "src/mneme/replay.py", + "tests/test_crucible_replay.py" ] } diff --git a/src/plexus/manifest.py b/src/plexus/manifest.py index 8421d79..bd116f9 100644 --- a/src/plexus/manifest.py +++ b/src/plexus/manifest.py @@ -3,7 +3,7 @@ A manifest is a tool's interop contract: the capabilities it EMITS (re-checkable artifacts another tool could consume) and the capabilities it CONSUMES (inputs it accepts). A capability is a stable string: a schema id like -"mneme.crucible-export/1" or a shared-spine kind like +"mneme.crucible-export/2" or a shared-spine kind like "project-telos.flagship-action/v1". Matching is by capability string, so an edge forms when a producer DECLARES a capability the consumer DECLARES it accepts. @@ -28,7 +28,7 @@ class Port: module: str = "" # evidence: repo-relative file:function summary: str = "" consumable_as: tuple = () # extra capabilities an EMIT also satisfies - # (e.g. mneme.crucible-export/1 -> crucible.thesis) + # (e.g. mneme.crucible-export/2 -> crucible.thesis) def satisfies(self, capability: str) -> bool: return capability == self.capability or capability in self.consumable_as diff --git a/src/plexus/registry.py b/src/plexus/registry.py index daa35b3..017f942 100644 --- a/src/plexus/registry.py +++ b/src/plexus/registry.py @@ -4,9 +4,10 @@ flagship source during a 2026-07-07 survey. plexus does not re-read that source at runtime, so these pointers are DECLARED citations, not probed receipts: if a flagship renames a cited symbol, the manifest here goes stale silently until the -next manual survey. Capability keys are aligned across producers and consumers so +next manual survey. The Mneme contract was refreshed from public main on +2026-09-14. Capability keys are aligned across producers and consumers so a declared edge forms where the code composed at survey time: gather.digest/1 -> -crucible, gather.items/1 -> mneme, mneme.crucible-export/1 (as crucible.thesis/1) +crucible, gather.items/1 -> mneme, mneme.crucible-export/2 (as crucible.thesis/1) -> crucible, crucible.replay-template/1 -> mneme, crucible.replay-pack/1 -> crucible, index.verification/1 -> crucible, and every flagship's project-telos.flagship-action/v1 envelope -> index's spine loader. @@ -127,29 +128,37 @@ "organ": "mneme", "invoke": {"cli": "mneme", "mcp_server": "mneme.mcp:serve", "python_import": "mneme"}, "emits": [ - {"capability": "mneme.crucible-export/1", "title": "memory as crucible thesis", + {"capability": "mneme.crucible-export/2", "title": "memory as crucible thesis", "module": "src/mneme/compose.py:to_crucible_thesis", + "summary": "claims, drift measurements, and declarative mneme.recheck/1 descriptors", "consumable_as": ["crucible.thesis/1"]}, + {"capability": "crucible.replay-pack/1", "title": "assessment-bound Mneme drift replay", + "module": "src/mneme/replay.py:replay_crucible", + "summary": "replays descriptor-bound measurements without importing Crucible or executing commands"}, + {"capability": "mneme.local-origin-recheck/1", "title": "supported local origin freshness report", + "module": "src/mneme/origin.py:recheck_local_origins", + "summary": "explicit read-only local docs/file-read freshness checks under a caller-approved root"}, {"capability": "mneme.provenance-chain/1", "title": "memory -> source origin", - "module": "src/mneme/ingest.py:provenance_chain"}, + "module": "src/mneme/ingest.py:provenance_chain", + "summary": "memory-to-origin receipt chain; external freshness is checked separately when supported"}, {"capability": "mneme.recall/1", "title": "re-derivable recall receipt", "module": "src/mneme/receipt.py:RecallReceipt.as_dict"}, {"capability": "mneme.drift-report/1", "title": "memory faithfulness verdicts", "module": "src/mneme/drift.py:drift_report"}, - {"capability": "crucible.replay-pack/1", "title": "assessment-bound replay pack", - "module": "src/mneme/replay.py:replay_crucible"}, ], "consumes": [ {"capability": "gather.items/1", "title": "accountable intake items", "module": "src/mneme/ingest.py:from_gather"}, {"capability": "conversation-turns/1", "title": "raw turns to remember", "module": "src/mneme/memory.py:AgentMemory.remember"}, - {"capability": "crucible.replay-template/1", "title": "oracle replay template", - "module": "src/mneme/replay.py:replay_crucible"}, + {"capability": "crucible.replay-template/1", "title": "assessment-bound measurement replay template", + "module": "src/mneme/replay.py:replay_crucible", + "summary": "decoded Crucible template plus an explicitly supplied Mneme state"}, ], "evidence": ["src/mneme/compose.py", "src/mneme/ingest.py", - "src/mneme/receipt.py", "src/mneme/drift.py", - "src/mneme/replay.py"], + "src/mneme/origin.py", "src/mneme/receipt.py", + "src/mneme/drift.py", "src/mneme/replay.py", + "tests/test_crucible_replay.py"], }, { "organ": "learn", diff --git a/tests/test_mneme_contract.py b/tests/test_mneme_contract.py new file mode 100644 index 0000000..304e17a --- /dev/null +++ b/tests/test_mneme_contract.py @@ -0,0 +1,62 @@ +"""Mneme public-main contract falsifiers for Plexus declarations.""" +from pathlib import Path + +import pytest + +from plexus.registry import builtin_manifests, load_dir + + +MNEME_CRUCIBLE_EXPORT = "mneme.crucible-export/2" +STALE_MNEME_CRUCIBLE_EXPORT = "mneme.crucible-export/1" +LOCAL_ORIGIN_RECHECK = "mneme.local-origin-recheck/1" +CRUCIBLE_THESIS = "crucible.thesis/1" + + +def _manifest_sets(): + shipped = Path(__file__).resolve().parents[1] / "manifests" + return { + "builtin registry": builtin_manifests(), + "shipped manifests": load_dir(str(shipped)), + } + + +def _mneme(manifests): + return next(manifest for manifest in manifests if manifest.organ == "mneme") + + +def _capabilities(manifest): + declared = set() + for port in [*manifest.emits, *manifest.consumes]: + declared.add(port.capability) + declared.update(port.consumable_as) + return declared + + +def _emit(manifest, capability): + return next((port for port in manifest.emits if port.capability == capability), None) + + +@pytest.mark.parametrize("source", ["builtin registry", "shipped manifests"]) +def test_mneme_declares_schema_v2_crucible_export_and_not_stale_v1(source): + mneme = _mneme(_manifest_sets()[source]) + declared = _capabilities(mneme) + export = _emit(mneme, MNEME_CRUCIBLE_EXPORT) + + assert export is not None + assert export.module == "src/mneme/compose.py:to_crucible_thesis" + assert "declarative mneme.recheck/1 descriptors" in export.summary + assert CRUCIBLE_THESIS in export.consumable_as + assert STALE_MNEME_CRUCIBLE_EXPORT not in declared + + +@pytest.mark.parametrize("source", ["builtin registry", "shipped manifests"]) +def test_mneme_declares_local_origin_recheck_as_terminal_capability(source): + mneme = _mneme(_manifest_sets()[source]) + origin = _emit(mneme, LOCAL_ORIGIN_RECHECK) + + assert origin is not None + assert origin.module == "src/mneme/origin.py:recheck_local_origins" + assert "caller-approved root" in origin.summary + assert origin.consumable_as == () + assert "src/mneme/origin.py" in mneme.evidence + assert "tests/test_crucible_replay.py" in mneme.evidence