Skip to content

feat: show the fan-out while it runs — collaboration.panels + panel state in the sidebar - #271

Merged
saucam merged 1 commit into
mainfrom
feat/panel-state-ui
Jul 29, 2026
Merged

feat: show the fan-out while it runs — collaboration.panels + panel state in the sidebar#271
saucam merged 1 commit into
mainfrom
feat/panel-state-ui

Conversation

@saucam

@saucam saucam commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

The last demo gap. A panel's whole point is that N agents work at once, and that was the one part of the feature a client could not see: the sidebar showed the fleet, the transcript showed the joined result, and the parallelism in between was invisible.

Confirmed the hard way — a live run where opus 4.8 and gpt-5.6-sol reviewed the same file simultaneously on different backends rendered as one ordinary transcript message.

It was invisible because nothing on the wire carried it. No client verb could see dispatch state at all, so this is a protocol gap, not a styling one.

collaboration.panels

The goal's recent fan-outs, newest first, each with members in dispatch order and their live queue status. sessionId accepts the orchestrator or any child, resolving the hop the way blackboard.index does.

  • Gated on session:list — same tier as the blackboard index, same reasoning: metadata about sessions the holder can already enumerate, no prompts and no artifact bodies.
  • Scoped by createdBy, so one collaboration's panels never surface in another's UI.
  • History bounded to 5 groups in SQL — a sidebar wants the live fan-out plus a little context, not an orchestrator's whole dispatch career.
  • joined is derived from the members in the same payload rather than stored, so the flag and the member list cannot disagree.

What the UI shows now

where what
orchestrator row ⇉ panel 2/3 with a progress bar, while a fan-out is in flight
each participating child a ⇉N badge with its position and state — working / finished / failed

Both count settled members, not successful ones, because the barrier joins on all-terminal. Counting successes would leave a finished panel showing 2/3 forever — exactly the confusion the indicator exists to remove. A failed member renders in red rather than being omitted: §7's "disagreement is shown, not hidden" applies to a member that failed just as much as to one that disagreed.

Polled every 3s for the focused collaboration only, so cost stays one cheap metadata query per tick regardless of how many fleets exist. A failed poll keeps the last state rather than blanking a live 2/3 and implying the panel vanished.

Verification

suite before after
daemon 2191 2200
web 370 382

biome + both typechecks clean; web eslint unchanged at 30 warnings / 0 errors.

Four mutations, each caught by exactly the right tests:

mutation caught by
joined from a stored flag instead of the members 2 handler tests
settled counting only successes a FAILED member counts as settled
panels not scoped to the goal's dispatches 4 handler tests
web recomputing liveness from statuses instead of joined keys liveness off joined

Live over the real socket — 9/9: no panels before a fan-out; the panel visible while all three members are still queued; ordinals in dispatch order; member sessions matching the children; settled=2 with one member BLOCKED; joined flipping only when the third settled; and a child id resolving to its goal.

Release readiness

With this in, the §7 breadth panel is demo-complete end to end: create a mixed-vendor fleet in the web modal → the orchestrator plans and calls fleet_panel → the R3 gate shows the goal's running cost → you watch the fan-out progress in the sidebar → the barrier joins → synthesis reads each role's artifact off the blackboard.

Still deferred, and not demo-blocking: the pipeline panel phase kind (§8 item 4), reads/writes as live scheduling edges (P4), the per-collaboration token budget (P6), and Telegram collaboration creation (it renders approvals with the cost line today, but can't start one).

🤖 Generated with Claude Code

…tate in the sidebar

The last demo gap. A panel's whole point is that N agents work AT ONCE, and
that was the one part of the feature a client could not see: the sidebar
showed the fleet, the transcript showed the joined result, and the
parallelism in between was invisible. Confirmed the hard way — a live run
where opus 4.8 and gpt-5.6-sol reviewed the same file simultaneously
rendered as a single ordinary transcript message.

It was invisible because nothing on the wire carried it. No client verb
could see dispatch state at all, so this is a protocol gap rather than a
styling one.

## collaboration.panels

Returns the goal's recent fan-outs, newest first, each with its members in
dispatch order and their live queue status. `sessionId` accepts the
orchestrator or any child, resolving the hop like `blackboard.index` does.

Gated on `session:list` — the same tier as the blackboard index, and for the
same reason: metadata about sessions the holder can already enumerate,
carrying no prompts and no artifact bodies. Scoped by `createdBy` so one
collaboration's panels never surface in another's UI. History is bounded to
5 groups in SQL; a sidebar wants the live fan-out plus a little context, not
an orchestrator's whole dispatch career.

`joined` is derived from the members in the same payload rather than stored,
so the flag and the member list cannot disagree with each other.

## What the UI now shows

- **On the orchestrator row:** `⇉ panel 2/3` with a progress bar while a
  fan-out is in flight.
- **On each participating child:** a `⇉N` badge carrying its position and
  state — working, finished, or failed.

Both count SETTLED members, not successful ones, because the barrier joins
on all-terminal. Counting successes would leave a finished panel showing
2/3 forever, which is precisely the confusion the indicator exists to
remove. A failed member is shown in red rather than omitted — §7's
"disagreement is shown, not hidden" applies to a member that failed just as
much as to one that disagreed.

Polled every 3s for the FOCUSED collaboration only, so the cost stays one
cheap metadata query per tick no matter how many fleets exist. A failed poll
keeps the last state rather than blanking a live "2 of 3" and implying the
panel vanished.

## Verification

Daemon 2191 to 2200, web 370 to 382. Four mutations each caught by exactly
the right tests: `joined` from a stored flag, `settled` counting only
successes, panels unscoped from the goal, and the web recomputing liveness
from statuses instead of trusting `joined`.

Live over the real socket: no panels before a fan-out; the panel visible
while all three members are still `queued`; ordinals in dispatch order;
member sessions matching the children; `settled=2` with one member BLOCKED;
`joined` flipping only when the third settled; and a child id resolving to
its goal.
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@saucam
saucam merged commit e49cf5f into main Jul 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants