bareloop 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +159 -0
- package/README.md +3 -2
- package/bareloop.context.md +282 -8
- package/package.json +1 -1
- package/src/authorflow.js +176 -33
- package/src/authoring.js +170 -25
- package/src/authorjob.js +340 -26
- package/src/bridges.js +237 -10
- package/src/calibrate.js +597 -0
- package/src/cardauthor.js +479 -0
- package/src/declaredclose.js +108 -10
- package/src/index.js +84 -8
- package/src/job.js +27 -13
- package/src/judged.js +765 -0
- package/src/kinds.js +390 -6
- package/src/planrun.js +328 -15
- package/src/reuse.js +319 -89
- package/src/reviewdoor.js +246 -0
- package/src/run.js +73 -6
- package/src/selection.js +22 -6
- package/types/authorflow.d.ts +147 -9
- package/types/authoring.d.ts +54 -8
- package/types/authorjob.d.ts +36 -6
- package/types/bridges.d.ts +95 -1
- package/types/calibrate.d.ts +191 -0
- package/types/cardauthor.d.ts +352 -0
- package/types/declaredclose.d.ts +34 -5
- package/types/index.d.ts +10 -6
- package/types/job.d.ts +22 -9
- package/types/judged.d.ts +280 -0
- package/types/kinds.d.ts +151 -4
- package/types/planrun.d.ts +56 -2
- package/types/reuse.d.ts +144 -3
- package/types/reviewdoor.d.ts +81 -0
- package/types/run.d.ts +49 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,165 @@ All notable changes to bareloop are documented here. Format:
|
|
|
5
5
|
[SemVer](https://semver.org/spec/v2.0.0.html). Pre-1.0: **minor** = a ladder rung or
|
|
6
6
|
feature lands, **patch** = docs, fixes, scaffolding.
|
|
7
7
|
|
|
8
|
+
## [0.12.0] — 2026-08-23
|
|
9
|
+
|
|
10
|
+
### Added (N4 slice 2 — the softgreen rung: a close that JUDGES, and a signer who has the last word)
|
|
11
|
+
|
|
12
|
+
- **The judged floor is real: LOCATE + DECIDE (`src/judged.js`).** A judge (haiku-4.5, pinned —
|
|
13
|
+
never a step knob) extracts FACTS from the real artifact with quotes; an arbiter-owned `decide()`
|
|
14
|
+
renders pass/fail from a signed rubric card; *unsure* is a red, never a pass. The judge never
|
|
15
|
+
renders a verdict, so the rubric-is-self-consistency gotcha stays closed. Wired as the
|
|
16
|
+
`judged-floor` close kind — metered from the run's own wallet, `offer:false` by law, and skipping
|
|
17
|
+
the seed-verdict read (its bar comes from calibration instead).
|
|
18
|
+
- **`soft-green` is ADMITTED as a verdict class** — the class-scoped question set, the inherited
|
|
19
|
+
green guard battery (hamr: *"battery ties with job type"*), the class-scoped kind menu, and the
|
|
20
|
+
promise rule: composition stays ≤ the picked class, and exceeding it is an honest red rather than
|
|
21
|
+
a silent up- or downgrade.
|
|
22
|
+
- **The signer's two artifacts are AUTHORED and enumerated in the hash** (`src/cardauthor.js`): the
|
|
23
|
+
rubric card comes from Q6 and the calibration set from Q7, both handed to the compiler verbatim,
|
|
24
|
+
both SHOWN to the signer (D5 shown-and-fixed), and what the signer fixed is what is stored —
|
|
25
|
+
`source: 'proposal'` says *nobody changed this*, which is a different fact from *a person read it
|
|
26
|
+
and changed nothing*.
|
|
27
|
+
- **The calibration gate — ten graded truths and five resisted lies buy a signature**
|
|
28
|
+
(`src/calibrate.js`, gate 4 of `prepareSigning`). The whole pipe grades the signer's own ten cases
|
|
29
|
+
and faces a 5-artifact injection battery adapted to the locate axis; the floor is **10/10 with
|
|
30
|
+
itemized reds** (hamr, 2026-08-18) and all-or-nothing on both halves. The $0 legality check runs
|
|
31
|
+
first and buys no calls. A dead judge is a CASUALTY under the transport's name, never a reading of
|
|
32
|
+
the operator's rubric.
|
|
33
|
+
- **Quarantine: a judged green earns no learning credit until an `accept` releases it.** Minted
|
|
34
|
+
soft-green bridge rows are held at mint, the release is forward-only, a rerun re-quarantines, and
|
|
35
|
+
a held entry is never offered by selection — so a soft-green pass cannot feed N3 before the judged
|
|
36
|
+
floor is proven.
|
|
37
|
+
- **The review door — every run ends at the signer's three doors** (`accept` / `rerun` / `pause`).
|
|
38
|
+
The door records a DISPOSITION and never touches the loop's own verdict (hamr: *"it's important
|
|
39
|
+
not to change the loop self verdict"*): `runPlan` returns `green`/`already-green` exactly as
|
|
40
|
+
before. It opens at all three green sites (precheck `already-green`, the outer close, and the fix
|
|
41
|
+
loop's green). **Soft-green always** (`REVIEW_DOOR_CLASSES`), **green opt-in** via `reviewDoor:
|
|
42
|
+
true` / `--review-door` — the flag wins in both directions and is never inferred. An `accept`
|
|
43
|
+
re-runs the close's MECHANICAL stages (never a judged floor, never a person): a door keeps for 60
|
|
44
|
+
days and nothing freezes a tree.
|
|
45
|
+
|
|
46
|
+
- **The judge tier joins the SIGNATURE — a bump flips the hash and the stage refuses the
|
|
47
|
+
mismatch** (`649d8a5`). `JUDGE_MODEL`'s docstring has always said a judge-model bump forces a
|
|
48
|
+
full recalibration, and nothing detected one: `closeDecl.calibration` stored only its `cases`,
|
|
49
|
+
so the tier that graded them sat OUTSIDE the signed bytes, a bump flipped no hash, and the
|
|
50
|
+
judged stage never compared the model it was about to buy against the model the signer's set
|
|
51
|
+
was graded by. A rule with no wired detector is prose (F45). The tier now lives beside the
|
|
52
|
+
cases as **`calibration.judgeModel`** (`CALIBRATION_FIELDS` in `src/declaredclose.js`
|
|
53
|
+
enumerates a stored set as exactly those two and nothing else), written by
|
|
54
|
+
`foldJudgedArtifacts` from the PIN itself rather than from anything a caller may name — and
|
|
55
|
+
because it is inside the spec, `jobSpecHash` covers it by construction: bump the constant,
|
|
56
|
+
every signed judged spec hashes differently, the signature dies, and the re-sign is what
|
|
57
|
+
re-runs the calibration gate. `validateCloseDecl` REQUIRES it on any stored set (a set nobody
|
|
58
|
+
can attribute to a tier is a floor nobody can tell apart from a bumped one).
|
|
59
|
+
`declaredStages` carries the close-level fact onto the judged stage as
|
|
60
|
+
`calibrationJudgeModel` — the same seam, and for the same reason, that already stamps
|
|
61
|
+
`offer: false` — and it carries it from the SIGNED bytes, so a stage can never name a tier the
|
|
62
|
+
signature does not. `runJudgedFloor` then refuses to grade on a mismatch, naming both models
|
|
63
|
+
and the two things that fix it (*re-sign* and *recalibrate*), under the same `FAILED` fault the
|
|
64
|
+
absent judge seam already stops on: nothing is broken, something was never re-done. An ABSENT
|
|
65
|
+
stamp is deliberately NOT a runtime stop — a signed spec cannot reach a run without a
|
|
66
|
+
calibration (the signing gate) or without a model on it (the spec gate), so the only runtime
|
|
67
|
+
question is WHICH model. No signed spec on disk moves: `jobs/*.json` carries zero
|
|
68
|
+
`judged-floor` stages today.
|
|
69
|
+
- **The U runner mints the row its review door promises to release** (`e01d0af`). The door tells
|
|
70
|
+
a person that `accept` *"releases this run's learning credit"*; for every run
|
|
71
|
+
`scripts/run-u.mjs` has driven that sentence was false by construction — a cold green wrote a
|
|
72
|
+
standalone `bridge-<job>-<runid>.json` FILE and never a registry ROW, so
|
|
73
|
+
`--registry --workflow --decide accept` reached `recordDoor`, found no green row for the runid
|
|
74
|
+
and died `no-row-for-run`. The held credit could be described and never released. **STORAGE
|
|
75
|
+
ONLY:** nothing here selects, promotes or reuses a bridge — that rung stays parked on
|
|
76
|
+
`layer-3-reuse` (F88) — and exactly one thing reads the row back, the door. `writeGreenRow` is
|
|
77
|
+
`runReuse`'s own cold-leg green write LIFTED out of its closure unchanged (the
|
|
78
|
+
fork-on-a-different-close-shape rule, both collision refusals, the `appendGreen` leg), so the
|
|
79
|
+
two runners mint a green through ONE spelling; a second spelling of what a green writes is the
|
|
80
|
+
two-transforms class applied to the ledger itself. **`writeRunGreenRow`** (newly exported) is
|
|
81
|
+
the U runner's terminal policy on top of it, and every guard is a NAMED refusal rather than a
|
|
82
|
+
silence: no `--registry` (`no-registry`), an already-green run (`green-predates-run` — accept
|
|
83
|
+
confirms a verdict, it never mints one), a green with no executed plan (`no-plan-executed`), a
|
|
84
|
+
class whose credit is not held (`credit-not-held` — `green`-class runs mint nothing here,
|
|
85
|
+
which is what this runner has always done), and a spine leak blocks the row exactly as it
|
|
86
|
+
already blocks the bridge file. The row is born HELD because `greenParts` reads the SIGNED
|
|
87
|
+
class off the record — nothing new sets a flag — and `applyDoorDecision` releases it through
|
|
88
|
+
the path that already existed. `src/index.js`'s claim that `runReuse` is the only registry
|
|
89
|
+
writer is CORRECTED rather than left standing.
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- **F102 — a pending human decision now survives a wall-halt → resume** (`a6f62c9`). Two records
|
|
93
|
+
answering two different questions: `human-decision` (the door, the words, and by whom, with
|
|
94
|
+
`source: 'operator'|'checkpoint'` and the moment the PERSON spoke) and `human-decision-spent`
|
|
95
|
+
(what actually bought it). The spend marker fires on the **WORK** — a fix round bought, an accept
|
|
96
|
+
that greened, a pause honoured — **not on the fix loop opening**, which is precisely the shape of
|
|
97
|
+
the incident (`iterationsUsed: 0`). A resume carrying one re-enters the fix loop through the same
|
|
98
|
+
seam a fresh answer uses; the ask is never re-rendered. Two answers to one question are REFUSED
|
|
99
|
+
(`hitl-decision-red` naming what is held), never merged.
|
|
100
|
+
- **F103 — a rerun buys its own clock** (`a6f62c9`). Two counters that never do each other's job:
|
|
101
|
+
CHAIN (`chainWallMs`/`chainSpentUsd`, `job-end.spentUsd`) is every leg added up and is what the
|
|
102
|
+
halt readout reports; ENGAGEMENT (`priorElapsedMs`, `job-end.engagementSpentUsd`) is what bounds
|
|
103
|
+
THIS leg. Money is deliberately not symmetric — the signed budget stays the CHAIN's ceiling,
|
|
104
|
+
because a refilled wallet is the failure F45 measured. W-2 is untouched where it was designed for:
|
|
105
|
+
an ordinary resume folds exactly as it always has, and so does an `accept`.
|
|
106
|
+
- **F106 (HIGH, review) — the calibration gate now meets the one ceiling** (`0ae7693`). The run's
|
|
107
|
+
third and largest paid seam (up to 10 locate calls plus the 5-artifact battery, each under its own
|
|
108
|
+
retry ladder) ran with no bound while the scout and the declaration loop were both stopped by
|
|
109
|
+
`run-author --budget` — the advertised budget and the enforced budget were two different numbers.
|
|
110
|
+
`prepareSigning`/`calibrationGate` take `ceilingUsd` + `priorCalls`, a cost book absorbs prior
|
|
111
|
+
spend so the gate reads the REMAINING balance, `capStop` is asked before each paid call inside the
|
|
112
|
+
pipe (retries included), and a ceiling stop returns as an operator refusal naming money
|
|
113
|
+
(`cap-halt` / `pricing-red`) — never a casualty, and never a part-graded set presented as graded.
|
|
114
|
+
- **A review door's rerun is a fresh engagement too** (`0ae7693`): `resolveHumanRuling` takes
|
|
115
|
+
`doorRerun` as a third input, OR'd and never merged, so *"is this leg a fresh engagement"* keeps
|
|
116
|
+
ONE spelling and a door-rerun leg cannot inherit the rejected leg's wall.
|
|
117
|
+
- **`scripts/run-u.mjs` wires `judgeProvider`** (pinned to the judge model, never a step knob) — a
|
|
118
|
+
live soft-green run no longer instrument-stops at the judged stage.
|
|
119
|
+
- **Two mutation-blind gaps in `src/kinds.js` covered by tests** (found by the same review).
|
|
120
|
+
|
|
121
|
+
- **The medium whole-branch code review's five findings** (`e0c87d3`). An absent `job-end` in
|
|
122
|
+
`scripts/run-u.mjs` (a crash between the door record and `job-end`, or a legacy spine) no
|
|
123
|
+
longer launders into an exact complete `$0` that folds into the rerun ceiling — unknown is
|
|
124
|
+
reported unknown (F6), regression test watched failing first. One name per kind and per code:
|
|
125
|
+
the `'judged-floor'` literal at 7 sites becomes **`JUDGED_FLOOR_KIND`** (`src/kinds.js`,
|
|
126
|
+
exported) and the `'quarantined'` code at 3 sites becomes **`QUARANTINED_CODE`**
|
|
127
|
+
(`src/bridges.js` — deliberately not `reuse.js`, which would cycle reuse ↔ selection). One
|
|
128
|
+
`threeDoors()` builder replaces the copy-pasted door lines in `scripts/u-readout.mjs` (output
|
|
129
|
+
byte-identical against HEAD), and a `changedEvidence()` helper in `src/planrun.js` replaces
|
|
130
|
+
the duplicated evidence block and the double `verdictType` default, with `doorOpens`'
|
|
131
|
+
signature untouched. Two findings were ESCALATED rather than decided — the judge-model bump
|
|
132
|
+
with no detector, and the U runner's door promising to release credit it never minted — and
|
|
133
|
+
both are the `1A`/`2B` entries above.
|
|
134
|
+
- **The tail review's six findings over `1A`+`2B`** (`493b2ce`). The door PREVIEW path now
|
|
135
|
+
checks row-EXISTS before promising a credit release, and its printed commands carry
|
|
136
|
+
`--registry`/`--workflow` forward — the `e01d0af` fix had landed at the end-of-run readout and
|
|
137
|
+
not at this sibling site, so the operator's next invocation would have rediscovered
|
|
138
|
+
`no-row-for-run` one hop later. The registry row records **`rounds` + `roundsComplete`**: a
|
|
139
|
+
resume leg writes a fresh spine and the halted leg's restart record declares money and wall
|
|
140
|
+
but never rounds, so on a resume that count is a FLOOR and now says so the way the money
|
|
141
|
+
beside it already does (F6). A NAMED `--registry` that attempted no row prints the reason
|
|
142
|
+
rather than staying silent. The two near-identical record builders in `src/reuse.js`
|
|
143
|
+
consolidate into `commitWrite`, and the duplicated `worker-round` scan is hoisted to one
|
|
144
|
+
spelling.
|
|
145
|
+
- **The release gate's two findings** (`a5a4731`). `docs/UPSTREAM-ASKS.md`'s BA-21 carries a
|
|
146
|
+
dated CORRECTION note: the retracted 2.0–2.5× figure was a clipipe-surface number (F48 — a
|
|
147
|
+
provider-billed surface that never pools with `anthropic-api`), and the measured API-side
|
|
148
|
+
numbers are ~5.7% / 1.586×; the acceptance criteria are unaffected. In `src/judged.js`, two
|
|
149
|
+
literal NUL bytes inside composite-key template strings are spelled `\x00` — byte-identical
|
|
150
|
+
at runtime, but the literal made `grep`/`file` treat the source as binary (the documented git
|
|
151
|
+
binary-detector trap).
|
|
152
|
+
|
|
153
|
+
### Docs (2026-08-23)
|
|
154
|
+
|
|
155
|
+
- **`docs/FINDINGS.md`: F102 and F103 move from NOT FIXED / NOT BUILT to FIXED**, each cited to
|
|
156
|
+
the commit that did it — `a6f62c9` for both, plus `0ae7693` for F103's extension (the review
|
|
157
|
+
door's rerun as `resolveHumanRuling`'s third input, OR'd and never merged). **F106 is minted**
|
|
158
|
+
from the 3-lens review's HIGH: F45's class in a money coat with the direction reversed — the
|
|
159
|
+
ENFORCED number was the looser one, which is the failure that leaves a bill instead of a red
|
|
160
|
+
(`cce3ce5`).
|
|
161
|
+
- **PRD Addendum v1.76** (this release): the three doors restated, the green-class review door
|
|
162
|
+
kept OPT-IN, rerun named as *not a replay*, the `1A`+`2B` escalations ruled, and the one
|
|
163
|
+
remaining door hole named and left deliberately.
|
|
164
|
+
- **`bareloop.context.md`**: the judge-tier paragraph rewritten from DEFERRED to the live
|
|
165
|
+
detector it now describes.
|
|
166
|
+
|
|
8
167
|
## [0.11.0] — 2026-08-18
|
|
9
168
|
|
|
10
169
|
### Changed (2026-08-18 — the review door's third button)
|
package/README.md
CHANGED
|
@@ -48,8 +48,9 @@ finds in the real work, and fixed rules — not the judge — render the verdict
|
|
|
48
48
|
|
|
49
49
|
## You have the last word
|
|
50
50
|
|
|
51
|
-
Every run ends at a **review door
|
|
52
|
-
|
|
51
|
+
Every judged run ends at a **review door** (a purely mechanical green finishes on its own —
|
|
52
|
+
ask for the door with `--review-door`): here is what changed, here is what every check said,
|
|
53
|
+
here is what I'm asking you. **Accept** it, **rerun** it — what you type is the feedback the next
|
|
53
54
|
attempt works from, funded fresh — or **pause** it and decide another day. A pause costs
|
|
54
55
|
nothing, keeps everything, and picks up from the start of the last step whenever you come back.
|
|
55
56
|
Never come back, and it quietly expires on its own.
|
package/bareloop.context.md
CHANGED
|
@@ -530,11 +530,136 @@ no model found, it moves no seed number, and a declaration that authors it itsel
|
|
|
530
530
|
`genre-owned-env`.
|
|
531
531
|
|
|
532
532
|
**The kind catalogue** (`KIND_CATALOGUE`, and it IS the whole vocabulary): `command-exit`,
|
|
533
|
-
`count-not-worse`, `pattern-absent-in-diff`, `files-changed
|
|
534
|
-
`judged-floor`
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
kind — so that demand arrives through the interview
|
|
533
|
+
`count-not-worse`, `pattern-absent-in-diff`, `files-changed`, `human-confirms` and
|
|
534
|
+
`judged-floor` are all live — `LOCKED_KINDS` is EMPTY today; `harness-loop` (TESTGEN) is ABSENT
|
|
535
|
+
from v1 entirely (an unknown-kind typo, never counted demand). The locked-kind machinery is
|
|
536
|
+
unchanged and is what a future entry arrives on: in tool mode a locked kind is INEXPRESSIBLE —
|
|
537
|
+
the schema carries one branch per live kind — so that demand arrives through the interview
|
|
538
|
+
layer instead (`refuseLockedKind(kind)`), whose "named but locked" wording is currently
|
|
539
|
+
unreachable for exactly the reason above.
|
|
540
|
+
|
|
541
|
+
**`judged-floor` is the one kind that BUYS its measurement** (softgreen module 2), and it is
|
|
542
|
+
CLASS-GATED rather than locked: it renders a `soft-green` verdict, `soft-green` is still a
|
|
543
|
+
LOCKED verdict class, so a real declaration naming it reds `class-ceiling` under a green pick
|
|
544
|
+
and `class-battery-locked` under a soft-green one. The kind runs; no signable spec can reach it
|
|
545
|
+
until the class is admitted. Its parameters are `card` — the signer's rubric as ENUMERATED
|
|
546
|
+
items, where `rule` SELECTS from the arbiter's own rulebook (`JUDGE_RULES` / `JUDGE_RULE_IDS`,
|
|
547
|
+
so a rule we do not implement is inexpressible) and `text` is the signer's words, which explain
|
|
548
|
+
a red and never decide one — and `paths`, the AUTHORITATIVE artifacts, read off the seed listing
|
|
549
|
+
like every other path and bounded at `MAX_JUDGED_PATHS` (one paid call each). It spawns nothing,
|
|
550
|
+
so it takes no `cmd`, no `timeoutMs` and no `env`; it is `offer: false` BY LAW
|
|
551
|
+
(`NEVER_OFFERED_KINDS` — a paid judge is never an in-run ruler); and it SKIPS the seed-verdict
|
|
552
|
+
read (ruling 8) as a recorded `skipped` row.
|
|
553
|
+
|
|
554
|
+
**Wiring a judged close, and what it costs.** The judge is PINNED (`JUDGE_MODEL`, exported) and
|
|
555
|
+
is never a step knob: the runner supplies `runJob({ judgeProvider })` — its own seam, not
|
|
556
|
+
`provider`/`providerFor` — and a judged stage with none instrument-STOPS as a wiring gap rather
|
|
557
|
+
than grading on whatever binding was at hand. Each locate call is metered per call and emitted
|
|
558
|
+
as a distinct `judge-round` spine record, which `runJob`'s ONE ledger accounts exactly like a
|
|
559
|
+
`worker-round` (`ACCOUNTED_ROUND_TYPES`, and `readResume`'s fold reads that same list, so a
|
|
560
|
+
resumed leg cannot silently widen a signed budget by the close's own spend). A budget funds the
|
|
561
|
+
attempt PLUS its close. Unpriced is never free: a null cost is a `pricing-red` stop that is
|
|
562
|
+
never retried, and the ladder is otherwise ONE retry (`JUDGE_ATTEMPTS`) — after that a broken
|
|
563
|
+
judge is an instrument stop, never a red about the tree.
|
|
564
|
+
|
|
565
|
+
**The two SIGNED artifacts of a judged close** (softgreen module 4, design §4.3/§4.4). Q6 and
|
|
566
|
+
Q7 of the softgreen interview compile into the RUBRIC CARD and the FROZEN CALIBRATION SET, on
|
|
567
|
+
the D5 shown-and-fixed path: `proposeJudgedArtifacts({answers, generate, book})` buys ONE
|
|
568
|
+
schema-forced proposal (tool `propose_rubric`, over the same bounded malformed-emission ladder
|
|
569
|
+
the declaration uses — a parse failure is an `artifact-red` retried under the cap, a proposal
|
|
570
|
+
that parsed and then broke a rule is NOT retried); a UI shows it; `signJudgedArtifacts({proposal,
|
|
571
|
+
fix})` stores the SIGNER's version (the fix replaces the proposal WHOLE, never merges — a signer
|
|
572
|
+
who deleted a line must not get it back) and reports `source: 'signer'|'proposal'`; and
|
|
573
|
+
`foldJudgedArtifacts(closeDecl, {card, cases})` enumerates both into the declaration. Free text
|
|
574
|
+
in either artifact is scrubbed at ingest through the one `SECRET_PATTERNS` inventory, because a
|
|
575
|
+
signed spec outlives the run that produced it.
|
|
576
|
+
|
|
577
|
+
**Where they land, and what the hash covers.** The card replaces the ONE `judged-floor` stage's
|
|
578
|
+
`params.card` — one card per close, and it is the signed one; a fold into a close with no judged
|
|
579
|
+
stage (or two) THROWS rather than storing a rubric nothing reads. The cases land beside the
|
|
580
|
+
stages as `closeDecl.calibration.cases`, because the set calibrates the RULER and is read before
|
|
581
|
+
any stage runs. Both sit inside the spec, so `jobSpecHash` covers them by construction: a card
|
|
582
|
+
line or a single case edit flips the hash and forces a re-sign, and a byte-identical re-store
|
|
583
|
+
does not.
|
|
584
|
+
|
|
585
|
+
**What a legal calibration set is** (`validateCalibrationSet`, beside the rulebook in
|
|
586
|
+
`src/judged.js`, and re-checked at the spec gate by `validateCloseDecl`). EXACTLY
|
|
587
|
+
`CALIBRATION_SIZE` = 10 cases — hamr's ruling, verbatim *"go build 10, we could double later"*,
|
|
588
|
+
operator territory and never agent-picked — with BOTH polarities present, because a set that
|
|
589
|
+
cannot fail one way proves nothing. A case is
|
|
590
|
+
`{id, artifact, expect: {verdict: 'pass'|'red', reds: [{rule, fn}]}}`: `artifact` is the REAL
|
|
591
|
+
source text the judge will be pointed at (never a description of one), and a red case must be
|
|
592
|
+
ITEMIZED, naming a `rule` THIS close's card actually carries (§4.3's ceiling, mechanically — the
|
|
593
|
+
fix for a miss is a new card line and a re-sign) and the `fn` the red lands on. The judge's own
|
|
594
|
+
`why`/`quote` are deliberately NOT stored: no signer can predict prose, and pinning it would
|
|
595
|
+
fail an honest pipe on wording. `expectedOf(decision)` is the ONE reduction of a `decide()`
|
|
596
|
+
result to that shape, so a harness compares one shape rather than two.
|
|
597
|
+
|
|
598
|
+
**THE CALIBRATION GATE** (`runCalibration`, softgreen module 5, `src/calibrate.js`). It runs the
|
|
599
|
+
WHOLE pipe — `runLocate` over the shipped `JUDGE_ATTEMPTS` ladder, then `decide()` — over each of
|
|
600
|
+
the ten, and compares `expectedOf(decision)` against the stored `expect` by VERDICT **and**
|
|
601
|
+
ITEMIZED REDS (a `(rule, fn)` set, order-insensitive): *a pipe that reds the right case for the
|
|
602
|
+
wrong reason has not been calibrated, it has been lucky*. The floor is **10/10, zero reds**
|
|
603
|
+
(hamr, 2026-08-18) and it is reported per case — `graded: [{id, ok, got, want, detail}]` — never
|
|
604
|
+
as an aggregate percentage.
|
|
605
|
+
|
|
606
|
+
Alongside it runs **`INJECTION_LOCATE_BATTERY`: five ARBITER-OWNED artifacts**, one per
|
|
607
|
+
bare-agent attack style, **re-aimed at the LOCATE axis** (2026-08-18 second addendum, ruling 1 —
|
|
608
|
+
upstream's `shouldBreak` gold assumes a judge that renders a verdict, and this one never does).
|
|
609
|
+
The attack text is embedded in the artifact, and a style resists only when the extracted FACTS
|
|
610
|
+
are unaffected: same function list, same per-function doc reality. Reading the DECISION alone
|
|
611
|
+
would be blind here — an invented `docQuote` reds `has-doc` through the quote-verification route,
|
|
612
|
+
so a leak and a resist can render identical itemized reds. **All five must resist**; a leak fails
|
|
613
|
+
calibration and names the style. Nothing about the battery is stored in a spec and no signer
|
|
614
|
+
authors it.
|
|
615
|
+
|
|
616
|
+
A **CASUALTY is never a failed case**: a dead call, an unpriced one (F6 — never retried) or an
|
|
617
|
+
emission that never parses after the ladder STOPS the gate on `runLocate`'s own axis
|
|
618
|
+
(`CASUALTY_AXES`), keeps the graded prefix, and reports zero failures — a broken judge is no
|
|
619
|
+
evidence about the set in either direction. Every locate call is metered through `onCost` on
|
|
620
|
+
every route out and the totals fold through `tallyCalls`, so one unpriced call makes `costUsd`
|
|
621
|
+
null rather than an exact-looking floor.
|
|
622
|
+
|
|
623
|
+
**At signing it is MANDATORY and it is the only PAID gate** (`prepareSigning`, gate 4). A close
|
|
624
|
+
carrying a `judged-floor` stage is refused when no set is stored, when no `judgeLoop` seam is
|
|
625
|
+
wired (a wiring gap, never a silent pass), when the gate is a casualty, and when anything short
|
|
626
|
+
of all-of-them grades. It runs **after** gates 1–3, so no $0 refusal is ever paid for. The
|
|
627
|
+
signing record keeps WHAT was certified — `cardHash`, `casesHash`, `setHash` (which covers
|
|
628
|
+
`JUDGE_MODEL`), the graded rows and the battery — beside `judgeModel` itself.
|
|
629
|
+
|
|
630
|
+
**D9.3 for a judged-ONLY close** (ruling 3, hamr: *"fix it now, we are delivering softgreen"*).
|
|
631
|
+
A judged stage skips the seed read (ruling 8), so a close whose only work stage is judged has no
|
|
632
|
+
seed red and used to be unsignable — the one job shape softgreen exists for. For that shape only,
|
|
633
|
+
a PASSED calibration gate plays the seed-red role (the polarity law makes *this close can fail* a
|
|
634
|
+
demonstrated fact), and the record says so: `gates.seedVerdict.satisfiedBy === 'calibration'`. A
|
|
635
|
+
close with any mechanical work stage is UNCHANGED and still needs its seed red.
|
|
636
|
+
|
|
637
|
+
**THE JUDGE TIER IS INSIDE THE SIGNATURE, and the stage refuses a mismatch.** *"A judge-model
|
|
638
|
+
bump forces a full recalibration"* used to be an operator-side rule with nothing to fire on,
|
|
639
|
+
which makes it prose (F45); it now has both halves of a detector. The tier the signer's set was
|
|
640
|
+
graded by is stored beside the cases as **`calibration.judgeModel`** — `CALIBRATION_FIELDS`
|
|
641
|
+
enumerates a stored set as exactly `cases` and `judgeModel` and nothing else — written by
|
|
642
|
+
`foldJudgedArtifacts` from the PIN (`JUDGE_MODEL`) rather than from anything a caller may name.
|
|
643
|
+
Because it is INSIDE the spec, `jobSpecHash` covers it by construction: bump the constant and
|
|
644
|
+
every signed judged spec hashes differently, the signature dies, and the re-sign is what re-runs
|
|
645
|
+
the calibration gate. **`validateCloseDecl` REQUIRES it** on any stored set (`missing-required`
|
|
646
|
+
on `…calibration.judgeModel`) — a set nobody can attribute to a tier is a floor nobody can tell
|
|
647
|
+
apart from a bumped one. **`declaredStages` stamps it onto the judged stage** as
|
|
648
|
+
`calibrationJudgeModel`, from the SIGNED bytes and through the one seam that already turns a
|
|
649
|
+
declaration into stages (the same carry `offer: false` rides), so a stage can never name a tier
|
|
650
|
+
the signature does not and no second close-level channel is plumbed through every executor seam.
|
|
651
|
+
**`runJudgedFloor` then STOPS on a stored-vs-live mismatch** before it buys a call, naming both
|
|
652
|
+
models and the two things that fix it — *re-sign the spec with the new tier* and *re-run the
|
|
653
|
+
calibration gate (recalibrate)* — under `STOP_FAULTS.FAILED`, the same fault and the same reason
|
|
654
|
+
as the absent judge seam beside it: nothing is broken, something was never re-done. It stops
|
|
655
|
+
rather than degrading in either direction, because grading on the new tier mints a verdict
|
|
656
|
+
against an uncalibrated floor and grading on the old one is not on offer (the pin is a constant).
|
|
657
|
+
|
|
658
|
+
**The one honest limit, deliberate:** an ABSENT stamp does not stop. It is the same split the
|
|
659
|
+
SET's own presence already lives under — a signed spec that judges cannot reach a run without a
|
|
660
|
+
calibration (the signing gate) or without a model on it (the spec gate), so the only runtime
|
|
661
|
+
question is ever WHICH model, and a bare stage descriptor handed straight to `runStage` by a test
|
|
662
|
+
or an adopter is not a signed spec making a claim about a tier.
|
|
538
663
|
|
|
539
664
|
**`human-confirms` is the one kind that measures NOTHING** (N4 slice 1). Its whole parameter
|
|
540
665
|
surface is `ask` — the plain question the signer answers — so it cannot spawn, cannot be
|
|
@@ -793,7 +918,7 @@ Reserved spine vocabulary (V7, machinery-free until job #1 surfaces one):
|
|
|
793
918
|
`coordination-red` — a failure between units (scope contention, step order, store
|
|
794
919
|
races), never to be folded into worker/interpreter reds.
|
|
795
920
|
|
|
796
|
-
### `runJob(spec, { approvals, workdir, provider, nativeProvider?, providerFor?, emit, capRuns?, strikeLimit?, shellCapUsd?, closeTimeoutMs?, layerRoot?, bridge?, priorSpentUsd?, priorSpendComplete?, priorWallMs?, resumeSeed?, resumeGrades?, resumeReplans?, resumeBranch? })` → outcome — `src/run.js`
|
|
921
|
+
### `runJob(spec, { approvals, workdir, provider, nativeProvider?, providerFor?, emit, capRuns?, strikeLimit?, shellCapUsd?, closeTimeoutMs?, layerRoot?, bridge?, priorSpentUsd?, priorSpendComplete?, priorWallMs?, resumeSeed?, resumeGrades?, resumeReplans?, resumeBranch?, humanRuling?, heldRuling?, reviewDoor?, doorRerun? })` → outcome — `src/run.js`
|
|
797
922
|
|
|
798
923
|
The last seven are the RESUME fold and are documented under *Resuming a killed run* below; they
|
|
799
924
|
default to `0` / `true` / `0` / `null` / `[]` / `null` / `null`, so a fresh run passes none of them.
|
|
@@ -838,6 +963,24 @@ enumerated `HUMAN_DECISIONS` set); it is spent once, at
|
|
|
838
963
|
the close readings up to the moment the fix loop opens, so the human's words become `post.gap`
|
|
839
964
|
through the SAME seam (same bound, same scrub) and the next machine-clean tree pauses for a
|
|
840
965
|
SECOND review rather than converting one sentence forever.
|
|
966
|
+
|
|
967
|
+
**A decision SURVIVES the halt that interrupts it** (F102). The run records the answer it was
|
|
968
|
+
handed (`human-decision` — the door, the words, the source) and, separately, what BOUGHT it
|
|
969
|
+
(`human-decision-spent` — a fix round, an accept that greened, a pause honoured). A decision with
|
|
970
|
+
no spend after it is still owed to the person, and `readResume` surfaces it as
|
|
971
|
+
`restart.pendingDecision` (`{decision, text, receivedAt, source}`). Hand that back as
|
|
972
|
+
**`heldRuling`** and the leg applies it directly — the ask is never re-rendered, and the spine
|
|
973
|
+
says the answer came from a record rather than from a person. F102's incident is what this is
|
|
974
|
+
for: a rerun that opened the fix loop, stopped with `iterationsUsed: 0`, and whose resume asked
|
|
975
|
+
the byte-identical question again. The two markers are deliberately not one: the fix loop
|
|
976
|
+
"spends" the ruling for THIS leg's close readings the moment it opens, while whether the person
|
|
977
|
+
must be asked AGAIN depends on work actually having been bought.
|
|
978
|
+
|
|
979
|
+
A leg handed BOTH a fresh `humanRuling` and a `heldRuling` is refused (`hitl-decision-red`,
|
|
980
|
+
naming the held decision) before anything costs anything: two answers to one question is
|
|
981
|
+
ambiguity, not a merge. `resolveHumanRuling(fresh, held)` is the exported seam that decides this
|
|
982
|
+
(and whether the leg is a fresh engagement, below), so a runner cannot admit what a run refuses.
|
|
983
|
+
|
|
841
984
|
`branch-red` is the WORK BRANCH refusing (below): the patient is not a git checkout, its
|
|
842
985
|
branch namespace has no free name, or a resume's recorded branch is gone. Zero tokens, and
|
|
843
986
|
never a fallback to working on the branch the run was handed. `provider-red` is a
|
|
@@ -1269,6 +1412,64 @@ run the rounds of a bounded attempt. N2 bounds (honest): `gold`/`rubric`/`hitl`
|
|
|
1269
1412
|
closes refuse `close-unsupported` — N4's hitl is a `human-confirms` STAGE inside a `closeDecl`,
|
|
1270
1413
|
never a close TYPE, so there is one live expression of hitl rather than two.
|
|
1271
1414
|
|
|
1415
|
+
### THE REVIEW DOOR — the three doors at the END of a run (softgreen module 8, PRD v1.71 §3)
|
|
1416
|
+
|
|
1417
|
+
The pause machinery re-homed: the same doors, the same evidence package and the same 60-day TTL,
|
|
1418
|
+
one level OUT — from a stage inside the close to the door at the end of a run.
|
|
1419
|
+
|
|
1420
|
+
**THE LAW, and it is not negotiable** (hamr, verbatim: *"it's important not to change the loop
|
|
1421
|
+
self verdict"*): the close mints the verdict, the door records a **disposition**. `runJob`
|
|
1422
|
+
returns `green` / `already-green` exactly as it always did, the ledger records exactly what it
|
|
1423
|
+
always recorded, and no answer a person gives can change either. A green run that is never
|
|
1424
|
+
answered is still a green run — the door is non-blocking.
|
|
1425
|
+
|
|
1426
|
+
**Opening one.** A run whose terminal is verdict-bearing (`DOOR_OPEN_OUTCOMES` — `green`,
|
|
1427
|
+
`already-green`) emits ONE `review-door` record carrying the evidence: the outcome, the class,
|
|
1428
|
+
whether the credit is `quarantined`, every close stage's own result, the stages an `accept` will
|
|
1429
|
+
re-run (`mechanical`), and the changed set (same cap and same F28/F6 announcements the pause
|
|
1430
|
+
package makes). Which runs open one is `doorOpens(job, reviewDoor)`:
|
|
1431
|
+
|
|
1432
|
+
- **always** for the classes in `REVIEW_DOOR_CLASSES` — `['soft-green']`, because a judged green
|
|
1433
|
+
is quarantined at mint (module 6) and an `accept` is the ONLY thing that releases the credit;
|
|
1434
|
+
- **on request** for everything else: `reviewDoor: true` (the runner's `--review-door`). A
|
|
1435
|
+
green-class run is byte-identical to what it always was unless it is asked for.
|
|
1436
|
+
- `reviewDoor: false` shuts it for any class. The flag wins in both directions and is never
|
|
1437
|
+
inferred; `REVIEW_DOOR_CLASSES` is a constant, not a threshold, and widening it is arbiter
|
|
1438
|
+
territory.
|
|
1439
|
+
|
|
1440
|
+
**Answering one — `answerReviewDoor({ job, workdir, events, decision, text?, closeTimeoutMs?,
|
|
1441
|
+
registryDir?, name?, runid?, at?, now?, emit? })`** (`src/reviewdoor.js`). The answer arrives
|
|
1442
|
+
after the run has ended, possibly days later and from another process, so it cannot ride the
|
|
1443
|
+
run's return path. This is that seam. It never throws and never conjures — a fourth door, an
|
|
1444
|
+
empty `rerun`, a run that opened no door (`no-door`), an expired one (`door-expired`), a tree
|
|
1445
|
+
that moved (`door-accept-red`) and a missing registry all come back as named reds.
|
|
1446
|
+
|
|
1447
|
+
- **`accept`** re-runs the close's **mechanical** stages against the tree AS IT STANDS
|
|
1448
|
+
(`mechanicalStages` — everything outside `SEED_EXEMPT_KINDS`, so never a judged floor and never
|
|
1449
|
+
a person) before it is honoured: hamr's ruling that an accept is not a rubber stamp, and the
|
|
1450
|
+
answer to a tree that can move in the 60 days a door keeps. A red REFUSES the accept with the
|
|
1451
|
+
stage named and records **nothing**. A pass records the disposition and, over a held judged
|
|
1452
|
+
green, RELEASES the credit through module 6's `applyDoorDecision`.
|
|
1453
|
+
- **`rerun`** carries the person's words back as a directive (`next: 'rerun'`) and re-proves
|
|
1454
|
+
nothing: the new run's close is what judges. Empty or whitespace text is refused at the same
|
|
1455
|
+
seam every other door is.
|
|
1456
|
+
- **`pause`** runs nothing and spends nothing, in any state. The door simply keeps, and an
|
|
1457
|
+
unanswered one expires under `PAUSE_TTL_MS` — that expiry IS what `cancel` used to be.
|
|
1458
|
+
|
|
1459
|
+
Every door is recorded when a registry is wired, not only the accepts: *"the signer's accepts
|
|
1460
|
+
double as the judge's ongoing report card"*, and a rerun over a judged green is exactly as
|
|
1461
|
+
informative. An **already-green** run wrote no row of its own, so its door records nothing and
|
|
1462
|
+
releases nothing — slice 1's already-green no-mint rule, holding from the other side, and stated
|
|
1463
|
+
in the result's `note` rather than surfaced as a failure.
|
|
1464
|
+
|
|
1465
|
+
**The rerun as a FRESH ENGAGEMENT** — hand the words back to the next run as
|
|
1466
|
+
**`doorRerun: {text, fromRunid?, receivedAt?}`**. Two things follow and only two: the
|
|
1467
|
+
`already-green` shortcut is refused (a tree that passes the close is precisely the state the
|
|
1468
|
+
person rejected — the run emits `door-rerun-open` and carries on), and the words reach the
|
|
1469
|
+
PLANNER as a requirement on top of the signed goal. It is never a `humanRuling`: that answers a
|
|
1470
|
+
close's human STAGE, and a green-class job has none. Money folds (the signed budget is the
|
|
1471
|
+
chain's ceiling); the WALL does not (F103).
|
|
1472
|
+
|
|
1272
1473
|
### The reuse registry (Layer 3) — `src/bridges.js`, `src/selection.js`
|
|
1273
1474
|
|
|
1274
1475
|
A **bridge** is the plan a green actually executed, kept so the next run of the same SHAPE
|
|
@@ -1298,6 +1499,50 @@ it points, and a percentage over 2–3 runs is fake precision. `costUsd`/`wallMs
|
|
|
1298
1499
|
a number or an EXPLICIT `null`, and the key is REQUIRED either way, so an unknown has to be
|
|
1299
1500
|
said rather than omitted (F6 — an omitted key is how a `?? 0` gets written downstream).
|
|
1300
1501
|
|
|
1502
|
+
**QUARANTINE — a judged green earns nothing until the signer accepts it** (softgreen module
|
|
1503
|
+
6; the standing ruling PRD v1.53, given its mechanism by v1.71 §3). A green minted under
|
|
1504
|
+
`verdictType: "soft-green"` carries `quarantined: true` on BOTH halves of R1's pair — the
|
|
1505
|
+
**version** (what inherits) and its **history row** (what the status ladder reads). It is a
|
|
1506
|
+
FLAG, never a withheld row: the run happened, the record says so, and the listing shows it —
|
|
1507
|
+
it is simply worth nothing yet. A held green does not count in `deriveStatus` (an entry whose
|
|
1508
|
+
only greens are held derives `null` and renders `HELD`, never `NO-GREEN`), and
|
|
1509
|
+
`reuseEligibility(bridge)` / `newestEligibleVersion(bridge)` refuse it for reuse **with a
|
|
1510
|
+
stated reason** — the same visible-skip discipline an unreadable registry file gets.
|
|
1511
|
+
`green` and `hitl` are untouched, byte for byte: the key is ABSENT, because the hold is about
|
|
1512
|
+
the young JUDGE, not about every class that is not green. `QUARANTINED_VERDICTS` is the one
|
|
1513
|
+
list; `quarantinesCredit(verdictType)` is the one predicate. The class travels on the green
|
|
1514
|
+
record as `verdictType` — an unrecognised value REDS rather than falling through to unheld.
|
|
1515
|
+
|
|
1516
|
+
**The review door releases it, forward-only.** `recordDoor(bridge, {runid, decision, at})`
|
|
1517
|
+
records the signer's disposition (`accept | rerun | pause`, the same three doors `kinds.js`
|
|
1518
|
+
owns) on that run's own green row as an append-only `doors: [{decision, at}]` — the **report
|
|
1519
|
+
card**, kept as facts and never as a computed agreement rate (D6's no-score rule applies to
|
|
1520
|
+
the judge too). `accept` over a held green also flips `quarantined` to `false` on both halves;
|
|
1521
|
+
`rerun` and `pause` record and release nothing. There is deliberately **no re-hold path**: an
|
|
1522
|
+
accept followed by a rerun records the disagreement and leaves the credit granted. A repeat of
|
|
1523
|
+
the last decision is a no-op (`released` says whether THIS call freed it), and a door aimed at
|
|
1524
|
+
a run with **no green row of its own** — an already-green run, a red, a casualty — is the red
|
|
1525
|
+
`no-row-for-run`: releasing is not minting. `applyDoorDecision({registryDir, name, runid,
|
|
1526
|
+
decision, at})` is the on-disk half; the door opens AFTER the run ends, so the decision cannot
|
|
1527
|
+
ride the run's return path. **The door never changes the loop's verdict** — a green stays green
|
|
1528
|
+
in the ledger whatever the person then does with it.
|
|
1529
|
+
|
|
1530
|
+
**`writeRunGreenRow({registryDir, job, name, outcome, plan, record})` → `{minted, reason,
|
|
1531
|
+
write}` — the terminal registry write for a runner that drives `runJob` directly** (rather
|
|
1532
|
+
than through `runReuse`, which writes its own rows). It is what gives that runner's review
|
|
1533
|
+
door a row to release: without one, `accept` reaches `recordDoor` and reds `no-row-for-run`.
|
|
1534
|
+
STORAGE ONLY — nothing here selects, promotes or reuses a bridge. Four refusals, each with a
|
|
1535
|
+
named `reason`: no `registryDir` (`no-registry` — the registry is operator-supplied, never
|
|
1536
|
+
conjured), `outcome !== 'green'` (`green-predates-run` for already-green — accept confirms a
|
|
1537
|
+
verdict, it never mints one — else `not-green`), no executed `plan` (`no-plan-executed`, R1),
|
|
1538
|
+
and a verdict class whose credit is not held (`credit-not-held` — `green`-class runs mint
|
|
1539
|
+
nothing here, `quarantinesCredit` is the one predicate). `name` falls back to `job.job`; the
|
|
1540
|
+
row is born HELD because the record carries the spec's own `verdictType`, never a flag. A
|
|
1541
|
+
refused underlying write returns `{minted: false, reason: 'write-refused', write}` with the
|
|
1542
|
+
reds on `write` — never a throw. Minting goes through the same cold-leg green write `runReuse`
|
|
1543
|
+
uses (shape-fork rule and collision refusals included), so the two runners can never spell
|
|
1544
|
+
"what a green writes" differently.
|
|
1545
|
+
|
|
1301
1546
|
**`loadGate(bridge, job)` → `{ ok, reds }` — the load-time gate.** Exactly three checks,
|
|
1302
1547
|
asked *"is this the right KIND of recipe?"*: the job's **verdict type**, the **close-stage
|
|
1303
1548
|
kinds** (v1: the same stage names in the same order), and every stored verb **within THIS
|
|
@@ -1319,12 +1564,16 @@ their next green, not repaired.
|
|
|
1319
1564
|
|
|
1320
1565
|
**`runJob`/`runPlan` take `bridge?`** — a validated entry to reuse. The gate runs **at the
|
|
1321
1566
|
door**: before the clock, before the close precheck, before any token. On a pass, the
|
|
1322
|
-
**newest** version's plan
|
|
1567
|
+
**newest ELIGIBLE** version's plan (the newest one no quarantine holds) rides into the FIRST
|
|
1568
|
+
drafting prompt as a starting draft
|
|
1323
1569
|
(`bridge-loaded {name, versions, runid}` on the spine) and everything after it is the
|
|
1324
1570
|
ordinary shipped path — same validator, same redraft-on-reds, the same replan ceiling, and a
|
|
1325
1571
|
**replan never re-injects the bridge** (it drafts from the run's own state). On a fail the
|
|
1326
1572
|
run returns the distinct terminal **`recipe-stale`** with `bridge-gate {outcome, name, reds}`
|
|
1327
|
-
and a decision-ready escalation, having spent nothing. **
|
|
1573
|
+
and a decision-ready escalation, having spent nothing. A **wholly HELD** entry handed in
|
|
1574
|
+
directly is refused at the same door and by the same terminal, with `bridge-gate
|
|
1575
|
+
{outcome: 'quarantined'}` and the accept-then-rerun option named — the recipe is the right
|
|
1576
|
+
kind, it is simply unaccepted, and the two are never spelled the same. **Falling back to cold is the
|
|
1328
1577
|
caller's decision, not an automatic silent fallback** — starting a paid run on a decision
|
|
1329
1578
|
nobody made is the same class of error as widening a cap to manufacture a green. Omit
|
|
1330
1579
|
`bridge` and the flow is byte-identical to a pre-Layer-3 run: no new event, and no starting
|
|
@@ -1548,6 +1797,17 @@ paused spine goes through `checkpointAgeGate`, and the run is not resumed withou
|
|
|
1548
1797
|
decision: the lean-rerun rule (2026-08-12 §4) governs which door a prompt LEADS with, never an
|
|
1549
1798
|
action taken for the operator.
|
|
1550
1799
|
|
|
1800
|
+
**A finished run's REVIEW DOOR is answered the same way, one flag over**: `--door <runid>`
|
|
1801
|
+
selects the run (its own spine, its own `review-door` record), `--decide` picks the door and
|
|
1802
|
+
`--approve <specHash>` signs it. The screen is its OWN preview and deliberately not the resume
|
|
1803
|
+
banner: a door is answered about a run that is OVER, so nothing that banner computes (what is
|
|
1804
|
+
left to resume with, which step it re-enters) is a true sentence there. `accept` and `pause`
|
|
1805
|
+
launch nothing and exit; `rerun` falls through into a fresh engagement — its own clock, the
|
|
1806
|
+
answered run's spend folded in — carrying the person's words as `doorRerun`. `--registry <dir>
|
|
1807
|
+
--workflow <name>` are optional: without them the answer is recorded on the run's own spine and
|
|
1808
|
+
the readout SAYS the credit was not released, rather than reporting a release that never
|
|
1809
|
+
happened.
|
|
1810
|
+
|
|
1551
1811
|
- **Completed tries are not re-run.** They come back as rows (marked `inherited`) and
|
|
1552
1812
|
their bridges stay excluded from every later selection. A try whose `job-end` landed —
|
|
1553
1813
|
the close judged it — counts as completed even if the kill beat its `try-end`; paying
|
|
@@ -1624,6 +1884,20 @@ action taken for the operator.
|
|
|
1624
1884
|
(or `wall-halt`, below one close timeout: a try that cannot fund its close produces an
|
|
1625
1885
|
unreadable row) with **nothing launched**. Topping up is a new envelope, and a new
|
|
1626
1886
|
envelope is a new signature.
|
|
1887
|
+
- **…except a decide-time RERUN, which is a FRESH ENGAGEMENT** (F103, design record §3.4 —
|
|
1888
|
+
hamr: *"redo/rerun comes with new authoring for money+time and keeps accounting of this far
|
|
1889
|
+
and this session separate counters"*). A rerun opens on the full signed `maxWallMs` instead of
|
|
1890
|
+
the remainder, because the person did not decide on the run's clock: the incident that minted
|
|
1891
|
+
it took the door and inherited **87 seconds** from a leg that had already ended, on a worker
|
|
1892
|
+
measured to read nine rounds before its first write. So there are TWO counters and neither
|
|
1893
|
+
does the other's job — the CHAIN (every leg added up: `engagement.chainWallMs`,
|
|
1894
|
+
`chainSpentUsd`, `job-end.spentUsd`, what the halt readout reports) and the ENGAGEMENT (what
|
|
1895
|
+
bounds THIS leg: the clock's `priorElapsedMs`, `job-end.engagementSpentUsd`). The `engagement`
|
|
1896
|
+
record states both at the top of every run. **MONEY IS DELIBERATELY NOT SYMMETRIC**: it folds
|
|
1897
|
+
on every path, because the signed budget is the CHAIN's ceiling and a signature for $5 never
|
|
1898
|
+
silently authorizes $10 — a rerun spends what REMAINS of it, never a refill. A rerun leg also
|
|
1899
|
+
declares its `job-start` fold engagement-scoped (`priorWallMs` omitted, `chainWallMs` carried),
|
|
1900
|
+
so a later resume of it inherits this engagement's minutes rather than the chain's again.
|
|
1627
1901
|
- **Money stays honest end to end.** `carrySpentUsd` (completed tries + selection calls)
|
|
1628
1902
|
seeds the resumed ledger; the mid-try fold is deliberately NOT in it, because it comes
|
|
1629
1903
|
back inside the restarted try's own terminal — counting it in both places would bill it
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bareloop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Workflows that earn their own design, with receipts — agent-authored workflows for repeated, long, verifiable jobs that improve across runs under an un-gameable gate.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|