Skip to content

feat(orchestration): return the fleet echo from every run-scoped command - #14892

Closed
Tauri-EPO wants to merge 11 commits into
stablyai:mainfrom
Tauri-EPO:feat/orchestration-fleet-echo-all-methods
Closed

Tauri-EPO wants to merge 11 commits into
stablyai:mainfrom
Tauri-EPO:feat/orchestration-fleet-echo-all-methods

Conversation

@Tauri-EPO

@Tauri-EPO Tauri-EPO commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #14891, which is stacked on #14889. Opened now for scope visibility — so the shape of #14891 is judged knowing where it goes — rather than for immediate review. Please settle #14891 first. If its approach changes, this PR changes with it or closes. Until both land, their commits appear in this diff; the change that belongs to this PR is the last commit only.

ELI5

#14891 makes orca orchestration check tell you whether each of your Run's lanes actually received its prompt. This extends that to the other orchestration commands, so you find out from whichever one you happen to run next instead of having to remember to run check.

What Changed

Extends the fleet block from check to the eight remaining Run-scoped methods: send, reply, inbox, taskCreate, taskList, taskUpdate, dispatch and dispatchShow.

ask and reset stay unwired on purpose. ask blocks until answered, so a snapshot taken at return time is stale by construction. reset tears the Run down.

Two methods needed a way to reach the caller's Run, and both are worth a look:

  • inbox takes a new optional callerTerminalHandle. It already had a terminal param, but that one means "whose mailbox to list", not "who is asking" — reusing it would attach the wrong pane's Run whenever a coordinator inspects another handle's inbox. callerTerminalHandle is the name and meaning already used by taskCreate, taskList, taskUpdate and dispatch. inbox's existing messages/count output is unchanged, and a client that omits the param simply gets no block.
  • dispatchShow resolves the caller's own Run and attaches only when it matches the task's Run. Attaching the task's Run unconditionally would have handed any caller naming a --task from another Run that Run's full lane roster. On a mismatch the block is omitted; nothing else about the method changes.

Why

Same motivation as #14891 — relates to #14809 and #14523 — applied to the rest of the surface. The value of the fleet echo is that a coordinator never has to remember to check; leaving it on check alone preserves exactly the round-trip it was meant to remove.

Kept separate from #14891 so the design can be argued on one method before it is spread across nine.

Linked Issue

Fixes #14907 — with this merged, the block rides on every Run-scoped command, which is what that issue asks for. #14891 delivers the same capability on check alone.

Also relates to #14809 (the silence it removes, though the --inject default is unchanged) and #14523 (the O(n) triage round-trips it removes, though terminal list preview freshness is untouched).

Visual Proof

N/A for UI — CLI/RPC surface only, no renderer changes. The rendered block is unchanged from #14891; only the set of commands that carry it grows.

Testing

  • New coverage in orchestration-send.test.ts and orchestration-tasks-dispatch.test.ts, including a case per wired method and both the matching and mismatching Run paths for dispatchShow — 164 passing across the four affected test files.
  • pnpm exec tsc --noEmit -p config/tsconfig.node.json — clean.
  • pnpm exec oxlint src/ config/ — clean.
  • pnpm run lint and pnpm build — both pass locally.

Tested on Windows 11.

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

AI Disclosure

Written with Claude Opus 5 via Claude Code. Design decisions were made in collaboration with the author; implementation and review passes were agent-assisted, then verified by the author.

Review

  • Security: the dispatchShow change is a narrowing — it stops a caller from receiving another Run's lane roster. Note dispatchShow has no caller authorization check today; that is pre-existing and out of scope here, but this PR makes sure the fleet block does not widen what it exposes.
  • Cross-platform: no path or shell assumptions.
  • Remote SSH / federation: unchanged from feat(orchestration): return a fleet echo from orchestration check #14891 — supervision facts stay host-local and federated lanes report unknown. No new wire opcode; InboxParams is a plain z.object, so an older host drops the unknown callerTerminalHandle and an older client omitting it just gets no block.
  • Mobile: unaffected.
  • Backwards compatibility: additive only, in both directions.
  • Performance: the block's cost is per command and unchanged from feat(orchestration): return a fleet echo from orchestration check #14891 — one SQLite read plus one handle-scoped terminal read, skipped entirely when the Run has no active lanes, and wrapped so it can never fail the command carrying it. Spreading it to eight more methods does mean that cost now attaches to commands a coordinator runs in tighter loops; if reviewers would rather it were opt-in, that is a one-line change.

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Note on the last box: pnpm lint and both typechecks pass locally. The full pnpm test suite cannot start on Windows from a clean install of this repo — see #14918. Briefly: windows-native-registry@3.2.2 installs with an empty build/, so the Windows branch of ensure-native-runtime refuses to run the suite. Not specific to this branch, and not a Node version problem (reproduced identically on Node 22 and 24).

Running vitest directly, bypassing that wrapper, the suite has pre-existing failures on this Windows machine unrelated to this change (missing POSIX shell, spawnSync … EINVAL, assertions expecting / and receiving \). Attribution was verified by running the entire suite on the merge base and on the feature branch and diffing the failing-file lists: the base fails 81 files, the branch fails the same 81 plus one timing-flaky test in remote-runtime-shared-control-connection.test.ts that is untouched here and passes 28/28 in isolation.

Author

  • X / Twitter: @EnricoPin

@coderabbitai

coderabbitai Bot commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 54647d9d-87a6-4dd6-91fb-8e9164e65be2

📥 Commits

Reviewing files that changed from the base of the PR and between e317b8bfaf206c998c2315ef1a73dc65f1bff9c2 and 90098c0b4868d459f902f273576e17b3e794b70c.

📒 Files selected for processing (2)
  • skill-guides/orchestration.md
  • src/cli/bundled-skill-guides.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • skill-guides/orchestration.md

Included review availability: Your plan includes up to 10 reviews per rolling hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Added Fleet Echo data contracts and bounded lane construction from active dispatches, worker stages, terminal signals, delivery state, and quiet time. Added runtime lookup and caller-run ownership checks. Added Fleet Echo metadata to orchestration RPC results, with fleet: false suppression. Added CLI text rendering, --no-fleet flags, tests, liveness coverage, and documentation.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the fleet echo as the main orchestration change, although it broadly describes the covered command set.
Description check ✅ Passed The description explains the change, rationale, issue, testing, compatibility, and review considerations; some template sections are omitted.
Linked Issues check ✅ Passed The changes satisfy #14907 by attaching bounded fleet state to the remaining Run-scoped orchestration methods without failing the carrying command.
Out of Scope Changes check ✅ Passed The implementation, runtime support, CLI updates, documentation, and tests directly support the linked fleet-echo reporting objective.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 8


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3da21ff8-8a0f-437a-8839-fcf36d0ac62b

📥 Commits

Reviewing files that changed from the base of the PR and between e4e54a1 and 3c642f9065c4629b5fb233728599ffd120e52670.

📒 Files selected for processing (18)
  • skill-guides/orchestration.md
  • src/cli/bundled-skill-guides.ts
  • src/cli/handlers/orchestration-fleet-echo-format.test.ts
  • src/cli/handlers/orchestration-fleet-echo-format.ts
  • src/cli/handlers/orchestration.ts
  • src/cli/specs/orchestration.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/orchestration/db-dispatch-liveness.test.ts
  • src/main/runtime/orchestration/db.test.ts
  • src/main/runtime/orchestration/db.ts
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.ts
  • src/main/runtime/rpc/methods/orchestration-send.test.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • src/shared/orchestration-fleet-echo.test.ts
  • src/shared/orchestration-fleet-echo.ts
💤 Files with no reviewable changes (1)
  • src/main/runtime/orchestration/db.test.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 7 remain after this review.

Comment thread skill-guides/orchestration.md Resolved
Comment thread src/cli/handlers/orchestration.ts Resolved
Comment thread src/cli/specs/orchestration.ts Resolved
Comment thread src/main/runtime/orchestration/db.ts Resolved
Comment thread src/shared/orchestration-fleet-echo.ts Resolved
Comment thread src/shared/orchestration-fleet-echo.ts Resolved
@Tauri-EPO

Copy link
Copy Markdown
Contributor Author

All eight addressed. Four were already fixed by rebasing onto the updated #14891 (the fence language, the dispatch_contexts.run_id scoping, the legacy-Run fixture, and --no-fleet in the usage strings — that last one now covers all nine commands, not just check). Taking the four that were unique to this PR:

Authorize the Run before attaching — you found a real hole, and a wider one than I had fixed. I had already gated dispatchShow, because its Run comes from the task. I missed that reply has exactly the same shape: it reaches a Run through the message id it was handed, so any caller holding an id from another Run received that Run's lane roster.

Both now go through one helper:

runIdIfCallerOwns(runtime, params.from, original.run_id)

which returns the Run only when the caller's own bound Run matches, and null otherwise — so the block is omitted rather than the call failing. inbox uses the matching resolveCallerRunId. Regression tests assert both directions on reply: the owning caller gets the block, a caller outside the Run gets nothing.

I checked the other attach sites while I was in there. check is safe — it resolves through resolveRunScope with requireCurrentConsumer: true, so naming another Run with --run is already rejected before the block is built. The worker-mailbox paths resolve from the dispatch the caller owns.

This is the same family as #14898, which I filed earlier for dispatchShow specifically; that issue is about the pre-existing missing authorization on the method itself, which this PR does not attempt.

inbox never received callerTerminalHandle from the CLI — correct, and it made the parameter inert on the path it exists for. --terminal names whose mailbox to list, not who is asking, so the handler had nothing to resolve a Run from and the block never attached to an inbox at all. The CLI now resolves the coordinator terminal and sends it.

The lane cap is now clamped inside buildFleetEcho. Agreed that a default is not a contract when the block rides on every response.

Inferring acceptance from output — I have taken this partly, and pushed back on the rest. You are right that output is not an acceptance signal and that the consequence was mispriced: the guide told a coordinator to re-dispatch on not_accepted, and a false positive there duplicates work that is already running.

What I have not done is report unknown for injected dispatches, because that would blind the feature to the case it exists for — a dispatch that was recorded and never delivered (#14809) produces no acceptance signal to read, by definition. Reporting unknown there returns the coordinator to discovering the failure minutes later by noticing an absence.

Instead the guide now separates the two sources and changes the prescribed action:

for a worker-start lane it is authoritative (the worker never reached input_accepted), but for a plain dispatch --inject there is no acceptance signal to read, so it is inferred from the terminal having produced no output since the dispatch. Confirm with terminal read before re-dispatching — a re-dispatch on a false positive duplicates work that is already running.

So the signal keeps its value, the inference is disclosed at the point of use, and the expensive action is no longer prescribed off a heuristic. If maintainers would rather the inferred verdict carry its own value — no_output_since_dispatch rather than reusing not_accepted — I think that is a better end state and I am happy to make the change; it just widens the type and the renderer beyond what this PR set out to do.

Verification after rebasing this branch onto the updated #14891: 179 tests across the five affected files, both typechecks and oxlint clean.

@Tauri-EPO
Tauri-EPO force-pushed the feat/orchestration-fleet-echo-all-methods branch from e2c4aa3 to e317b8b Compare August 17, 2026 20:10
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@Tauri-EPO

Copy link
Copy Markdown
Contributor Author

Rebased onto the rebased #14891

Both branches were 91 commits behind main (60805f5c) and conflicting; both are MERGEABLE again. The orchestration/db.ts split that main landed is handled in #14891 and described there — this note covers only what is new here.

send composes two wrappers now. main added withSendWarnings(...) around the same six return sites this PR wraps with attachFleetEcho(...). Rather than nest one inside the other six times, they compose once next to the existing helper:

// Why: every send return site owes both passengers — the recipient warnings this call
// collected and the Run's fleet echo — so compose them once instead of at each return.
const sendReceipt = <T extends object>(
  receipt: T
): Promise<T & { warnings?: SendRecipientWarning[]; fleet?: FleetEcho }> =>
  attachFleetEcho(runtime, runId, fleetEnabled, withSendWarnings(receipt))

Every site that was withSendWarnings({...}) on main and attachFleetEcho(runtime, runId, fleetEnabled, {...}) here is now sendReceipt({...}). Same arity, so the call sites read as they did before either change.

The group-send path takes main's receipt, not this branch's. This PR built a fresh { messages, recipients: handles.length }; main now builds a receipt that also carries groupWarnings and counts recipients: messages.length. The rebase keeps main's object and wraps it:

return attachFleetEcho(runtime, runId, fleetEnabled, receipt)

So on that path recipients counts messages actually created rather than handles resolved, and group warnings survive — both main's behaviour, which this PR has no business changing.

One new commit, and it is not a cleanup — it was forced. orchestration-send.test.ts sits at 790 counted lines on main. The five fleet-echo cases this PR appends took it to 844, past the 800 budget:

src/main/runtime/rpc/methods/orchestration-send.test.ts:981:3:
  error eslint(max-lines): File has too many lines (844). Maximum allowed is 800.

AGENTS.md rules out both escapes — no max-lines disable, no per-file bump — so the block moved to orchestration-send-fleet-echo.test.ts behind the same createOrchestrationRpcHarness(), exactly the split #14889 performs on db.test.ts. orchestration-send.test.ts is byte-identical to main again. The commit is separate and last so it can be read on its own.

Also new: an explicit import type { FleetEcho } in rpc/methods/orchestration.ts, which the helper's return type needs.

Verification on the rebased head e317b8bf, Node 24:

tsc --noEmit -p config/tsconfig.node.json      ok
tsc --noEmit -p config/tsconfig.tc.cli.json    ok
vitest (7 affected files)   Test Files 7 passed | Tests 167 passed
vitest (send + the split file)  Test Files 2 passed | Tests 48 passed
oxlint src config tests --deny-warnings        clean
generate-bundled-skill-guides.mjs --check      clean
check-max-lines-ratchet.mjs   OK — 190 grandfathered, no new bypasses

pnpm build and the full suite were not run here.

CI still reports nothing on this PR, and not for a reason in the diff. Every PR Checks and PR test LoC run on this fork branch ends action_required — the fork-workflow approval gate — so no check has ever executed. That is what keeps mergeStateStatus at UNSTABLE. A maintainer approving the workflow run is the only thing that changes it.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4235d7f3-d146-42a5-aa8b-44b9ffc4e1f8

📥 Commits

Reviewing files that changed from the base of the PR and between 32ee3b0 and e317b8bfaf206c998c2315ef1a73dc65f1bff9c2.

📒 Files selected for processing (18)
  • skill-guides/orchestration.md
  • src/cli/bundled-skill-guides.ts
  • src/cli/handlers/orchestration-fleet-echo-format.test.ts
  • src/cli/handlers/orchestration-fleet-echo-format.ts
  • src/cli/handlers/orchestration.ts
  • src/cli/specs/orchestration.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/orchestration/db-dispatch-liveness.test.ts
  • src/main/runtime/orchestration/db.test.ts
  • src/main/runtime/orchestration/db/dispatch-context/dispatch-lookup.ts
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.ts
  • src/main/runtime/rpc/methods/orchestration-send-fleet-echo.test.ts
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • src/shared/orchestration-fleet-echo.test.ts
  • src/shared/orchestration-fleet-echo.ts
💤 Files with no reviewable changes (1)
  • src/main/runtime/orchestration/db.test.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/cli/handlers/orchestration-fleet-echo-format.test.ts
  • src/cli/handlers/orchestration-fleet-echo-format.ts
  • src/main/runtime/orca-runtime.ts
  • src/main/runtime/rpc/methods/orchestration-check.test.ts
  • src/shared/orchestration-fleet-echo.ts
  • src/cli/specs/orchestration.ts
  • src/shared/orchestration-fleet-echo.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.ts
  • src/cli/handlers/orchestration.ts
  • src/main/runtime/rpc/methods/orchestration.ts
  • src/main/runtime/orchestration/db-dispatch-liveness.test.ts
  • src/main/runtime/rpc/methods/orchestration-fleet-echo-sources.test.ts
  • skill-guides/orchestration.md
  • src/main/runtime/rpc/methods/orchestration-tasks-dispatch.test.ts

Included review availability: Your plan includes up to 10 reviews per rolling hour; 8 remain after this review.

db.test.ts sits just under the 800-line max-lines budget, leaving no
room for new coverage. Move the recordHeartbeat and getStaleDispatches
tests into a new db-dispatch-liveness.test.ts — a coherent unit around
detecting whether a dispatched task is still alive — and leave the
dispatch-context CRUD coverage behind, which is a different concern.

No assertions or fixture behaviour changed; only file location.
Add a `fleet` block that orchestration methods can attach to their
response: a live snapshot of the caller's active dispatch lanes
(handle, task, dispatch, lifecycle, quiet time, and delivery state),
capped at 12 lanes with truncation reported. The `delivery` column is
the point: `not_accepted` means a dispatched prompt never actually
started a turn in the worker terminal, something a coordinator would
otherwise only discover minutes later by noticing silence.

This wires the fleet echo into `orchestration.check` only, including
every wait/timeout return path — a complete, reviewable vertical
slice covering the builder, runtime adapter, the check RPC method,
CLI rendering, and the skill guide. The remaining eight orchestration
methods (send, reply, inbox, task-create/list/update, dispatch,
dispatch-show) get the same wiring in a follow-up PR.
- listActiveDispatchesForRun now requires dispatch_contexts.run_id to match
  the caller's Run and to agree with the task's, so a divergent denormalized
  row cannot leak another Run's lane. Regression test covers both.
- A remote worker mailbox resolves its Run from the task instead of passing
  undefined, which had omitted the block entirely for remote worker checks.
- The check fixture now creates its task in the bound Run; without it the
  assertion could pass against the legacy Run rather than the caller's.
- quietMs null-checks the timestamp instead of testing truthiness, so an
  epoch-zero value means the same thing to it as it does to delivery.
- The TZ-pinned test deletes TZ when it was originally unset, rather than
  restoring the literal string "undefined" into sibling tests.
- check's usage string documents --no-fleet, and the guide's output example
  carries a fence language.
… a blind re-dispatch

buildFleetEcho now clamps a caller-supplied limit to FLEET_ECHO_MAX_LANES.
The cap is the response contract, not a default, and this block rides on
every orchestration response.

The guide told a coordinator to re-dispatch on `not_accepted`. That is
right for a worker-start lane, where the verdict comes from the worker
never reaching `input_accepted`. For a plain `dispatch --inject` there is
no acceptance signal to read, so the verdict is inferred from the terminal
having produced no output since the dispatch — and acting on a false
positive duplicates work that is already running. The guide now
distinguishes the two sources and says to confirm with `terminal read`
first.
@Tauri-EPO
Tauri-EPO force-pushed the feat/orchestration-fleet-echo-all-methods branch from e317b8b to 90098c0 Compare August 17, 2026 21:19
…from

The block reported accepted/not_accepted from two observations of unequal
strength under the same word. A worker-start lane reads stage from the
worker-dispatch row; an unsupervised `dispatch --inject` lane has no such row
and the verdict was inferred from the terminal having stayed quiet since
dispatched_at. Lanes now carry deliveryEvidence, rendered as NOT_ACCEPTED:output
or accepted:stage, so a coordinator can tell a read verdict from an inferred one
without consulting the guide.

The guide's claim that a worker-start verdict is authoritative was also stronger
than the code supports, and is corrected here. markWorkerDispatchReady writes
stage='input_accepted' as soon as sendTerminalAgentPrompt returns, so it records
that the runtime wrote the prompt, not that the agent began a turn: a composer
that swallowed the submit still reports accepted (stablyai#14525). Only not_accepted is
authoritative on that path.
…p repeating a healthy table

Three changes to the same problem: the block rides on every run-scoped response,
so what it costs and what it hides both matter.

Ranking. The cap was applied by the query's oldest-first order, so a Run past 12
active lanes truncated its newest — which is where a freshly broken lane lives.
Severity cannot be a SQL predicate because it needs runtime signals, so the query
now reads a wider bounded window and the builder ranks it before cutting: a
not_accepted read from the worker row, then one inferred from silence, then a dead
process, then the longest silence. Truncation lands on the healthy tail. Past the
window ranking degrades to age, which the guide states rather than hides.

Repetition. A healthy fleet says the same thing on every response. Text mode now
collapses it to one line and opens the full table as soon as any lane needs
attention, so the table itself is the signal. JSON keeps every lane: a machine
consumer can summarize, and a payload that changes shape with its contents is a
worse contract than one that does not.

Honesty. The guide now says the block answers which lane to look at, and does not
cover a coordinator parked in check --wait, since it only arrives when asked. It
also drops the lifecycle column from the table, which delivery already implies.
Extends the fleet echo from `check` to the eight remaining run-scoped
methods: send, reply, inbox, taskCreate, taskList, taskUpdate, dispatch
and dispatchShow. A coordinator now learns a lane's delivery state from
whichever command it happens to run next, rather than only from check.

`ask` and `reset` stay unwired on purpose: ask blocks until answered, so
a snapshot taken at return time is stale by construction, and reset tears
the Run down.

Two methods needed a way to reach the caller's Run. inbox takes an
optional callerTerminalHandle, matching the param already used by
taskCreate, taskList, taskUpdate and dispatch; its existing output is
unchanged and older clients that omit it simply get no block.
dispatchShow resolves the caller's own Run and attaches only when it
matches the task's Run, so it cannot hand one Run's lane roster to a
caller working in another.
reply reaches a Run through the message id it was handed, so echoing that
Run's lanes handed its roster to any caller holding an id from another Run.
It now attaches only when the caller's own bound Run matches, with a
regression test proving both directions.

dispatchShow had the same shape and the same fix; both now share
runIdIfCallerOwns rather than repeating the lookup, and inbox uses the
matching resolveCallerRunId.

The CLI also never sent callerTerminalHandle on inbox, so the block could
not attach there at all — --terminal names whose mailbox to list, not who
is asking.
orchestration-send.test.ts is at 790 counted lines on main; appending the
five fleet-echo cases pushed it to 844 and over the 800-line budget. Same
split as db-dispatch-liveness.test.ts rather than a suppression.
…fleet block attaches

dispatch-show reaches a Run through the task it was handed, so the runtime only
attaches the block once it can prove the caller owns that Run. The CLI sent
task, preamble, from and devMode and never the caller handle, so the gate
resolved null and the block silently never appeared on one of the nine commands
the guide lists. It reuses the handle --preamble already resolves, and skips the
resolve entirely under --no-fleet.

Also binds the tasks-dispatch fixture to the caller Run, which otherwise creates
its task in the legacy Run and asserts against lanes the bound-Run query excludes.

The new CLI cases live in their own file: orchestration.test.ts sits at its
max-lines budget, and the remint case there now pins the reminted handle instead
of the whole param object, which is what that case is actually about.
@Tauri-EPO

Copy link
Copy Markdown
Contributor Author

Pushed 047afc436d, taking the two findings that belong to this PR.

dispatch-show never attached the block, and this was the same bug as inbox. The runtime gates it on the caller owning the task's Run:

const runId = runIdIfCallerOwns(runtime, params.callerTerminalHandle, taskRunId)

and the CLI sent task, preamble, from and devMode — no caller handle. The gate resolved null, and the block was silently absent from one of the nine commands the guide advertises. It now reuses the handle --preamble already resolves and only pays for its own resolve when it has to, skipping it entirely under --no-fleet since nothing would consume it.

That is the second time this exact shape has bitten in this PR — inbox had it too. Both are commands whose Run comes from something other than the caller, so both need the caller stated explicitly. Worth remembering if a tenth command joins the list.

The tasks-dispatch fixture now names the bound Run. createTask defaults an omitted runId to the legacy Run, which the bound-Run query then excludes, so the lane assertions were not exercising the caller's Run. Same correction already applied to orchestration-check.test.ts.

Two notes on where the new tests live. orchestration.test.ts sits exactly at its 800-line budget, so the new dispatch-show cases went into orchestration-fleet-echo-cli.test.ts rather than a suppression. The remint case in the original file also stopped pinning the whole param object and now pins the reminted handle, which is what that case is about — the full param shape is asserted in the new file, in both the --preamble and plain-read paths.

The comment-length nitpick on orchestration-send-fleet-echo.test.ts is applied too.

Verification on 047afc436d, Node 24: typecheck:node, typecheck:cli, oxlint src config tests --deny-warnings and the max-lines ratchet clean; 48 CLI handler tests and 44 across the two RPC suites passed.

@nwparker nwparker removed the P2 label Aug 19, 2026
@Tauri-EPO

Copy link
Copy Markdown
Contributor Author

Closing this along with #14891, which it was stacked on. The reasoning is recorded there: the fleet echo re-derives agentWait (#15261), unsupervised (#15105) and the pinned live / unverifiable / exited vocabulary (#14971) by hand, and more importantly it is a read surface over DEC-01, which #14962 changed rather than settled.

One observation from this branch is worth keeping, and I want to state it accurately rather than overclaim it. While wiring the echo into dispatch-show I found that the CLI reaches the runtime with no caller identity: on main, orchestration dispatch-show resolves from only when --preamble is passed, and never sends callerTerminalHandle at all.

// src/cli/handlers/orchestration.ts:1219
const from = showPreamble ? await resolveCoordinatorTerminalHandle(flags, cwd, client) : undefined
await client.call('orchestration.dispatchShow', { task, preamble: showPreamble, from, devMode })

That is not a defect on its own — nothing upstream is gated on it today; the gate this PR added was its own. It is a constraint on #14898 (READ-04): a Run-scoping fix for dispatchShow that keys off the calling terminal cannot take effect from the CLI unless the CLI starts sending one. #14900 is the open attempt at #14898 and currently conflicts with main, so I am recording the constraint on that thread rather than leaving it in a closed branch.

READ-01 and READ-02 on #15190 now read blank for implementation.

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.

[Feature]: Inspect delivery and activity across a Run without one call per worker

4 participants