Skip to content

Wire Muse Code into the session-log collector + backfill (CROW-1106) - #1108

Merged
dhilgaertner merged 1 commit into
mainfrom
feature/crow-1106-wire-muse-collector
Aug 24, 2026
Merged

Wire Muse Code into the session-log collector + backfill (CROW-1106)#1108
dhilgaertner merged 1 commit into
mainfrom
feature/crow-1106-wire-muse-collector

Conversation

@dhilgaertner

Copy link
Copy Markdown
Contributor

Closes #1106. Follow-up to the CROW-1099 research spike (#1099 / PR #1102): wires Muse Code into the live session-log collector (CROW-1056) and the historical backfill (CROW-1075), mirroring the Codex/Grok pattern (#1092, #1103).

⚠️ The CROW-1099 gate was overridden (operator decision)

Step 0 of the ticket is a hard gate: verify payload.record.workspace_root on a real session.jsonl before wiring. That gate could not run — Muse Code is Meta-auth-gated and is not installable on this dev machine (verified five ways: no muse binary on any fallback path, no ~/.local/share/muse store, no session.jsonl anywhere, no META_API_KEY, crow agents listavailable:false). This is the same blocker CROW-1099 recorded.

Asked how to proceed, the operator explicitly chose to wire against the documented third-party evidence (superbasedapp/observer's Muse 0.1.0 parse — payload.record.workspace_root on the line-1 runtime.session.metadata record) rather than wait for a live install. This is recorded here for reviewers: the acceptance item "workspace_root verified on a real session.jsonl" is not satisfied, by design.

It fails safe. Attribution is content-filtered (Codex-style): if the real key or store path differs from the third-party evidence, the cwd filter matches nothing and Muse silently collects zero transcripts — never a misattributed upload (the never-guess posture CROW-1089 requires). Confirming workspace_root on a real journal stays a version-pinned re-check target (recorded in agent-harness-matrix.md).

What changed (mirrors the Codex/Grok wiring)

  • TranscriptHead.absorb learns Muse's payload.record.workspace_root (nested one level deeper than Codex's payload.cwd; the three shapes are disjoint).
  • LogSyncHarness gains .muse — internally first-class (drives the ledger slot / backfill display / format+agentKind), wireValue collapses to unknown until the server CHECK (corveil#2426) accepts muse, exactly like .grok.
  • AgentLogSource gains excludePathComponents, used to skip Muse's nested subagent/<child>/session.jsonl child sessions — in lockstep across the live collector (LogSyncCollector.resolveFiles) and the backfill scanner.
  • MuseHome (new) resolves ${XDG_DATA_HOME:-~/.local/share}/muse.
  • MuseAgent.logSources — recursive, cwd-filtered .logDir source (session-prefixed, subagent-excluded), replacing the CROW-1099 research note.
  • BackfillBackfillScanner.museSessionsDir + museSessionFiles() + reconstructMuse(); BackfillService injects MuseHome.sessionsDir() and maps .muse (.logDir stamp matching the live path, muse agentKind).
  • Docs — Muse flipped Deferred → Wired in session-log-collector.md, harness-transcript-locations.md, session-backfill.md, plus a re-check row in agent-harness-matrix.md.

Testing

  • swift test green across CrowCore (780 tests), CrowMuse, and the CrowDaemon LogSync/Backfill suites (28 tests). New coverage: Muse head parsing, logSources shape, cwd-filter + subagent exclusion + drop-on-no-cwd, backfill reconstruction (incl. subagent skip and low-confidence orphan when workspace_root is absent), harness-scoped ledger keying, MuseHome XDG resolution.
  • Root swift build links clean; make parity green.
  • Two unrelated CrowDaemon suites (RPCLanePolicyTests, WebNotificationCenterTests.bootCatchResetsTheHistory) fail — verified pre-existing on the base commit 47c74331, in code this PR does not touch.

🤖 Generated with Claude Code

@dhilgaertner dhilgaertner added the crow:merge Crow auto-merge on green label Aug 24, 2026

@dgershman dgershman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code & Security Review

Muse is wired through the same Codex-shaped path the collector already uses for a globally pooled, cwd-attributed NDJSON store — AgentLogSource + TranscriptHeadReader.absorb + BackfillScanner + LogSyncHarness wire-collapse. That is the right shape. Tests cover parse, subagent skip, fail-closed missing-cwd, ledger slotting, and MuseHome XDG resolution. swift build succeeded.

Critical Issues

None.

Architecture / Existing Patterns

  • Existing pathway: Codex content-filtered global store (AgentLogSource.cwdFilter + recursive .logDir + TranscriptHeadReader.absorb + BackfillScanner.reconstructX + LogSyncHarness internal/wire split). This PR extends that pathway; excludePathComponents is a small generic addition, not a parallel collector.
  • No architecture defect. Muse is Codex-like (pooled tree, cwd in the journal) rather than Grok-like (path-partitioned), and the code treats it that way.

Security Review

Strengths:

  • Fail-closed attribution: no readable workspace_root ⇒ drop (live) / low-confidence orphan (backfill), never a guessed worktree. Matches CROW-1089.
  • LogSyncHarness.muse.wireValue collapses to unknown, same as Grok — uploads cannot trip the server CHECK.
  • Opt-in collector, destination/credential still only from the workspace's local-only gateway. No new secret surface. MuseHome does not read ~/.config/muse/auth.json.
  • Empty XDG_DATA_HOME= is treated as unset (no CWD-relative path), matching CodexHome / GrokHome.

Concerns:

  • The workspace_root key is still unverified against a live Muse journal. That is an accepted, documented risk (PR body + matrix row) and the fail-closed filter makes a wrong key collect nothing rather than misattribute. Not blocking. Confirm against a real session.jsonl when Muse is installable (already listed as a version-pinned re-check).
  • Third-party observer (superbasedapp/observer internal/adapter/muse) agrees on the store path ($XDG_DATA_HOME|~/.local/share/muse/sessions/YYYY/MM/DD/<id>/session.jsonl) and on payload.record.workspace_root. Crow's simplified test fixtures omit the real envelope (schema_version / payload_type); absorb is key-tolerant so the real envelope still parses — worth a fixture that matches observer's line-1 record when you re-check.

Code Quality

Yellow — operator-facing CLI docs still say Muse is unwired. CROW-1098 updated these same sentences when Grok was wired. This PR correctly flipped Muse to Wired in docs/session-log-collector.md, docs/harness-transcript-locations.md, docs/session-backfill.md, and docs/agent-harness-matrix.md, but left the CLI/operator surface claiming only Claude, Codex, and Grok:

  • docs/cli.md:1119 — "Claude Code, Codex, and Grok Build transcripts are collected today (CROW-1089, CROW-1098); other harnesses are wired as their on-disk log locations are confirmed."
  • docs/cli-reference.md:1766 (live collector) and :1772 (backfill) — same roster, "all three reconstruct reliably."
  • CLAUDE.md:317 and :321 — same stale roster (this is what Manager sessions read).

An operator (or a later agent) reading the CLI help will think Muse is still deferred. Add Muse / CROW-1106 next to Grok / CROW-1098, matching the collector docs this PR already landed. Also refresh the stale comment at Packages/CrowDaemon/Sources/CrowDaemon/LogSyncCollector.swift:110-114 ("everything but Claude, Codex, and Grok today").

Green — subagent logs are dropped rather than folded into the parent. MuseAgent.logSources (Packages/CrowMuse/Sources/CrowMuse/MuseAgent.swift:260-262, :276-280) and BackfillScanner.museSessionFiles skip <id>/subagent/<child>/session.jsonl. Observer includes those child journals in the parent (they carry tokens the parent log does not, and children often have no metadata record of their own). Skipping is a documented v1 choice and is fail-safe if children inherit the parent's cwd (avoids minting extra backfill rows / concatenating a different session into the live artifact). When you re-check against a real tree, decide whether v2 should fold children into the parent the way observer does.

Green — fileNamePrefix: "session" is slightly broader than session.jsonl. It will also match a hypothetical session-foo.jsonl. Observer only reads session.jsonl. Harmless today; lock it to the exact name if Muse ever drops siblings.

Summary Table

Color Meaning Verdict effect
Red Must-fix Request changes
Yellow Should-fix Request changes
Green Consider Approve allowed

Recommendation: Request Changes — 0 Red, 1 Yellow, 2 Green.


🐦‍⬛ Reviewed by Crow via Cursor

@dhilgaertner
dhilgaertner force-pushed the feature/crow-1106-wire-muse-collector branch 2 times, most recently from adeee6a to b14286d Compare August 24, 2026 17:58
@dhilgaertner
dhilgaertner requested a review from dgershman August 24, 2026 17:59

@dgershman dgershman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code & Security Review

This is a second look after the prior request-changes (operator-facing CLI roster). The collector/backfill wiring itself is still the right Codex-shaped path. The follow-up patched generated docs/cli.md by hand instead of the ArgumentParser source, and that fails the docs freshness gate.

Critical Issues

Red — docs/cli.md was hand-edited; CLIDocsTests.committedGeneratedDocIsUpToDate fails. Verified by running swift test --package-path Packages/CrowCLI --filter committedGeneratedDocIsUpToDate on this HEAD (b14286d): expectation failed, docs/cli.md is stale — run make docs and commit the result.

docs/cli.md is generated (crow generate-docs / make docs) from ArgumentParser metadata. Its header says not to edit it by hand. This follow-up added Muse to docs/cli.md:1119 (the crow logsync discussion) but left the actual source stale:

  • Packages/CrowCLI/Sources/CrowCLILib/Commands/LogsyncCommands.swift:28-31crow logsync --help still ends at OpenCode (CROW-1089 / CROW-1098 / CROW-1095 / CROW-1096).
  • Packages/CrowCLI/Sources/CrowCLILib/Commands/BackfillCommands.swift:87--session help still says "Claude Code, Codex, Grok Build, or Cursor", which is why docs/cli.md:428 (in this PR's own diff) still does too.

The matching hand-written copy in docs/cli-reference.md:1804 was updated. Fix: add Muse / CROW-1106 in LogsyncCommands.swift and BackfillCommands.swift (same lockstep #1104 used for OpenCode), then make docs so the generated file matches. Do not keep a hand-patch in docs/cli.md.

Architecture / Existing Patterns

  • Existing pathway: Codex-style content-filtered global NDJSON store — AgentLogSource (recursive .logDir + cwdFilter) + TranscriptHeadReader.absorb + BackfillScanner.reconstructX + LogSyncHarness internal/wire split + *Home XDG resolution. excludePathComponents is a small generic extension of that path, applied in LogSyncCollector.resolveFiles, not a parallel collector.
  • No architecture defect. Muse is pooled + cwd-in-journal (Codex-like), not path-partitioned (Grok-like), and the code treats it that way.

Security Review

Strengths:

  • Fail-closed attribution: no readable workspace_root ⇒ drop (live) / low-confidence orphan (backfill). Matches CROW-1089.
  • LogSyncHarness.muse.wireValue collapses to unknown, same as Grok — uploads cannot trip the server CHECK.
  • Opt-in collector; destination/credential still only from the workspace's local-only gateway. MuseHome does not read ~/.config/muse/auth.json.
  • Empty XDG_DATA_HOME= is treated as unset (no CWD-relative path), matching OpenCodeHome.

Concerns:

  • Green — unverified workspace_root key. Accepted, documented risk (PR body, matrix row, TranscriptHead.swift absorb comment). A wrong key collects nothing rather than misattributing. Confirm on a real session.jsonl when Muse is installable.

Code Quality

  • Green — prior Yellow on collector/manager docs is addressed in CLAUDE.md, docs/cli-reference.md, docs/session-log-collector.md, docs/session-backfill.md, docs/harness-transcript-locations.md, and the LogSyncCollector.swift comment. The remaining roster gap is the Red above (CLI source + generated docs/cli.md), not those files.
  • Green — subagent journals are skipped, not folded. MuseAgent.logSources and BackfillScanner.museSessionFiles drop <id>/subagent/<child>/session.jsonl. Safe v1 choice; revisit on a live tree if children should fold into the parent.
  • Green — fileNamePrefix: "session" is slightly broader than session.jsonl. Harmless today.
  • CrowMuse tests: 63 passed. Root swift build linked clean. CrowCLI docs freshness test failed as above. Did not re-run the unrelated CrowDaemon suites the PR notes as pre-existing on 47c74331.

Summary Table

Color Meaning Verdict effect
Red Must fix Request changes
Yellow Should fix Request changes
Green Consider Approve allowed

Recommendation: Request Changes — driven by 1 Red, 0 Yellow, 3 Green findings.


🐦‍⬛ Reviewed by Crow via Cursor

@dhilgaertner
dhilgaertner force-pushed the feature/crow-1106-wire-muse-collector branch 2 times, most recently from 3c97b90 to 543e96d Compare August 24, 2026 18:15
@dhilgaertner
dhilgaertner requested a review from dgershman August 24, 2026 18:15

@dgershman dgershman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code & Security Review

Second look on HEAD 543e96d after the earlier request-changes rounds (stale operator-facing roster, then hand-patched docs/cli.md). Those are resolved: LogsyncCommands.swift / BackfillCommands.swift name Muse, generated docs/cli.md matches, and CLIDocsTests.committedGeneratedDocIsUpToDate passed. Root swift build linked clean.

Critical Issues

None.

Architecture / Existing Patterns

  • Existing pathway: Codex-style content-filtered global NDJSON store — recursive .logDir + cwdFilter on AgentLogSource, TranscriptHeadReader.absorb for the cwd key, BackfillScanner.reconstructX + daemon-injected *Home, LogSyncHarness internal/wire split. This PR extends that path; excludePathComponents is a small generic addition applied in LogSyncCollector.resolveFiles and BackfillScanner.museSessionFiles(), not a parallel collector.
  • Muse is pooled + cwd-in-journal (Codex-like), not path-partitioned (Grok-like), and the code treats it that way. MuseHome follows OpenCodeHome's XDG resolution.

Security Review

Strengths:

  • Fail-closed attribution: no readable workspace_root ⇒ drop (live) / low-confidence orphan (backfill), never a guessed worktree (TranscriptHead.swift absorb fallback; BackfillScannerTests.museJournalWithoutWorkspaceRootIsLowConfidence). Matches CROW-1089.
  • LogSyncHarness.muse.wireValue collapses to unknown, same as Grok — uploads cannot trip the server CHECK. Ledger still keys on rawValue (muse), so Muse/Grok/Claude slots do not collide (BackfillServiceTests.museSessionUploadsUnderMuseHarnessSlot).
  • Opt-in collector; destination/credential still only from the workspace's local-only gateway. MuseHome does not read Muse auth files.
  • Empty XDG_DATA_HOME= is treated as unset (no CWD-relative path), matching OpenCodeHome.

Concerns:

  • Green — unverified workspace_root key. Accepted, documented risk (PR body, matrix row, TranscriptHead.swift absorb comment). Cross-checked against superbasedapp/observer internal/adapter/muse/adapter.go: same store path, same payload.record.workspace_root, same subagent/ child dir. A wrong key collects nothing rather than misattributing. Confirm on a real session.jsonl when Muse is installable.

Code Quality

  • Green — prior Red/Yellow on CLI docs is addressed. Muse / CROW-1106 is in LogsyncCommands.swift, BackfillCommands.swift (--session help included), generated docs/cli.md, docs/cli-reference.md, CLAUDE.md, and the LogSyncCollector.swift wired-harness comment. Freshness test passed on this HEAD.
  • Green — subagent journals are skipped, not folded. MuseAgent.logSources and BackfillScanner.museSessionFiles drop <id>/subagent/<child>/session.jsonl. Observer includes children (they carry tokens the parent log does not). Skipping is a documented v1 choice and is fail-safe if children inherit the parent's cwd. Revisit on a live tree if v2 should fold them.
  • Green — fileNamePrefix: "session" is slightly broader than session.jsonl. Observer only reads the exact basename. Harmless today; lock it to the exact name if Muse ever drops siblings.

Summary Table

Color Meaning Verdict effect
Red Must fix Request changes
Yellow Should fix Request changes
Green Consider Approve allowed

Recommendation: Approve — driven by 0 Red, 0 Yellow, 3 Green findings.


🐦‍⬛ Reviewed by Crow via Cursor

Follow-up to the CROW-1099 research spike (#1102): wire Muse Code into the live
session-log collector (CROW-1056) and the historical backfill (CROW-1075),
mirroring the Codex/Grok pattern (#1092, #1103).

Muse pools its journals globally at
${XDG_DATA_HOME:-~/.local/share}/muse/sessions/<date>/<id>/session.jsonl, so it is
attributed by content (Codex-style): the recorded cwd is read from the line-1
runtime.session.metadata record at payload.record.workspace_root.

- TranscriptHead.absorb learns payload.record.workspace_root (Muse cwd).
- LogSyncHarness gains .muse (internally first-class; wireValue collapses to
  unknown until the server CHECK accepts muse, exactly like .grok).
- AgentLogSource gains excludePathComponents, used to skip Muse's nested
  subagent/ child sessions in lockstep across the live collector + backfill.
- MuseHome resolves ${XDG_DATA_HOME:-~/.local/share}/muse.
- MuseAgent.logSources: recursive, cwd-filtered .logDir source (session-prefixed,
  subagent-excluded), replacing the CROW-1099 research note.
- BackfillScanner: museSessionsDir + museSessionFiles() + reconstructMuse();
  BackfillService injects MuseHome and maps .muse (.logDir stamp, muse agentKind).
- Tests across CrowCore / CrowMuse / CrowDaemon; docs flipped Deferred -> Wired.

Gate override: CROW-1099's hard gate (verify workspace_root on a REAL
session.jsonl) could NOT run here -- Muse is Meta-auth-gated and not installable
on the dev machine (crow agents list -> available:false). The operator explicitly
chose to wire against the documented third-party evidence
(superbasedapp/observer's Muse 0.1.0 parse) rather than wait. It fails safe: if
the real key or store path differs, the cwd filter matches nothing and Muse
silently collects zero transcripts -- never a misattributed upload (the
never-guess posture CROW-1089 requires). Confirming workspace_root on a real
journal remains a version-pinned re-check target.

🐦‍⬛ Generated with Claude Code, orchestrated by Crow

Co-Authored-By: Claude <noreply@anthropic.com>
Crow-Session: 205288D2-7741-436C-8836-B5AA976ED626
@dhilgaertner
dhilgaertner force-pushed the feature/crow-1106-wire-muse-collector branch from 543e96d to 6f169df Compare August 24, 2026 18:57
@dhilgaertner
dhilgaertner enabled auto-merge (squash) August 24, 2026 18:58
@dhilgaertner
dhilgaertner merged commit 3c60712 into main Aug 24, 2026
4 checks passed
@dhilgaertner
dhilgaertner deleted the feature/crow-1106-wire-muse-collector branch August 24, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crow:merge Crow auto-merge on green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire Muse Code into the session-log collector + backfill (CROW-1099 follow-up)

2 participants