bareloop 0.38.0 → 0.40.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/bareloop.context.md +87 -24
  3. package/package.json +3 -3
  4. package/src/authorflow.js +335 -59
  5. package/src/authoring.js +125 -3
  6. package/src/authorjob.js +93 -32
  7. package/src/authorreadout.js +498 -3
  8. package/src/authorrun.js +26 -6
  9. package/src/authorscout.js +9 -6
  10. package/src/bridges.js +1 -1
  11. package/src/calibrate.js +85 -11
  12. package/src/cardauthor.js +8 -2
  13. package/src/declaredclose.js +12 -5
  14. package/src/draftspend.js +6 -1
  15. package/src/interviewrun.js +56 -27
  16. package/src/job.js +38 -5
  17. package/src/jobblock.js +140 -0
  18. package/src/judged.js +323 -29
  19. package/src/kinds.js +13 -1
  20. package/src/ledger.js +1 -1
  21. package/src/panel/authorroutes.js +17 -11
  22. package/src/panel/authorsession.js +202 -75
  23. package/src/panel/index.html +302 -312
  24. package/src/panel/jobplan.js +107 -0
  25. package/src/panel/server.js +67 -13
  26. package/src/planrun.js +6 -5
  27. package/src/promptregisters.js +1 -1
  28. package/src/providers.js +111 -2
  29. package/src/reuse.js +1 -1
  30. package/src/root.js +1 -1
  31. package/src/run.js +3 -3
  32. package/src/selection.js +1 -1
  33. package/src/source.js +64 -1
  34. package/src/text.js +13 -0
  35. package/src/transport.js +1 -1
  36. package/src/trend.js +1 -0
  37. package/src/userrun.js +3 -3
  38. package/types/authorflow.d.ts +258 -39
  39. package/types/authoring.d.ts +30 -1
  40. package/types/authorjob.d.ts +52 -13
  41. package/types/authorreadout.d.ts +123 -1
  42. package/types/authorscout.d.ts +5 -3
  43. package/types/calibrate.d.ts +4 -1
  44. package/types/declaredclose.d.ts +5 -1
  45. package/types/draftspend.d.ts +8 -2
  46. package/types/job.d.ts +1 -1
  47. package/types/jobblock.d.ts +102 -0
  48. package/types/judged.d.ts +21 -2
  49. package/types/panel/authorsession.d.ts +57 -7
  50. package/types/panel/jobplan.d.ts +58 -0
  51. package/types/panel/server.d.ts +20 -0
  52. package/types/planrun.d.ts +1 -1
  53. package/types/providers.d.ts +52 -1
  54. package/types/run.d.ts +1 -1
  55. package/types/source.d.ts +26 -0
  56. package/types/trend.d.ts +1 -0
@@ -80,6 +80,14 @@ export function envCapableKind(kind: string, catalogue?: Record<string, KindSpec
80
80
  * @param {string} cmd @returns {string|null}
81
81
  */
82
82
  export function deniedCommandReason(cmd: string): string | null;
83
+ /**
84
+ * The warning line for a job whose ACTUAL stages carry the js `any` pattern, else
85
+ * ''. Derived from the stages' patterns (never goal prose), so a job without the
86
+ * guard is told nothing about it.
87
+ * @param {any[]|null|undefined} stages
88
+ * @returns {string}
89
+ */
90
+ export function anySuppressionWarning(stages: any[] | null | undefined): string;
83
91
  /**
84
92
  * The picked class's mandatory guards, FULLY ENUMERATED (D13 forward-compat
85
93
  * point 3: an omittable-with-a-default field is the omitted-`tools` shape, where
@@ -219,6 +227,16 @@ export function ungroundedGenreEnv(lang: string, recorded: Record<string, string
219
227
  element: string;
220
228
  resolved: string;
221
229
  }[];
230
+ /**
231
+ * Which of a judged stage's paths lie OUTSIDE the job's write fence? One owner of the rule "a check must be
232
+ * free to edit every file it can report on", called from every door that validates a declaration. It uses
233
+ * the shipped fence spelling (`globToPrefix`, the same containment reading plan.js's `insideFence` has) and
234
+ * returns `[]` when there is no fence to compare against or the paths are not a string list (shape is the
235
+ * schema walk's business).
236
+ * @param {unknown} paths @param {string[]|null|undefined} writeScope
237
+ * @returns {string[]}
238
+ */
239
+ export function judgedOutsideFence(paths: unknown, writeScope: string[] | null | undefined): string[];
222
240
  /**
223
241
  * Validate an authored close DECLARATION. Never throws on model output — every
224
242
  * failure is a named red, in the shipped `{ok, reds, <parsed>}` shape, and the
@@ -256,7 +274,12 @@ export function ungroundedGenreEnv(lang: string, recorded: Record<string, string
256
274
  * @param {{catalogue?: Record<string, KindSpec>, listing?: string[]|null,
257
275
  * guards?: {name: string, kind: string, params: Record<string, any>, fill: string[]}[]|null,
258
276
  * envOwned?: string[]|null, envInjected?: Record<string, string>|null, deferListing?: boolean,
259
- * verdictType?: string|null}} [opts]
277
+ * verdictType?: string|null, writeScope?: string[]|null, jobLines?: {n: number}[]|null}} [opts]
278
+ * `jobLines` — the person's numbered job lines (P7). Present, every stage must name the line it serves and every
279
+ * line needs a stage or a refusal ({@link checkJobLines}); absent (every spec that predates the job block), the
280
+ * rule is not run.
281
+ * `writeScope` — the job's signed write fence. Every path a judged stage judges must sit inside it
282
+ * ({@link judgedOutsideFence}); absent, the rule is not run (the plain-folder deferral has no fence).
260
283
  * `listing` — repo-relative paths at the seed (`git ls-tree -r --name-only`).
261
284
  * `guards` — the picked class's injected guards (`classGuards`).
262
285
  * `verdictType` — the class the USER picked (`VERDICT_CLASSES`).
@@ -283,6 +306,10 @@ export function validateDeclaration(declaration: any, opts?: {
283
306
  envInjected?: Record<string, string> | null;
284
307
  deferListing?: boolean;
285
308
  verdictType?: string | null;
309
+ writeScope?: string[] | null;
310
+ jobLines?: {
311
+ n: number;
312
+ }[] | null;
286
313
  }): {
287
314
  ok: boolean;
288
315
  reds: Red[];
@@ -455,6 +482,8 @@ export const DENIED_COMMANDS: readonly string[];
455
482
  */
456
483
  export const TYPES_GENRE_TEMPLATE: "1. The STRICT form of the language's type checker is used only when a confirmed check \u2014 or,\n absent a confirm turn, the goal and interview answers \u2014 asks for strict typing; otherwise the\n checker runs at whatever strictness the repo's own scripts already use.\n2. Tools are invoked so their binaries actually resolve \u2014 through the project's own package\n runner or language module runner, never a bare binary name.\n3. The WORK stages \u2014 typecheck (error count IN the target scope, baseline 0, lower-is-better),\n typecheck-outside (error count OUTSIDE the target scope, baseline measured at seed, a\n ceiling \u2014 required whenever a typecheck stage is scoped to a subset of the tree), tests-kept\n (a floor on tests that actually EXECUTED, baseline at seed, higher-is-better; a skipped or\n deselected test did not run and must not count), and suite-green (the suite exits clean AND\n reports zero failing tests \u2014 two assertions) \u2014 are composed ONLY for the checks a confirmed\n plan asked for (or, absent a confirm turn, the goal and interview answers). The GUARDS \u2014\n changed-from-seed and no-suppressions \u2014 are composed always, first-red-wins:\n changed-from-seed before every WORK stage, no-suppressions last.\n4. One population per stage \u2014 two structurally different counts never share a stage.\n5. The checker must judge the PATIENT's own tree: if imports could resolve to an installed or\n editable copy elsewhere, the environment is set so they resolve inside the patient.\n6. A number the tool did not report is unknown, never zero.";
457
484
  export const GENRE_LANGUAGES: readonly string[];
485
+ /** The worker-facing line that rides with the js `any` guard (run mv13ery3). */
486
+ export const ANY_SUPPRESSION_WARNING: string;
458
487
  /**
459
488
  * THE GENRE, as data. The suppression batteries are the hand-written closes'
460
489
  * own `SUPPRESSIONS` tables (`scripts/u-pulselog-close.mjs:35`,
@@ -79,26 +79,38 @@ export function refuseLockedKind(kind: string): Refusal;
79
79
  * one-genre-at-a-time law is untouched.
80
80
  *
81
81
  * @param {{answers: Record<string|number, any>, repoPath?: string|null, lang: string,
82
+ * jobLines?: {n: number, text: string}[]|null, inputs?: {n: number, label: string, value: string}[]|null,
82
83
  * verdictType?: string|null,
83
84
  * questions?: Record<string|number, string>|null, generate?: Function, provider?: any,
84
85
  * seedRef?: string|null, scout?: any, listing?: any, ceilingUsd?: number|null, judgeModel?: string|null,
85
- * rates?: {in: number, out: number}|null,
86
+ * rates?: {in: number, out: number}|null, draftThinking?: 'on'|'off',
86
87
  * onPhase?: (phase: string, data?: any) => void,
87
- * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
88
+ * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number, thinkingApplied?: boolean|null}) => void,
88
89
  * seedFn?: Function, scoutFn?: Function, listingFn?: Function,
89
90
  * authorFn?: Function, authorOpts?: object, writeScope?: string[]|null,
90
91
  * signerFix?: Function|any, proposeFn?: Function, compileOpts?: object,
91
92
  * ask?: ((step: {kind: string, [k: string]: any}) => Promise<string|null>)|null,
93
+ * answerQuestions?: ((o: {questions: {line: number, question: string}[], dropped: {reason: string, raw: any}[], confirmed: any}) =>
94
+ * Promise<{jobLines: {n: number, text: string, rule?: string}[], answers: Record<string|number, any>}|null>)|null,
92
95
  * confirmGenerate?: Function|null, isRepo?: boolean,
93
96
  * langResult?: {kind: string, candidates?: string[], [k: string]: any}|null}} o
94
97
  * @returns {Promise<{ok: boolean, refusal: Refusal|null, verdictType: string|null,
95
98
  * closeDecl: any, seedRef: string|null, authoring: any, judged: any, reds: Red[],
96
99
  * stop: string|null, cost: any, interview: any, confirmed: any}>}
97
100
  */
98
- export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, generate, provider, seedRef, scout, listing, ceilingUsd, rates, writeScope, judgeModel, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, ask, confirmGenerate, isRepo, langResult, }: {
101
+ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questions, jobLines, inputs, generate, provider, seedRef, scout, listing, ceilingUsd, rates, draftThinking, writeScope, judgeModel, onPhase, onCall, seedFn, scoutFn, listingFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, ask, confirmGenerate, isRepo, langResult, answerQuestions, }: {
99
102
  answers: Record<string | number, any>;
100
103
  repoPath?: string | null;
101
104
  lang: string;
105
+ jobLines?: {
106
+ n: number;
107
+ text: string;
108
+ }[] | null;
109
+ inputs?: {
110
+ n: number;
111
+ label: string;
112
+ value: string;
113
+ }[] | null;
102
114
  verdictType?: string | null;
103
115
  questions?: Record<string | number, string> | null;
104
116
  generate?: Function;
@@ -112,11 +124,13 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
112
124
  in: number;
113
125
  out: number;
114
126
  } | null;
