bareloop 0.41.0 → 0.42.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 (47) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/README.md +13 -21
  3. package/bareloop.context.md +44 -4
  4. package/package.json +4 -3
  5. package/src/authorflow.js +337 -29
  6. package/src/authoring.js +92 -7
  7. package/src/authorjob.js +78 -16
  8. package/src/authorreadout.js +89 -5
  9. package/src/authorrun.js +14 -5
  10. package/src/authorscout.js +108 -0
  11. package/src/declaredclose.js +23 -12
  12. package/src/facts.js +317 -0
  13. package/src/factwords.js +129 -0
  14. package/src/inputlook.js +301 -0
  15. package/src/job.js +2 -1
  16. package/src/jobblock.js +7 -2
  17. package/src/kinds.js +84 -3
  18. package/src/labelscan.js +170 -0
  19. package/src/pagefetch.js +125 -0
  20. package/src/panel/authorroutes.js +15 -2
  21. package/src/panel/authorsession.js +99 -22
  22. package/src/panel/index.html +33 -7
  23. package/src/panel/jobplan.js +34 -11
  24. package/src/panel/server.js +19 -3
  25. package/src/planrun.js +3 -2
  26. package/src/rubricstep.js +804 -0
  27. package/src/source.js +166 -1
  28. package/src/u-readout.js +1 -1
  29. package/src/userrun.js +14 -2
  30. package/types/authorflow.d.ts +267 -13
  31. package/types/authoring.d.ts +29 -1
  32. package/types/authorjob.d.ts +7 -5
  33. package/types/authorreadout.d.ts +27 -2
  34. package/types/authorscout.d.ts +70 -0
  35. package/types/declaredclose.d.ts +4 -2
  36. package/types/facts.d.ts +71 -0
  37. package/types/factwords.d.ts +42 -0
  38. package/types/inputlook.d.ts +238 -0
  39. package/types/jobblock.d.ts +8 -1
  40. package/types/labelscan.d.ts +38 -0
  41. package/types/pagefetch.d.ts +71 -0
  42. package/types/panel/authorsession.d.ts +18 -2
  43. package/types/panel/jobplan.d.ts +12 -4
  44. package/types/panel/server.d.ts +4 -2
  45. package/types/rubricstep.d.ts +286 -0
  46. package/types/source.d.ts +94 -0
  47. package/types/userrun.d.ts +11 -0
@@ -64,6 +64,15 @@ export function classMenu(verdictType: string | null, catalogue?: Record<string,
64
64
  * @param {string} kind @param {Record<string, KindSpec>} [catalogue]
65
65
  */
66
66
  export function envCapableKind(kind: string, catalogue?: Record<string, KindSpec>): boolean;
67
+ /**
68
+ * The catalogue a close of this language may use. A rubric job on local files (`RUBRIC_LANG`) sees only
69
+ * {@link RUBRIC_LANG_KINDS}; every code language sees the whole catalogue MINUS the rubric-only kinds, so a code job's
70
+ * composer, schema and validator can never reach for a stage that reads step files. One filter, both directions.
71
+ * @param {string|null|undefined} lang
72
+ * @param {Record<string, KindSpec>} [catalogue]
73
+ * @returns {Record<string, KindSpec>}
74
+ */
75
+ export function catalogueForLang(lang: string | null | undefined, catalogue?: Record<string, KindSpec>): Record<string, KindSpec>;
67
76
  /**
68
77
  * The floor's decision for one declared `cmd`, as a reason or null.
69
78
  *
@@ -80,6 +89,8 @@ export function envCapableKind(kind: string, catalogue?: Record<string, KindSpec
80
89
  * @param {string} cmd @returns {string|null}
81
90
  */
82
91
  export function deniedCommandReason(cmd: string): string | null;
92
+ /** @param {unknown} lang @returns {string} the genre a close of this language is authored under */
93
+ export function genreForLang(lang: unknown): string;
83
94
  /**
84
95
  * The warning line for a job whose ACTUAL stages carry the js `any` pattern, else
85
96
  * ''. Derived from the stages' patterns (never goal prose), so a job without the
@@ -274,7 +285,8 @@ export function judgedOutsideFence(paths: unknown, writeScope: string[] | null |
274
285
  * @param {{catalogue?: Record<string, KindSpec>, listing?: string[]|null,
275
286
  * guards?: {name: string, kind: string, params: Record<string, any>, fill: string[]}[]|null,
276
287
  * envOwned?: string[]|null, envInjected?: Record<string, string>|null, deferListing?: boolean,
277
- * verdictType?: string|null, writeScope?: string[]|null, jobLines?: {n: number}[]|null}} [opts]
288
+ * verdictType?: string|null, writeScope?: string[]|null, jobLines?: {n: number}[]|null, inputLabels?: string[]|null}} [opts]
289
+ * `inputLabels` — the labels of the person's inputs (Part 1a). Present, a rubric-step `cited` part must name one of them.
278
290
  * `jobLines` — the person's numbered job lines (P7). Present, every stage must name the line it serves and every
279
291
  * line needs a stage or a refusal ({@link checkJobLines}); absent (every spec that predates the job block), the
280
292
  * rule is not run.
@@ -310,6 +322,7 @@ export function validateDeclaration(declaration: any, opts?: {
310
322
  jobLines?: {
311
323
  n: number;
312
324
  }[] | null;
325
+ inputLabels?: string[] | null;
313
326
  }): {
314
327
  ok: boolean;
315
328
  reds: Red[];
@@ -482,6 +495,21 @@ export const DENIED_COMMANDS: readonly string[];
482
495
  */
483
496
  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.";
484
497
  export const GENRE_LANGUAGES: readonly string[];
498
+ /**
499
+ * PART 1a: the "language" of a RUBRIC job on local text files. It is not a code language and carries no suppression
500
+ * battery, no environment and no instruments — it only lets such a close declare which genre-shaped guards apply to it
501
+ * (`classGuards`) without pretending the file is JavaScript. `GENRE_LANGUAGES` stays the code-language menu (it is what a
502
+ * repo job's language detection and the confirm turn offer); this is the one extra value a close may DECLARE.
503
+ */
504
+ export const RUBRIC_LANG: "text";
505
+ /** the genre label a close over local text files carries (`closeDecl.genre`); the code languages' is `TYPES_GENRE.name`. Never the other's. */
506
+ export const TEXT_GENRE: "TEXT";
507
+ /** every `closeDecl.lang` a close may declare: the code languages plus the rubric-files one */
508
+ export const DECLARABLE_LANGUAGES: readonly string[];
509
+ /** the kinds that exist only for a rubric job on local files — a code job's menu, schema and validator never offer them */
510
+ export const RUBRIC_ONLY_KINDS: readonly string[];
511
+ /** the whole kind menu of a rubric job on local files: the one machine guard that applies to a file tree, plus its own stage */
512
+ export const RUBRIC_LANG_KINDS: readonly string[];
485
513
  /** The worker-facing line that rides with the js `any` guard (run mv13ery3). */
486
514
  export const ANY_SUPPRESSION_WARNING: string;
487
515
  /**
@@ -30,18 +30,19 @@ export function refusalEvents(refusal: Refusal): {
30
30
  * makes between a locked verdict and an invalid one).
31
31
  *
32
32
  * @param {{answers: Record<string|number, any>, verdictType?: string|null,
33
- * repoPath?: string|null, questions?: Record<string|number, string>|null}} o
34
- * `verdictType` and `repoPath` are STRUCTURED input from the UI, never parsed
33
+ * repoPath?: string|null, questions?: Record<string|number, string>|null, required?: (string|number)[]|null}} o
34
+ * `required` — the answer keys that must be present; absent = the picked class's whole set. `verdictType` and `repoPath` are STRUCTURED input from the UI, never parsed
35
35
  * out of the prose of an answer: a class is picked off a radio and a path is
36
36
  * read off the machine, or neither exists.
37
37
  * @returns {{ok: boolean, answers: Record<string|number, string>,
38
38
  * verdictType: string|null, repoPath: string|null, refusal: Refusal|null, reds: Red[]}}
39
39
  */
40
- export function runInterview({ answers, verdictType, repoPath, questions }: {
40
+ export function runInterview({ answers, verdictType, repoPath, questions, required: requiredOverride }: {
41
41
  answers: Record<string | number, any>;
42
42
  verdictType?: string | null;
43
43
  repoPath?: string | null;
44
44
  questions?: Record<string | number, string> | null;
45
+ required?: (string | number)[] | null;
45
46
  }): {
46
47
  ok: boolean;
47
48
  answers: Record<string | number, string>;
@@ -86,7 +87,7 @@ export function refuseLockedKind(kind: string): Refusal;
86
87
  * rates?: {in: number, out: number}|null, draftThinking?: 'on'|'off',
87
88
  * onPhase?: (phase: string, data?: any) => void,
88
89
  * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number, thinkingStatus?: string}) => void,
89
- * seedFn?: Function, scoutFn?: Function, listingFn?: Function,
90
+ * seedFn?: Function, scoutFn?: Function, listingFn?: Function, lookFn?: Function|null,
90
91
  * authorFn?: Function, authorOpts?: object, writeScope?: string[]|null,
91
92
  * signerFix?: Function|any, proposeFn?: Function, compileOpts?: object,
92
93
  * ask?: ((step: {kind: string, [k: string]: any}) => Promise<string|null>)|null,
@@ -98,7 +99,7 @@ export function refuseLockedKind(kind: string): Refusal;
98
99
  * closeDecl: any, seedRef: string|null, authoring: any, judged: any, reds: Red[],
99
100
  * stop: string|null, cost: any, interview: any, confirmed: any}>}
