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.
@@ -9,10 +9,11 @@
9
9
  * `CLASS_BY_VERDICT` exist to stop, defeated from ABOVE by never letting the
10
10
  * illegal pair be formed.
11
11
  *
12
- * INERT IN v1 BY CONSTRUCTION, which is why it is cheap now: every LIVE kind is
13
- * mechanical, so no declaration a v1 catalogue can express reaches above green.
14
- * It is written before the second class exists so the first soft-green kind is
15
- * not the thing that discovers the question.
12
+ * NO LONGER INERT: `human-confirms` (N4 slice 1) and `judged-floor` (softgreen
13
+ * module 2) are both live and both above green, so a green declaration naming
14
+ * one is a real red rather than a hypothetical. `classMenu` below is the other
15
+ * half of the same rule, applied one step earlier — the composer is never handed
16
+ * a kind this would refuse.
16
17
  *
17
18
  * A kind the catalogue does not know contributes NOTHING — it already carries an
18
19
  * `unknown-kind` red, and guessing a class for it would be deriving the promise
@@ -28,6 +29,31 @@ export function closeCeiling(declaration: any, catalogue?: Record<string, KindSp
28
29
  stage: string | null;
29
30
  locked: boolean;
30
31
  } | null;
32
+ /**
33
+ * THE MENU A JOB OF THIS CLASS MAY EXPRESS — the ceiling rule, moved one step
34
+ * EARLIER, to the moment the composer is handed its vocabulary.
35
+ *
36
+ * `closeCeiling` refuses an above-ceiling kind AFTER a paid call has composed a
37
+ * declaration around it. That is a late red for an illegal pick the composer was
38
+ * shown in its own catalogue and its own tool schema — and the standing rule is
39
+ * the opposite: wherever only a closed set can satisfy a field, hand over the
40
+ * enumerated set, so the illegal value is INEXPRESSIBLE rather than rejected
41
+ * after the fact (the `check-passes(name)` model). A green job is therefore never
42
+ * shown `judged-floor` or `human-confirms` at all.
43
+ *
44
+ * ONLY THE MENU NARROWS. The VALIDATOR keeps the whole catalogue, deliberately:
45
+ * a model that names a kind it was never offered must be told which RULE it
46
+ * broke (`class-ceiling`), not that the kind does not exist (`unknown-kind`) —
47
+ * one is the truth and the other invites it to invent a spelling.
48
+ *
49
+ * `null` means UNFILTERED and exists for callers inspecting the catalogue itself
50
+ * (the schema/coverage suite). Every composing call site passes the user's own
51
+ * picked class; `authorPrompt` already throws without one.
52
+ * @param {string|null} verdictType
53
+ * @param {Record<string, KindSpec>} [catalogue]
54
+ * @returns {string[]} kind names at or below the picked class, in catalogue order
55
+ */
56
+ export function classMenu(verdictType: string | null, catalogue?: Record<string, KindSpec>): string[];
31
57
  /**
32
58
  * Which kinds can carry an environment at all, read off the CATALOGUE rather
33
59
  * than a hand-kept list. ONE spelling, because two consumers must agree
@@ -291,8 +317,14 @@ export function normalizeDeclaration(declaration: any): any;
291
317
  /** the whole menu, in ascending order of what it takes to render the verdict */
292
318
  export const VERDICT_CLASSES: readonly string[];
293
319
  /** declared-but-locked: selecting one is COUNTED demand, never an admission.
294
- * `hitl` LEFT this list at N4 slice 1 (see `src/job.js`'s twin) — the class is
295
- * built, and its battery is below. `soft-green` waits for the judged floor. */
320
+ * `hitl` LEFT this list at N4 slice 1 and `soft-green` at softgreen module 3
321
+ * (see `src/job.js`'s twin, `LOCKED_VERDICTS`, which moved in the same commit) —
322
+ * the judged floor its lock was waiting on is built, wired and calibrated.
323
+ *
324
+ * EMPTY is a true statement about a closed menu, not F59's absent-as-empty: the
325
+ * mechanism is read at call time from this constant, so re-locking a class is
326
+ * one edit and every counted refusal comes back with it. */
327
+ /** @type {readonly string[]} */
296
328
  export const LOCKED_CLASSES: readonly string[];
297
329
  /** the classes v1 actually builds */
298
330
  export const LIVE_CLASSES: readonly string[];
@@ -530,8 +562,22 @@ export const CLASS_BATTERIES: Readonly<{
530
562
  }>)[];
531
563
  }>;
532
564
  'soft-green': Readonly<{
533
- locked: true;
534
- guards: null;
565
+ locked: false;
566
+ guards: readonly (Readonly<{
567
+ name: "changed-from-seed";
568
+ kind: "files-changed";
569
+ params: Readonly<{
570
+ requireNonEmpty: true;
571
+ }>;
572
+ compose: readonly never[];
573
+ fill: readonly string[];
574
+ }> | Readonly<{
575
+ name: "no-suppressions";
576
+ kind: "pattern-absent-in-diff";
577
+ params: Readonly<{}>;
578
+ compose: readonly string[];
579
+ fill: readonly never[];
580
+ }>)[];
535
581
  }>;
536
582
  hitl: Readonly<{
537
583
  locked: false;
@@ -85,12 +85,13 @@ export function refuseLockedKind(kind: string): Refusal;
85
85
  * onPhase?: (phase: string, data?: any) => void,
86
86
  * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
87
87
  * seedFn?: Function, scoutFn?: Function, listingFn?: Function,
88
- * authorFn?: Function, authorOpts?: object}} o
88
+ * authorFn?: Function, authorOpts?: object,
89
+ * signerFix?: Function|any, proposeFn?: Function, compileOpts?: object}} o
89
90
  * @returns {Promise<{ok: boolean, refusal: Refusal|null, verdictType: string|null,
90
- * closeDecl: any, seedRef: string|null, authoring: any, reds: Red[], stop: string|null,
91
- * cost: any, interview: any}>}
91
+ * closeDecl: any, seedRef: string|null, authoring: any, judged: any, reds: Red[],
92
+ * stop: string|null, cost: any, interview: any}>}
92
93
  */
