Wire Muse Code into the session-log collector + backfill (CROW-1106) - #1108
Conversation
dgershman
left a comment
There was a problem hiding this comment.
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+LogSyncHarnessinternal/wire split). This PR extends that pathway;excludePathComponentsis 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.wireValuecollapses tounknown, 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.
MuseHomedoes not read~/.config/muse/auth.json. - Empty
XDG_DATA_HOME=is treated as unset (no CWD-relative path), matchingCodexHome/GrokHome.
Concerns:
- The
workspace_rootkey 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 realsession.jsonlwhen Muse is installable (already listed as a version-pinned re-check). - Third-party observer (
superbasedapp/observerinternal/adapter/muse) agrees on the store path ($XDG_DATA_HOME|~/.local/share/muse/sessions/YYYY/MM/DD/<id>/session.jsonl) and onpayload.record.workspace_root. Crow's simplified test fixtures omit the real envelope (schema_version/payload_type);absorbis 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:317and: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.
adeee6a to
b14286d
Compare
dgershman
left a comment
There was a problem hiding this comment.
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-31—crow logsync --helpstill ends at OpenCode (CROW-1089 / CROW-1098 / CROW-1095 / CROW-1096).Packages/CrowCLI/Sources/CrowCLILib/Commands/BackfillCommands.swift:87—--sessionhelp still says "Claude Code, Codex, Grok Build, or Cursor", which is whydocs/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+LogSyncHarnessinternal/wire split +*HomeXDG resolution.excludePathComponentsis a small generic extension of that path, applied inLogSyncCollector.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.wireValuecollapses tounknown, same as Grok — uploads cannot trip the server CHECK.- Opt-in collector; destination/credential still only from the workspace's local-only gateway.
MuseHomedoes not read~/.config/muse/auth.json. - Empty
XDG_DATA_HOME=is treated as unset (no CWD-relative path), matchingOpenCodeHome.
Concerns:
- Green — unverified
workspace_rootkey. Accepted, documented risk (PR body, matrix row,TranscriptHead.swiftabsorb comment). A wrong key collects nothing rather than misattributing. Confirm on a realsession.jsonlwhen 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 theLogSyncCollector.swiftcomment. The remaining roster gap is the Red above (CLI source + generateddocs/cli.md), not those files. - Green — subagent journals are skipped, not folded.
MuseAgent.logSourcesandBackfillScanner.museSessionFilesdrop<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 thansession.jsonl. Harmless today. - CrowMuse tests: 63 passed. Root
swift buildlinked clean. CrowCLI docs freshness test failed as above. Did not re-run the unrelated CrowDaemon suites the PR notes as pre-existing on47c74331.
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.
3c97b90 to
543e96d
Compare
dgershman
left a comment
There was a problem hiding this comment.
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+cwdFilteronAgentLogSource,TranscriptHeadReader.absorbfor the cwd key,BackfillScanner.reconstructX+ daemon-injected*Home,LogSyncHarnessinternal/wire split. This PR extends that path;excludePathComponentsis a small generic addition applied inLogSyncCollector.resolveFilesandBackfillScanner.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.
MuseHomefollowsOpenCodeHome's XDG resolution.
Security Review
Strengths:
- Fail-closed attribution: no readable
workspace_root⇒ drop (live) / low-confidence orphan (backfill), never a guessed worktree (TranscriptHead.swiftabsorb fallback;BackfillScannerTests.museJournalWithoutWorkspaceRootIsLowConfidence). Matches CROW-1089. LogSyncHarness.muse.wireValuecollapses tounknown, same as Grok — uploads cannot trip the server CHECK. Ledger still keys onrawValue(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.
MuseHomedoes not read Muse auth files. - Empty
XDG_DATA_HOME=is treated as unset (no CWD-relative path), matchingOpenCodeHome.
Concerns:
- Green — unverified
workspace_rootkey. Accepted, documented risk (PR body, matrix row,TranscriptHead.swiftabsorb comment). Cross-checked againstsuperbasedapp/observerinternal/adapter/muse/adapter.go: same store path, samepayload.record.workspace_root, samesubagent/child dir. A wrong key collects nothing rather than misattributing. Confirm on a realsession.jsonlwhen Muse is installable.
Code Quality
- Green — prior Red/Yellow on CLI docs is addressed. Muse / CROW-1106 is in
LogsyncCommands.swift,BackfillCommands.swift(--sessionhelp included), generateddocs/cli.md,docs/cli-reference.md,CLAUDE.md, and theLogSyncCollector.swiftwired-harness comment. Freshness test passed on this HEAD. - Green — subagent journals are skipped, not folded.
MuseAgent.logSourcesandBackfillScanner.museSessionFilesdrop<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 thansession.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.
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
543e96d to
6f169df
Compare
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).
Step 0 of the ticket is a hard gate: verify
payload.record.workspace_rooton a realsession.jsonlbefore wiring. That gate could not run — Muse Code is Meta-auth-gated and is not installable on this dev machine (verified five ways: nomusebinary on any fallback path, no~/.local/share/musestore, nosession.jsonlanywhere, noMETA_API_KEY,crow agents list→available: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_rooton the line-1runtime.session.metadatarecord) rather than wait for a live install. This is recorded here for reviewers: the acceptance item "workspace_rootverified on a realsession.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_rooton a real journal stays a version-pinned re-check target (recorded inagent-harness-matrix.md).What changed (mirrors the Codex/Grok wiring)
TranscriptHead.absorblearns Muse'spayload.record.workspace_root(nested one level deeper than Codex'spayload.cwd; the three shapes are disjoint).LogSyncHarnessgains.muse— internally first-class (drives the ledger slot / backfill display / format+agentKind),wireValuecollapses tounknownuntil the server CHECK (corveil#2426) acceptsmuse, exactly like.grok.AgentLogSourcegainsexcludePathComponents, used to skip Muse's nestedsubagent/<child>/session.jsonlchild 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.logDirsource (session-prefixed,subagent-excluded), replacing the CROW-1099 research note.BackfillScanner.museSessionsDir+museSessionFiles()+reconstructMuse();BackfillServiceinjectsMuseHome.sessionsDir()and maps.muse(.logDirstamp matching the live path,museagentKind).session-log-collector.md,harness-transcript-locations.md,session-backfill.md, plus a re-check row inagent-harness-matrix.md.Testing
swift testgreen across CrowCore (780 tests), CrowMuse, and the CrowDaemon LogSync/Backfill suites (28 tests). New coverage: Muse head parsing,logSourcesshape, cwd-filter + subagent exclusion + drop-on-no-cwd, backfill reconstruction (incl. subagent skip and low-confidence orphan whenworkspace_rootis absent), harness-scoped ledger keying,MuseHomeXDG resolution.swift buildlinks clean;make paritygreen.RPCLanePolicyTests,WebNotificationCenterTests.bootCatchResetsTheHistory) fail — verified pre-existing on the base commit47c74331, in code this PR does not touch.🤖 Generated with Claude Code