Same conversation_id and full row hash before merge, after merge and after inverse.
The actual edit ledger
Read either receipt. Keep both in view.
Both reads came from the existing audit endpoint. Batch labels below stand for the synthetic IDs preserved in the downloadable receipt.
Read the forward audit
Merge batch · 2 fields normalized
Recorded run: source=mcp · canonicalize=2
Triple 1 · object
Snapshot before this editslate padNew value recordedslate tablet
Triple 2 · subject
Snapshot before this editslate padNew value recordedslate tablet
The actual response reports affected=2. Each audit action carries the pre-edit identity and a map containing just its changed field.
Read request and correlation detailsGET /api/mcp/knowledge/edits?batch_id=[merge batch]
HTTP 200. Full synthetic batch/action IDs and exact response bodies are preserved in the JSON receipt.
Read the inverse audit
Inverse batch · 2 fields restored
Recorded run: source=mcp · canonicalize=2
Triple 2 · subject
Snapshot before this editslate tabletNew value recordedslate pad
Triple 1 · object
Snapshot before this editslate tabletNew value recordedslate pad
The actual response reports reverted=2 and not_invertible=0. Its original action IDs plus triple IDs correlate this new batch with the forward edits.
Read request and correlation detailsGET /api/mcp/knowledge/edits?batch_id=[inverse batch]
HTTP 200. Full synthetic batch/action IDs and exact response bodies are preserved in the JSON receipt.
Forward action 2 connects to inverse action 3 on triple 2.
Forward action 1 connects to inverse action 4 on triple 1.
What the execution proves, and where it stops
Actual path: the Laravel HTTP test kernel authenticated a fictional owner and executed the tagged validation, routes, controllers, curation service and disposable MySQL writes. The ledger’s source=mcp value is a recorded field; no live MCP transport or gateway authorization was exercised.
Manual exact-string selection: the request supplies from=Slate Pad, to=Slate Tablet, entity_type=product and a reason. Names normalize to lowercase. The triples were seeded, so this does not demonstrate automatic extraction or semantic discovery.
Immediate inverse: there is no compare-and-swap check. Reverting an older batch could overwrite a later change to the same identity field. This test applies the inverse immediately, with no intervening identity edit.
Identity restored, review metadata retained: the target rows’ prune_batch, reviewed_at and updated_at record the inverse. Full target rows do not return to their original bytes. Both controls and all source conversation/message rows remain byte-for-byte unchanged.
Profile boundary: the graph’s source profile groups exact labels without separating types. The typed mutation was verified; type-separated profile identities are outside this proof.
Verification: 18 feature tests / 189 assertions passed, with 1,600 additional mechanical checks of source files, responses and row hashes. No source patch, model inference, queue worker or production connection was needed. The owned runtime was removed.
View a captured merge state A capture of this portfolio replay. It displays synthetic results recorded by the actual Laravel endpoint test; it is not a shipped PanelForge screen. Open the full-size replay capture
Two different ways to explore memory
Understand the sample. Inspect the edit.
Memory Lab explains the shape of a reviewed knowledge-graph sample. This Curation Lab follows a separately executed write-and-inverse proof with synthetic fixtures.
A name is useful for finding things. A retained source is what lets someone inspect why a relationship exists.