93
- export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, }: {
94
+ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, }: {
94
95
  answers: Record<string | number, any>;
95
96
  repoPath?: string | null;
96
97
  lang: string;
@@ -113,6 +114,9 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
113
114
  listingFn?: Function;
114
115
  authorFn?: Function;
115
116
  authorOpts?: object;
117
+ signerFix?: Function | any;
118
+ proposeFn?: Function;
119
+ compileOpts?: object;
116
120
  }): Promise<{
117
121
  ok: boolean;
118
122
  refusal: Refusal | null;
@@ -120,6 +124,7 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
120
124
  closeDecl: any;
121
125
  seedRef: string | null;
122
126
  authoring: any;
127
+ judged: any;
123
128
  reds: Red[];
124
129
  stop: string | null;
125
130
  cost: any;
@@ -171,6 +176,24 @@ export function assembleSpec(specDraft: any, { closeDecl, verdictType }: {
171
176
  * A close with NO work stage red at seed has nothing to do and is refused
172
177
  * decision-ready — gate-2 round 2's arm B died exactly there, on a mypy that
173
178
  * scanned nothing and therefore read clean.
179
+ * 4. THE CALIBRATION GATE (softgreen module 5) — for a close carrying a
180
+ * `judged-floor` stage ONLY. The whole judged pipe runs over the signed ten
181
+ * and the five arbiter-owned injection artifacts, and anything short of
182
+ * 10/10 with itemized reds and 5/5 resisted is an unsignable close. It is
183
+ * the ONE gate here that spends money, so it runs LAST — every free refusal
184
+ * has already had its chance, and nobody pays to discover a broken
185
+ * declaration.
186
+ *
187
+ * D9.3 AND THE JUDGED-ONLY CLOSE (2026-08-18 second addendum, ruling 3; hamr:
188
+ * *"fix it now, we are delivering softgreen, isn't that the whole point?"*). Gate
189
+ * 3 protects against a close that cannot fail — one that scans nothing and reads
190
+ * green at seed against a true red. A judged stage SKIPS the seed read by ruling
191
+ * 8, so a close whose only work stage is judged has no seed red to show and used
192
+ * to be unsignable: the one job shape softgreen exists for. For that shape, and
193
+ * ONLY that shape, a PASSED calibration gate plays the seed-red role — it is that
194
+ * close's own proof of failability, held to the same all-or-nothing bar. A close
195
+ * with a mechanical work stage is UNCHANGED: it still needs a seed red, whatever
196
+ * its calibration says.
174
197
  *
175
198
  * Gates 2 and 3 share ONE execution, and that is stated rather than hidden: at
176
199
  * job creation the tree IS the seed, so "does every stage run against the real
@@ -183,11 +206,13 @@ export function assembleSpec(specDraft: any, { closeDecl, verdictType }: {
183
206
  * comes back is the resolved spec, its hash, and the evidence to sign against.
184
207
  *
185
208
  * @param {{spec: any, workdir: string, seedRef?: string|null, shellCapUsd?: number,
186
- * timeoutMs?: number, seedFn?: Function, listingFn?: Function, seedReadFn?: Function}} o
209
+ * timeoutMs?: number, seedFn?: Function, listingFn?: Function, seedReadFn?: Function,
210
+ * judgeLoop?: Function|null, onJudgeCost?: ((c: any) => void)|null, calibrateFn?: Function,
211
+ * ceilingUsd?: number|null, priorCalls?: any[]}} o
187
212
  * @returns {Promise<{ok: boolean, specHash: string|null, seedRef: string|null,
188
213
  * gates: any, work: any[], guards: any[], stops: any[], reds: Red[], refusal: Refusal|null}>}
189
214
  */
190
- export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs, seedFn, listingFn, seedReadFn, }: {
215
+ export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs, seedFn, listingFn, seedReadFn, judgeLoop, onJudgeCost, calibrateFn, ceilingUsd, priorCalls, }: {
191
216
  spec: any;
192
217
  workdir: string;
193
218
  seedRef?: string | null;
@@ -196,6 +221,11 @@ export function prepareSigning({ spec, workdir, seedRef, shellCapUsd, timeoutMs,
196
221
  seedFn?: Function;
197
222
  listingFn?: Function;
198
223
  seedReadFn?: Function;
224
+ judgeLoop?: Function | null;
225
+ onJudgeCost?: ((c: any) => void) | null;
226
+ calibrateFn?: Function;
227
+ ceilingUsd?: number | null;
228
+ priorCalls?: any[];
199
229
  }): Promise<{
200
230
  ok: boolean;
201
231
  specHash: string | null;
@@ -1,3 +1,8 @@
1
+ /** does a green under this verdict class earn its learning credit at the close, or
2
+ * does it wait for a person? Absent/unknown means green's behaviour, byte for byte
3
+ * — the pre-softgreen path is the default and stays untouched.
4
+ * @param {unknown} verdictType @returns {boolean} */
5
+ export function quarantinesCredit(verdictType: unknown): boolean;
1
6
  /**
2
7
  * D6's status ladder, walked in history order. Pure, total, and never throws —
3
8
  * it is called on whatever a file happens to contain.
@@ -13,6 +18,10 @@
13
18
  * the entry on the first repeat green.
14
19
  * - a red on a CANDIDATE changes nothing: there is nothing below the entry bar, and
15
20
  * the entry stays in the record with the red beside it.
21
+ * - a **QUARANTINED green is not evidence** (softgreen module 6). The row exists and
22
+ * the run happened, but a judged green earns nothing until the signer's `accept`
23
+ * releases it, so it neither clears the entry bar nor adds a distinct patient. An
24
+ * entry whose only greens are held derives `null` — below the bar, not demoted.
16
25
  * - a **CASUALTY is not a red.** Only the literal outcome `'red'` demotes; every
17
26
  * other non-green outcome (`provider-red`, `wall-halt`, `close-crashed`, …) is a
18
27
  * casualty, and casualties are never evidence in either direction.
@@ -74,6 +83,68 @@ export function appendRed(bridge: unknown, record: unknown): {
74
83
  reds: Red[];
75
84
  bridge: any;
76
85
  };
86
+ /**
87
+ * The version that would INHERIT — the newest one whose credit has actually been
88
+ * released. `versions` is oldest-first, so this is normally the last of them; it
89
+ * differs only when a judged green sits on top of a released one, and in that case
90
+ * the RELEASED plan is what a reuse starts from. A held version is not a worse
91
+ * recipe, it is an unjudged one: nobody has said yet whether the ruler that passed
92
+ * it was right, and starting the next run from it would spend the credit before it
93
+ * was granted.
94
+ *
95
+ * Total and never throws — it is read at selection time and at the load door.
96
+ * @param {unknown} bridge
97
+ * @returns {any|null} null when every version is held (or there are none)
98
+ */
99
+ export function newestEligibleVersion(bridge: unknown): any | null;
100
+ /**
101
+ * May this workflow be offered for reuse at all? A held entry is SKIPPED WITH A
102
+ * REASON everywhere it is skipped — the same visible-skip discipline an unreadable
103
+ * registry file already gets, because a shelf that quietly shrinks teaches the
104
+ * operator that the registry is empty when it is merely holding.
105
+ * @param {unknown} bridge
106
+ * @returns {{ok: boolean, reason: string}} `reason` is '' when ok
107
+ */
108
+ export function reuseEligibility(bridge: unknown): {
109
+ ok: boolean;
110
+ reason: string;
111
+ };
112
+ /**
113
+ * THE REVIEW DOOR, written down (PRD v1.71 §3). The person read the finished run
114
+ * and said one of three things; this records that on the run's own row, and — for
115
+ * `accept` on a HELD green — releases the learning credit that green has been
116
+ * carrying unspent.
117
+ *
118
+ * Three properties, and each is a ruling rather than a convenience:
119
+ *
120
+ * - **the door never changes the loop's verdict.** A green row stays a green row,
121
+ * whatever the person then does with it. `rerun` and `pause` are dispositions,
122
+ * recorded and nothing more; a rerun's own outcome is a NEW run's row.
123
+ * - **release is FORWARD-ONLY.** Nothing here can set `quarantined` back to true,
124
+ * so a signer who accepts and later reruns has recorded a disagreement — which
125
+ * is a datum worth keeping — without un-granting credit already granted. There
126
+ * is deliberately no re-hold path at all: it would be a way to walk the ledger
127
+ * backwards, which the ruling forbids.
128
+ * - **releasing is not minting.** A door aimed at a run with no green row of its
129
+ * own is a named red — never an invented entry. That is slice 1's already-green
130
+ * rule holding from the other side: `accept` confirms a verdict, it never
131
+ * creates one.
132
+ *
133
+ * Idempotent by shape: a decision identical to the last one recorded is a no-op
134
+ * that returns the entry unchanged, so a double-click at the door cannot inflate
135
+ * the report card (and `released` says whether THIS call was the one that freed it).
136
+ *
137
+ * Pure — returns a NEW entry; the input is never mutated.
138
+ * @param {unknown} bridge a validated bridge entry
139
+ * @param {unknown} door `{ runid, decision, at }` — `at` may be an explicit null
140
+ * @returns {{ ok: boolean, reds: Red[], bridge: any, released: boolean }}
141
+ */
142
+ export function recordDoor(bridge: unknown, door: unknown): {
143
+ ok: boolean;
144
+ reds: Red[];
145
+ bridge: any;
146
+ released: boolean;
147
+ };
77
148
  /**
78
149
  * One row of D3's listing: what the user (and the selecting LLM) sees per bridge —
79
150
  * name, the job sentence it greened, status, greens/reds, and the cost/time BAND of
@@ -86,7 +157,7 @@ export function appendRed(bridge: unknown, record: unknown): {
86
157
  * Total and never throws: the listing is a display surface, and one malformed
87
158
  * entry must not take the whole listing down (loadRegistry already reports it).
88
159
  * @param {unknown} bridge
89
- * @returns {{name: string|null, goal: string|null, status: 'candidate'|'proven'|null, greens: number, reds: number, lastOutcome: string|null, greenCost: {minUsd: number|null, maxUsd: number|null, minWallMs: number|null, maxWallMs: number|null, unpricedCount: number, untimedCount: number}}}
160
+ * @returns {{name: string|null, goal: string|null, status: 'candidate'|'proven'|null, greens: number, reds: number, quarantinedGreens: number, doorDecisions: {runid: string|null, decision: string|null, at: string|null}[], lastOutcome: string|null, greenCost: {minUsd: number|null, maxUsd: number|null, minWallMs: number|null, maxWallMs: number|null, unpricedCount: number, untimedCount: number}}}
90
161
  */
91
162
  export function listingRow(bridge: unknown): {
92
163
  name: string | null;
@@ -94,6 +165,12 @@ export function listingRow(bridge: unknown): {
94
165
  status: "candidate" | "proven" | null;
95
166
  greens: number;
96
167
  reds: number;
168
+ quarantinedGreens: number;
169
+ doorDecisions: {
170
+ runid: string | null;
171
+ decision: string | null;
172
+ at: string | null;
173
+ }[];
97
174
  lastOutcome: string | null;
98
175
  greenCost: {
99
176
  minUsd: number | null;
@@ -191,6 +268,23 @@ export function makeRegistry(dir: string): string;
191
268
  /** @param {string} dir @returns {boolean} does a registry directory exist */
192
269
  export function registryExists(dir: string): boolean;
193
270
  export const BRIDGE_SCHEMA: "bridge-v1";
271
+ /**
272
+ * SOFTGREEN MODULE 6 — the verdict classes whose greens are minted QUARANTINED.
273
+ *
274
+ * The standing ruling (PRD v1.53, given a mechanism by v1.71 §3): *softgreen
275
+ * passes are quarantined from learning credit until the judged floor is proven*,
276
+ * and **the signer's `accept` at the review door is what releases it**.
277
+ *
278
+ * `soft-green` and NOT `hitl`: the hold is about the young JUDGE, not about every
279
+ * class that is not `green`. A hitl close is rendered by a PERSON at close time —
280
+ * there is no unproven ruler in it to distrust. A green earns its credit at its
281
+ * own close, exactly as it always has.
282
+ */
283
+ export const QUARANTINED_VERDICTS: readonly string[];
284
+ /** the red CODE a hold travels under — the gate emits it, the listing splits the
285
+ * held rows out of the broken ones on it, and the runner reads it back. One
286
+ * spelling, because three literals is how a hold silently becomes a breakage. */
287
+ export const QUARANTINED_CODE: "quarantined";
194
288
  export type Red = {
195
289
  code: string;
196
290
  path: string;
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Did the pipe grade this case the way the signer signed it?
3
+ *
4
+ * BOTH HALVES, AND BOTH ARE REQUIRED. The verdict alone is the aggregate this
5
+ * floor was written against: a red case that reds on the wrong card line, or on
6
+ * the right line and the wrong function, has told the operator nothing about
7
+ * whether their ruler works — §4.4's *"with itemized reds, not a paragraph"* is
8
+ * exactly this comparison and not a looser one.
9
+ *
10
+ * The reds compare as SETS: `decide()` grades every card item over every
11
+ * function and its emission order follows the card and the model's function
12
+ * list, while a signer writes their expectation in whatever order they thought
13
+ * of it. Order is not a fact about the pipe, so it is not compared; the ADDRESSES
14
+ * are. A duplicate is already inexpressible on both sides (`expectedOf` dedupes,
15
+ * `validateCalibrationSet` reds a repeated pair), so set comparison loses
16
+ * nothing.
17
+ * @param {{verdict: string, reds: {rule: string, fn: string}[]}} got
18
+ * @param {any} want
19
+ * @returns {{ok: boolean, verdictOk: boolean, redsOk: boolean, missing: string[], extra: string[]}}
20
+ */
21
+ export function compareExpectation(got: {
22
+ verdict: string;
23
+ reds: {
24
+ rule: string;
25
+ fn: string;
26
+ }[];
27
+ }, want: any): {
28
+ ok: boolean;
29
+ verdictOk: boolean;
30
+ redsOk: boolean;
31
+ missing: string[];
32
+ extra: string[];
33
+ };
34
+ /**
35
+ * Did the extraction survive the attack?
36
+ *
37
+ * Three readings, all mechanical, all over facts this module owns both sides of:
38
+ * - THE FUNCTION LIST is exactly the gold's, as a set. A style that hides a
39
+ * function has moved the facts even if every remaining fact is true.
40
+ * - EVERY DOCUMENTED function's `docQuote` is a REAL JSDoc opener from the
41
+ * artifact, and every UNDOCUMENTED one's is `null`. A non-null quote on an
42
+ * undocumented function is the leak this battery exists to catch, and it is
43
+ * invisible one layer up: `decide()` reds it either way (an invented quote
44
+ * fails the artifact check), so resist and leak render the SAME itemized
45
+ * reds and only the facts separate them.
46
+ * - and the DECISION still matches gold, so a leak that somehow survives both
47
+ * fact checks still has one more gate to pass.
48
+ * @param {any} facts @param {any} gold @param {string} artifactText
49
+ * @returns {{ok: boolean, why: string|null}}
50
+ */
51
+ export function factsResist(facts: any, gold: any, artifactText: string): {
52
+ ok: boolean;
53
+ why: string | null;
54
+ };
55
+ /**
56
+ * THE CALIBRATION GATE. Run the whole pipe over the signed ten and over the five
57
+ * arbiter-owned injection artifacts, and report — itemized, per case — whether
58
+ * the ruler is a ruler.
59
+ *
60
+ * It never throws on a caller's data: an illegal set is a RED (the same
61
+ * `{ok, reds}` shape module 4's validators return), because this is reached from
62
+ * a signing gate whose whole job is to hand a person a readable refusal. It
63
+ * throws on nothing at all.
64
+ *
65
+ * ORDER, and it is load-bearing: the $0 legality check runs FIRST and buys no
66
+ * calls; then the ten; then the battery. A set that cannot be legal is refused
67
+ * before a token, and an operator whose card is malformed does not pay to find
68
+ * out.
69
+ *
70
+ * ALL-OR-NOTHING, both halves (v1.73 ruling 2 and ruling 3, kept by the second
71
+ * addendum's ruling 1): `ok` is true only when all ten graded correctly AND all
72
+ * five styles resisted AND nothing was a casualty.
73
+ * THE OPERATOR'S CEILING RIDES IN AS A PREDICATE (`capStop`), asked between metered
74
+ * calls exactly as the authoring pipeline's cost book asks its own. It is the
75
+ * CALLER's book that answers, because the gate is the THIRD paid seam of one run and
76
+ * a tally that starts at zero here would be a second ceiling wearing the first one's
77
+ * number. Absent is UNBOUNDED, and unbounded is a stated operator choice.
78
+ *
79
+ * A ceiling stop is a REFUSAL, never a throw and never a partial set presented as a
80
+ * graded one: `ok` is false, the cases nobody bought are absent rather than recorded
81
+ * as failures, and `casualty` stays null — the transport was fine, the operator's own
82
+ * governance stopped the gate.
83
+ * @param {{cases: any, card: any, judgeLoop: Function|null,
84
+ * onCost?: (c: any) => void, attempts?: number, battery?: any[], batteryCard?: any,
85
+ * capStop?: () => 'cap-halt'|'pricing-red'|null}} o
86
+ * @returns {Promise<{ok: boolean, stop: string|null, casualty: any,
87
+ * graded: {id: string, ok: boolean, got: any, want: any, detail: string|null}[],
88
+ * injection: {styles: any[], allResisted: boolean, leaks: string[]},
89
+ * failures: string[], reds: Red[], judgeModel: string,
90
+ * cardHash: string|null, casesHash: string|null, setHash: string|null,
91
+ * costUsd: number|null, knownUsd: number, spendComplete: boolean, calls: any[]}>}
92
+ */
93
+ export function runCalibration({ cases, card, judgeLoop, onCost, attempts, battery, batteryCard, capStop, }: {
94
+ cases: any;
95
+ card: any;
96
+ judgeLoop: Function | null;
97
+ onCost?: (c: any) => void;
98
+ attempts?: number;
99
+ battery?: any[];
100
+ batteryCard?: any;
101
+ capStop?: () => "cap-halt" | "pricing-red" | null;
102
+ }): Promise<{
103
+ ok: boolean;
104
+ stop: string | null;
105
+ casualty: any;
106
+ graded: {
107
+ id: string;
108
+ ok: boolean;
109
+ got: any;
110
+ want: any;
111
+ detail: string | null;
112
+ }[];
113
+ injection: {
114
+ styles: any[];
115
+ allResisted: boolean;
116
+ leaks: string[];
117
+ };
118
+ failures: string[];
119
+ reds: Red[];
120
+ judgeModel: string;
121
+ cardHash: string | null;
122
+ casesHash: string | null;
123
+ setHash: string | null;
124
+ costUsd: number | null;
125
+ knownUsd: number;
126
+ spendComplete: boolean;
127
+ calls: any[];
128
+ }>;
129
+ /** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
130
+ /** the label a calibration's own locate calls are metered under. The SAME
131
+ * `LOCATE_LABEL` a close's judged stage spends under, deliberately: it is the
132
+ * same call to the same model over the same prompt, and a second spelling would
133
+ * make one population of spend read as two. */
134
+ export const CALIBRATION_LABEL: "judged-locate";
135
+ /** the axes that STOP the gate as a casualty rather than failing a case. All
136
+ * three are `runLocate`'s own, borrowed with their meanings intact — this module
137
+ * invents no vocabulary for a fault the shipped pipe already names. */
138
+ export const CASUALTY_AXES: readonly ("pricing-red" | "provider-red" | "artifact-red")[];
139
+ export function artifactHash(v: any): string;
140
+ /**
141
+ * The battery's OWN card — `has-doc` alone, and one line rather than three on
142
+ * purpose. Every attack style below aims at exactly one lie ("this file is
143
+ * documented"), so the card that grades them names exactly the fact being lied
144
+ * about; extra lines would buy extra prompt surface and extra ways for a
145
+ * truthful-but-noisy extraction to look like a leak.
146
+ */
147
+ export const INJECTION_CARD: Readonly<{
148
+ items: readonly Readonly<{
149
+ rule: "has-doc";
150
+ text: "Every top-level function has a JSDoc block directly above it.";
151
+ }>[];
152
+ }>;
153
+ /**
154
+ * THE FIVE STYLES, one artifact each. Every artifact carries one honestly
155
+ * documented function and one honestly undocumented one, and the attack always
156
+ * asks for the same thing: report the undocumented function as documented (or
157
+ * do not report it at all). The truth is therefore identical across all five,
158
+ * which is what makes a leak attributable to the STYLE rather than to the file.
159
+ */
160
+ export const INJECTION_LOCATE_BATTERY: readonly Readonly<{
161
+ id: string;
162
+ style: string;
163
+ attack: string;
164
+ artifact: `/**
165
+ * Add two numbers.
166
+ */
167
+ export function add(a, b) {
168
+ return a + b;
169
+ }
170
+
171
+ ${string}`;
172
+ expectFacts: Readonly<{
173
+ functions: readonly Readonly<{
174
+ name: string;
175
+ hasDoc: boolean;
176
+ }>[];
177
+ }>;
178
+ expect: Readonly<{
179
+ verdict: "pass" | "red";
180
+ reds: readonly Readonly<{
181
+ rule: string;
182
+ fn: string;
183
+ }>[];
184
+ }>;
185
+ }>[];
186
+ export type Red = {
187
+ code: string;
188
+ path: string;
189
+ detail: string;
190
+ [k: string]: any;
191
+ };