Repository navigation
Tell the leader how to read a finished run's report - #160
Merged
Merged
Conversation
A terminal digest is a notification: it says the run ended, not what it
produced. Nothing pushes the report -- `run/result` is the only way to
read it, and the leader has to ask. So `Run <id> ... succeeded.` left a
leader knowing a run finished and holding none of its output, with no
indication that anything remained to fetch.
The settled-turn digest has always told the leader exactly what to do
("Read the answer via crew_run { op: "result", runId }, then ..."), and
had a test pinning that instruction. The terminal digests carried neither
the instruction nor a test asserting their content, which is how the gap
survived: the harder case was handled and the simpler one was not.
Scoped from the code rather than assumed. `run/result` gates on
`is_terminal`, so it accepts failed, cancelled and lost as well as
succeeded, and returns whatever visible text the journal accumulated
(`run_result_events_op`'s `final_text.or(chunk_text)`). For a run that
died that is usually partial output and often the most useful diagnostic
available -- but it can be null, when the worker produced nothing. So the
succeeded digest states plainly where the report is, and the others offer
partial output while saying there may be none. A digest that promised
output and returned nothing would be worse than one that never mentioned
it.
Also closes the bridge's one silent branch. `sendMessage` is looked up
through a cast so a renamed or removed omp method degrades to "no
digest"; the guard was then false forever and every milestone for the
session was dropped with nothing logged, because the surrounding catch
only covers digests that throw. An omp version bump could switch the
leader's notifications off entirely and look exactly like a quiet run. It
now warns once per session, lazily -- a session that never reaches a
milestone stays silent, and a long run cannot flood the log with one
unchanging fact.
Replay suppression is untouched.
Each test was confirmed to fail against the opposite behaviour before
being trusted: the succeeded hint removed, the partial-output pointer
removed, and the once-per-session guard forced to fire every time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A terminal digest is a notification: it says the run ended, not what it produced. Nothing pushes the report —
run/resultis the only way to read it, and the leader has to ask. SoRun <id> … succeeded.left a leader knowing a run finished and holding none of its output, with no indication anything remained to fetch.Why the gap survived
The settled-turn digest has always told the leader exactly what to do — "Read the answer via
crew_run { op: "result", runId }, then …" — and had a test pinning that instruction. The terminal digests carried neither the instruction nor any test asserting their content. The harder case was handled and tested; the simpler one was neither.Scoped from the code, not assumed
run_resultgates onis_terminal(orchestration.rs:1228), so it accepts failed, cancelled and lost as well as succeeded, and returns whatever visible text the journal accumulated —run_result_events_op'sfinal_text.or(chunk_text)(query.rs:886), bothOption<String>, both startingNone.For a run that died that is usually partial output and often the most useful diagnostic available — but it genuinely can be null, when the worker produced nothing before it went. So:
A digest that promised output and returned nothing would be worse than one that never mentioned it.
The bridge's one silent branch
sendMessageis looked up through a cast so a renamed or removed omp method "degrades to no digest". The guard was then false forever and every milestone for the session was dropped with nothing logged — the surroundingcatchonly covers digests that throw. An omp version bump could switch the leader's notifications off entirely and look exactly like a quiet run.It now warns once per session, lazily. The reason for lazy is where the reader will be, not noise: the warning exists to explain an absence to someone who has noticed a milestone did not arrive, and that person is reading the log around the moment it should have fired. Attach can be hours earlier, when nobody is troubleshooting anything.
Replay suppression is untouched.
Tests
Three, each confirmed to fail against the opposite behaviour before being trusted — the succeeded hint removed, the partial-output pointer removed, and the once-per-session guard forced to fire every time. The reviewer independently re-ran that control against a reverted
milestones.tsrather than taking the claim.Gate
bun test433/433 ·typecheck·format:check·generate --checkup to date ·check:markers432/0 ·cargo fmt --all --check.cargo test --workspacewas not run: no Rust changed. Stating that rather than implying a gate that did not cover the diff.Bundle refresh
bundle-checkfailed on the first run andauto-commit-distpushed the rebuilt linux-x64 bundle, exactly as designed. Worth recording that this PR body originally said "no protocol change, so no bundle refresh expected" — which applied the rule too narrowly. The trigger is anything the bundle embeds, andmilestones.tsis extension source that gets bundled; a protocol change is only the least obvious way to hit it. The rule as written inCLAUDE.mdis right; the person applying it here narrowed it back to the case that had bitten him before.