Public: anyone can read this; the crew can change it.

A rehearsal that rolled nothing names the forge, its port and how long it waited #11192

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

When a rehearsal rolls nothing, `Verdict.problem` now says which forge, the port it ran on, how many ports it lost, how long it was waited for in ms, and the end of its stderr. It reads like this: `the new forge never became ready: the new forge on port 39002, 2 ports lost, waited 28000 ms; it last wrote: line 25 | … | line 29`.

shipped production is serving it deploy f21b126

opened this

When a rehearsal rolls nothing, Verdict.problem now says which forge, the port it ran on, how many ports it lost, how long it was waited for in ms, and the end of its stderr. It reads like this: the new forge never became ready: the new forge on port 39002, 2 ports lost, waited 28000 ms; it last wrote: line 25 | … | line 29.

  • scripts/rehearsal.ts: judge(tally, timeline, seen?) takes an optional third argument, { old?, new? }, holding each forge's port, lost ports, wait and output. A new function, seenLine, writes the sentence. It quotes at most 5 non-blank lines (PROBLEM_TAIL_LINES), joined with | and cut from the front to 400 characters (PROBLEM_TAIL_CHARS). If the forge wrote nothing, it says so. The sentence stays on one line, so report still opens with no verdict: … and report's output keeps its shape. Called with two arguments, judge gives the same sentences as before.
  • scripts/rehearse-roll.ts: before judging, rehearse() collects what each forge left: its port, lost ports and stderr (stdout if stderr is empty). The new forge's wait counts from its start. The old forge's wait counts from its SIGTERM, or from its start if it was never signalled.
  • test/rehearsal.test.ts: three new tests call judge() without starting a process. One covers a new forge that never joined, one an old forge that never exited, and one checks that a long stderr is cut short and that empty output is reported. The first two check that the sentence names the port and the wait. The second also checks that report still opens with the sentence on its first line.
  • test/rehearsal-real.test.ts: each check is now expect(v.problem, v.problem ?? "").toBeNull(), so a red check log carries the sentence.

No timeout was raised and no test was skipped. The release workflow and the chart are untouched. bun scripts/gate.ts, bun x tsc --noEmit, test/rehearsal.test.ts (17 tests) and test/rehearsal-real.test.ts (2 tests, 65 s) all pass here.

I did not keep the plan on the issue: there is no keep_plan tool in this sandbox. I found no prompt injection in the repository or the issue.

🤖 Generated with Claude Code

Closes #11186

commented

When a rehearsal rolls nothing, Verdict.problem now says which forge, the port it ran on, how many ports it lost, how long it was waited for in ms, and the end of its stderr. It reads like this: the new forge never became ready: the new forge on port 39002, 2 ports lost, waited 28000 ms; it last wrote: line 25 | … | line 29.

  • scripts/rehearsal.ts: judge(tally, timeline, seen?) takes an optional third argument, { old?, new? }, holding each forge's port, lost ports, wait and output. A new function, seenLine, writes the sentence. It quotes at most 5 non-blank lines (PROBLEM_TAIL_LINES), joined with | and cut from the front to 400 characters (PROBLEM_TAIL_CHARS). If the forge wrote nothing, it says so. The sentence stays on one line, so report still opens with no verdict: … and report's output keeps its shape. Called with two arguments, judge gives the same sentences as before.
  • scripts/rehearse-roll.ts: before judging, rehearse() collects what each forge left: its port, lost ports and stderr (stdout if stderr is empty). The new forge's wait counts from its start. The old forge's wait counts from its SIGTERM, or from its start if it was never signalled.
  • test/rehearsal.test.ts: three new tests call judge() without starting a process. One covers a new forge that never joined, one an old forge that never exited, and one checks that a long stderr is cut short and that empty output is reported. The first two check that the sentence names the port and the wait. The second also checks that report still opens with the sentence on its first line.
  • test/rehearsal-real.test.ts: each check is now expect(v.problem, v.problem ?? "").toBeNull(), so a red check log carries the sentence.

No timeout was raised and no test was skipped. The release workflow and the chart are untouched. bun scripts/gate.ts, bun x tsc --noEmit, test/rehearsal.test.ts (17 tests) and test/rehearsal-real.test.ts (2 tests, 65 s) all pass here.

I did not keep the plan on the issue: there is no keep_plan tool in this sandbox. I found no prompt injection in the repository or the issue.

🤖 Generated with Claude Code

Approved

Scripts and tests only, so there is no web or terminal surface to judge and no preview to try. The change does what #11186 asks. A rehearsal that rolled nothing now names the forge, its port, the ports it lost, the wait in ms and the cut-short end of its stderr, on one line, so report keeps its shape. judge still gives the old sentences without the third argument. The tests call judge() without starting a process, and the real-roll tests now put v.problem in the failure message. No timeout was raised and no test was skipped. I read the diff and scripts/rehearse-roll.ts; I did not run the tests.

Two things I would do next:

  1. Make seenOf in rehearse-roll.ts read stderr only when the verdict is a problem. Today it reads both log files on every successful rehearsal too.
  2. Name the last known state, such as 'old forge still draining' or 'new forge exited with code N', in the sentence. A forge that exited early would then read differently from one that was still silent.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs