Emit fork and continuation relationships from Claude parser (#112)#122
Merged
willwashburn merged 3 commits intomainfrom Apr 26, 2026
Merged
Emit fork and continuation relationships from Claude parser (#112)#122willwashburn merged 3 commits intomainfrom
willwashburn merged 3 commits intomainfrom
Conversation
Closes the deferred-work item from #77/#42: the Claude passive reader now populates the full RelationshipType lattice instead of only `root` and `subagent`. Per-file evidence — in-log sessionId vs filename mismatches, the first user line's parentUuid, version, all in-file uuids, and `/resume` / `/continue` slash-command markers — is collected during the existing parse pass and surfaced as a new `evidence: ClaudeRelationshipEvidence` field on ParseResult / ParseIncrementalResult. A `/resume` marker in the file emits a local `continuation` row directly; a new exported `reconcileClaudeSessionRelationships(inputs)` helper takes per-file evidence from a multi-file pass and emits the cross-file `fork` / `continuation` rows that single-file parsers can't surface. Existing `root` / `subagent` rows are stamped with `sourceSessionId` (foreign in-log id) and `sourceVersion` whenever the file carries them. Reconciliation strategy is append, not mutate: a prior `root` row and a later `continuation` / `fork` row for the same session id produce different relationshipIdHash values (the hash includes relationshipType), so both rows coexist on disk and consumers prefer the more specific row when both are present. Re-ingesting the same session is idempotent — the writer's existing dedup folds duplicates across the new types too. The CLI ingest path runs the cross-file reconciliation step at end of each pass after every Claude file has parsed. New fixtures cover resume-marker, cross-file parentUuid continuation, and shared-source fork detection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
# Conflicts: # packages/cli/CHANGELOG.md # packages/cli/src/ingest.ts
…w on #112) A leading sidechain user line was arming the WeakSet, which then blocked the first non-sidechain user line from setting `firstParentUuid` and silently dropped the cross-file continuation signal for that session. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
RelationshipTypelattice (root/continuation/fork/subagent), not justrootandsubagent.sessionIdvs filename mismatches, the first user line'sparentUuid,version, all in-file uuids, and/resume//continueslash-command markers) and surfaces it as a newevidence: ClaudeRelationshipEvidencefield onParseResult/ParseIncrementalResult. A/resumemarker emits a localcontinuationrow directly.reconcileClaudeSessionRelationships(inputs)helper takes per-file evidence from a multi-file pass and emits the cross-filefork/continuationrows single-file parsers can't surface. The CLI ingest path runs it at end of pass.root/subagentrows are stamped withsourceSessionId(foreign in-log id) andsourceVersionwhenever the file carries them.Reconciliation strategy
Append, not mutate.
relationshipIdHashkeys onrelationshipType, so a priorrootrow and a latercontinuation/forkrow for the same session id produce different hashes — both rows coexist on disk after a follow-up reconciliation pass. Consumers that care about "is this session a child of another?" prefer the more specific row (fork/continuation>root) when both are present. This keeps the ledger append-only and re-ingest idempotent (the writer's existingrelationshipIdHashdedup folds duplicates of the new types too).Test plan
pnpm run test:ts(461 tests, all pass)packages/reader/src/claude.test.ts:/resumemarker, withrelatedSessionIdset to the resumed-from idsourceSessionIdandsourceVersionon existingrootrows when the in-log id differs from the file idreconcileClaudeSessionRelationshipsemits a continuation row when one file's firstparentUuidlives in another filereconcileClaudeSessionRelationshipsemits fork rows when two files share asourceSessionIdreconcileClaudeSessionRelationshipsdoes not emit a fork row when one file is a strict continuation of the other/resumealready named the same parentsourceSessionId/sourceVersionon subagent rows when the in-log id differs from the file basenameresume-marker.jsonl,original-session.jsonl,cross-file-parent.jsonl,fork-branch-a.jsonl,fork-branch-b.jsonlRefs
🤖 Generated with Claude Code