Skip to content

bench(lab): carry the rejection forward and bound the loop - #273

Closed
luuuc wants to merge 1 commit into
lab/05-01-the-phase-graphfrom
lab/05-02-the-levers-and-the-ceilings
Closed

bench(lab): carry the rejection forward and bound the loop#273
luuuc wants to merge 1 commit into
lab/05-01-the-phase-graphfrom
lab/05-02-the-levers-and-the-ceilings

Conversation

@luuuc

@luuuc luuuc commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Problem

Authoring is a cycle, not a line. Most drafts do not become a benched win on the first attempt, and what happens on the second attempt is where the method lives.

Three verdicts send work back — NO-ANCHOR from a draft, REQUESTION from a mini-bench, DO-NOT-PAY from a validation — and each one is an opportunity to lose the thing that made the previous attempt worth improving. The instinct when a draft fails is to clear it and start clean, and the cost of yielding to it is invisible: six unrelated attempts look exactly like six iterations from the outside.

A loop that re-enters itself also needs a bound, and this binary spends money unattended.

Summary

lab/internal/loop holds a repository's position in the authoring cycle and the rules for re-entering it. lab/internal/budget reports what a campaign has spent by reading the run tree rather than by holding a counter.

Changes

  • A re-entry that carries no table is refused. The rejection is a required input, not an optional one, so a re-entry cannot become a fresh guess wearing the previous attempt's number.
  • Nothing is deleted on re-entry. The finished attempt is filed with its anchor, its draft and the rejection that stopped it, and the next attempt answers every rejection so far rather than only the last.
  • Re-anchoring is its own decision. Only ReAnchor changes the anchor, and it refuses unless a verdict asked for one. A NO-ANCHOR records that an anchor is owed without discarding the one that failed, because a sub-floor cell is a question the anchor could not carry rather than necessarily a bad anchor.
  • The authoring ceiling parks. After the sixth cycle the repository stops, and no transition re-enters it. Resume is the deliberate human action, and it hands a fresh cycle count while keeping the anchor, every attempt and every rejection.
  • A diagnosis and a ceiling both land on handoff and mean opposite things, and they are told apart by asking the graph rather than by holding a flag: one is a swap handed up with its numbers, the other is a repository parked.
  • Spend is recomputed from disk, never accumulated. The total is the size of a set of run directories, so reading it twice cannot change it and a restart cannot spend the budget twice. Orphaned bench runs are counted and named rather than dropped, because a run that started and never recorded a terminal state still spent its money.
  • The ceiling is per campaign over its lifetime, and it refuses rather than warns.
  • No phase may ask a human anything. The lab boundary test now walks every production file for a read of os.Stdin, allowed only where a stream is handed to a command. --manual stops before a phase and prints the artifact it awaits; there is no second bypass.

Decisions recorded during the build

Spend is counted in paid runs, not dollars. Nothing on disk records a price — the model files carry an id, a provider and the tools that can drive them, and no rate — so a dollar figure would be a number the instrument invented.

budget.Ceiling and --manual have no caller yet, because no command drives the loop until the flywheel cycle. The mechanisms are here and tested; the flag and the pay-path check are wired when the driver lands.

Test Plan

  • make ci green: build, tests, per-file coverage floor with no new exception, zero complexity suppressions, lint clean.
  • 100% line and function coverage on both new packages.
  • Every lever carries its table into the next attempt, and a re-entry with an empty table is refused.
  • Six cycles across three different levers, asserting the anchor, every prior draft and every rejection survive.
  • The ceiling is reached by driving real re-entries rather than by assigning the cycle count, so the test proves the road as well as the guard.
  • A parked repository refuses to advance; a repository that was never parked refuses to resume.
  • Spend read twice without a run in between is unchanged, and one new run moves it by exactly one.
  • The no-prompt check was verified to fail when its allowlist is narrowed, so it is not vacuous.

Authoring is a cycle, not a line, and what happens on the second attempt
is where the method lives. Three verdicts send work back, and each is an
opportunity to lose the thing that made the previous attempt worth
improving. The instinct when a draft fails is to clear it and start
clean, and the cost of yielding to it is invisible: six unrelated
attempts look exactly like six iterations from the outside.

lab/internal/loop holds a repository's position and refuses a re-entry
that carries no table. Nothing is deleted: the attempt is filed with its
anchor, its draft and the rejection, and the next attempt answers every
rejection so far rather than only the last. Re-anchoring is its own
decision with its own verdict; a re-question never touches the anchor,
and a NO-ANCHOR records that one is owed without discarding the one that
failed.

Both ceilings refuse rather than warn. The authoring ceiling parks after
the sixth cycle and is re-entered only by a deliberate resume, which
hands a fresh cycle count and keeps the history. lab/internal/budget
reads spend from the run tree every time instead of holding a counter, so
a restart cannot spend the budget twice: the total is the size of a set
of run directories, which makes double-counting unrepresentable rather
than merely guarded against.

A campaign runs unattended for hours, so no phase may ask a human
anything. The lab boundary test now walks every production file for a
read of os.Stdin and allows it only where a stream is handed to a
command.
@luuuc
luuuc deleted the branch lab/05-01-the-phase-graph August 17, 2026 07:17
@luuuc luuuc closed this Aug 17, 2026
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.

1 participant