Symptom
remember returns a provenance block whose hint contradicts its own checkable_refs in the same payload:
"provenance": {
"grade": "unverifiable",
"checkable_refs": {"file": 3, "commit": 0, "url": 1, "artifact": 0, "citation": 0},
"hint": "No checkable reference found (file path, commit SHA, URL, or content-addressed artifact digest). For a durable claim, add one -- ..."
}
Three file references and one URL were extracted, and the hint says none was found. The writer is told to add a reference they already added, and is given no way to discover what actually went wrong.
The grading is correct — the message is not
Reproduced on memory 4338538 (written 2026-08-02 with directory pointing at the Cortex checkout). One of the extracted paths was plugins/hypermnesia-mcp-codex/.mcp.json, which exists only on the unmerged agent/add-codex-plugin branch and is absent from the checked-out worktree:
$ ls plugins/hypermnesia-mcp-codex/.mcp.json
ls: plugins/hypermnesia-mcp-codex/.mcp.json: No such file or directory
So grade_provenance (mcp_server/core/provenance.py:181-186) correctly classified it as a dead ref, and the worst-outcome rule (provenance.py:227) correctly rebated the whole memory to unverifiable. No bug there — the grader cannot verify a path that is not on disk.
The defect is in the feedback. _build_reason (provenance.py:144-151) already computes the exact diagnosis and distinguishes the two cases:
if grade == UNVERIFIABLE and dead:
return f"dead_refs: {', '.join(dead[:3])}"
if grade == UNVERIFIABLE:
return "no_extractable_reference"
But write_time_hint (provenance.py:292-308) ignores it and keys a fixed string off report.grade alone:
hint = _WRITE_TIME_HINTS[report.grade]
and _WRITE_TIME_HINTS[UNVERIFIABLE] (provenance.py:274-277) unconditionally asserts "No checkable reference found". Meanwhile remember_helpers.py:867-872 surfaces only grade, checkable_refs, and hint — report.reason, report.dead_refs, and report.uncheckable_refs are all dropped from the write response, even though validate_memory.py:560 does surface uncheckable_refs on its own path.
Net effect: the one field that names the actual problem is computed, then discarded, and replaced by a statement that the same payload disproves.
Why it matters beyond cosmetics
The hint is the write-time correction loop (M-D5: "so the writer sees, in the SAME response, whether their claim carries a checkable reference and can complete it by superseding this memory if not"). When the message misdiagnoses a dead ref as a missing ref, that loop cannot close: the writer has no way to learn which of their paths did not resolve, so the memory stays unverifiable and, per the appended deliberate suffix, degrades under recall competition. This is the mechanism behind the cluster of otherwise-well-referenced archival entries currently graded unverifiable.
Proposed fix
Make the write-time hint reflect report.reason rather than report.grade alone, and stop dropping the diagnosis:
- In
write_time_hint, branch on the dead-ref case and name the offending paths — the data is already in report.dead_refs.
- Add
reason (and dead_refs, capped as _build_reason already caps it at 3) to the provenance block in remember_helpers.py:867-872, matching what validate_memory already exposes.
- Keep the existing
no_extractable_reference wording for the genuinely-empty case only.
A dead-ref hint should read closer to: "1 of 4 references could not be resolved on disk: plugins/hypermnesia-mcp-codex/.mcp.json. Fix the path or drop it, then supersede this memory."
Non-goals
- Not proposing to change the grading rule. Worst-outcome is correct: a memory citing a path that is not there should not grade as verified.
- Not proposing to resolve refs against git branches or history. A ref that only exists on an unmerged branch is genuinely unverifiable from the worktree; the writer should know that, which is exactly what this issue asks for.
Acceptance
A remember call whose content cites one existing and one non-existent path returns a provenance block that names the non-existent path and does not claim that no reference was found.
Symptom
rememberreturns aprovenanceblock whosehintcontradicts its owncheckable_refsin the same payload:Three file references and one URL were extracted, and the hint says none was found. The writer is told to add a reference they already added, and is given no way to discover what actually went wrong.
The grading is correct — the message is not
Reproduced on memory 4338538 (written 2026-08-02 with
directorypointing at the Cortex checkout). One of the extracted paths wasplugins/hypermnesia-mcp-codex/.mcp.json, which exists only on the unmergedagent/add-codex-pluginbranch and is absent from the checked-out worktree:So
grade_provenance(mcp_server/core/provenance.py:181-186) correctly classified it as a dead ref, and the worst-outcome rule (provenance.py:227) correctly rebated the whole memory tounverifiable. No bug there — the grader cannot verify a path that is not on disk.The defect is in the feedback.
_build_reason(provenance.py:144-151) already computes the exact diagnosis and distinguishes the two cases:But
write_time_hint(provenance.py:292-308) ignores it and keys a fixed string offreport.gradealone:and
_WRITE_TIME_HINTS[UNVERIFIABLE](provenance.py:274-277) unconditionally asserts "No checkable reference found". Meanwhileremember_helpers.py:867-872surfaces onlygrade,checkable_refs, andhint—report.reason,report.dead_refs, andreport.uncheckable_refsare all dropped from the write response, even thoughvalidate_memory.py:560does surfaceuncheckable_refson its own path.Net effect: the one field that names the actual problem is computed, then discarded, and replaced by a statement that the same payload disproves.
Why it matters beyond cosmetics
The hint is the write-time correction loop (M-D5: "so the writer sees, in the SAME response, whether their claim carries a checkable reference and can complete it by superseding this memory if not"). When the message misdiagnoses a dead ref as a missing ref, that loop cannot close: the writer has no way to learn which of their paths did not resolve, so the memory stays
unverifiableand, per the appendeddeliberatesuffix, degrades under recall competition. This is the mechanism behind the cluster of otherwise-well-referenced archival entries currently gradedunverifiable.Proposed fix
Make the write-time hint reflect
report.reasonrather thanreport.gradealone, and stop dropping the diagnosis:write_time_hint, branch on the dead-ref case and name the offending paths — the data is already inreport.dead_refs.reason(anddead_refs, capped as_build_reasonalready caps it at 3) to theprovenanceblock inremember_helpers.py:867-872, matching whatvalidate_memoryalready exposes.no_extractable_referencewording for the genuinely-empty case only.A dead-ref hint should read closer to: "1 of 4 references could not be resolved on disk: plugins/hypermnesia-mcp-codex/.mcp.json. Fix the path or drop it, then supersede this memory."
Non-goals
Acceptance
A
remembercall whose content cites one existing and one non-existent path returns aprovenanceblock that names the non-existent path and does not claim that no reference was found.