You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Paper §4.4 (Materials Binding) describes the session merkle tree as built over Claude Code's session JSONL:
The materialsFrom directive binds the policy to external artifacts. The session merkle tree is particularly important: by constructing a merkle tree over the session JSONL, we can prove:
Order: Turn n came after turns 0 through n−1
Completeness: No turns were omitted
Distance: Turns are contiguous (no gaps)
Code reality: aflock builds the merkle over aflock.ActionRecord — our own per-tool-call decision log (PreToolUse / PostToolUse records aflock chose to write). It is not the Claude session JSONL transcript.
Concretely:
internal/state/session.go:214ComputeSessionMerkleRoot iterates state.Actions (slice of aflock.ActionRecord).
internal/verify/verifier.goverifySessionMerkle re-marshals the same ActionRecords and compares.
The actual Claude JSONL transcript lives in ~/.claude/projects/<repo>/<session-uuid>.jsonl and is not input to either function.
Why this matters
The merkle root we publish today proves what aflock observed, not what Claude actually did. Concrete divergences:
Conceptual gap: even when aflock is fully on the call path, aflock records only decision/reason snapshots, not the full assistant message / tool result content. An auditor following the paper's claim would expect the merkle to bind to the JSONL line content; today it binds to a derived summary.
Paper reference
paper/aflock.tex §4.4 "Materials Binding". Also referenced by the §7 capability table row "Session ordering proofs: Merkle".
Proposed fix
Pick one — both are scoped, neither blocks the other:
Option A — Docs (smallest, recommended for v1)
Update the paper §4.4 wording to match implementation:
"by constructing a merkle tree over aflock's per-action record log..."
And note in §4.4 (and the §7 table caption) that the proof is bound to aflock's view of the session, with #100 as the known gap. This should land alongside or inside #65 (docs alignment) so we're not documenting a moving target.
Option B — Implementation (paper-90, larger)
Extend ComputeSessionMerkleRoot to also fold the Claude session JSONL lines into the tree:
Problem
Paper §4.4 (Materials Binding) describes the session merkle tree as built over Claude Code's session JSONL:
Code reality: aflock builds the merkle over
aflock.ActionRecord— our own per-tool-call decision log (PreToolUse/PostToolUserecords aflock chose to write). It is not the Claude session JSONL transcript.Concretely:
internal/state/session.go:214ComputeSessionMerkleRootiteratesstate.Actions(slice ofaflock.ActionRecord).internal/verify/verifier.goverifySessionMerklere-marshals the sameActionRecords and compares.~/.claude/projects/<repo>/<session-uuid>.jsonland is not input to either function.Why this matters
The merkle root we publish today proves what aflock observed, not what Claude actually did. Concrete divergences:
Agenttool uses native Bash/Write that bypassaflock-uds. Those tool calls land in the JSONL transcript but never inaflock.Actions— the merkle root and verify pipeline are silent on them.decision/reasonsnapshots, not the full assistant message / tool result content. An auditor following the paper's claim would expect the merkle to bind to the JSONL line content; today it binds to a derived summary.Paper reference
paper/aflock.tex§4.4 "Materials Binding". Also referenced by the §7 capability table row "Session ordering proofs: Merkle".Proposed fix
Pick one — both are scoped, neither blocks the other:
Option A — Docs (smallest, recommended for v1)
Update the paper §4.4 wording to match implementation:
And note in §4.4 (and the §7 table caption) that the proof is bound to aflock's view of the session, with #100 as the known gap. This should land alongside or inside #65 (docs alignment) so we're not documenting a moving target.
Option B — Implementation (paper-90, larger)
Extend
ComputeSessionMerkleRootto also fold the Claude session JSONL lines into the tree:~/.claude/projects/<digest>/<session-uuid>.jsonl(already discovered byinternal/usagein PR feat(usage): track JSONL tokens + cost, gated by api_key auth, with subagent rollup #127).ActionRecords.aflock.Actionwould now leave a detectable footprint in the merkle.Acceptance for closing this issue
ComputeSessionMerkleRootextended to include Claude JSONL leaves and verify enforces the binding (Option B).