Audit — R93 B5 Document session_id Binding in Audit-Proof Workflow
Round: R93 debug-sweep (fix #5 of 6, doc-only)
Branch: feature/r93-b5-session-id-binding-docs
Base SHA: fbc8808a
β task: c4aba667-892c-4c99-94fb-1ae25050331d
Closes parked R89 investigation: 6f309f3a-7d22-4e2c-a02d-3a62fc46c834 (merkle_finalize ERR_NO_RECORDS root cause).
§1. Goal
The R88 calling pattern that produced merkle_finalize ERR_NO_RECORDS even with task-bound thought_record rows was caused by missing session_id on the thought_record calls. Document the requirement so the next executor working a proof-grade slice doesn’t repeat the mistake.
§2. Code reality
§2.1. merkle_finalize binding
src/tools/merkle.ts:296-300:
const hashesStmt = db.prepare<[string], { hash: string }>(
`SELECT hash FROM thought_records
WHERE session_id = ?
ORDER BY rowid ASC`,
);
The query is WHERE session_id = ?. The binding key is thought_records.session_id, not task_id.
§2.2. thought_record schema
src/domains/trail/repository.ts:139-145:
const CreateThoughtRecordInputSchema = z.object({
type: z.enum(THOUGHT_TYPES),
task_id: z.string().min(1),
agent_id: z.string().min(1),
content: z.string().min(1, 'thought content must be non-empty'),
session_id: z.string().min(1).optional(),
});
session_id is optional. When omitted, repository.ts:252 stores NULL:
const sessionId = parsed.session_id ?? null;
This is correct — non-proof-grade work writes thought records without a session. But the moment a caller opens audit_session_start, every subsequent thought_record in that proof chain MUST pass the returned session_id, otherwise merkle_finalize (whose WHERE session_id = ? query excludes NULL-bound rows) returns ERR_NO_RECORDS.
§3. Existing documentation gaps
§3.1. .agents/skills/colibri-audit-proof/SKILL.md
- §”The load-bearing ordering rule” lifecycle diagram (lines 28-40) mentions the ordering of calls but not the session_id propagation requirement.
- All
thought_recordexample JSON blocks (lines 82-106) usethought_type(wrong; the actual field istype) and passsession_idbut omit the requiredtask_id+agent_id. The examples will fail Zod validation if pasted verbatim into an MCP call. - §”Operating rules” rule 4 says “Carry forward
session_idfrom the initial call to every subsequent call in the chain” but isn’t load-bearing enough to surface the failure mode.
§3.2. docs/agents/writeback-protocol.md
- §1.2 thought_record example uses
thought_type(wrong; should betype) and omitstask_id+agent_id. - §3.1 audit_session_start example uses
name=<task-slug>, scope="task"— neither field exists in the actual schema. Real fields areintent,task_id?,session_id?. - §3.3 audit_verify_chain example uses
session_id=<from start>— butaudit_verify_chainaccepts onlytask_id?, notsession_id. - §10 “Proof-grade example” reproduces all three errors.
- No explicit anti-pattern entry for “writing thought_record without session_id between audit_session_start and merkle_finalize”.
§3.3. .claude/skills/colibri-audit-proof/SKILL.md
R77.C mirror of .agents/skills/colibri-audit-proof/SKILL.md. Must be kept byte-clean.
§4. Constraints on the fix
- MUST NOT modify any source code or any handler behaviour.
- MUST update the audit-proof skill (canonical + mirror) and the writeback protocol document to make session_id propagation explicit.
- MUST fix the example field shapes to match the live Zod schemas so the docs stop teaching the wrong calling pattern.
- MAY fix the audit_session_start + audit_verify_chain example shapes while in the neighbourhood (adjacent to the session_id story).
- MUST NOT touch
CLAUDE.md§7 in this slice (separate concern, broader review scope). - After PR merges, the parked R89 task
6f309f3a-7d22-4e2c-a02d-3a62fc46c834should be marked DONE — but that’s a separate β writeback after merge, not part of this slice.
§5. Path forward
Three doc edits + one mirror sync:
.agents/skills/colibri-audit-proof/SKILL.md— fix examples + add session_id callout.docs/agents/writeback-protocol.md— fix audit_session_start, audit_verify_chain, thought_record examples + add session_id anti-pattern..claude/skills/colibri-audit-proof/SKILL.md— mirror sync.
Proceeding to contract + packet (combined for XS scope).