100
101
  */
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, }: {
102
+ 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, lookFn, authorFn, authorOpts, signerFix, proposeFn, compileOpts, ask, confirmGenerate, isRepo, langResult, answerQuestions, }: {
102
103
  answers: Record<string | number, any>;
103
104
  repoPath?: string | null;
104
105
  lang: string;
@@ -135,6 +136,7 @@ export function authorCloseForJob({ answers, repoPath, lang, verdictType, questi
135
136
  seedFn?: Function;
136
137
  scoutFn?: Function;
137
138
  listingFn?: Function;
139
+ lookFn?: Function | null;
138
140
  authorFn?: Function;
139
141
  authorOpts?: object;
140
142
  writeScope?: string[] | null;
@@ -199,6 +199,29 @@ export function plainKinds(): string[];
199
199
  export function plainReasons(reds: PlainRed[], { cases }?: {
200
200
  cases?: any;
201
201
  }): PlainReason[];
202
+ /**
203
+ * WHY one drafting try was refused, in the code's own words: the unique `detail` of each red it raised (the same sentences
204
+ * `draftStopText` quotes at a stop), else the plain `reason` the loop gave (a seed-read failure raises no red). Scrubbed,
205
+ * one line, bounded; never empty.
206
+ * @param {{reds?: PlainRed[]|null, reason?: string|null}} o
207
+ * @returns {string}
208
+ */
209
+ export function tryRefusedText({ reds, reason }: {
210
+ reds?: PlainRed[] | null;
211
+ reason?: string | null;
212
+ }): string;
213
+ /**
214
+ * A refused declaration as the drafting log keeps it (live fix A3), so a failed draft can be read and replayed at $0: the declaration
215
+ * itself, every secret masked as everywhere else (the JSON text goes through `redactSecrets`, then parses back), and bounded.
216
+ * @param {unknown} declaration
217
+ * @returns {{declaration: unknown}|{declarationText: string, declarationCut: true}|{}} nothing when there is no declaration
218
+ */
219
+ export function declarationRecord(declaration: unknown): {
220
+ declaration: unknown;
221
+ } | {
222
+ declarationText: string;
223
+ declarationCut: true;
224
+ } | {};
202
225
  /**
203
226
  * THE MESSAGE a person reads when the rubric proposal was refused. Both doors
204
227
  * (the panel's failed step and the CLI) print exactly this.
@@ -218,10 +241,11 @@ export function proposalStopText({ stop, reds, cases, spend, source }: {
218
241
  }): string;
219
242
  /**
220
243
  * @param {{stop: string, reds?: PlainRed[]|null, refusal?: {detail?: string}|null,
221
- * spend?: {knownUsd?: number|null, spendComplete?: boolean|null}|null}} o
244
+ * spend?: {knownUsd?: number|null, spendComplete?: boolean|null}|null, wholeJob?: boolean}} o `wholeJob` - a rubric job on the person's
245
+ * own inputs (PART 1c, I1): a failed draft asks nothing piecemeal; the person reviews the whole job and submits it again
222
246
  * @returns {string}
223
247
  */
224
- export function draftStopText({ stop, reds, refusal, spend }: {
248
+ export function draftStopText({ stop, reds, refusal, spend, wholeJob }: {
225
249
  stop: string;
226
250
  reds?: PlainRed[] | null;
227
251
  refusal?: {
@@ -231,6 +255,7 @@ export function draftStopText({ stop, reds, refusal, spend }: {
231
255
  knownUsd?: number | null;
232
256
  spendComplete?: boolean | null;
233
257
  } | null;
258
+ wholeJob?: boolean;
234
259
  }): string;
235
260
  /**
236
261
  * Plain sentences for the reds of a refused signing, one or more per red. Card and practice-case reds reuse the
@@ -147,6 +147,72 @@ export function runAuthorScout({ workdir, provider, rounds, minBytes, blobMax, m
147
147
  }[];
148
148
  budgetStop: "cap-halt" | "pricing-red" | null;
149
149
  }>;
150
+ /**
151
+ * Run the look. `createLoop` is the same seam the repo scout has; nothing else here needs a live process.
152
+ * @param {{texts: Record<string, string>, inputs: {n: number, label: string}[], jobLines: {n: number, text: string, rule?: string, rules?: string[]}[],
153
+ * provider?: any, rounds?: number, maxTokens?: number, ceilingUsd?: number|null, callTimeoutMs?: number,
154
+ * onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number, thinkingStatus?: string}) => void,
155
+ * createLoop?: (o: {system: string, policy: any, onLlmResult: any, provider: any, rates?: {in: number, out: number}}) => any,
156
+ * rates?: {in: number, out: number}|null, callOptions?: Record<string, any>,
157
+ * prove?: (source: string, phrase: string) => number}} o
158
+ * @returns {Promise<{state: 'PRESENT'|'ABSENT', facts: any, reason: string|null, cause: string|null, meta: any, raw: string,
159
+ * raws: ReturnType<typeof scrubRaw>[], calls: {label: string, costUsd: number|null, unpricedRounds: number}[],
160
+ * budgetStop: 'cap-halt'|'pricing-red'|null}>}
161
+ */
162
+ export function runInputLook({ texts, inputs, jobLines, provider, rounds, maxTokens, ceilingUsd, callTimeoutMs, onCall, createLoop, rates, callOptions, prove, }: {
163
+ texts: Record<string, string>;
164
+ inputs: {
165
+ n: number;
166
+ label: string;
167
+ }[];
168
+ jobLines: {
169
+ n: number;
170
+ text: string;
171
+ rule?: string;
172
+ rules?: string[];
173
+ }[];
174
+ provider?: any;
175
+ rounds?: number;
176
+ maxTokens?: number;
177
+ ceilingUsd?: number | null;
178
+ callTimeoutMs?: number;
179
+ onCall?: (call: {
180
+ label: string;
181
+ costUsd: number | null;
182
+ unpricedRounds: number;
183
+ thinkingStatus?: string;
184
+ }) => void;
185
+ createLoop?: (o: {
186
+ system: string;
187
+ policy: any;
188
+ onLlmResult: any;
189
+ provider: any;
190
+ rates?: {
191
+ in: number;
192
+ out: number;
193
+ };
194
+ }) => any;
195
+ rates?: {
196
+ in: number;
197
+ out: number;
198
+ } | null;
199
+ callOptions?: Record<string, any>;
200
+ prove?: (source: string, phrase: string) => number;
201
+ }): Promise<{
202
+ state: "PRESENT" | "ABSENT";
203
+ facts: any;
204
+ reason: string | null;
205
+ cause: string | null;
206
+ meta: any;
207
+ raw: string;
208
+ raws: ReturnType<typeof scrubRaw>[];
209
+ calls: {
210
+ label: string;
211
+ costUsd: number | null;
212
+ unpricedRounds: number;
213
+ }[];
214
+ budgetStop: "cap-halt" | "pricing-red" | null;
215
+ }>;
150
216
  /**
151
217
  * `git ls-tree -r --name-only <seed>` — the files as of the SEED COMMIT.
152
218
  * Deliberately NOT `ls-files`, which reads the index and the working tree: this
@@ -336,6 +402,10 @@ export const SCOUT_SYSTEM: string;
336
402
  * produce) — never by asking politely in prose (F19/F37).
337
403
  */
338
404
  export const SCOUT_RECOVERY_PROMPT: string;
405
+ /** the look's hard round bound */
406
+ export const LOOK_ROUNDS: 8;
407
+ export const LOOK_SYSTEM: string;
408
+ export const LOOK_RECOVERY_PROMPT: "You are out of looking turns. Report NOW, from what you have already read: call the report tool once with everything you can check and everything you could not find.";
339
409
  /** per-path full-listing cap; over it, names give way to counted directories */
340
410
  export const LIST_CAP: 40;
341
411
  /** whole-block ceiling — the block is a prompt ingredient, like the survey */
@@ -53,7 +53,8 @@ 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, writeScope?: string[]|null, jobLines?: {n: number}[]|null}} [opts]
56
+ * catalogue?: Record<string, any>, verdictType?: string|null, writeScope?: string[]|null, jobLines?: {n: number}[]|null,
57
+ * inputLabels?: string[]|null}} [opts]
57
58
  * @returns {{ok: boolean, reds: Red[], closeDecl: any, grounded: boolean,
58
59
  * scoped: {scoped: boolean, via: string|null},
59
60
  * ceiling: {class: string, kind: string, stage: string|null, locked: boolean}|null}}
@@ -68,6 +69,7 @@ export function validateCloseDecl(closeDecl: any, opts?: {
68
69
  jobLines?: {
69
70
  n: number;
70
71
  }[] | null;
72
+ inputLabels?: string[] | null;
71
73
  }): {
72
74
  ok: boolean;
73
75
  reds: Red[];
@@ -162,7 +164,7 @@ export function closeGrade(v: any): {
162
164
  /** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
163
165
  /** The genres a `closeDecl` may name. v1 admits exactly one (D13) — a genre
164
166
  * classifier is designed the day there is a second genre to classify. */
165
- export const DECLARED_GENRES: readonly "TYPES"[];
167
+ export const DECLARED_GENRES: readonly string[];
166
168
  /**
167
169
  * The exact field set of a `closeDecl` — anything else is a smuggle channel, the
168
170
  * same rule `STAGE_FIELDS` enforces on a command stage.
@@ -0,0 +1,71 @@
1
+ /** the `fact` part of a step's parameters, or null (a step has at most one) @param {any} params @returns {any|null} */
2
+ export function factPartOf(params: any): any | null;
3
+ /**
4
+ * The SHAPE of a `fact` part (what it may carry), pushed as reds in the same form `rubricStepShapeReds` uses. Whether the
5
+ * bareguard rubric it builds is signable is asked of bareguard itself (`checkRubricParts` builds it once at drafting).
6
+ * @param {any} part @param {string} w the path prefix @param {(code: string, path: string, detail: string) => void} red
7
+ */
8
+ export function factShapeReds(part: any, w: string, red: (code: string, path: string, detail: string) => void): void;
9
+ /**
10
+ * bareguard's `decides` list for a fact part: one decide per fact, in the fact order (so `d<j>` is the fact's own index).
11
+ * @param {any} part @returns {Record<string, any>[]}
12
+ */
13
+ export function factDecides(part: any): Record<string, any>[];
14
+ /**
15
+ * The claims bareguard reads for a fact step, built from the step file's `results`. The claim TEXT is written here, by code,
16
+ * from the values the worker gave (the worker writes no claim text): `name: value; name: value`. A phrase fact contributes its
17
+ * own signed words. A result that is not an object, or has no string quote, still becomes a claim — an empty one — so
18
+ * bareguard reds it by name rather than the result vanishing.
19
+ * @param {any} part @param {unknown} results @returns {{claim: string, quote: string, values?: Record<string, string>}[]}
20
+ */
21
+ export function factClaims(part: any, results: unknown): {
22
+ claim: string;
23
+ quote: string;
24
+ values?: Record<string, string>;
25
+ }[];
26
+ /**
27
+ * One fact as a plain row, written by code from the signed fields:
28
+ * `fact · price — money, at most 450 US dollars, after "Price", quoted from "Flights"`.
29
+ * @param {any} f @param {string} source
30
+ * @returns {string}
31
+ */
32
+ export function factSentence(f: any, source: string): string;
33
+ /**
34
+ * One fact as the WORKER is told it (item 7): what to write for it and where in the quote it sits, in plain words, from the signed
35
+ * fields. A phrase fact has no value to write — the quote has to say it.
36
+ * @param {any} f @returns {string}
37
+ */
38
+ export function factBrief(f: any): string;
39
+ /** the "N results" row of a fact part, or null @param {any} part @returns {string|null} */
40
+ export function countSentence(part: any): string | null;
41
+ /**
42
+ * Every plan-card row a fact part carries: its facts, then its count.
43
+ * @param {any} part @returns {string[]}
44
+ */
45
+ export function factRows(part: any): string[];
46
+ /**
47
+ * One bareguard `cited` item (`#<result>:d<j>:<reason>[:<detail>]`, or `#<result>:<reason>`) as a sentence the worker can act
48
+ * on. The names and numbers are bareguard's measurements and the person's signed facts, never inferred here.
49
+ * @param {string} item @param {any} part @returns {string}
50
+ */
51
+ export function plainFactItem(item: string, part: any): string;
52
+ /**
53
+ * The fields each fact shape takes, in the fact part's own names (`rule` = bareguard's op/value/lo/hi; `unit`/`currency`; `phrase`
54
+ * = the presence decide's phrases), read off bareguard's rubric vocabulary.
55
+ * @returns {Record<string, string[]>} shape -> the fields it takes besides name and shape
56
+ */
57
+ export function factShapeFields(): Record<string, string[]>;
58
+ /**
59
+ * The lines the drafter is shown about which shape takes which fields, generated from {@link factShapeFields} (shapes with the same
60
+ * fields are listed together). One owner: the composer brief and the confirm note both print this.
61
+ * @returns {string}
62
+ */
63
+ export function factShapeGuide(): string;
64
+ /** the shapes a fact may have (bareguard's value kinds, plus `phrase` = a presence decide) */
65
+ export const FACT_SHAPES: readonly string[];
66
+ /** the comparison ops a rule may use (bareguard's) */
67
+ export const FACT_OPS: readonly string[];
68
+ /** bareguard signs at most this many decides on one `cited` check */
69
+ export const MAX_FACTS: 10;
70
+ /** every field a part of class `fact` may carry (the shared ones are checked by rubricStepShapeReds) */
71
+ export const FACT_PART_FIELDS: readonly string[];
@@ -0,0 +1,42 @@
1
+ /**
2
+ * How many times exact words occur in a source, white space blind. Zero for empty words.
3
+ * @param {string} source the raw source text @param {string} words
4
+ * @returns {number}
5
+ */
6
+ export function countExact(source: string, words: string): number;
7
+ /**
8
+ * How many times a phrase or unit occurs as WHOLE words, case and spacing aside ("SFO" is not found inside "sfocus").
9
+ * @param {string} source @param {string} words @returns {number}
10
+ */
11
+ export function countPhrase(source: string, words: string): number;
12
+ /**
13
+ * The reds for ONE fact part against its frozen source text.
14
+ * @param {{part: any, text: string, line: number|string, scan?: import('./labelscan.js').LabelScan}} o
15
+ * @returns {{code: string, detail: string}[]}
16
+ */
17
+ export function checkFactWords({ part, text, line, scan }: {
18
+ part: any;
19
+ text: string;
20
+ line: number | string;
21
+ scan?: import("./labelscan.js").LabelScan;
22
+ }): {
23
+ code: string;
24
+ detail: string;
25
+ }[];
26
+ /**
27
+ * The reds for every fact part of a declaration. A fact part whose input text is not at hand is a red: a check whose words were never
28
+ * proved against the source is never signed.
29
+ * @param {any} declaration @param {Record<string, string>|null} texts label -> frozen text
30
+ * @returns {{code: string, path: string, detail: string}[]}
31
+ */
32
+ export function checkDeclarationWords(declaration: any, texts: Record<string, string> | null): {
33
+ code: string;
34
+ path: string;
35
+ detail: string;
36
+ }[];
37
+ /**
38
+ * The look's own proof hook: how often a phrase the look built is in an input.
39
+ * @param {Record<string, string>} texts @returns {(source: string, phrase: string) => number}
40
+ */
41
+ export function proverOf(texts: Record<string, string>): (source: string, phrase: string) => number;
42
+ export function squash(t: string): string;
@@ -0,0 +1,238 @@
1
+ /**
2
+ * The input as the AI sees it: lines with any run of white space (U+202F included) made one space and the page reader's bracketed tags
3
+ * (`[ref=549]`) removed - an id that is only the page reader's, never part of a label.
4
+ * @param {string} text @returns {string[]}
5
+ */
6
+ export function lookLines(text: string): string[];
7
+ /**
8
+ * The two read-only tools: search the input text, read a slice around a hit. They are closures over in-memory text and touch nothing
9
+ * else - read-only BY CONSTRUCTION, not by a fence. Several inputs: the `input` argument names which (its label).
10
+ * @param {Record<string, string>} texts label -> frozen text
11
+ * @returns {{name: string, description: string, parameters: any, execute: (a: any) => Promise<any>}[]}
12
+ */
13
+ export function lookReadTools(texts: Record<string, string>): {
14
+ name: string;
15
+ description: string;
16
+ parameters: any;
17
+ execute: (a: any) => Promise<any>;
18
+ }[];
19
+ /** the strict answer form (a JSON schema - never free prose with JSON inside) */
20
+ export function lookReportSchema(): {
21
+ type: string;
22
+ additionalProperties: boolean;
23
+ required: string[];
24
+ properties: {
25
+ facts: {
26
+ type: string;
27
+ items: {
28
+ type: string;
29
+ additionalProperties: boolean;
30
+ required: string[];
31
+ properties: {
32
+ line: {
33
+ type: string;
34
+ minimum: number;
35
+ description: string;
36
+ };
37
+ name: {
38
+ type: string;
39
+ minLength: number;
40
+ description: string;
41
+ };
42
+ shape: {
43
+ enum: string[];
44
+ };
45
+ source: {
46
+ type: string;
47
+ minLength: number;
48
+ description: string;
49
+ };
50
+ label: {
51
+ type: string;
52
+ description: string;
53
+ };
54
+ value: {
55
+ type: string;
56
+ description: string;
57
+ };
58
+ example: {
59
+ type: string;
60
+ description: string;
61
+ };
62
+ rule: {
63
+ type: string;
64
+ additionalProperties: boolean;
65
+ required: string[];
66
+ properties: {
67
+ op: {
68
+ enum: string[];
69
+ };
70
+ value: {};
71
+ lo: {};
72
+ hi: {};
73
+ };
74
+ description: string;
75
+ };
76
+ aiProposal: {
77
+ type: string;
78
+ description: string;
79
+ };
80
+ forRule: {
81
+ type: string;
82
+ minimum: number;
83
+ description: string;
84
+ };
85
+ };
86
+ };
87
+ };
88
+ prose: {
89
+ type: string;
90
+ description: string;
91
+ items: {
92
+ type: string;
93
+ additionalProperties: boolean;
94
+ required: string[];
95
+ properties: {
96
+ line: {
97
+ type: string;
98
+ minimum: number;
99
+ };
100
+ text: {
101
+ type: string;
102
+ };
103
+ };
104
+ };
105
+ };
106
+ notFound: {
107
+ type: string;
108
+ description: string;
109
+ items: {
110
+ type: string;
111
+ additionalProperties: boolean;
112
+ required: string[];
113
+ properties: {
114
+ line: {
115
+ type: string;
116
+ minimum: number;
117
+ };
118
+ rule: {
119
+ type: string;
120
+ minimum: number;
121
+ description: string;
122
+ };
123
+ words: {
124
+ type: string;
125
+ description: string;
126
+ };
127
+ why: {
128
+ type: string;
129
+ minLength: number;
130
+ };
131
+ };
132
+ };
133
+ };
134
+ };
135
+ };
136
+ /**
137
+ * What the AI is told: the numbered job, the inputs and their label lists, and what to do.
138
+ * @param {{jobLines: {n: number, text: string, rule?: string, rules?: string[]}[], labels: string[], lists: Record<string, string>}} o
139
+ * @returns {string}
140
+ */
141
+ export function lookPrompt({ jobLines, labels, lists }: {
142
+ jobLines: {
143
+ n: number;
144
+ text: string;
145
+ rule?: string;
146
+ rules?: string[];
147
+ }[];
148
+ labels: string[];
149
+ lists: Record<string, string>;
150
+ }): string;
151
+ /**
152
+ * Turn the AI's raw report into a VERIFIED one, by code, at $0. A fact is carried only when: its shape is a real shape, its source is
153
+ * a real input, and its label is ON THE LIST for that input and shape (an id is resolved to its exact words). Anything else is moved
154
+ * to `notFound` with a plain reason naming the word - never dropped silently. `prove` is the "found in the source" test of the
155
+ * phrase a phrase fact builds (label + value), supplied by the caller.
156
+ * @param {unknown} raw
157
+ * @param {{scans: Record<string, import('./labelscan.js').LabelScan>, jobLines: {n: number}[], prove?: (source: string, phrase: string) => number}} o
158
+ * @returns {LookReport}
159
+ */
160
+ export function verifyLookReport(raw: unknown, { scans, jobLines, prove }: {
161
+ scans: Record<string, import("./labelscan.js").LabelScan>;
162
+ jobLines: {
163
+ n: number;
164
+ }[];
165
+ prove?: (source: string, phrase: string) => number;
166
+ }): LookReport;
167
+ /**
168
+ * The look's report as the DRAFTER reads it: one block, per job line, of what can be checked (with the exact words to copy) and what
169
+ * could not be found. Written by code from the verified report.
170
+ * @param {LookReport} report @returns {string}
171
+ */
172
+ export function renderLookReport(report: LookReport): string;
173
+ /**
174
+ * The label scans and the rendered lists for the inputs the look will read.
175
+ * @param {Record<string, string>} texts
176
+ * @returns {{scans: Record<string, import('./labelscan.js').LabelScan>, lists: Record<string, string>}}
177
+ */
178
+ export function labelListsOf(texts: Record<string, string>): {
179
+ scans: Record<string, import("./labelscan.js").LabelScan>;
180
+ lists: Record<string, string>;
181
+ };
182
+ /**
183
+ * L3: a reason the AI gave, cut only at a sentence end (never mid-sentence): whole sentences while they fit in `max` characters,
184
+ * and nothing at all if the first one alone does not fit. A trailing full stop is dropped (the caller closes the clause).
185
+ * @param {string} text @param {number} max @returns {string}
186
+ */
187
+ export function wholeSentences(text: string, max: number): string;
188
+ /**
189
+ * I1 (hamr, 2026-10-13, "Ruled by hamr" 2): when the look shows the person's intent on one `~` rule was NOT captured - its words or
190
+ * meaning are not in the source - the person is asked about THAT rule at once, named by its line and rule. Only a look entry that names
191
+ * a rule number counts; anything else the look could not find is not asked piecemeal (it is Not checked, or the whole job is reviewed).
192
+ * The wording is the code's own, never the model's. The keep-or-drop and the cap are `normalizeQuestions` (src/authorflow.js).
193
+ * @param {LookNotFound[]} notFound @param {{n: number, text?: string, rule?: string, rules?: string[]}[]} jobLines
194
+ * @returns {{line: number, question: string}[]} every candidate question (the caller applies the machine's caps)
195
+ */
196
+ export function ruleQuestions(notFound: LookNotFound[], jobLines: {
197
+ n: number;
198
+ text?: string;
199
+ rule?: string;
200
+ rules?: string[];
201
+ }[]): {
202
+ line: number;
203
+ question: string;
204
+ }[];
205
+ /** the name of the answer tool - the one place the AI's report enters */
206
+ export const LOOK_REPORT_TOOL: "report_look";
207
+ /** how many hits one search returns at most, and how long a snippet or a read line is */
208
+ export const LOOK_MAX_HITS: 40;
209
+ export { LABEL_SHAPES };
210
+ export type LookFact = {
211
+ line: number;
212
+ name: string;
213
+ shape: string;
214
+ source: string;
215
+ label?: string;
216
+ labelId?: string;
217
+ value?: string;
218
+ phrase?: string;
219
+ example: string;
220
+ rule?: any;
221
+ aiProposal?: boolean;
222
+ forRule?: number;
223
+ };
224
+ export type LookNotFound = {
225
+ line: number;
226
+ rule?: number;
227
+ words?: string;
228
+ why: string;
229
+ };
230
+ export type LookReport = {
231
+ facts: LookFact[];
232
+ prose: {
233
+ line: number;
234
+ text?: string;
235
+ }[];
236
+ notFound: LookNotFound[];
237
+ };
238
+ import { LABEL_SHAPES } from './labelscan.js';
@@ -52,11 +52,18 @@ export function renderInputs(inputs: JobInput[]): string;
52
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
53
  * `FAIL:` example (the calibration compile reads them); a DETERMINISTIC job has no judge, so an example line would be
54
54
  * silently dropped — a red instead.
55
+ * PART 1a (hamr's ruling P1=B, docs/product/ITEM33-BUILD.md "Addendum 2026-10-12"): the examples are required of a rubric
56
+ * job ONLY when it holds a judged part. A rubric job on the person's own local files holds none in this build (its
57
+ * parts are counted or checked against a quote), so the caller says `judged: false` and a block without examples fits.
58
+ * Examples written anyway are never a red there — they simply have no judge to read them yet.
55
59
  * @param {JobLine[]} lines
56
60
  * @param {boolean} rubric
61
+ * @param {{judged?: boolean}} [o] `judged` (default true): does this job hold a judged part, so that it needs examples?
57
62
  * @returns {string|null} the plain red, or null when the block fits the Check type
58
63
  */
59
- export function jobBlockFitsCheck(lines: JobLine[], rubric: boolean): string | null;
64
+ export function jobBlockFitsCheck(lines: JobLine[], rubric: boolean, { judged }?: {
65
+ judged?: boolean;
66
+ }): string | null;
60
67
  /**
61
68
  * The signed `jobLines` field from parsed lines: the person's own words, `{n, text, rule, rules}` (examples stay inside the
62
69
  * rule text, where the person wrote them). `rules` is the same `~` lines as an array, BESIDE the joined `rule` (never