bareloop 0.11.0 → 0.13.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,8 +73,21 @@ 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';
64
- export { classifyIncidents, foldLedger, ledgerDeltas, updateLedger, LEDGER_CLASSES } from './ledger.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';
85
+ // BA-21 pricing provenance rides out with the ledger because it is the same job: reading
86
+ // a run's own spend record honestly. `rateProvenance`/`spendProvenance` answer "how much of
87
+ // this was priced by a rate nobody vouched for" — REPORTING ONLY, no halt, no refusal.
88
+ // Exported because an adopter enforcing a budget against these numbers is entitled to know
89
+ // which of them are guesses (see bareloop.context.md, "Every cost figure … is an ESTIMATE").
90
+ export { classifyIncidents, foldLedger, ledgerDeltas, updateLedger, LEDGER_CLASSES, VOUCHED_RATE_SOURCES, rateProvenance, spendProvenance } from './ledger.js';
65
91
  // THE WORK BRANCH (PRD v1.57 §3). `workBranchName` is exported so an operator runner can
66
92
  // SHOW, before the approval gate, which branch the run will work on — the same reason the
67
93
  // resolved per-try hash is printed there: a bound the human is agreeing to should not be
@@ -70,6 +96,16 @@ export { classifyIncidents, foldLedger, ledgerDeltas, updateLedger, LEDGER_CLASS
70
96
  // still there before spending anything. The runner applies the rule itself either way —
71
97
  // neither export is a way to opt out of it.
72
98
  export { workBranchName, prepareWorkBranch, WORK_BRANCH_PREFIX, WORK_BRANCH_RE } from './workbranch.js';
99
+ // THE READ SHIM (arm-gated, OFF by default via `runJob`'s `readShim`). The cap is exported
100
+ // because bareloop.context.md names it, and documented-but-unexported is a false contract;
101
+ // the wrapper goes with it so a caller building its own worker seam wraps the SAME ledger
102
+ // rather than reimplementing the one rule that matters (a pointer keys on what was
103
+ // DELIVERED, never on path+hash).
104
+ //
105
+ // `readShimArm` is exported for the same reason the cap is: a battery driver has to be able
106
+ // to name and check the arm it is about to run BEFORE it launches, and the legal set living
107
+ // only inside a runner would leave the driver guessing at spellings the guard will reject.
108
+ export { createReadShim, wrapReadTool, readShimArm, readShimStrategy, READ_SHIM_CAP, READ_SHIM_STRATEGY, READ_SHIM_DIFF_STRATEGY, READ_SHIM_ARMS } from './readshim.js';
73
109
  // ── CLOSE AUTHORING v1 (gate 4) — the user declares what done means ──────────
74
110
  // The public surface is settled ONCE, here, at M4 (M2's header flagged the
75
111
  // naming collision and deferred it rather than exporting piecemeal).
@@ -92,8 +128,63 @@ export {
92
128
  // N4 slice 1 — the hitl surface an adopting runner needs: the three doors, the
93
129
  // gate that reads a signer's answer (and refuses an empty one), and the seed
94
130
  // exemption ruling 8 states.
95
- HUMAN_DECISIONS, SEED_EXEMPT_KINDS, normalizeHumanRuling,
131
+ HUMAN_DECISIONS, SEED_EXEMPT_KINDS, JUDGED_FLOOR_KIND, normalizeHumanRuling, resolveHumanRuling,
132
+ // SOFTGREEN module 2 — the judged stage's own arbiter-owned bounds. An adopter
133
+ // wiring `judgeProvider` needs both numbers to reason about what a judged close
134
+ // can cost: one paid call per artifact, at most one retry each.
135
+ JUDGE_ATTEMPTS, MAX_JUDGED_PATHS,
136
+ // SOFTGREEN module 8 — the REVIEW DOOR's vocabulary: the record type a run
137
+ // writes when it ends at the door, which terminals open one, which classes open
138
+ // one unasked, and the mechanical-only rule an `accept` re-proves against.
139
+ REVIEW_DOOR, DOOR_OPEN_OUTCOMES, REVIEW_DOOR_CLASSES, doorOpens, mechanicalStages,
96
140
  } from './kinds.js';
141
+ // SOFTGREEN module 8 — the door's ANSWERING half. A run OPENS the door on its own
142
+ // spine and ends; a person answers minutes or days later, from another process, so
143
+ // the answer cannot ride the run's return path. `answerReviewDoor` is that seam:
144
+ // it re-proves the tree for an `accept`, releases a held judged green through
145
+ // module 6's registry half, and refuses an expired door under the same 60-day TTL a
146
+ // hitl checkpoint keeps. It never returns, writes or implies a verdict.
147
+ export { answerReviewDoor, doorRecordOf, doorAgeGate } from './reviewdoor.js';
148
+ // SOFTGREEN module 1 — the judged floor's core. The pieces an adopter (and an
149
+ // integrating UI) genuinely needs: the PIN (`JUDGE_MODEL` — what a wired judge
150
+ // provider must be bound to, and a bump of which forces recalibration), the
151
+ // rulebook a card SELECTS from, the card gate, and the two halves themselves so a
152
+ // calibration harness can grade the whole pipe without running a close.
153
+ // `defaultJudgeLoop` is the one spelling of how this repo drives a judge; the
154
+ // runner reaches it through `runPlan`'s `judgeProvider`, and it is exported so a
155
+ // caller building its own harness does not spell a second one.
156
+ export {
157
+ JUDGE_MODEL, JUDGE_MAX_TOKENS, JUDGE_RULES, JUDGE_RULE_IDS, LOCATE_AXES, LOCATE_LABEL,
158
+ validateCard, validateFacts, locatePrompt, runLocate, decide, defaultJudgeLoop,
159
+ // SOFTGREEN module 4 — what a legal SIGNED calibration set is. The SIZE is
160
+ // hamr's own ruling and a size change is a spec-level threshold change;
161
+ // `expectedOf` is the ONE reduction of a `decide()` result to the shape a case
162
+ // stores, so a calibration harness compares one shape rather than two.
163
+ CALIBRATION_SIZE, CASE_VERDICTS, validateCalibrationSet, validateJudgedArtifacts, expectedOf,
164
+ } from './judged.js';
165
+ // SOFTGREEN module 4 — the COMPILE. Q6 becomes the rubric card and Q7 becomes the
166
+ // frozen calibration set, both on the D5 shown-and-fixed path: the LLM proposes
167
+ // through `proposeJudgedArtifacts`, an integrating UI shows the proposal, the
168
+ // SIGNER's fix goes through `signJudgedArtifacts`, and `foldJudgedArtifacts`
169
+ // enumerates both into the closeDecl — where the spec hash covers them, so a card
170
+ // line or a case is a re-sign like every other spec edit.
171
+ export {
172
+ proposeJudgedArtifacts, signJudgedArtifacts, foldJudgedArtifacts,
173
+ proposalSchema, proposalTool, cardCasesPrompt,
174
+ PROPOSAL_TOOL_NAME, PROPOSAL_LABEL, MAX_PROPOSAL_RETRIES, COMPILE_SYSTEM,
175
+ } from './cardauthor.js';
176
+ // SOFTGREEN module 5 — THE CALIBRATION GATE. `runCalibration` grades the whole
177
+ // pipe (locate + decide) over the signed ten and the five arbiter-owned injection
178
+ // artifacts; `prepareSigning` runs it and refuses on anything short of all of
179
+ // them. Exported because an integrating UI has to be able to RUN and RENDER the
180
+ // gate — the graded rows are what a signer reads before giving a signature — and
181
+ // because the battery is evidence a reader may want to inspect rather than take
182
+ // on trust. `INJECTION_LOCATE_BATTERY` and `INJECTION_CARD` are ARBITER-OWNED
183
+ // constants: no signer authors them and nothing stores them in a spec.
184
+ export {
185
+ runCalibration, compareExpectation, factsResist, artifactHash,
186
+ INJECTION_LOCATE_BATTERY, INJECTION_CARD, CALIBRATION_LABEL, CASUALTY_AXES,
187
+ } from './calibrate.js';
97
188
  // M2 — what a declaration may SAY, and whether one said it legally. The
98
189
  // catalogue and the genre are DATA an integrating UI renders (the kind menu, the
99
190
  // guard batteries it must show the user under D5 and cannot let them remove).
@@ -106,7 +197,7 @@ export {
106
197
  DIRECTIONS, BASELINES, MAX_STAGES,
107
198
  // the verdict-class surface (PRD v1.57 §1–§2): the radio's own menu, the guard
108
199
  // battery keyed off it, and the ceiling that makes the pick a promise
109
- VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, closeCeiling,
200
+ VERDICT_CLASSES, LOCKED_CLASSES, LIVE_CLASSES, CLASS_BATTERIES, classGuards, classMenu, closeCeiling,
110
201
  // ruling 5 as data: the kinds no agent may ever be offered as an in-run ruler
111
202
  NEVER_OFFERED_KINDS,
112
203
  } from './authoring.js';
@@ -125,7 +216,7 @@ export {
125
216
  export { scrubRaw, RAW_PERSIST_MAX, RAW_TRIM_MARKER } from './text.js';
126
217
  export {
127
218
  authorClose, authorPrompt, declarationSchema, makeLoopGenerate, MAX_REVISIONS,
128
- QUESTION_SETS, GREEN_QUESTIONS, CLASS_STATEMENTS, questionsFor, requiredAnswersFor,
219
+ QUESTION_SETS, GREEN_QUESTIONS, SOFTGREEN_QUESTIONS, CLASS_STATEMENTS, questionsFor, requiredAnswersFor,
129
220
  } from './authorflow.js';
130
221
  // M4a — the runtime bridge. `validateCloseDecl` is the spec-level gate (the job
131
222
  // 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`);