127
+ draftThinking?: "on" | "off";
115
128
  onPhase?: (phase: string, data?: any) => void;
116
129
  onCall?: (call: {
117
130
  label: string;
118
131
  costUsd: number | null;
119
132
  unpricedRounds: number;
133
+ thinkingApplied?: boolean | null;
120
134
  }) => void;
121
135
  seedFn?: Function;
122
136
  scoutFn?: Function;
@@ -131,6 +145,24 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
131
145
  kind: string;
132
146
  [k: string]: any;
133
147
  }) => Promise<string | null>) | null;
148
+ answerQuestions?: ((o: {
149
+ questions: {
150
+ line: number;
151
+ question: string;
152
+ }[];
153
+ dropped: {
154
+ reason: string;
155
+ raw: any;
156
+ }[];
157
+ confirmed: any;
158
+ }) => Promise<{
159
+ jobLines: {
160
+ n: number;
161
+ text: string;
162
+ rule?: string;
163
+ }[];
164
+ answers: Record<string | number, any>;
165
+ } | null>) | null;
134
166
  confirmGenerate?: Function | null;
135
167
  isRepo?: boolean;
136
168
  langResult?: {
@@ -185,6 +217,14 @@ export function assembleSpec(specDraft: any, { closeDecl, verdictType }: {
185
217
  closeDecl: any;
186
218
  verdictType: string;
187
219
  }): any;
220
+ /**
221
+ * THE one spelling of "a passed calibration gate stands in for the seed red": the
222
+ * close carries a judged stage AND the gate ran and passed. A failed or missing
223
+ * calibration never satisfies it, and a close with no judged stage never reaches it.
224
+ * @param {any[]} judged `judgedStages(closeDecl)` @param {any} calibration `gates.calibration`
225
+ * @returns {boolean}
226
+ */
227
+ export function seedProofIsCalibration(judged: any[], calibration: any): boolean;
188
228
  /**
189
229
  * D9, in code: *nothing JUDGES the close; three mechanical gates plus a
190
230
  * signature.* No LLM validates another LLM's close, here or anywhere.
@@ -206,16 +246,15 @@ export function assembleSpec(specDraft: any, { closeDecl, verdictType }: {
206
246
  * has already had its chance, and nobody pays to discover a broken
207
247
  * declaration.
208
248
  *
209
- * D9.3 AND THE JUDGED-ONLY CLOSE (2026-08-18 second addendum, ruling 3; hamr:
210
- * *"fix it now, we are delivering softgreen, isn't that the whole point?"*). Gate
211
- * 3 protects against a close that cannot fail — one that scans nothing and reads
212
- * green at seed against a true red. A judged stage SKIPS the seed read by ruling
213
- * 8, so a close whose only work stage is judged has no seed red to show and used
214
- * to be unsignable: the one job shape softgreen exists for. For that shape, and
215
- * ONLY that shape, a PASSED calibration gate plays the seed-red role — it is that
216
- * close's own proof of failability, held to the same all-or-nothing bar. A close
217
- * with a mechanical work stage is UNCHANGED: it still needs a seed red, whatever
218
- * its calibration says.
249
+ * D9.3 AND THE JUDGED CLOSE (2026-08-18 second addendum, ruling 3; hamr: *"fix it now,
250
+ * we are delivering softgreen, isn't that the whole point?"*; widened 2026-10-09 to mixed
251
+ * closes, hamr: *"a rubric job should check if judge can judge (calibration) and judge
252
+ * rules can apply properly to pass ... we can't close everything upfront"*). Gate 3
253
+ * protects against a close that cannot fail. A judged stage SKIPS the seed read by ruling
254
+ * 8, so it can never show red there. For ANY close carrying a judged stage (pure or
255
+ * mixed with mechanical stages), a PASSED calibration gate plays the seed-red role
256
+ * (`seedProofIsCalibration`). A close with NO judged stage is UNCHANGED: some work stage
257
+ * must be red at the seed. A failed or missing calibration never satisfies it.
219
258
  *
220
259
  * Gates 2 and 3 share ONE execution, and that is stated rather than hidden: at
221
260
  * job creation the tree IS the seed, so "does every stage run against the real
@@ -12,7 +12,7 @@ export function declarationLines({ goal, closeDecl }: {
12
12
  * F176'S FALLBACK, SAID OUT LOUD — the revise ladder kept the NEWEST SOUND
13
13
  * declaration rather than the last one it happened to try, because "kept the
14
14
  * last accepted revision" is not the same claim as "kept the best revision"
15
- * (docs/logs/FINDINGS.md F176). Absent on every run where the fallback never
15
+ * (docs/wiki/FINDINGS.md F176). Absent on every run where the fallback never
16
16
  * fired (the overwhelming majority), which is why this returns an EMPTY list
17
17
  * rather than a "no fallback" line — a green close has nothing to say here and
18
18
  * printing it every run would be noise, not information.
@@ -87,6 +87,20 @@ export function answeredQuestionLines(confirmed: {
87
87
  * @returns {string[]}
88
88
  */
89
89
  export function calibrationLines(calibration: any): string[];
90
+ /**
91
+ * The calibration gate's real result as one line a person reads next to the step (hamr, 2026-10-09: the panel
92
+ * showed `calibrating ✓` over a gate that graded 8 of 10 and let 2 attack styles leak). PASS IS THE GATE'S OWN:
93
+ * `ok` is `calibration.ok` as `runCalibration` decided it (every case right as a SET of reds, every style
94
+ * resisted), never recomputed here, so there is no second spelling of the floor. The counts are read from the
95
+ * record (`graded[].ok` is `compareExpectation`, which compares reds as sets); the denominators are the live
96
+ * constants (CALIBRATION_SIZE, the battery length), so a gate that stopped part-way reads "x of 10", not "x of x".
97
+ * @param {any} calibration `signing.gates.calibration`
98
+ * @returns {{ok: boolean, note: string}|null} null when the gate was not reached
99
+ */
100
+ export function calibrationSummary(calibration: any): {
101
+ ok: boolean;
102
+ note: string;
103
+ } | null;
90
104
  /**
91
105
  * THE AUTHORING CEILING, parsed from `--budget`. Housed here for the same reason
92
106
  * the readout above is: the runner is a script, and a rule no test can reach is a
@@ -169,4 +183,112 @@ export function crashRecord(err: unknown): {
169
183
  code: string | null;
170
184
  raw: ReturnType<typeof scrubRaw>;
171
185
  };
186
+ /**
187
+ * Every plain kind the table can emit — the list the test enumerates against.
188
+ * @returns {string[]}
189
+ */
190
+ export function plainKinds(): string[];
191
+ /**
192
+ * Map the technical reds of a refused proposal to plain sentences, one per red.
193
+ * An unknown code is NEVER dropped: it becomes a generic sentence that still
194
+ * quotes the code and path, under the kind `unmapped`.
195
+ * @param {PlainRed[]} reds
196
+ * @param {{cases?: any}} [o] the proposed cases, to name a case by its own id
197
+ * @returns {PlainReason[]}
198
+ */
199
+ export function plainReasons(reds: PlainRed[], { cases }?: {
200
+ cases?: any;
201
+ }): PlainReason[];
202
+ /**
203
+ * THE MESSAGE a person reads when the rubric proposal was refused. Both doors
204
+ * (the panel's failed step and the CLI) print exactly this.
205
+ * @param {{stop: string, reds: PlainRed[], cases?: any, spend?: {knownUsd?: number|null, spendComplete?: boolean|null}|null,
206
+ * source?: 'proposal'|'signer'}} o
207
+ * @returns {string}
208
+ */
209
+ export function proposalStopText({ stop, reds, cases, spend, source }: {
210
+ stop: string;
211
+ reds: PlainRed[];
212
+ cases?: any;
213
+ spend?: {
214
+ knownUsd?: number | null;
215
+ spendComplete?: boolean | null;
216
+ } | null;
217
+ source?: "proposal" | "signer";
218
+ }): string;
219
+ /**
220
+ * @param {{stop: string, reds?: PlainRed[]|null, refusal?: {detail?: string}|null,
221
+ * spend?: {knownUsd?: number|null, spendComplete?: boolean|null}|null}} o
222
+ * @returns {string}
223
+ */
224
+ export function draftStopText({ stop, reds, refusal, spend }: {
225
+ stop: string;
226
+ reds?: PlainRed[] | null;
227
+ refusal?: {
228
+ detail?: string;
229
+ } | null;
230
+ spend?: {
231
+ knownUsd?: number | null;
232
+ spendComplete?: boolean | null;
233
+ } | null;
234
+ }): string;
235
+ /**
236
+ * Plain sentences for the reds of a refused signing, one or more per red. Card and practice-case reds reuse the
237
+ * proposal table; an unknown code is a generic sentence that quotes the code.
238
+ * @param {PlainRed[]} reds @param {{cases?: any}} [o]
239
+ * @returns {{kind: string, sentence: string, todo: string, red: PlainRed}[]}
240
+ */
241
+ export function signingReasons(reds: PlainRed[], { cases }?: {
242
+ cases?: any;
243
+ }): {
244
+ kind: string;
245
+ sentence: string;
246
+ todo: string;
247
+ red: PlainRed;
248
+ }[];
249
+ /** every plain kind `signingReasons` can emit besides the proposal table's — what the test enumerates
250
+ * @returns {string[]} */
251
+ export function signingKinds(): string[];
252
+ /**
253
+ * THE MESSAGE a person reads when the signing gates refuse. The panel's failed step and the CLI print exactly this.
254
+ * @param {{reds: PlainRed[], refusal?: {detail?: string}|null, cases?: any,
255
+ * spend?: {knownUsd?: number|null, spendComplete?: boolean|null}|null}} o
256
+ * @returns {string}
257
+ */
258
+ export function signingStopText({ reds, refusal, cases, spend }: {
259
+ reds: PlainRed[];
260
+ refusal?: {
261
+ detail?: string;
262
+ } | null;
263
+ cases?: any;
264
+ spend?: {
265
+ knownUsd?: number | null;
266
+ spendComplete?: boolean | null;
267
+ } | null;
268
+ }): string;
269
+ /**
270
+ * The reds as the drafting log keeps them: every structured field, the plain
271
+ * sentence beside it, every string secret-scrubbed and bounded, the list capped.
272
+ * @param {PlainRed[]} reds @param {{cases?: any, signing?: boolean}} [o] `signing`: the reds are the signing gates', worded by signingReasons
273
+ * @returns {Record<string, any>[]}
274
+ */
275
+ export function redsRecord(reds: PlainRed[], { cases, signing }?: {
276
+ cases?: any;
277
+ signing?: boolean;
278
+ }): Record<string, any>[];
279
+ /** the stops this module explains in plain words */
280
+ export const PLAIN_PROPOSAL_STOPS: readonly string[];
281
+ /** codes the declaration gates (validateJob, validateCloseDecl) raise: one plain sentence covers the family */
282
+ export const DECLARATION_CODES: readonly string[];
283
+ export type PlainRed = {
284
+ code: string;
285
+ path: string;
286
+ detail: string;
287
+ [k: string]: any;
288
+ };
289
+ export type PlainReason = {
290
+ kind: string;
291
+ sentence: string;
292
+ red: PlainRed;
293
+ };
172
294
  import { scrubRaw } from './text.js';
@@ -92,15 +92,15 @@ export function defaultSurveyor({ workdir, granted, auditPath, ctx }: {
92
92
  * @param {{workdir: string, provider?: any,
93
93
  * rounds?: number, minBytes?: number, blobMax?: number, maxTokens?: number, ctx?: boolean,
94
94
  * attempts?: number, ceilingUsd?: number|null, callTimeoutMs?: number,
95
- * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
95
+ * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number, thinkingApplied?: boolean|null}) => void,
96
96
  * createLoop?: (o: {system: string, policy: any, onLlmResult: any, provider: any, rates?: {in: number, out: number}}) => any,
97
- * rates?: {in: number, out: number}|null,
97
+ * rates?: {in: number, out: number}|null, callOptions?: Record<string, any>,
98
98
  * createSurveyor?: (o: {workdir: string, granted: readonly string[], ctx: boolean}) => Promise<any>}} o
99
99
  * @returns {Promise<Survey & {raw: string, raws: ReturnType<typeof scrubRaw>[],
100
100
  * calls: {label: string, costUsd: number|null, unpricedRounds: number}[],
101
101
  * budgetStop: 'cap-halt'|'pricing-red'|null}>}
102
102
  */
103
- export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, maxTokens, ctx, attempts, ceilingUsd, callTimeoutMs, onCall, createLoop, rates, createSurveyor, }: {
103
+ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, maxTokens, ctx, attempts, ceilingUsd, callTimeoutMs, onCall, createLoop, rates, callOptions, createSurveyor, }: {
104
104
  workdir: string;
105
105
  provider?: any;
106
106
  rounds?: number;
@@ -115,6 +115,7 @@ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, m
115
115
  label: string;
116
116
  costUsd: number | null;
117
117
  unpricedRounds: number;
118
+ thinkingApplied?: boolean | null;
118
119
  }) => void;
119
120
  createLoop?: (o: {
120
121
  system: string;
@@ -130,6 +131,7 @@ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, m
130
131
  in: number;
131
132
  out: number;
132
133
  } | null;
134
+ callOptions?: Record<string, any>;
133
135
  createSurveyor?: (o: {
134
136
  workdir: string;
135
137
  granted: readonly string[];
@@ -90,7 +90,7 @@ export function factsResist(facts: any, gold: any, artifactText: string): {
90
90
  * onCost?: (c: any) => void, attempts?: number, battery?: any[], batteryCard?: any,
91
91
  * capStop?: () => 'cap-halt'|'pricing-red'|null}} o
92
92
  * @returns {Promise<{ok: boolean, stop: string|null, casualty: any,
93
- * graded: {id: string, ok: boolean, got: any, want: any, detail: string|null}[],
93
+ * graded: {id: string, ok: boolean, got: any, want: any, detail: string|null, diag: any}[],
94
94
  * injection: {styles: any[], allResisted: boolean, leaks: string[]},
95
95
  * failures: string[], reds: Red[], judgeModel: string,
96
96
  * cardHash: string|null, casesHash: string|null, setHash: string|null,
@@ -116,6 +116,7 @@ export function runCalibration({ cases, card, judgeLoop, judgeModel, onCost, att
116
116
  got: any;
117
117
  want: any;
118
118
  detail: string | null;
119
+ diag: any;
119
120
  }[];
120
121
  injection: {
121
122
  styles: any[];
@@ -190,6 +191,8 @@ ${string}`;
190
191
  }>[];
191
192
  }>;
192
193
  }>[];
194
+ /** the per-string cap on anything the diagnostic keeps (bytes, scrubbed) */
195
+ export const DIAG_STRING_CAP: 400;
193
196
  export type Red = {
194
197
  code: string;
195
198
  path: string;
@@ -53,7 +53,7 @@ export function declaredStages(closeDecl: any): any[] | null;
53
53
  *
54
54
  * @param {any} closeDecl
55
55
  * @param {{at?: string, listing?: string[]|null, deferListing?: boolean,
56
- * catalogue?: Record<string, any>, verdictType?: string|null}} [opts]
56
+ * catalogue?: Record<string, any>, verdictType?: string|null, writeScope?: string[]|null, jobLines?: {n: number}[]|null}} [opts]
57
57
  * @returns {{ok: boolean, reds: Red[], closeDecl: any, grounded: boolean,
58
58
  * scoped: {scoped: boolean, via: string|null},
59
59
  * ceiling: {class: string, kind: string, stage: string|null, locked: boolean}|null}}
@@ -64,6 +64,10 @@ export function validateCloseDecl(closeDecl: any, opts?: {
64
64
  deferListing?: boolean;
65
65
  catalogue?: Record<string, any>;
66
66
  verdictType?: string | null;
67
+ writeScope?: string[] | null;
68
+ jobLines?: {
69
+ n: number;
70
+ }[] | null;
67
71
  }): {
68
72
  ok: boolean;
69
73
  reds: Red[];
@@ -2,7 +2,10 @@
2
2
  * One line of the drafting log. `no` = the step's position in the session's progress list (a step id can repeat).
3
3
  * - `step-start` {no, id, label, at}
4
4
  * - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
5
- * - `call` {no, step, label, model, costUsd (null stays null), unpricedRounds, at}: one METERED model call
5
+ * - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway")
6
+ * - `call` {no, step, label, model, thinking, thinkingApplied?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
7
+ * (`thinking` = what was asked and sent: off | on | not-switchable | unverified; `thinkingApplied` = bare-agent's own verdict for the
8
+ * call's run (true | false | null), present only when thinkingMode was sent)
6
9
  * (no token counts: the call path does not carry them without reworking the library, so none are recorded)
7
10
  * @typedef {{kind: string, no: number, at: string, [k: string]: any}} DraftEvent
8
11
  */
@@ -105,7 +108,10 @@ export const DRAFT_LOG_FILE: "draft-log.jsonl";
105
108
  * One line of the drafting log. `no` = the step's position in the session's progress list (a step id can repeat).
106
109
  * - `step-start` {no, id, label, at}
107
110
  * - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
108
- * - `call` {no, step, label, model, costUsd (null stays null), unpricedRounds, at}: one METERED model call
111
+ * - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway")
112
+ * - `call` {no, step, label, model, thinking, thinkingApplied?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
113
+ * (`thinking` = what was asked and sent: off | on | not-switchable | unverified; `thinkingApplied` = bare-agent's own verdict for the
114
+ * call's run (true | false | null), present only when thinkingMode was sent)
109
115
  * (no token counts: the call path does not carry them without reworking the library, so none are recorded)
110
116
  */
111
117
  export type DraftEvent = {
package/types/job.d.ts CHANGED
@@ -272,7 +272,7 @@ export const PROVIDERS: readonly string[];
272
272
  export const CONDITION_KEYS: readonly string[];
273
273
  /**
274
274
  * The fields a "Reuse workflow" run may change: where the work lands (the write fence, `writeScope`, and a
275
- * `destination`/`source` where a spec ever carries them) and the two ceilings. Everything else in a signed spec is
275
+ * `destination`/`source` where a spec ever carries them), the `inputs` the person pointed at (P7: Inputs is open on a reuse) and the two ceilings. Everything else in a signed spec is
276
276
  * the WORKFLOW — goal, checks, guardrails, close (the worker model is the third kind, {@link WORKFLOW_KEY_IDENTITY_FIELDS}). ONE list, shared by {@link workflowKey} and by the panel's
277
277
  * reuse (so what the key ignores is exactly what the person may edit, never two spellings).
278
278
  */
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Parse "The job" box. A plain line is a numbered job line (1, 2, 3...). A line starting `~` has no number and belongs
3
+ * to the numbered line above; consecutive `~` lines become ONE rule joined with `'; '`. A `~` line starting `PASS:` or
4
+ * `FAIL:` is also a judge example (kept with its line number); any other `~` line is a guardrail. Empty lines are
5
+ * ignored. A `~` before line 1 is a red.
6
+ * @param {unknown} text the box's raw text
7
+ * @returns {{ok: true, lines: JobLine[]}|{ok: false, error: string}}
8
+ */
9
+ export function parseJobBlock(text: unknown): {
10
+ ok: true;
11
+ lines: JobLine[];
12
+ } | {
13
+ ok: false;
14
+ error: string;
15
+ };
16
+ /**
17
+ * Parse the "Inputs" box: one `label: value` per line, numbered 1, 2, 3 in the order written. Empty lines are ignored.
18
+ * This only checks the SHAPE — what a value must point at (line 1 an absolute repo, lines 2+ tracked files inside it)
19
+ * is proven by the panel at $0.
20
+ * @param {unknown} text
21
+ * @returns {{ok: true, inputs: JobInput[]}|{ok: false, error: string}}
22
+ */
23
+ export function parseInputs(text: unknown): {
24
+ ok: true;
25
+ inputs: JobInput[];
26
+ } | {
27
+ ok: false;
28
+ error: string;
29
+ };
30
+ /**
31
+ * The person's job lines as the drafter reads them (answer 1 of the interview): each numbered line, then its rule
32
+ * (the `~` lines joined) indented under it. One spelling, so the number the person typed beside a line is the number a
33
+ * stage's `fromLine` names.
34
+ * @param {JobLine[]} lines
35
+ * @returns {string}
36
+ */
37
+ export function renderJobLines(lines: JobLine[]): string;
38
+ /**
39
+ * The PASS:/FAIL: examples the person wrote, each kept with its line number (answer 2 of a rubric interview — what the
40
+ * calibration compile reads). Empty string when there are none.
41
+ * @param {JobLine[]} lines
42
+ * @returns {string}
43
+ */
44
+ export function renderExamples(lines: JobLine[]): string;
45
+ /**
46
+ * The inputs as the drafter is told about them: "the person pointed at these inputs: N label path".
47
+ * @param {JobInput[]} inputs
48
+ * @returns {string}
49
+ */
50
+ export function renderInputs(inputs: JobInput[]): string;
51
+ /**
52
+ * The two cross-checks between a parsed job block and the Check type: a RUBRIC job needs at least one `PASS:` and one
53
+ * `FAIL:` example (the calibration compile reads them); a DETERMINISTIC job has no judge, so an example line would be
54
+ * silently dropped — a red instead.
55
+ * @param {JobLine[]} lines
56
+ * @param {boolean} rubric
57
+ * @returns {string|null} the plain red, or null when the block fits the Check type
58
+ */
59
+ export function jobBlockFitsCheck(lines: JobLine[], rubric: boolean): string | null;
60
+ /**
61
+ * The signed `jobLines` field from parsed lines: the person's own words, `{n, text, rule, rules}` (examples stay inside the
62
+ * rule text, where the person wrote them). `rules` is the same `~` lines as an array, BESIDE the joined `rule` (never
63
+ * replacing it); it is omitted on a line with no `~` line, and an older spec lacks it entirely.
64
+ * @param {JobLine[]} lines
65
+ * @returns {{n: number, text: string, rule: string, rules?: string[]}[]}
66
+ */
67
+ export function signedJobLines(lines: JobLine[]): {
68
+ n: number;
69
+ text: string;
70
+ rule: string;
71
+ rules?: string[];
72
+ }[];
73
+ /** @typedef {{verdict: 'PASS'|'FAIL', text: string}} JobExample a `~ PASS:` / `~ FAIL:` line (rubric only), kept with its job line */
74
+ /** @typedef {{n: number, text: string, rule: string, rules: string[], examples: JobExample[]}} JobLine one numbered job line; `rule` = its `~` lines joined with '; ' ('' when none), `rules` = those same `~` lines one by one (so an example's own '; ' survives) */
75
+ /** @typedef {{n: number, label: string, value: string}} JobInput one numbered `label: value` input line */
76
+ /** the joiner for consecutive `~` lines (fwd's joinGuardrails) */
77
+ export const RULE_JOINER: "; ";
78
+ /**
79
+ * a `~ PASS:` / `~ FAIL:` line (rubric only), kept with its job line
80
+ */
81
+ export type JobExample = {
82
+ verdict: "PASS" | "FAIL";
83
+ text: string;
84
+ };
85
+ /**
86
+ * one numbered job line; `rule` = its `~` lines joined with '; ' ('' when none), `rules` = those same `~` lines one by one (so an example's own '; ' survives)
87
+ */
88
+ export type JobLine = {
89
+ n: number;
90
+ text: string;
91
+ rule: string;
92
+ rules: string[];
93
+ examples: JobExample[];
94
+ };
95
+ /**
96
+ * one numbered `label: value` input line
97
+ */
98
+ export type JobInput = {
99
+ n: number;
100
+ label: string;
101
+ value: string;
102
+ };
package/types/judged.d.ts CHANGED
@@ -97,6 +97,15 @@ export function resolveJobJudge(source: {
97
97
  provider: string;
98
98
  model: string;
99
99
  };
100
+ /**
101
+ * THE ONE ACCEPTANCE for "this quote points at the JSDoc block of this declaration":
102
+ * every non-empty line of `docQuote` is a line inside the block directly above the
103
+ * declaration. `has-doc`'s check and the calibration gate's injection facts check
104
+ * both call this, so the two can never disagree about what a good pointer is (F192).
105
+ * @param {string} text the artifact @param {string|null} declQuote @param {string} docQuote
106
+ * @returns {boolean}
107
+ */
108
+ export function docQuoteInBlock(text: string, declQuote: string | null, docQuote: string): boolean;
100
109
  /**
101
110
  * The rubric card: Q6's answer compiled into enumerated items, signed by the
102
111
  * person and enumerated in the spec hash. `rule` selects from `JUDGE_RULES`;
@@ -359,15 +368,25 @@ export const LOCATE_AXES: Readonly<{
359
368
  PROVIDER: "provider-red";
360
369
  ARTIFACT: "artifact-red";
361
370
  }>;
371
+ /**
372
+ * Function words ONLY: articles, prepositions, conjunctions. No judgement words
373
+ * ("returns", "gets", "function"): a description that adds one of those has added
374
+ * something, and deciding whether it is MEANINGFUL is exactly what this rule
375
+ * refuses to do.
376
+ */
377
+ export const SAYS_WHAT_STOPWORDS: readonly string[];
362
378
  /**
363
379
  * THE OWNED RULE TABLE. Frozen: the rulebook is the arbiter's, and a caller that
364
380
  * could add a rule at runtime would be authoring the arbiter.
365
- * @type {Readonly<Record<string, {id: string, ask: string, check: (fn: any, lines: Set<string>|null) => RuleRed[]}>>}
381
+ * `means` is the rule's plain-words reach: what it CAN check, and what it cannot. The case-proposal
382
+ * prompt renders it, so a proposed case never expects a red the rule cannot raise.
383
+ * @type {Readonly<Record<string, {id: string, means: string, ask: string, check: (fn: any, text: string|null) => RuleRed[]}>>}
366
384
  */
367
385
  export const JUDGE_RULES: Readonly<Record<string, {
368
386
  id: string;
387
+ means: string;
369
388
  ask: string;
370
- check: (fn: any, lines: Set<string> | null) => RuleRed[];
389
+ check: (fn: any, text: string | null) => RuleRed[];
371
390
  }>>;
372
391
  /** the enumerated set a card may name — handed over verbatim in every refusal */
373
392
  export const JUDGE_RULE_IDS: readonly string[];