Expose native Codex memory source policy, retrieval explanation, and foreign-source provenance controls
Problem
Codex needs a native, per-source memory policy so historical or provenance-only records can remain stored and inspectable while becoming ineligible for native search and prompt injection. This should not be implemented through a plugin, hook, MCP context layer, direct Markdown or SQLite edits, memory/reset, or a test-only selector.
At rust-v0.146.0-alpha.3.1, the experimental app-server protocol exposes thread/memoryMode/set({ threadId, mode }) with enabled | disabled and an empty response. It persists thread-level memory eligibility, but does not expose source-level retrieval selection.
Proposed API
All mutations and foreign-source admission use the existing app-server authorization model.
Thread-level eligibility integrity
This is separate from source-level retrieval policy.
thread/memoryMode/read({ threadId })
-> { threadId, mode, revision, effectiveAt }
thread/memoryMode/set({ threadId, expectedRevision, mode })
-> { threadId, previousMode, mode, revision, effectiveAt }
thread/memoryMode/updated
-> { threadId, previousMode, mode, revision, effectiveAt }
The setter must fail closed on a stale revision and must not reset, re-extract, reconsolidate, rewrite memory files, or imply source-level retrieval filtering.
Native source policy and explanation
memory/sources/list
-> [{ sourceId, revision, sourceKind, classification, effectiveRetrievalState }]
memory/retrieval/explain
-> [{ sourceId, revision, classification, included, selectionOrFilterReason }]
memory/sources/classification/set({
sourceId,
expectedRevision,
classification: "active" | "cold"
})
-> { sourceId, previousClassification, classification, revision, effectiveAt }
cold preserves source bytes, generated form, and provenance metadata while making that source ineligible before both native search and prompt injection. Responses use opaque source IDs and metadata by default; they do not return raw memory text, file paths, session identifiers, or unrelated source content unless an existing permitted read surface already permits it.
Foreign-source ingress
For a newly admitted source containing foreign-domain facts, native active-retrieval ingress should require an immutable source identity, canonical-owner assent bound to that identity, and thin_pointer content only. Missing, invalid, expired, revoked, or stale assent must deny publication and native query/prompt use. Existing legacy sources remain unchanged.
Derived index, summary, cache, transclusion, and prompt records need provenance metadata sufficient for revocation readback. Revocation must prevent future retrieval and prompt assembly; any residual derivative is excluded until readback is clean.
Implementation route
The app-server/protocol route owns request and response types, capability gating, schema generation, compare-and-swap errors, and notifications. The memory-runtime route owns source identity/revisions, classification metadata, effective retrieval state, filtering before search and injection, provenance metadata, audit receipts, and explanation/citation evidence. Both routes are required; protocol-only work does not change native retrieval.
Acceptance tests
- Two native sources, one
activeand onecold, remain stored while matching retrieval selects and injects only the active source. - Retrieval explanation reports the cold source as filtered with source ID, revision, classification, and reason, without raw source content by default.
- A stale revision fails without changing effective retrieval state; a compensating compare-and-swap restores the exact prior explanation and selection result.
- A foreign-source candidate without valid canonical-owner assent creates no derivative; a valid thin pointer can be admitted.
- Revocation prevents future native query and prompt use, and readback shows no residual derivative eligible for retrieval.
- Unrelated sources and threads retain baseline behavior; thread-level eligibility changes remain separate from source classification.
Related work
- #21889 — Open app-server thread-unload proposal; lifecycle context only.
- #18343 — Open scoped memory-management proposal; scope routing, not per-source policy or retrieval explanation.
- #19758 — Open topic-directory and memory-authoring proposal; storage and authoring shape, not native source policy.
- #20987 — Open memory read-only visibility report; capability visibility, not source classification.
- #17496 — Closed CWD-aware read-path filtering report; useful precedent, but not per-source state, compare-and-swap, or explanation.
- Discussion #12567 — Ideas discussion on Memories; feedback context, not an API contract.
None is a duplicate of the combined contract proposed here.
1 Comment
Two implementation details seem important for making the acceptance tests diagnostic rather than only behavioral:
active | coldbefore candidate search and ranking, not only before final prompt assembly. Otherwise a cold source can still perturb top-k selection, cache keys, or scores even if its content is later omitted.memory/retrieval/explainto the exact retrieval snapshot: query hash, policy revision, source revisions, candidate-set hash, and assembly outcome. If source-policy propagation or index invalidation is still pending, the receipt should saypending/incompleterather than describe a different snapshot.(sourceId, sourceRevision, policyRevision). The revocation test should pass only when no derivative from a revoked revision remains eligible for search or prompt assembly; deleting the top-level source alone is not enough.I maintain GoodMemory, where a read-only recall trace plus revision/forget paths have been useful for testing this receipt boundary. It is not a substitute for the native Codex policy requested here. The relevant lesson is that an explanation is trustworthy only when it is generated from the same immutable selection snapshot as the result it explains.