Skip to content

feat(review): exact scope and parallel skills for reviewer agents - #1647

Open
peyton-alt wants to merge 27 commits into
mainfrom
feat/review-child-context
Open

feat(review): exact scope and parallel skills for reviewer agents#1647
peyton-alt wants to merge 27 commits into
mainfrom
feat/review-child-context

Conversation

@peyton-alt

@peyton-alt peyton-alt commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

https://entire.io/gh/entireio/cli/trails/766

One-sentence summary

When entire review launches a reviewer, it now hands that reviewer everything the CLI already knows — exactly which code to review, how long it may run, which tools it may use, and how to start its configured skill — instead of a vague instruction each reviewer had to interpret for itself.

Problems, as observed in real runs

  1. Reviewers re-derived — and sometimes got wrong — what code to review. The composed prompt only said "review the commits unique to this branch vs origin/HEAD." Each reviewer then ran its own git commands to work out what that meant. In one live run, codex diffed in the wrong direction on a branch that was behind main and reported main's newer code as regressions the branch had introduced — 2 of the 4 high-severity findings in that run's final verdict were such phantoms, and the judge consolidated them without any way to notice.
  2. Reviewers' tool calls were silently denied. Headless claude -p auto-denies any tool call that isn't pre-approved, and the review command passed no permission config. Reviewers bounced off denials for git diff / git log, then either worked around them slowly or skipped verifying their findings.
  3. The configured skill never actually ran (claude). The composed prompt started with the skill line (/pr-review-toolkit:review-pr). claude -p treats a leading slash as a slash command and expanded it — resolving to the built-in /review skill with the entire composed prompt stuffed in as its argument (it interpolated the skill name where a GitHub PR number belongs). Every claude review was silently running the wrong workflow.
  4. Setup wrote the built-in review brief into your settings file. Guided setup and first-run persisted the default task text into review_profiles.<name>.task as if you had typed it — indistinguishable from user config, and frozen: improving the default wording could never reach existing profiles.

Changes (numbered to match the problems)

  1. The exact scope is now in the composed prompt. The review command already computes the commit list, the changed-file list (three-dot, vs merge-base), and the uncommitted files for its banner line — it now passes all of that to every reviewer, marked "authoritative — use as-is, do not re-derive", plus the diff itself when it fits a size budget (otherwise the exact git diff base...HEAD command to run). The judge additionally receives the changed-file list with an instruction to discard findings that point outside it — so even a reviewer that somehow mis-scopes can't pollute the final verdict.
  2. Read-only tools are pre-approved. Reviewers launch with --allowedTools: Read/Grep/Glob/Task/Skill plus enumerated read-only git subcommands (diff, log, show, status, blame, rev-parse, merge-base, ls-files). Deliberately not Bash(git:*) — git aliases/hooks execute arbitrary code and push/commit would match the blanket — and never --dangerously-skip-permissions: reviewers process untrusted diffs and must stay unable to modify the repo.
  3. The configured skill actually runs. When the composed prompt would start with /, a prose preamble is prepended — "Lines starting with «/» name configured review skills: invoke each with the Skill tool and follow it" — making slash-expansion structurally impossible. Verified in live transcripts: real Skill tool invocations of the configured skill, followed by that skill's actual workflow.
  4. The built-in review brief is a runtime default, not saved config. Reviewer behavior is unchanged from main: every reviewer still receives the profile's task, or the built-in default when none is set (Multi-agent review profiles for entire review #1312's deliberate design — a measured A/B without the brief was faster but missed a real finding). The only change is that setup persists an empty task, so saved profiles stay clean and pick up improved default wording. Pinned by TestRunReview_TaskSemantics.

What a reviewer receives now (abridged real capture)

Perform the review below. Lines starting with "/" name configured review skills: invoke each with the Skill tool and follow it.

/review

Review profile: general

Task: Review this change for correctness, regressions, API design, missing tests, … [profile task, or built-in default]
[output-format instructions]

Scope: review the commits unique to this branch vs main, plus any uncommitted changes in the working tree. …

Authoritative scope, computed by entire — use it as-is, do not re-derive it:

Commits under review (oldest first):
3ae0a76 add feature

