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/src/index.js CHANGED
@@ -31,23 +31,36 @@ export { validateJob, jobSpecHash, checkApproval, checkMenu, CLOSE_TYPES, CLASS_
31
31
  export { validatePlan, stageClose, EXIT_TYPES, MAX_EXITS_PER_STEP, MAX_PLAN_STEPS, WRITE_VERBS } from './plan.js';
32
32
  export { snapshotScope, evalExits } from './exits.js';
33
33
  export { runPlan } from './planrun.js';
34
- export { runJob } from './run.js';
34
+ // `ACCOUNTED_ROUND_TYPES` rides with it: the round records the ONE ledger sums.
35
+ // A runner reconstructing a killed run's spend (the resume fold) must add exactly
36
+ // these and nothing else, and a second hand-kept list is how a paid call comes to
37
+ // be free (`judge-round` — the close's own spend — joined at softgreen module 2).
38
+ export { runJob, ACCOUNTED_ROUND_TYPES } from './run.js';
35
39
  // Layer 3 — the REUSE registry (bridge-v1) and D3's display half. The registry is a
36
40
  // directory of plain files at an OPERATOR-supplied path (never a default location), the
37
41
  // load gate is the code half of D2's split, and `renderListing`/`selectionPrompt` are
38
42
  // pure text: they send nothing, parse nothing and decide nothing. The selection CALL and
39
43
  // the pin/shortlist/force-cold flow are the adopter's, which is why the pieces they need
40
44
  // are exported rather than kept internal to the runner.
45
+ //
46
+ // Softgreen module 6 exports the QUARANTINE surface with them: a judged green is minted
47
+ // HELD and earns nothing until the signer's `accept` at the review door releases it
48
+ // (PRD v1.71 §3). `recordDoor` is the pure half (record the disposition, release
49
+ // forward-only) and `reuseEligibility`/`newestEligibleVersion` are what every consumer
50
+ // asks before starting from a stored plan.
41
51
  export {
42
52
  BRIDGE_SCHEMA, validateBridge, deriveStatus, listingRow, loadGate,
43
53
  mintBridge, appendGreen, appendRed,
44
54
  loadBridge, loadRegistry, saveBridge, makeRegistry, registryExists,
55
+ QUARANTINED_VERDICTS, QUARANTINED_CODE, quarantinesCredit, newestEligibleVersion, reuseEligibility, recordDoor,
45
56
  } from './bridges.js';
46
57
  export { renderListing, selectionPrompt } from './selection.js';
47
58
  // Layer 3 modules 4+5 — the D7 envelope and the reuse runner. `runReuse` composes
48
- // `runJob` under an operator-signed envelope (three explicit numbers, tighten-only) and
49
- // is the only thing in the library that WRITES the registry — minting is a graded
50
- // green's privilege (R1), never a caller's. `validateEnvelope`/`resolveTrySpec` are
59
+ // `runJob` under an operator-signed envelope (three explicit numbers, tighten-only). It
60
+ // is not the only registry WRITER any more (2B: `writeRunGreenRow`), but the rule it
61
+ // enforced is unchanged and now lives in both — minting is a graded green's privilege
62
+ // (R1), never a caller's: both writers go through `writeGreenRow`, and neither can mint
63
+ // a row for anything but a green that this run actually earned. `validateEnvelope`/`resolveTrySpec` are
51
64
  // exported because an operator runner has to show the resolved per-try spec's HASH at
52
65
  // its approval gate: a tightened envelope is a new spec version, and the human signs it.
53
66
  // `resolveReuse`/`reuseSpecHash` are the pair that gate must actually PRINT: the try
@@ -60,7 +73,15 @@ export { renderListing, selectionPrompt } from './selection.js';
60
73
  // `resumeTreeGate` is the ruling that a resumed patient is continued dirty and never
61
74
  // reset. Both are read by a runner BEFORE the approval gate, so neither can live behind
62
75
  // `runReuse`'s own entry.
63
- export { validateEnvelope, resolveTrySpec, resolveReuse, reuseSpecHash, selectBridge, runReuse, REUSE_GRADED_RED, readResume, resumeTreeGate, CHECKPOINT_OUTCOMES, PAUSE_TTL_MS, checkpointAgeGate } from './reuse.js';
76
+ // `applyDoorDecision` is the registry half of the REVIEW DOOR (softgreen module 6): the
77
+ // door opens AFTER a run has ended, so a person's answer cannot ride the run's own return
78
+ // path — the runner calls this with the runid it printed at the door.
79
+ // `writeRunGreenRow` is that door's other half (2B), and it is exported for the same
80
+ // reason: a runner that drives `runJob` directly rather than through `runReuse` still ends
81
+ // at a review door, and a door with no row to act on can only describe a held learning
82
+ // credit it has no way to release. STORAGE ONLY — nothing here selects, promotes or reuses
83
+ // a bridge; those stay parked on `layer-3-reuse`.
84
+ export { validateEnvelope, resolveTrySpec, resolveReuse, reuseSpecHash, selectBridge, runReuse, REUSE_GRADED_RED, readResume, resumeTreeGate, CHECKPOINT_OUTCOMES, PAUSE_TTL_MS, checkpointAgeGate, applyDoorDecision, writeRunGreenRow } from './reuse.js';
64
85
  export { classifyIncidents, foldLedger, ledgerDeltas, updateLedger, LEDGER_CLASSES } from './ledger.js';
65
86
  // THE WORK BRANCH (PRD v1.57 §3). `workBranchName` is exported so an operator runner can
66
87
  // SHOW, before the approval gate, which branch the run will work on — the same reason the
@@ -92,8 +113,63 @@ export {
92
113
  // N4 slice 1 — the hitl surface an adopting runner needs: the three doors, the
93
114
  // gate that reads a signer's answer (and refuses an empty one), and the seed
94
115
  // exemption ruling 8 states.
95
- HUMAN_DECISIONS, SEED_EXEMPT_KINDS, normalizeHumanRuling,
116
+ HUMAN_DECISIONS, SEED_EXEMPT_KINDS, JUDGED_FLOOR_KIND, normalizeHumanRuling, resolveHumanRuling,
117
+ // SOFTGREEN module 2 — the judged stage's own arbiter-owned bounds. An adopter
118
+ // wiring `judgeProvider` needs both numbers to reason about what a judged close
119
+ // can cost: one paid call per artifact, at most one retry each.
120
+ JUDGE_ATTEMPTS, MAX_JUDGED_PATHS,
121
+ // SOFTGREEN module 8 — the REVIEW DOOR's vocabulary: the record type a run
122
+ // writes when it ends at the door, which terminals open one, which classes open
123
+ // one unasked, and the mechanical-only rule an `accept` re-proves against.
124
+ REVIEW_DOOR, DOOR_OPEN_OUTCOMES, REVIEW_DOOR_CLASSES, doorOpens, mechanicalStages,
96
125
  } from './kinds.js';
126
+ // SOFTGREEN module 8 — the door's ANSWERING half. A run OPENS the door on its own
127
+ // spine and ends; a person answers minutes or days later, from another process, so
128
+ // the answer cannot ride the run's return path. `answerReviewDoor` is that seam:
129
+ // it re-proves the tree for an `accept`, releases a held judged green through
130
+ // module 6's registry half, and refuses an expired door under the same 60-day TTL a
131
+ // hitl checkpoint keeps. It never returns, writes or implies a verdict.
132
+ export { answerReviewDoor, doorRecordOf, doorAgeGate } from './reviewdoor.js';
133
+ // SOFTGREEN module 1 — the judged floor's core. The pieces an adopter (and an
134
+ // integrating UI) genuinely needs: the PIN (`JUDGE_MODEL` — what a wired judge
135
+ // provider must be bound to, and a bump of which forces recalibration), the
136
+ // rulebook a card SELECTS from, the card gate, and the two halves themselves so a
137
+ // calibration harness can grade the whole pipe without running a close.
138
+ // `defaultJudgeLoop` is the one spelling of how this repo drives a judge; the
139
+ // runner reaches it through `runPlan`'s `judgeProvider`, and it is exported so a
140
+ // caller building its own harness does not spell a second one.
141
+ export {
142
+ JUDGE_MODEL, JUDGE_MAX_TOKENS, JUDGE_RULES, JUDGE_RULE_IDS, LOCATE_AXES, LOCATE_LABEL,
143
+ validateCard, validateFacts, locatePrompt, runLocate, decide, defaultJudgeLoop,
144
+ // SOFTGREEN module 4 — what a legal SIGNED calibration set is. The SIZE is
145
+ // hamr's own ruling and a size change is a spec-level threshold change;
146
+ // `expectedOf` is the ONE reduction of a `decide()` result to the shape a case
147
+ // stores, so a calibration harness compares one shape rather than two.
148
+ CALIBRATION_SIZE, CASE_VERDICTS, validateCalibrationSet, validateJudgedArtifacts, expectedOf,
149
+ } from './judged.js';
150
+ // SOFTGREEN module 4 — the COMPILE. Q6 becomes the rubric card and Q7 becomes the
151
+ // frozen calibration set, both on the D5 shown-and-fixed path: the LLM proposes
152
+ // through `proposeJudgedArtifacts`, an integrating UI shows the proposal, the
153
+ // SIGNER's fix goes through `signJudgedArtifacts`, and `foldJudgedArtifacts`
154
+ // enumerates both into the closeDecl — where the spec hash covers them, so a card
155
+ // line or a case is a re-sign like every other spec edit.
156
+ export {
157
+ proposeJudgedArtifacts, signJudgedArtifacts, foldJudgedArtifacts,
158
+ proposalSchema, proposalTool, cardCasesPrompt,
159
+ PROPOSAL_TOOL_NAME, PROPOSAL_LABEL, MAX_PROPOSAL_RETRIES, COMPILE_SYSTEM,
160
+ } from './cardauthor.js';
161
+ // SOFTGREEN module 5 — THE CALIBRATION GATE. `runCalibration` grades the whole
162
+ // pipe (locate + decide) over the signed ten and the five arbiter-owned injection
163
+ // artifacts; `prepareSigning` runs it and refuses on anything short of all of
164
+ // them. Exported because an integrating UI has to be able to RUN and RENDER the
165
+ // gate — the graded rows are what a signer reads before giving a signature — and
166
+ // because the battery is evidence a reader may want to inspect rather than take
167
+ // on trust. `INJECTION_LOCATE_BATTERY` and `INJECTION_CARD` are ARBITER-OWNED
168
+ // constants: no signer authors them and nothing stores them in a spec.
169
+ export {
170
+ runCalibration, compareExpectation, factsResist, artifactHash,
171
+ INJECTION_LOCATE_BATTERY, INJECTION_CARD, CALIBRATION_LABEL, CASUALTY_AXES,
172
+ } from './calibrate.js';
97
173
  // M2 — what a declaration may SAY, and whether one said it legally. The
98
174
  // catalogue and the genre are DATA an integrating UI renders (the kind menu, the
99
175
  // guard batteries it must show the user under D5 and cannot let them remove).
@@ -106,7 +182,7 @@ export {
106
182
  DIRECTIONS, BASELINES, MAX_STAGES,
107
183
  // the verdict-class surface (PRD v1.57 §1–§2): the radio's own menu, the guard
108
184
  // battery keyed off it, and the ceiling that makes the pick a promise
109
- VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, closeCeiling,
185
+ VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, classMenu, closeCeiling,
110
186
  // ruling 5 as data: the kinds no agent may ever be offered as an in-run ruler
111
187
  NEVER_OFFERED_KINDS,
112
188
  } from './authoring.js';
@@ -125,7 +201,7 @@ export {
125
201
  export { scrubRaw, RAW_PERSIST_MAX, RAW_TRIM_MARKER } from './text.js';
126
202
  export {
127
203
  authorClose, authorPrompt, declarationSchema, makeLoopGenerate, MAX_REVISIONS,
128
- QUESTION_SETS, GREEN_QUESTIONS, CLASS_STATEMENTS, questionsFor, requiredAnswersFor,
204
+ QUESTION_SETS, GREEN_QUESTIONS, SOFTGREEN_QUESTIONS, CLASS_STATEMENTS, questionsFor, requiredAnswersFor,
129
205
  } from './authorflow.js';
130
206
  // M4a — the runtime bridge. `validateCloseDecl` is the spec-level gate (the job
131
207
  // validator's own branch calls it); `runDeclaredStages` is the executor seam a
package/src/job.js CHANGED
@@ -98,17 +98,30 @@ export const MIN_WALL_MS = 120_000;
98
98
  * counts admission demand, and a generic invalid-value would bury it as a typo. */
99
99
  export const LOCKED_TOOLS = Object.freeze(['run']);
100
100
  /** Layer 2 (design record 2026-07-21, decision 5): the verdict-type radio of
101
- * the four-field plan shape. v1 ADMITS only `green`; soft-green/hitl are
102
- * declared-but-locked — declaring one is a `request-red` (the tool-menu
103
- * pattern: disclosure ≠ admission), so the ledger counts the demand and the
104
- * non-code rung later fills a declared slot instead of reshaping the schema. */
101
+ * the four-field plan shape. All three are ADMITTED as of softgreen module 3;
102
+ * the declared-but-locked mechanism below (`LOCKED_VERDICTS`) is what carried
103
+ * them here one rung at a time — declaring a locked one is a `request-red` (the
104
+ * tool-menu pattern: disclosure ≠ admission), so the ledger counted the demand
105
+ * instead of the schema being reshaped when the rung finally landed. */
105
106
  export const VERDICT_TYPES = Object.freeze(['green', 'soft-green', 'hitl']);
106
- /** N4 slice 1: `hitl` is ADMITTED — the class whose *done* needs a person runs
107
- * through the same signed spec, the same agent-authored plan and the same
108
- * arbiter as a green job (the nine rulings, 2026-08-07; the three-button surface,
109
- * 2026-08-12). `soft-green` stays declared-but-locked until its judged floor is
110
- * built and proven (slice 2): a wobbly ruler must not mint anything. */
111
- export const LOCKED_VERDICTS = Object.freeze(['soft-green']);
107
+ /** N4 slice 1 admitted `hitl`; softgreen module 3 admits `soft-green`, and the
108
+ * menu is now EMPTY — every class the radio names is built.
109
+ *
110
+ * `soft-green`'s lock was never a policy, it was a missing floor: a judged
111
+ * verdict with no ruler mints nothing honestly. Modules 1 and 2 built the ruler
112
+ * (a pinned judge that only LOCATES, an arbiter-owned `decide()`, a calibration
113
+ * gate) and wired it as the `judged-floor` kind, so the lock has nothing left to
114
+ * protect (design record 2026-08-17 §4, and the 2026-08-18 thresholds addendum).
115
+ *
116
+ * EMPTY here means "nothing is locked", which is a TRUE statement about a closed
117
+ * menu — not F59's absent-read-as-empty, where a `{}` stood in for a fact nobody
118
+ * gathered. The mechanism below stays exactly as it is: it is read at call time
119
+ * from this constant, so re-locking a class (or admitting a fourth) is one edit
120
+ * and the counted `request-red` path comes back with it. `LOCKED_CLASSES` in
121
+ * src/authoring.js is the twin and moved in the same commit; the suite pins the
122
+ * two identical. */
123
+ /** @type {readonly string[]} */
124
+ export const LOCKED_VERDICTS = Object.freeze([]);
112
125
  /** which close CLASS a declared verdictType demands — the close hierarchy one
113
126
  * level up: the same laundering guard as CLASS_BY_CLOSE, applied to the plan
114
127
  * shape's single close (green on a rubric would be a fake-hard verdict). */
@@ -520,8 +533,9 @@ function validateStagedClose(stages, red) {
520
533
  * stages instead (PRD v1.28/v1.32), and a spec that still declares it gets the
521
534
  * `checks-derived` red below rather than a bare unknown-field.
522
535
  *
523
- * v1 admits only verdictType `green`; soft-green/hitl are declared-but-locked
524
- * and red as `request-red` — admission demand the ledger counts, never a grant.
536
+ * Every verdictType the radio names is admitted (softgreen module 3); a class
537
+ * that were locked reds as `request-red` — admission demand the ledger counts,
538
+ * never a grant.
525
539
  * The close is validated one level up as well: a declared verdict demands a
526
540
  * close CLASS, so green-on-rubric reds as `close-hierarchy` rather than
527
541
  * laundering a soft judgement into a hard one.
@@ -541,7 +555,7 @@ function validatePlanShape(spec, red, reds) {
541
555
  // the type rides as a structured field — the ledger keys admission demand
542
556
  // on it, never on prose. `lib: 'bareloop'`: the refused catalogue is OURS
543
557
  // (VERDICT_TYPES), so this demand is never an upstream ask.
544
- reds.push({ code: 'request-red', path: 'verdictType', verb: spec.verdictType, lib: 'bareloop', detail: `"${spec.verdictType}" is declared-but-locked — not at this rung (v1 admits green only); this red IS the admission evidence, never a grant` });
558
+ reds.push({ code: 'request-red', path: 'verdictType', verb: spec.verdictType, lib: 'bareloop', detail: `"${spec.verdictType}" is declared-but-locked — not at this rung (admitted: ${VERDICT_TYPES.filter((v) => !LOCKED_VERDICTS.includes(v)).join(', ')}); this red IS the admission evidence, never a grant` });
545
559
  demanded = CLASS_BY_VERDICT[spec.verdictType];
546
560
  } else if (!VERDICT_TYPES.includes(spec.verdictType)) {
547
561
  red('invalid-value', 'verdictType', `menu: ${VERDICT_TYPES.join('|')} — an unknown type is a typo, never a request`);