Skip to content

feat: before it closes on a capability, the house runs it once in a trial — and what throws does not close (greenhouse decisions/0605) - #767

Merged
rodrigoteamx merged 6 commits into
mainfrom
hp/greenhouse/t-0092-closing-exercises-what-it-gives-as-whole
Oct 9, 2026
Merged

rodrigoteamx merged 6 commits into
mainfrom
hp/greenhouse/t-0092-closing-exercises-what-it-gives-as-whole

Conversation

@rodrigoteamx

@rodrigoteamx rodrigoteamx commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

R1 of greenhouse decisions/0605, decided by Rod on 2026-10-08: «the closure exercises what it is about to give as whole», and everything thrown blocks. Design and its measure from outside: t-0106 (greenhouse#374, evidence/1166). Built and measured here: greenhouse evidence/1171. R2 is not in this pull request.

Why

Twenty houses a build station left (evidence/1166). The house closed six verified; in one, three of four operations call a method that does not exist and fail the first time anyone uses them. The closure had read what the capability declares and called nothing — and said so: exercised: "unjudged" (decisions/0595). Meanwhile the four sessions that tried to call what they had just built were stopped at the frontier. The house gave «verified» to the session that did not run its work.

What changes

The property: before the house says verified over a capability, it has run it once.

At the natural end of a leg, when the verdict is about to say verified over a capability the house saw declared whole, the house runs it:

  • in one copy of the house, made by the copier trials use — without its state, without any file that holds a secret — and run by the trial runner, the one confinement there is;
  • every operation the promotion declared, in catalogue order, twice, each call a process of its own, with one value of the declared type per required input (the first of its enum);
  • each operation is read by its worst answer: it answered, it refused, or it threw.

If any threw, there is no closure, and the reason names the operation, the class and the first line:

the house ran «Prestamos» in a trial before closing on it (seq 341) and 1 of its 4 operations threw: «prestamos:registrar» threw Error: Call to undefined method Milpa\Data\FileRepository::guardar() — an operation that throws is not whole: fix it with implement

If none did, the observation says exercised: "ran" with its counts — and behavior: "unjudged". exercised never says more than that.

What the house found is a receipt in the session's own stream (session.capability_exercised), and the verdict reads it from there, as it reads everything. So:

  • between steps nothing is ever run, and what threw stands there: the next leg does not open its epilogue over it, and the session can repair it;
  • a receipt speaks of the house it ran on: any change that lands later takes it back, ran and threw alike; a promotion that wrote nothing does not;
  • a declaration is run once.

The copy is no trial. It lives under var/exercises/; nothing that lists, opens, promotes or sweeps a trial can reach it, even while it runs; it is discarded. The mask of secrets covers it.

What the design did not say, and had to be built

  1. The receipt. Without it, the next leg's first step reads «declared whole, nothing changed», the epilogue opens, and two model calls are left: the session could never repair what it was just told.
  2. The leg's own process does not know what landed during the leg — it booted before. The operations are read from the promotion's receipt, and what each one takes is read in the copy, by a process started there: a second small runner, resources/exercise-run.php.
  3. The runner says what happened in fields, not in a sentence (thrown: {class, engine}, missing). Reading «Class: message» out of a text takes a refusal like «Validation: name is required» for a throw.
  4. An operation could answer that it did not exist. «Not found» leaves the whole unjudged, and unjudged closes. Those two fields are the runner's alone now.
  5. The reason came last, and could be counted and not said. A session that does not close is also told of every class it wrote that no call verified, and what the house saw came after those lines: ninth of ten on the script-3 house (t-0106 saw it in the blind output). And the verdict says sixteen facts and counts the rest. What the house saw is now the first reason said — a capability that threw, one not whole, a page that does not list, a house that changed after it was last seen — before what no call of the session can satisfy (last commit).

Three of these are t-0106's, from reading the first shape of it: the receipt bound to the state of the house, that it must be no change, no trial and no work of the session, and that it names no seat.

Measured (greenhouse evidence/1171) — no model

A throw-away container of the image a build run left, no network, this branch's src/ and resources/ mounted read-only over the installed runtime. Inside, the function a leg calls when its final answer comes, over the ledger as the run left it.

house the house had recorded now, at the natural end answered · refused · threw s
course · today's reference run, published train verified, unjudged verified, exercised: "ran" 2 · 2 · 0 0.4
course · on the admitted base verified, unjudged verified, exercised: "ran" 2 · 2 · 0 0.4
control · the first, one operation calling a method that does not exist verified, unjudged no closure, threw — the reason above 1 · 2 · 1 0.4
control · the first, a defect of conduct verified, unjudged verified, exercised: "ran" 2 · 2 · 0 0.4
script 3 · closed by the house, battery 0 of 8 — run blind by t-0106 verified, unjudged no closure, threw: operations 1, 2 and 3 of 4, class Error, the engine's, each line starting with «Call to undefined method» 1 · 0 · 3 0.4
script 3 · closed by the house, battery 4 of 8 — run blind by t-0106 verified, unjudged verified, exercised: "ran" 1 · 3 · 0 0.4
  • The first house's counts are the ones t-0106 measured for it from outside.
  • Of every file of the house — caches and logs aside — one changed: the ledger, by the receipt's line. No copy is left.
  • The two script-3 houses are the two of evidence/1166 the house had closed and the battery rejects. I do not read that script: t-0106 ran the instrument on them in blind mode — places, never names — and handed me its output after their own two filters. Both came out as I had written before seeing them: the first is left with no closure; the second still closes, which is what R1 does not catch.
  • In the control the reason is the first of nine. On the script-3 house it was the ninth of ten when t-0106 ran it, one commit before the last.

With main in it, and an invariant with rule A

  • Main is merged in (rule D of decisions/0604, feat: a leg is told what its session left half done — read from what landed, said after the conversation (greenhouse decisions/0604) #766). One line clashed — the return shape of HouseObservedClosure::of(): this branch adds what a capability's observation may carry, main adds the files where a scaffold still stands — and it now says both. AgentOperations.php, which both touch, merged by itself.
  • A pause is not a natural end. The house is about to continue by itself a leg paused for window or for steps (rule A, t-0104). R1's half of that is pinned here: a leg that runs out of steps over a stream that would close runs nothing and records no verdict; the leg that continues it and ends on its answer runs the capability once and closes. The other half — the continuation inside the same invocation, for both pauses, and the cap — is in A's pull request, on the same test house (ExercisedTaller).

What it does NOT catch

  • A defect of conduct. An operation that runs and does the wrong thing ran. The second control shows it: the battery would reject that house, and it closes verified with exercised: "ran". Only who compares states sees it.
  • A house that cannot confine a process, or switched trials off: it runs nothing, says unjudged with the reason beside it, and closes as it did. It never runs a session's code unconfined to find out.
  • An operation the runner does not find: the whole is unjudged. That is the house's failing, not the session's.
  • A session the house closed before this version: a «continue» is answered by the door, which reads and never runs. The next leg that really ends runs it.
  • It does not tell the next leg. The reason is in the verdict, which goes to whoever ran the leg; the model of the next leg is told nothing of it. Rule D now tells a leg what its session left half done, and what threw is that kind of line — proposed to t-0104 and the coordinator as a small follow-up, not in this pull request.
  • What only fails on data that was already there: the copy starts on an empty store, as every trial does.
  • The inputs are invented: text «7», number 7.

For whoever decides

  • Two kinds that «everything thrown» does not literally name: fatal — the process ended without answering — and timeout — the house stopped it at ten seconds. Both block today. A slow, legitimate operation is the possible false alarm.
  • Not built, t-0106's alternative: run it once when a declaration is about to open the epilogue, so a throw is repaired in the same leg. What was decided is «at the natural end, never between steps»; with that, a throw is told at the end of the leg.
  • Not marked breaking. Nothing is removed and no contract changes shape: exercised gains two values, the capability's observation gains fields, the stream gains a fact the reducer skips. What someone who updates will see: a session whose capability throws no longer closes.

Tests, mutants, suite

  • Red first where it was: the verdict reading the receipt (eight red, four controls), the leg (four), the cap of reasons (one). Where it was not, said: the runner's twelve were written after the runner; the exercise's were run for the first time with its class already written; nine were added after building. The mutants hold those.
  • 52 mutants by hand, 52 killed (scripts/lab/exercise-1171/mutants-exercise.py in greenhouse). Four survived a first pass and were weak tests; each has its test now.
  • Whole suite: 4,119 tests green before the merge; 4,136 with main in, 8 skipped — the baseline. PHPStan, formatter, docblocks, composer validate: clean. The last commit only adds a test: I ran its file and its mutant here, and CI ran the whole.
  • The guard of the security patch (OnlyOneConfinementIsBuiltAndItMasksTest) is green: this builds no confinement; it uses the runner's.
  • Nothing ran with a resident.

…rial — and what throws does not close (greenhouse decisions/0605)

Measured on twenty houses a build station left (greenhouse evidence/1166): the house closed six `verified`, and
in one of them three of four operations call a method that does not exist. It had read what the capability
declares and called nothing — `exercised: "unjudged"`.

At the natural end of a leg, when the verdict is about to say `verified` over a capability declared whole, the
house runs it: one trial of its own, through the trial runner; every operation the promotion declared, in
catalogue order, twice, each in a process of its own, with one value of the declared type per required input.
An operation is read by its worst answer: it answered, it refused, or it threw. What threw does not close, and
the reason names the operation, the class and the first line. `exercised` becomes `ran` or `threw`, never
«correct»: beside `ran` the verdict says `behavior: "unjudged"`.

What the house found is a receipt in the session's own stream, and the verdict reads it wherever it is read —
so between steps, where nothing is ever run, what threw stands and the next leg can repair it. A receipt speaks
of the house it ran on: any change that lands later takes it back.

The copy is no trial: it lives under var/exercises/, nothing lists, opens or promotes it, and it is discarded.
A house that cannot confine a process, or switched trials off, runs nothing and says so.
… are counted

A session that does not close is also told of every class it wrote that no call verified, and the house's own
finding came after those lines. The verdict says sixteen facts and counts the rest — so with enough classes, the
one line that names the operation that threw was counted and not said.

Measured on a house a build run left (greenhouse evidence/1171): eight such lines stood before it. What the house
saw — a capability that threw, one not whole, a page that does not list — now stays among the ones said; the
session's own record is what gets counted.
The cap keeps apart the reason the house gives when it did not derive its closure — not only what threw: here,
that the house changed after it was last seen. A mutant that dropped that line survived until this.
Measured blind on the house a build run left closed with three operations that throw (greenhouse
evidence/1171): the verdict carried ten reasons, and the one that names what threw was the ninth, after eight
lines of classes no call verified. A resident reads from the top.

What the house saw — a capability that threw, one not whole, a page that does not list, a house that changed
after it was last seen — now comes before what the session's own record lacks. Said first, it is also never
the part the cap of sixteen counts and does not say, so the cap is the plain one again.
… its leg)

One line clashed, in the return shape of HouseObservedClosure::of(): this branch adds what a capability's
observation may carry once the house ran it, main adds the files where a scaffold still stands. Resolved by hand
to the line that says both. AgentOperations.php, which both touch, merged by itself.
…ut of steps runs nothing and records no verdict

The house is about to continue a paused leg by itself (greenhouse decisions/0604, rule A). A pause is not a
natural end: nothing is exercised there and no verdict is recorded, though the same stream would close. The leg
that continues it and ends on its answer runs the capability once and closes.

This is R1's half of that invariant, pinned on the leg as it is today: one invocation that stops, and the next
that answers. The other half — the continuation inside the same invocation, for a pause of window and one of
steps — is in the pull request of rule A, on the same fixture: the recording of the promotion moves into it.
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