Files under review (vs merge-base with main):
A	feature.go

Uncommitted working-tree changes:
?? notes.txt

Only the files listed above are in scope. Findings that point anywhere else are out of scope — discard them.

Diff under review:
```diff
diff --git a/feature.go b/feature.go
…
```

Checkpoint context from commits in scope:
- a1b2c3d4e5f6: summary: add feature X handler; wire config loading; open: cover error path
- ... 3 more checkpoints omitted

Use `entire explain <id>` for full checkpoint context, or `entire explain <id> --raw-transcript` for raw transcripts.

In-progress session context (uncommitted):
  95131576 claude-code (touched: 4 files) prompt: add retry handling to the dispatcher

(The checkpoint/session sections come from entire's own history for exactly the commits and working tree under review — the intent behind each commit and what any still-uncommitted agent session was doing. They're empty in fresh repos, which is why the raw capture above was taken with them elided; predates this PR, included here for completeness of what a reviewer receives.)

Plus env (ENTIRE_REVIEW_* session-tagging handshake, unchanged) and the --allowedTools flag from change 2.

Deadline handling is deliberately NOT part of this PR — it landed as #1664: the default reviewer timeout is dropped entirely (reviewers run until done, --timeout stays as an explicit cap). An activity-based stall detector was investigated and ruled out — legitimate review subagents run 12+ minutes with zero parent output, so no liveness signal distinguishes quiet work from a hang.

Measured (same branch: 13 commits, 37 files, ~102KB diff; real claude runs)

before after
skill executed built-in /review (by accident) the configured skills, via real Skill invocations
phantom findings 2 of 4 highs in one run none
tool denials present none

Testing

  • TDD throughout; every behavior change had a failing test first
  • mise run test, test:integration (390), test:e2e:canary — green
  • Shim smoke: a fake claude on PATH captures argv/env through a real entire review run; asserts prompt contents, allowlist, and flag shape end-to-end
  • Multiple real-agent runs on a live branch verifying skill routing and scope accuracy, plus a dogfood run of the command against this PR itself (its findings became commits here)

🤖 Generated with Claude Code


