Read-surface parity audit (Vault R1)
Scope check of the original (June 18) “notes first-class on the read half” card against the retrieve stack that shipped after it (F1.5). Verdict per item, with the code that settles it.Already shipped — do NOT rebuild
- Explicit trust on every result —
apps/api/src/topics/retrieve.service.ts(trustOf: reviewed →knowledge, proposed →proposed, elsenote); every retrieve result carries a flattrustfield. - Trust-weighted ranking — same file (
score): reviewed +1.2 / proposed +0.5 over the ~0.5–1.0 signal base, so trust is the dominant axis and text-rank orders within a tier. - Own-drafts visible in retrieve —
topic-query.service.ts#search(draft-visibility clause): with a principal,status <> 'draft' OR created_by = :__pu. Another user’s private draft is never leaked (is_privateclause +TopicAccessPolicy.filterVisible). include_notesopt-in for surfacing beyond own drafts, on retrieve, search and list.
Gaps found → closed by this change
- Search route dropped the principal.
GET /topics/searchcalledsearch()withoutprincipalUserId, so the caller’s own fresh note was invisible in search while retrieve returned it — the write→read cycle broke on one of the two read surfaces. Fixed intopics.controller.ts#search(passesprincipal.clerkUserId); pinned bywrite-read-cycle.integration.spec.ts. - No CI gate on the write→read cycle. Now
write-read-cycle.integration.spec.ts: a note written today is retrievable by its author with the obvious query on BOTH surfaces, no opt-in; a stranger never sees it. (Placed as an integration spec, not inevals/run-retrieval-scale.mjs— that harness enforcesassertReadOnlyon every call and a live WRITE would break its invariant.) - Loop bundle had no trust labels.
card next’scontext_bundlereturned bare{type, ref}pointers, so the loop agent couldn’t weigh a hint against team truth without hydrating each topic. Fixed incards.service.ts(additivetruston topic/note pointers, same vocabulary as retrieve; best-effort, never failsnext).
Deliberately NOT changed
include_notesdefault stays opt-in. Flipping a retrieval default without a before/after measurement over ≥10 real-corpus queries is how agents break silently; the measurement needs the live workspace corpus. If the delta ever proves material, the change is scoped to the CALLER’S OWN notes only — never others’ private notes.- Search stays lexically ranked (ts_rank), without retrieve’s trust boost. Search is the literal-lookup surface; retrieve is the intent-ranked surface. Reordering search results would change a long-standing contract for no demonstrated gain — trust badges are already on every summary.
