Wave 4: ConversationArchive — custody of the vendor's session tree #52

Closed
mprihoda wants to merge 4 commits from wave-4-conversation-archive into wave-1-core-model
mprihoda commented 2026-07-15 12:13:51 +00:00 (Migrated from github.com)

Implements ADR 0001 decision 8 (custody, not attribution) and proposal §2.4. Stacked on #51.

What's here

  • ConversationArchive[F[_]] port in core/log following ConversationLogReader's tagless idiom: forSession / entries / subagentEntries / mirror, with a typed ArchiveError channel.
  • Pure decision core (FCIS): ArchivePaths (locates by encoding the configured cwd via ProjectPathEncoder — never decodes a directory name; the encoding is lossy) and MirrorPlanner (copy/extend/recopy/skip plan computed from file listings as data, unit-tested without IO). The planner iterates source files only, so vendor-pruned files are never touched in the archive — custody by construction.
  • ZioConversationArchive adapter: interprets the plan with file IO; append-extension reads bytes and appends only when the mirrored content is a true prefix of the source, falling back to full recopy on any divergence or shrink. Per-file failures are recorded in MirrorReport.failed instead of aborting a half-done mirror. Entry streaming delegates to ZioConversationLogReader, so RawLogEntry drift-tolerance is reused, not re-implemented; subagent join reuses ConversationLogIndex.listSubAgents via the meta.json toolUseId (additive field on SubAgentMetadata).
  • Mirrors the whole session TREE — main jsonl + subagents/*.jsonl + *.meta.json. ArchiveConfig(vendorProjectsDir, archiveDir, cwd) keeps CLAUDE_CONFIG_DIR configurable.
  • Per the ADR's rejected alternatives: no result journal, no attributed store. The library never grows a consumer's domain identifiers.

Known, deliberate limits (from the ADR's "does NOT settle" list)

  • Equal-size changed-content files are skipped (append-only vendor assumption; pinned by a test that documents the staleness).
  • File modes are not replicated; byte content is.

Verification

Full ./mill __.compile + all unit tests + zio.itest/core.itest green, including the real-CLI E2E: a live one-shot query with CLAUDE_CONFIG_DIR pointed at a temp dir, then locate → entries → subagentEntries → mirror → idempotency → extend → shrink-recopy against the transcript the CLI actually wrote. Reviewed by four dimension reviewers plus adversarial verification; all 5 confirmed findings fixed (incl. reuse of the index's subagent join and mirror non-atomicity hardening).

🤖 Generated with Claude Code

Implements ADR 0001 decision 8 (custody, not attribution) and proposal §2.4. Stacked on #51. ## What's here - **`ConversationArchive[F[_]]` port in `core/log`** following `ConversationLogReader`'s tagless idiom: `forSession` / `entries` / `subagentEntries` / `mirror`, with a typed `ArchiveError` channel. - **Pure decision core (FCIS)**: `ArchivePaths` (locates by **encoding** the configured cwd via `ProjectPathEncoder` — never decodes a directory name; the encoding is lossy) and `MirrorPlanner` (copy/extend/recopy/skip plan computed from file listings as data, unit-tested without IO). The planner iterates source files only, so vendor-pruned files are never touched in the archive — custody by construction. - **`ZioConversationArchive` adapter**: interprets the plan with file IO; append-extension reads bytes and appends **only** when the mirrored content is a true prefix of the source, falling back to full recopy on any divergence or shrink. Per-file failures are recorded in `MirrorReport.failed` instead of aborting a half-done mirror. Entry streaming delegates to `ZioConversationLogReader`, so `RawLogEntry` drift-tolerance is reused, not re-implemented; subagent join reuses `ConversationLogIndex.listSubAgents` via the meta.json `toolUseId` (additive field on `SubAgentMetadata`). - **Mirrors the whole session TREE** — main jsonl + `subagents/*.jsonl` + `*.meta.json`. `ArchiveConfig(vendorProjectsDir, archiveDir, cwd)` keeps `CLAUDE_CONFIG_DIR` configurable. - **Per the ADR's rejected alternatives: no result journal, no attributed store.** The library never grows a consumer's domain identifiers. ## Known, deliberate limits (from the ADR's "does NOT settle" list) - Equal-size changed-content files are skipped (append-only vendor assumption; pinned by a test that documents the staleness). - File modes are not replicated; byte content is. ## Verification Full `./mill __.compile` + all unit tests + `zio.itest`/`core.itest` green, **including the real-CLI E2E**: a live one-shot query with `CLAUDE_CONFIG_DIR` pointed at a temp dir, then locate → entries → subagentEntries → mirror → idempotency → extend → shrink-recopy against the transcript the CLI actually wrote. Reviewed by four dimension reviewers plus adversarial verification; all 5 confirmed findings fixed (incl. reuse of the index's subagent join and mirror non-atomicity hardening). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mprihoda commented 2026-07-15 14:26:11 +00:00 (Migrated from github.com)

Superseded by the consolidated PR #53 (single review over the full ADR 0001 implementation); the branch and its per-wave review history remain.

Superseded by the consolidated PR #53 (single review over the full ADR 0001 implementation); the branch and its per-wave review history remain.

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/claude-code-query!52
No description provided.