Also folded in: skill fan-out (was #1651)

A worker configured with N skills joined them into one child's prompt: the skills ran sequentially (or blended into one muddled pass), so selecting more skills grew the wait linearly. Measured live: a two-skill claude worker took ~9 minutes as a single child. The parallel machinery already existed one level up (worker slots fan out in run_multi); multi-skill selection just never used it.

  • explodeSkillWorkers: at plan time, each multi-skill worker becomes one worker per skill (keys like claude-code:review, deduped against existing worker names; agent/model/prompt preserved). Wait becomes max(skills) instead of sum(skills). Two exploded workers also engage the judge, extending crew+judge consolidation to single-agent multi-skill profiles.
  • --agent selects a filtered crew: all of that agent's workers run (previously: ambiguity error). Single-agent path only when exactly one worker matches.
  • Session matching by skills: same-agent same-model exploded workers defeat the agent+model matcher — AgentRun gains Skills, and the matcher requires skill-set agreement when both sides carry skills (recorded from ENTIRE_REVIEW_SKILLS by the lifecycle hook). Adversarially-ordered test fails without the discriminator.
  • TDD throughout; shim smoke: a two-skill profile spawns two one-skill children in parallel (~3s wall) plus one judge invocation.

Was stacked as #1651 (its diff was exactly the last commit here); combined into one PR for a single review/approval/merge.

@peyton-alt
peyton-alt requested a review from a team as a code owner July 6, 2026 11:32
Copilot AI review requested due to automatic review settings July 6, 2026 11:32

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit ac36d17. Configure here.

Comment thread cmd/entire/cli/review/scope.go
@peyton-alt peyton-alt changed the title review: give the child reviewer what the parent already knows (scope, budget, permissions) feat(review): pass authoritative scope, time budget, and read-only tool permissions to reviewer agents Jul 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR improves entire review orchestration by passing parent-computed review scope into spawned reviewer agents and the consolidating judge, adding explicit per-reviewer pacing guidance from the effective timeout, and pre-approving a constrained tool allowlist for headless Claude review children so read-only inspection commands aren’t auto-denied.

Changes:

  • Add ScopeContext to RunConfig, build it from git (commits/files/uncommitted + optionally inline diff), and inject it into reviewer prompts.
  • Thread authoritative scope into the judge/synthesis prompt so it can discard out-of-scope findings.
  • Add reviewer time-budget hint rendering, and pass per-agent timeouts in the multi-agent path.
  • Add --allowedTools allowlist to Claude review child invocation.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
cmd/entire/cli/review/types/reviewer.go Introduces ScopeContext on RunConfig and defines scope payload shape/zero check.
cmd/entire/cli/review/synthesis_sink.go Threads authoritative scope into synthesis prompt composition.
cmd/entire/cli/review/synthesis_prompt.go Adds “scope gate” section to judge prompt to discard out-of-scope findings.
cmd/entire/cli/review/synthesis_prompt_test.go Tests that synthesis prompt includes (or omits) the scope gate correctly.
cmd/entire/cli/review/scope.go Builds bounded scope context (commits/files/uncommitted + inline diff budget).
cmd/entire/cli/review/scope_test.go Adds coverage for scope context building, three-dot semantics, and caps.
cmd/entire/cli/review/prompt.go Renders scope context + time budget into reviewer prompt; optionally inlines diff.
cmd/entire/cli/review/prompt_test.go Tests scope injection and time budget hint behavior.
cmd/entire/cli/review/export_test.go Updates/export helpers for new synthesis prompt signature and scoped testing.
cmd/entire/cli/review/cmd.go Injects scope context into single/multi-agent configs; threads scope to sinks; sets per-agent timeout.
cmd/entire/cli/review/cmd_test.go Extends tests to validate per-agent timeout threading and scope context injection.
cmd/entire/cli/agent/claudecode/reviewer.go Adds --allowedTools allowlist to headless Claude review child.
cmd/entire/cli/agent/claudecode/reviewer_test.go Tests that allowlist is present and does not enable unsafe flags.

Comment thread cmd/entire/cli/review/scope.go
Comment thread cmd/entire/cli/review/prompt.go
Comment thread cmd/entire/cli/agent/claudecode/reviewer.go Outdated
…ge prompts

The parent computes the review scope (commits, files, uncommitted, diff)
for its banner, then discards it and tells each child agent only how to
re-derive it. That cost minutes of setup per reviewer and let one agent
diff a behind-main branch in the wrong direction, reporting mainline
evolution as branch regressions — two of four high findings in a real
run were such phantoms, and the judge consolidated them unchecked.

ComposeReviewPrompt now renders a parent-computed ScopeContext: commit
list (oldest first), three-dot name-status file list, porcelain
uncommitted lines, and the diff itself when it fits a 48KiB inline
budget (beyond that, the exact three-dot command). The judge prompt
gets the authoritative changed-file list with an instruction to discard
findings outside it. Lists are capped with truncation flags so agents
never mistake a bounded enumeration for an exhaustive one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: ca5fa66e3b98
@peyton-alt

Copy link
Copy Markdown
Contributor Author

Relationship to #1312's task design (for reviewers wondering whether the no-injected-task commits undo something intentional):

The default-task machinery (profileTask, defaultGeneralTask, the Task: prompt section + output-format protocol) all came from #1312. This PR preserves three of its four purposes and reverses exactly one, deliberately:

#1312 intent here
Judge receives a canonical task for consolidation kept — still resolved and threaded to the synthesis prompt
Skill-less workers (gemini/pi, whose default prompt says "according to the profile task") need a brief keptworkerTask falls back to the built-in task for skill-less workers only
User-configured tasks survive configure edits (#1312 follow-ups df29bfb/e0d56ac6d) keptguidedProfileTask honors custom + existing tasks; only the built-in text is no longer persisted
Skill-bearing workers get the uniform audit brief + output protocol reversed — product decision: entire invokes configured skills and adds no prompts the user didn't write. Measured: the injected brief ordered a maximal ~15-minute audit regardless of what the user configured

Default task texts remain in the code as runtime fallbacks (and TestDefaultReviewTasksRejectSlop still validates them).

@peyton-alt
peyton-alt force-pushed the feat/review-child-context branch from 1faf416 to 5507991 Compare July 7, 2026 09:49
@peyton-alt

Copy link
Copy Markdown
Contributor Author

Update to the #1312-relationship table above: after review discussion, the fourth row is now also kept — the branch no longer changes which workers receive the canonical task. Worker briefing is exactly main's behavior (every worker gets the user task or the built-in default; the A/B without the brief was ~35% faster but missed a real finding, so depth stays). The only task-related change in this PR is that setup persists an empty task and the built-in brief applies at runtime only — saved profiles stay clean and pick up improved default wording. Pinned by TestRunReview_TaskSemantics.

peyton-alt and others added 6 commits July 7, 2026 12:41
Headless claude -p auto-denies any tool call that would have prompted
interactively, and buildReviewCmd passed no permission config — so
finder subagents bounced off denials for git diff/log/show and detoured
around them (observed in a live review transcript: 'attempted tool
calls, hit approval/tool restrictions, and continued').

Pass --allowedTools with the read-only surface a review needs: Read/
Grep/Glob/Task/TodoWrite, enumerated read-only git subcommands (not
Bash(git:*) — aliases/hooks execute arbitrary code and push/commit
match the blanket), and entire's read-only lookup commands referenced
by the checkpoint context. Never --dangerously-skip-permissions:
reviewers process untrusted diffs and must stay unable to write.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: f0c2e8deec13
…h command

The composed prompt leads with the configured skill invocation line
(e.g. /pr-review-toolkit:review-pr). claude -p expands a leading slash
token as a command — observed live in two runs: it resolved to the
BUILT-IN /review skill with the entire composed prompt as its arguments,
interpolating the configured skill name where a PR number belongs. The
configured skill never ran; the built-in maximum-breadth PR-review
harness ran instead (its diff-proportional line-by-line finder alone
took 11.4 of the run's 15 minutes on a 102KB scope).

Prefix a prose preamble whenever the composed prompt starts with "/",
instructing the agent to invoke the skill lines via the Skill tool —
expansion is impossible once the first byte isn't a slash. Add Skill to
the reviewer allowlist so headless invocation is pre-approved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 5ffb689d299f
Both setup paths (guided picker fallback and non-interactive first-run)
wrote the built-in default brief into the saved profile's task field,
making it permanently indistinguishable from a task the user wrote —
which defeated the skill-workers-get-no-injected-task rule for every
profile created by setup. Persist empty; the built-in brief stays a
runtime fallback for skill-less workers and the judge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 53e0eeb2e399
Four review findings and one lint failure, all confirmed real:

- Commit cap kept the OLDEST commits (first lines of --reverse output)
  and silently dropped everything near HEAD, while the prompt forbids
  re-deriving scope. Cap newest-first, then reverse the kept slice for
  reading order — recent commits are the ones a review can least afford
  to lose. (Cursor Bugbot, high)
- Inline diff budget 48KiB could exceed Windows' ~32KiB CreateProcess
  command-line cap (prompt travels as argv and ENTIRE_REVIEW_PROMPT).
  Lowered to 24KiB. (Copilot)
- A diff containing ``` (any markdown-touching change) closed the
  diff fence early, letting diff content escape into instruction
  position. Fence is now one backtick longer than the longest run in
  the diff. (Copilot)
- Bash(git branch:*) allowed mutating -d/-D/-m; removed from the
  read-only allowlist. (Copilot)
- guidedProfileTask's profileName parameter became unused when the
  built-in fallback was removed; parameter dropped. (revive)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 320d86619050
…ted-task fix

Ran the fixed `entire review` against this branch itself; its verdict
identified that fd7d1cb was incomplete and five smaller defects. All
confirmed against the code:

- buildCrewProfile, saveReviewProfileConfig, and the flags-configure
  path still seeded the built-in task into saved profiles, so every
  interactively-configured profile reintroduced the maximal-audit brief
  for skill-bearing workers. The prior test was tautological (inputs
  production never produces); replaced with a test through the real
  constructor, plus an inverted stale assertion in configure_test.
- Scope-context failure degraded at Debug (invisible at default level)
  right after the banner claimed the scope was computed. Now Warn plus
  a one-line stderr notice.
- The categorical "discard out-of-scope findings" rule contradicted
  truncated file lists (files past the cap are in scope) and rendered
  nonsense for net-zero diffs (commit + revert). The rule now matches
  what was rendered: absent without lists, softened to verify-first
  when truncated.
- Rendered list bytes are charged against the inline-diff budget so the
  composed prompt stays bounded on ~32KiB-limited platforms.
- Allowlist comment now names the accepted --output residual instead of
  claiming blanket write-safety.
- Test gaps: fan-out loop now asserts per-worker ScopeContext/Task
  wiring; uncommitted-only scope pins Diff==""/!DiffOmitted; redundant
  Skill allowlist test folded into the main one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: d4ef50cdaee1
…rker, never persisted

Coverage note after review discussion: the branch no longer changes
which workers receive the canonical task (main's #1312 behavior stands:
every worker gets the user task or the built-in default). What it does
change is persistence — setup writes an empty task and the built-in
brief is applied at runtime only. Pin both halves so neither regresses:
worker briefing (skill-bearing, skill-less, user-task-verbatim) and the
runtime-only nature of the default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: a457400d7876
@peyton-alt
peyton-alt force-pushed the feat/review-child-context branch from 18f6e77 to c1e199c Compare July 7, 2026 10:46
…runs

A worker configured with N skills previously joined them into one
child's prompt: skills executed sequentially (or blended), so selecting
more skills made the user wait for the SUM of their durations. Measured
live: a two-skill claude worker ran ~9 minutes as one child.

explodeSkillWorkers splits each multi-skill worker into one worker per
skill at plan time (keys like claude-code:review, deduped against
existing workers), so skills run concurrently as ordinary slots — the
wait becomes the slowest skill. Two exploded workers also mean the
judge consolidates per-skill reports, extending the crew+judge value
prop to single-agent multi-skill profiles.

--agent now selects ALL of that agent's workers as a filtered crew
(previously an ambiguity error), running the single-agent path only
when exactly one worker matches.

Same-agent SAME-model exploded workers defeat the existing agent+model
session matching (assignments could cross, attributing tokens and
transcripts to the wrong skill). AgentRun gains Skills, propagated
through planned runs and both run paths, and the matcher requires
skill-set agreement when both sides carry skills — mirroring the
same-agent different-model disambiguation from #1313.

Verified end-to-end with a claude shim: a two-skill profile spawns two
one-skill children in parallel (~3s wall for both) plus the judge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 116f0cd95d56
@peyton-alt peyton-alt changed the title feat(review): pass authoritative scope, time budget, and read-only tool permissions to reviewer agents feat(review): authoritative child context + parallel skill fan-out Jul 8, 2026
peyton-alt and others added 3 commits July 8, 2026 14:58
…(trail findings)

Two trail findings on the scope-injection design:

- Commit subjects and filenames are attacker-controlled on a branch
  under review, yet they rendered unfenced inside the section framed as
  authoritative instructions — the exact injection surface the diff's
  dynamic fence already guards one paragraph below. The enumerations now
  ship inside their own dynamic fence (same longest-backtick-run
  sizing), introduced as untrusted data with an explicit do-not-act
  marker; entire's own instructions (authoritative-scope framing,
  discard rule) stay outside the fence.

- The list sections were capped by line count only (50/200/100), so a
  wide branch with long paths could push the rendered lists past the
  ~32KiB platform argv cap even with the diff omitted. Lists are now
  trimmed to half the inline budget (charged commits -> files ->
  uncommitted, keeping leading lines; commits trimmed newest-first
  before the oldest-first reversal so the newest survive), and the
  remainder is charged against the diff allowance as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 23a2d752af4a
…text

# Conflicts:
#	cmd/entire/cli/review/run.go
… allowlist, fanout fallback

A full-crew dogfood review of this branch (request changes, 4 mediums +
1 low, all verified) on the integrated stack:

- capScopeListsToBudget's 'defer slices.Reverse(sc.Commits)' captured
  the pre-trim slice header, so byte-trimmed commit lists reversed the
  FULL backing array and the trimmed view held the OLDEST commits —
  inverting keep-newest exactly when truncation matters. Now a closure
  re-reading sc.Commits at return; pinned by a test that reproduces the
  inversion.

- writeSynthesisScopeGate wrote branch-controlled file paths raw into
  the judge prompt ahead of the discard rule — the same injection class
  fixed for worker prompts, but feeding the FINAL verdict gate. The
  list now renders inside a dynamic fence introduced as untrusted data,
  instructions outside.

- The allowlist granted only 'entire checkpoint explain' while the
  injected checkpoint context tells reviewers to run 'entire explain
  <id>' — headless -p denied the prompt's own guidance. Added
  Bash(entire explain:*).

- Unconditional explodeSkillWorkers regressed single multi-skill
  agents without a review-runner adapter (previously served by
  RunMarkerFallback; explosion forced them into the multi-agent branch
  which hard-fails, with a circular --agent workaround). Explosion now
  skips adapter-less agents.

- picker.go task-persistence comment referenced a nonexistent
  workerTask function; aligned with the actual runtime contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KX14MDBGM3BNQK1JKDH030FY
@peyton-alt peyton-alt changed the title feat(review): authoritative child context + parallel skill fan-out feat(review): exact scope and parallel skills for reviewer agents Jul 8, 2026
peyton-alt and others added 12 commits July 8, 2026 18:18
…ail finding)

The absolute discard order ('findings that point at files not listed
are out of scope') dropped a legitimate finding class: an in-scope
change that breaks an UNCHANGED caller or consumer in an unlisted file
— a cross-file regression, exactly what reviews exist to surface — got
discarded because the finding anchors at the broken call site. Both the
worker prompt's rule and the judge's scope gate now gate on where the
CAUSE lives and explicitly keep in-scope-cause/out-of-scope-impact
findings, anchored to the in-scope change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KX18CRN7KXZZ55BS5R6WCMQA
…text

# Conflicts:
#	cmd/entire/cli/review/cmd_test.go
The fan-out was meant to be behavior-only (run an agent's skills as
parallel children instead of one blended pass), but it leaked into the
TUI: because rows are drawn one-per-worker, a two-skill agent showed as
two rows (claude-code:review + claude-code:pr-review). Restore the
pre-fan-out display — one row per agent — without changing the parallel
execution.

The collapse lives entirely in the TUI sink; execution, the summary,
the manifest, and skills-based session matching stay per-worker (all
load-bearing for attribution). TUISink.groupWorkers takes the per-agent
row order plus a worker->agent map; AgentEvent routes each worker's
events to its agent row (live events already key by name, so this is a
lookup), and RunFinished folds the per-worker summary into one entry
per agent row (worst-status wins, tokens summed) so the model's
by-index row sync still aligns. Grouping key is agent+model, so genuine
agent+model workers stay separate rows — only the skill dimension
collapses.

Verified: sink unit tests pin routing + collapse; a live shim run
showed a single claude-code row with two parallel children in flight.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXH1KM896NXV3ZV3XVJ8FEXK
Follow-on to the one-row-per-agent collapse: #1666 (merged) streams
cumulative token counts per worker, and the TUI row overwrites on each
Tokens event (CU2). With two skill-workers folded into one agent row,
their independent cumulative counts overwrote each other — the live
number bounced between skills instead of showing the agent total. (The
final summary was already summed; only the live display was wrong.)

The sink now tracks each worker's latest cumulative Tokens and forwards
the per-agent SUM on every Tokens event, so the row's overwrite shows a
correct running total. Single-worker rows pass through unchanged.
Runs on the serial dispatch goroutine, so no locking; race-clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXH2J8TTE8GJYBQE47W4BHKX
…olish

Pre-merge cleanup of the agent-row collapse, which had accreted across
three commits as scattered TUISink fields/methods. Same behavior, one
owner, plus the two facets found by reading rather than design.

(c) New agentGrouping type owns the whole reconciliation between
per-worker execution and one-row-per-agent display: worker->row
routing, live per-agent token summing, and the summary fold. TUISink
holds one *agentGrouping (nil on the single-agent path) instead of four
fields and four methods.

(a) The folded summary's duration now spans earliest-worker-start to
latest-worker-end instead of keeping one worker's slice. The live row
duration was already correct (wall-clock from first event to finish);
this makes the folded field honest for any future consumer.

(b) Drill-in (Ctrl+O) into a collapsed agent tags each event with its
skill when the buffer holds more than one worker, so two skills running
in parallel read cleanly instead of interleaving anonymously;
single-source buffers stay untagged. agentEventMsg carries the source
worker; the row buffer keeps it per event.

Execution, summary, manifest, and per-skill session attribution are
untouched — the collapse remains display-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXH6FFA9B5JWVHSRGMH1W20B
When codex fails, it wraps the upstream API error as a JSON string in
its envelope message, so a failed reviewer row showed the whole blob
(e.g. `codex: {"type":"error","status":400,"error":{"message":
"The 'gpt-5.6-sol' model requires a newer version of Codex..."}}`) —
the actual reason buried inside. cleanCodexFailureMessage unwraps it to
the `.error.message` text so the row reads "codex: The 'gpt-5.6-sol'
model requires a newer version of Codex...". Plain (non-JSON) messages
and JSON without a message pass through unchanged; unwrapping is bounded
against multiple nesting. Found while diagnosing a live codex failure
(model/CLI-version mismatch) that the raw blob made hard to read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXH8Z4S6VJF3PFYBW4V44WEN
…text

# Conflicts:
#	cmd/entire/cli/review/cmd.go
#	cmd/entire/cli/review/cmd_test.go
… native invocation

The user asked whether configured codex $code-reviewer skills are
retained after #1749's legacy-config repair merged in. They are, by two
independent guards; these tests lock that so a future migration edit
can't clobber real skills:

- normalizeLegacyCodexDefaultSkills only rewrites codex's exact
  ["/review"] artifact; a $code-reviewer config and multi-skill
  configs pass through untouched.
- codexNativeSkillInvocations rewrites only slash-form to $; $name and
  plain text pass through verbatim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KXHANJCZ4G2GCS548V1CKZSS
…inish (trail finding)

A Finished/RunError event stamped row.runEnd/status on the first worker to
finish, so a collapsed agent row (skill fan-out: N workers per row) showed
a frozen duration and a terminal status while sibling skills were still
running. groupWorkers now tells the model each row's worker count via
rowWorkerCountsMsg, and the row only turns terminal once every distinct
worker has emitted a terminal event — worst-status-wins across workers,
mirroring collapseSummary. The runFinishedMsg summary sync remains the
backstop for dropped events.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@peyton-alt
peyton-alt force-pushed the feat/review-child-context branch from 784245e to 68bb386 Compare July 16, 2026 18:33
peyton-alt and others added 4 commits July 16, 2026 14:59
…r consolidation

docs/architecture/review-command.md now covers the branch's three
undocumented subsystems: parent-computed scope enumeration (BuildScopeContext,
byte budgets, data fencing), the claude reviewer child's read-only tool
allowlist + guardSlashExpansion, and skill fan-out with the one-row-per-agent
collapse and judge scope fencing.

selectProfileWorker is now a thin single-match wrapper over
selectProfileWorkers instead of a parallel implementation, and
stringSetsEqual uses sorted-clone comparison instead of a bespoke
count map. Net −20 lines of code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Flow step understated reviewToolAllowlist (omitted Task/TodoWrite/Skill)
— for a security-relevant enumeration, an incomplete list reads as the
complete surface. Also 'no-write' not 'read-only': Task and TodoWrite are
not reads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s (trail finding)

Row grouping keyed purely on agent+model, so two independently configured
duplicate slots (claude-code / claude-code-2, same model) merged into one
dashboard row — blending live tokens, statuses, and summary entries of
unrelated reviewers. explodeSkillWorkers now reports which source worker
each exploded key came from, and planAgentRows collapses a row only for
genuine fan-out siblings; every other worker keeps its own row, with label
collisions falling back to the unique worker key.

Also reframes the runGit comment to state its real job (centralizing the
wrapcheck exemption for gitexec's pre-wrapped errors) rather than
churn-avoidance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants