A substitute that failed in round one said nothing about the tree that lands
after round two, yet the flag was sticky and doomed the run; the xfamily
string was never reset either, so clearing the stickiness alone would have let
a stale "substitute ALSO failed" sentence into the PR body. Both reset at the
top of review(). The harness runner is round-aware (ran per round, its own
counter reset) and a two-round case pins the fix; restoring the sticky flag
reddens it in both scripts. Step 4 of the mechanics page tells the referee to
read cross_family, not only error, before posting on a rubric-class PR.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
The runner builds nothing, so serialising it only added its wait to the
critical path; the worktree-isolated fallback is what must follow the lenses,
and the harness case now records lens count at the FALLBACK's start alone.
setTimeout in the harness is globalThis.setTimeout (the .mjs lint config has
ES builtins only). head_sha carries the same description in both scripts and
every fixer/implementer prompt asks for the worktree HEAD, not a PR head. The
mechanics page says why the cap stays at one after the serialisation and
restores the 20%/10% RAM thresholds by key; the record says "several", not
"three".
Decisions-Edit: yes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
One .NET slot's review round ran two worktree-isolated reviewers at once — the
correctness lens and, on a rubric change, the Codex fallback — and took swap
from 6.8 GB to 10.8 GB in three minutes on the 16 GB host; three slots reached
load 82. review() now awaits the lenses, then the Codex runner, then its
fallback. The finisher's fix attribution is the sha range the fixer's report
head advances (head_sha is required on every report), replacing a line-set
difference over free text that listed all eleven #563 commits as fixes. The
harness gains a case that records how many lenses were still in flight when
the cross-family agents started (must be zero); moving the fallback back into
the parallel batch reddens it in both scripts. The mechanics page and the
standing prompt state the measured cap: one .NET-building slot at a time.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
A round in which every lens returned null read as a clean pass and would now
have been quoted verbatim into the PR body; it is an error before the push,
in the review loop and in the post-rebase round, which also gains the same
blocking-or-should-fix filter; a fixer that dies or stops (no done) is an
error too, the same test the implementer already gets. The history entry now
carries the fix that answered that round and only the commits that fix added
(a line-set difference against the previous branch log — a fixer that
reformats or rebases mid-loop defeats it, which is why the finisher is told
to read git show, not the list). An empty fix-commit set is described as
"answered without a new commit" when a fix round ran, and as "round one was
clean" only when none did.
web/scripts/orchestration-workflow-loop.test.mjs compiles the committed script
bodies with stubbed agent/parallel and pins eleven paths per script (22
tests). Measured: reverting the loop condition to blocking-only reddens six
cases per script (every case that needs a should-fix round to reach the
fixer); deleting any of the three zero-lens guards, the fixer guard or its
done half, or the empty-fix sentence branch reddens its own case, in both
scripts. web/vite.config.ts is untouched: it is pinned whole by
test_image_build_delegates_the_spa_suite.py, comments included.
Decisions-Edit: yes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
The fixer brief already said "fix every blocking and should-fix one"; the loop
condition alone disagreed, so a merge-worded round with real defects skipped
the fixer and the finisher attested to fixes it never saw (#554 / PR #910).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
The marker-overwrite instruction asserted an antecedent no agent can verify
and, since same-session worktrees carry no marker, could only fire in another
session's worktree; the scripts now stop and report. `ran` and `patch_changed`
move into required keys of their own schemas so a missing field cannot read
as a successful cross-family review or an unchanged patch. A blocking finding
in the post-rebase round now returns an error like every other failure path.
Each reviewer lens gets its own E2E port; the gate text travels with the
reviewer brief. The standing prompt no longer contradicts the substitution
the scripts perform; the record names patch-id, the mechanism the scripts use.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
The mkdir lock around scripts/e2e-local.sh serialised the launch, not the run
(the launcher returns with the server up), and its stale-holder path double-
acquired in 4 of 91 measured races; the launcher's documented conflict is its
per-worktree wwwroot, so slots now run on their own port and the lock is gone
with its inventory row. process.orchestrated-session records the two scopings
the harness needed: a rebase pushed with --force-with-lease as the one sanctioned
rewrite, and the referee as the only agent that ticks Done-when boxes. Scripts:
required-arg guard, per-issue claim probe, reviewer fetch recipe, codex fallback
to a cold review-only agent with the substitution stated in the PR body, rebase
before the review loop with a patch-id check at the push, non-interactive
squash recipe, Land phase. README bullets re-parented; kickoff bullet keyed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV
The single-issue kickoff stays as it is; this adds the layer that runs several of
those under one referee. docs/handoffs/orchestration.md owns roles and sizing,
one worktree per issue under ~/orca/workspaces/ersatztv/, the landing order with
the review loop inside the worktree before the single push, and the merge through
the consent hook. Three Workflow scripts encode it: a picker over
scripts/select-queue.sh with two refuters, an issue-build pipeline (claim, recon,
implement, gate, cold review with a cross-family runner for the rubric's risk
classes, fix loop, finisher), and a resume pipeline for a paused branch.
scripts/e2e-gate.sh serialises live-E2E across worktrees because e2e-local.sh
refuses concurrent runs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015QqCpYFsKgnAnx6jVwrKiV