bareloop 0.25.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +303 -0
- package/bareloop.context.md +268 -83
- package/package.json +1 -1
- package/src/authorflow.js +713 -92
- package/src/authoring.js +33 -15
- package/src/authorjob.js +158 -5
- package/src/cardauthor.js +28 -18
- package/src/detectlang.js +200 -0
- package/src/index.js +25 -29
- package/src/job.js +3 -2
- package/src/promptregisters.js +6 -0
- package/src/providers.js +15 -3
- package/src/source.js +153 -33
- package/types/authorflow.d.ts +433 -104
- package/types/authoring.d.ts +23 -8
- package/types/authorjob.d.ts +22 -4
- package/types/cardauthor.d.ts +7 -3
- package/types/detectlang.d.ts +38 -0
- package/types/index.d.ts +15 -15
- package/types/job.d.ts +3 -2
- package/types/providers.d.ts +9 -2
- package/types/source.d.ts +42 -0
package/types/authorflow.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** @param {boolean} isRepo @returns {typeof DESTINATION_FIELD_REPO} */
|
|
2
|
+
export function destinationFieldFor(isRepo: boolean): typeof DESTINATION_FIELD_REPO;
|
|
1
3
|
/** The frozen question set for a picked class. Throws on a locked or unknown
|
|
2
4
|
* one: reaching here with either means admission did not refuse, which is a
|
|
3
5
|
* bareloop bug, and failing loudly beats interviewing for a class we cannot run.
|
|
@@ -6,6 +8,32 @@ export function questionsFor(verdictType: string): any;
|
|
|
6
8
|
/** The question numbers whose answer must be present for that class's interview
|
|
7
9
|
* to be finished. @param {string} verdictType @returns {number[]} */
|
|
8
10
|
export function requiredAnswersFor(verdictType: string): number[];
|
|
11
|
+
/** The signed table's label for each of that class's question keys (PRD item
|
|
12
|
+
* 33's "The intake form (RULED)" ruling) — a key with no table row (hitl's own
|
|
13
|
+
* fourth) is simply absent, never a fabricated label. Throws on the same locked
|
|
14
|
+
* or unknown class {@link questionsFor} does, for the same reason.
|
|
15
|
+
* @param {string} verdictType @returns {Record<string|number, string>} */
|
|
16
|
+
export function labelsFor(verdictType: string): Record<string | number, string>;
|
|
17
|
+
/**
|
|
18
|
+
* THE REAL PROTECTIONS a person is shown, and what {@link runConfirmTurn}
|
|
19
|
+
* records as `accepted.protections` — fixes finding #1 from live run
|
|
20
|
+
* mu0voeo4 (2026-09-14): the confirm turn used to show whatever prose the
|
|
21
|
+
* MODEL invented for `protections`, and that run's model invented a
|
|
22
|
+
* "behavior-preservation guard" this build cannot check — no kind in the
|
|
23
|
+
* catalogue can verify runtime behaviour, and the author call's own note
|
|
24
|
+
* elsewhere says outright that behaviour-preservation is not composed here.
|
|
25
|
+
* This reads the SAME guards `classGuards` will actually compose into the
|
|
26
|
+
* close — one source, never a second hand-typed list — rendered through the
|
|
27
|
+
* frozen line in {@link GUARD_DESCRIPTIONS}, plus the write fence (a real,
|
|
28
|
+
* signed fence — {@link writeScopeBlock}'s own subject) when one is set.
|
|
29
|
+
* @param {{verdictType: string, lang: string, writeScope?: string[]|null}} o
|
|
30
|
+
* @returns {string[]}
|
|
31
|
+
*/
|
|
32
|
+
export function confirmProtections({ verdictType, lang, writeScope }: {
|
|
33
|
+
verdictType: string;
|
|
34
|
+
lang: string;
|
|
35
|
+
writeScope?: string[] | null;
|
|
36
|
+
}): string[];
|
|
9
37
|
/**
|
|
10
38
|
* The mechanical seam between the catalogue and the schema, read BOTH ways: a
|
|
11
39
|
* catalogue parameter with no schema would be silently undeclarable, and a schema
|
|
@@ -196,6 +224,44 @@ export function catalogueBlock(catalogue?: Record<string, any>, { verdictType }?
|
|
|
196
224
|
export function instrumentsBlock(lang: string): string;
|
|
197
225
|
/** The three laws. Stated to the author; enforced, where checkable, by M2. */
|
|
198
226
|
export function lawsBlock(): string;
|
|
227
|
+
/**
|
|
228
|
+
* WHAT MAY CHANGE, AND WHAT IS ONLY READ — replaces the old Q2 (PRD item 33 M3
|
|
229
|
+
* piece 3). Q2 used to ask the person, in prose, which files change and which
|
|
230
|
+
* are read-only; that decision is now Destination, PROVEN against the
|
|
231
|
+
* repository rather than typed (`docs/product/ITEM33-BUILD.md` "M3", ruling 2),
|
|
232
|
+
* and for a repo source Destination's answer IS the signed `writeScope` fence.
|
|
233
|
+
* This states that fact to the composer instead of letting it vanish along
|
|
234
|
+
* with Q2 — the same "nothing the composer received before may silently
|
|
235
|
+
* disappear" rule `applyGenreEnv` already keeps for a dropped env var.
|
|
236
|
+
*
|
|
237
|
+
* THROWS on an empty `writeScope`: Destination is a MANDATORY fence
|
|
238
|
+
* (`run-interview.mjs` refuses an empty answer at capture), so a caller
|
|
239
|
+
* reaching this with nothing to state is a bareloop wiring bug, not a job with
|
|
240
|
+
* no fence — a composer told it may change everything guards nothing.
|
|
241
|
+
* @param {string[]} writeScope
|
|
242
|
+
*/
|
|
243
|
+
export function writeScopeBlock(writeScope: string[]): string;
|
|
244
|
+
/**
|
|
245
|
+
* THE CONFIRMED-PLAN BLOCK (PRD item 33 M3 piece 4) — present only when the
|
|
246
|
+
* person already ran a confirm turn (`runConfirmTurn`'s `accepted`). States
|
|
247
|
+
* the composition law as an ORDER over the ACCEPTED checks, exactly the
|
|
248
|
+
* pattern {@link writeScopeBlock} already is for the fence: "compose these
|
|
249
|
+
* checks and no other" rather than a code matcher over the goal prose
|
|
250
|
+
* (ruling 6). Protections are restated as unchanged, never as checks to add.
|
|
251
|
+
* Open questions the person's own fix rounds left unresolved (D3) are named
|
|
252
|
+
* so the composer states them in notes rather than silently deciding them.
|
|
253
|
+
* `notChecked` (fix #1, run mu0voeo4) is anything the person asked for that
|
|
254
|
+
* no listed check can verify — shown so the composer names the gap in its
|
|
255
|
+
* own notes rather than the plan quietly reading as if everything asked for
|
|
256
|
+
* is covered.
|
|
257
|
+
* @param {{checks: string[], protections: string[], openQuestions?: string[], notChecked?: string[]}} confirmed
|
|
258
|
+
*/
|
|
259
|
+
export function confirmedBlock(confirmed: {
|
|
260
|
+
checks: string[];
|
|
261
|
+
protections: string[];
|
|
262
|
+
openQuestions?: string[];
|
|
263
|
+
notChecked?: string[];
|
|
264
|
+
}): string;
|
|
199
265
|
/**
|
|
200
266
|
* The whole authoring prompt, as one string.
|
|
201
267
|
*
|
|
@@ -208,12 +274,19 @@ export function lawsBlock(): string;
|
|
|
208
274
|
* the one thing that tells the composer what DONE is allowed to mean here; a
|
|
209
275
|
* defaulted class would be the prompt answering a question the user was asked.
|
|
210
276
|
*
|
|
277
|
+
* `writeScope` carries what the old Q2 used to (PRD item 33 M3 piece 3): Q2 is
|
|
278
|
+
* gone from the numbered interview, so what may change and what is read-only
|
|
279
|
+
* reaches the composer through {@link writeScopeBlock} instead, fed from
|
|
280
|
+
* Destination's own proven fence — never silently dropped.
|
|
281
|
+
*
|
|
211
282
|
* @param {{answers: Record<string|number, string>, questions?: Record<string|number, string>,
|
|
212
283
|
* facts: any, listingBlock: string, lang: string, verdictType: string,
|
|
213
284
|
* guards: {name: string, kind: string, params: Record<string, any>, fill: string[]}[],
|
|
214
|
-
* ownedEnvNames?: string[], mode?: 'tool'|'text', catalogue?: Record<string, any
|
|
285
|
+
* ownedEnvNames?: string[], mode?: 'tool'|'text', catalogue?: Record<string, any>,
|
|
286
|
+
* writeScope?: string[]|null,
|
|
287
|
+
* confirmed?: {checks: string[], protections: string[], openQuestions?: string[], notChecked?: string[]}|null}} o
|
|
215
288
|
*/
|
|
216
|
-
export function authorPrompt({ answers, questions, facts, listingBlock, lang, verdictType, guards, ownedEnvNames, mode, catalogue }: {
|
|
289
|
+
export function authorPrompt({ answers, questions, facts, listingBlock, lang, verdictType, guards, ownedEnvNames, mode, catalogue, writeScope, confirmed, }: {
|
|
217
290
|
answers: Record<string | number, string>;
|
|
218
291
|
questions?: Record<string | number, string>;
|
|
219
292
|
facts: any;
|
|
@@ -229,6 +302,13 @@ export function authorPrompt({ answers, questions, facts, listingBlock, lang, ve
|
|
|
229
302
|
ownedEnvNames?: string[];
|
|
230
303
|
mode?: "tool" | "text";
|
|
231
304
|
catalogue?: Record<string, any>;
|
|
305
|
+
writeScope?: string[] | null;
|
|
306
|
+
confirmed?: {
|
|
307
|
+
checks: string[];
|
|
308
|
+
protections: string[];
|
|
309
|
+
openQuestions?: string[];
|
|
310
|
+
notChecked?: string[];
|
|
311
|
+
} | null;
|
|
232
312
|
}): string;
|
|
233
313
|
/**
|
|
234
314
|
* The seed read, as the model sees it: mechanical labels, no editorial. Per-stage
|
|
@@ -495,6 +575,109 @@ export function askStructured({ messages, generate, mode, retries, label, book,
|
|
|
495
575
|
red: Red | null;
|
|
496
576
|
budget: "cap-halt" | "pricing-red" | null;
|
|
497
577
|
}>;
|
|
578
|
+
/** The output channel. It records and acknowledges; it takes no action.
|
|
579
|
+
* @param {{calls: any[]}} box */
|
|
580
|
+
export function confirmTool(box: {
|
|
581
|
+
calls: any[];
|
|
582
|
+
}): {
|
|
583
|
+
name: string;
|
|
584
|
+
description: string;
|
|
585
|
+
parameters: Record<string, any>;
|
|
586
|
+
execute: (args: any) => Promise<string>;
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* The confirm turn's per-round prompt (model-facing, registered). Shows the
|
|
590
|
+
* person's own answers with their labels (the signed table's Field/Holds
|
|
591
|
+
* pairing, same as {@link authorPrompt}'s interview block), the survey or
|
|
592
|
+
* listing already paid for, the write fence, the detected language, "worse
|
|
593
|
+
* than before" when the person gave one (repo only), and — on a fix round —
|
|
594
|
+
* what the person asked to change.
|
|
595
|
+
* @param {{answers: Record<string|number, string>, questions: Record<string|number, string>,
|
|
596
|
+
* labels?: Record<string|number, string>, facts?: any, listing?: string|null,
|
|
597
|
+
* writeScope?: string[]|null, isRepo: boolean, lang: string, worseThanBefore?: string,
|
|
598
|
+
* fixText?: string|null}} o
|
|
599
|
+
*/
|
|
600
|
+
export function confirmPrompt({ answers, questions, labels, facts, listing, writeScope, isRepo, lang, worseThanBefore, fixText }: {
|
|
601
|
+
answers: Record<string | number, string>;
|
|
602
|
+
questions: Record<string | number, string>;
|
|
603
|
+
labels?: Record<string | number, string>;
|
|
604
|
+
facts?: any;
|
|
605
|
+
listing?: string | null;
|
|
606
|
+
writeScope?: string[] | null;
|
|
607
|
+
isRepo: boolean;
|
|
608
|
+
lang: string;
|
|
609
|
+
worseThanBefore?: string;
|
|
610
|
+
fixText?: string | null;
|
|
611
|
+
}): string;
|
|
612
|
+
/**
|
|
613
|
+
* THE CONFIRM TURN: the $0 half (worse-than-before for a repo, a language
|
|
614
|
+
* pick when `lang` carries `detectLanguage`'s own `ambiguous` shape), then up
|
|
615
|
+
* to 2 PAID rounds (ruling 5) of draft → show → the person's menu pick
|
|
616
|
+
* (ruling 5 addendum). `ask` is the ONE interactive seam — an async function
|
|
617
|
+
* from a "what's being asked" descriptor to the person's answer, or `null`
|
|
618
|
+
* meaning input ended (the same signal `scripts/run-interview.mjs`'s own
|
|
619
|
+
* `nextLine()` already uses) — never a process exit here, because this is a
|
|
620
|
+
* library function, not a script. A `null` at ANY ask stops the whole turn as
|
|
621
|
+
* `confirm-abandoned`, spending nothing beyond whatever rounds already ran.
|
|
622
|
+
*
|
|
623
|
+
* D3's shape is enforced by the loop bound alone (`round <= 2`), never a
|
|
624
|
+
* counter checked after the fact: a "fix" on round 2 returns immediately —
|
|
625
|
+
* there is no 3rd call to make.
|
|
626
|
+
*
|
|
627
|
+
* @param {{verdictType: string, answers: Record<string|number, string>,
|
|
628
|
+
* questions: Record<string|number, string>, labels?: Record<string|number, string>,
|
|
629
|
+
* facts?: any, listing?: string|null, writeScope?: string[]|null, isRepo: boolean,
|
|
630
|
+
* lang: string|{kind: 'ambiguous', candidates: string[], dir: string},
|
|
631
|
+
* generate: Function, book: ReturnType<typeof makeCostBook>,
|
|
632
|
+
* ask: (step: {kind: string, [k: string]: any}) => Promise<string|null>,
|
|
633
|
+
* onPhase?: (phase: string, data?: any) => void, mode?: 'tool'|'text',
|
|
634
|
+
* worseThanBefore?: string}} o
|
|
635
|
+
* @returns {Promise<{ok: boolean,
|
|
636
|
+
* stop: null|'cap-halt'|'pricing-red'|'provider-red'|'artifact-red'|'confirm-abandoned'|'confirm-restart',
|
|
637
|
+
* rounds: number,
|
|
638
|
+
* accepted: {goal: string, checks: string[], protections: string[], lang: string,
|
|
639
|
+
* worseThanBefore: string, openQuestions: string[], notChecked: string[]}|null,
|
|
640
|
+
* reds: Red[], cost: any}>}
|
|
641
|
+
*/
|
|
642
|
+
export function runConfirmTurn({ verdictType, answers, questions, labels, facts, listing, writeScope, isRepo, lang, generate, book, ask, onPhase, mode, worseThanBefore: presetWorseThanBefore, }: {
|
|
643
|
+
verdictType: string;
|
|
644
|
+
answers: Record<string | number, string>;
|
|
645
|
+
questions: Record<string | number, string>;
|
|
646
|
+
labels?: Record<string | number, string>;
|
|
647
|
+
facts?: any;
|
|
648
|
+
listing?: string | null;
|
|
649
|
+
writeScope?: string[] | null;
|
|
650
|
+
isRepo: boolean;
|
|
651
|
+
lang: string | {
|
|
652
|
+
kind: "ambiguous";
|
|
653
|
+
candidates: string[];
|
|
654
|
+
dir: string;
|
|
655
|
+
};
|
|
656
|
+
generate: Function;
|
|
657
|
+
book: ReturnType<typeof makeCostBook>;
|
|
658
|
+
ask: (step: {
|
|
659
|
+
kind: string;
|
|
660
|
+
[k: string]: any;
|
|
661
|
+
}) => Promise<string | null>;
|
|
662
|
+
onPhase?: (phase: string, data?: any) => void;
|
|
663
|
+
mode?: "tool" | "text";
|
|
664
|
+
worseThanBefore?: string;
|
|
665
|
+
}): Promise<{
|
|
666
|
+
ok: boolean;
|
|
667
|
+
stop: null | "cap-halt" | "pricing-red" | "provider-red" | "artifact-red" | "confirm-abandoned" | "confirm-restart";
|
|
668
|
+
rounds: number;
|
|
669
|
+
accepted: {
|
|
670
|
+
goal: string;
|
|
671
|
+
checks: string[];
|
|
672
|
+
protections: string[];
|
|
673
|
+
lang: string;
|
|
674
|
+
worseThanBefore: string;
|
|
675
|
+
openQuestions: string[];
|
|
676
|
+
notChecked: string[];
|
|
677
|
+
} | null;
|
|
678
|
+
reds: Red[];
|
|
679
|
+
cost: any;
|
|
680
|
+
}>;
|
|
498
681
|
/**
|
|
499
682
|
* THE AUTHORING FLOW.
|
|
500
683
|
*
|
|
@@ -531,9 +714,12 @@ export function askStructured({ messages, generate, mode, retries, label, book,
|
|
|
531
714
|
* onPhase?: (phase: string, data?: any) => void,
|
|
532
715
|
* onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number}) => void,
|
|
533
716
|
* maxRevisions?: number, structureRetries?: number,
|
|
534
|
-
* structuredMode?: 'tool'|'text', catalogue?: Record<string, any
|
|
717
|
+
* structuredMode?: 'tool'|'text', catalogue?: Record<string, any>, writeScope?: string[]|null,
|
|
718
|
+
* priorCalls?: {label: string, costUsd: number|null, unpricedRounds: number}[]|null,
|
|
719
|
+
* priorRaws?: any[]|null,
|
|
720
|
+
* confirmed?: {checks: string[], protections: string[], openQuestions?: string[], notChecked?: string[]}|null}} o
|
|
535
721
|
*/
|
|
536
|
-
export function authorClose({ workdir, seedRef, lang, verdictType, answers, questions, scout, listing, generate, seedReadFn, closeCtx, ceilingUsd, onPhase, onCall, maxRevisions, structureRetries, structuredMode, catalogue, }: {
|
|
722
|
+
export function authorClose({ workdir, seedRef, lang, verdictType, answers, questions, writeScope, scout, listing, priorCalls, priorRaws, confirmed, generate, seedReadFn, closeCtx, ceilingUsd, onPhase, onCall, maxRevisions, structureRetries, structuredMode, catalogue, }: {
|
|
537
723
|
workdir: string;
|
|
538
724
|
seedRef: string;
|
|
539
725
|
lang: string;
|
|
@@ -569,6 +755,19 @@ export function authorClose({ workdir, seedRef, lang, verdictType, answers, ques
|
|
|
569
755
|
structureRetries?: number;
|
|
570
756
|
structuredMode?: "tool" | "text";
|
|
571
757
|
catalogue?: Record<string, any>;
|
|
758
|
+
writeScope?: string[] | null;
|
|
759
|
+
priorCalls?: {
|
|
760
|
+
label: string;
|
|
761
|
+
costUsd: number | null;
|
|
762
|
+
unpricedRounds: number;
|
|
763
|
+
}[] | null;
|
|
764
|
+
priorRaws?: any[] | null;
|
|
765
|
+
confirmed?: {
|
|
766
|
+
checks: string[];
|
|
767
|
+
protections: string[];
|
|
768
|
+
openQuestions?: string[];
|
|
769
|
+
notChecked?: string[];
|
|
770
|
+
} | null;
|
|
572
771
|
}): Promise<any>;
|
|
573
772
|
/** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
|
|
574
773
|
/** the output channel's name. It takes no action; it carries the answer. */
|
|
@@ -604,114 +803,157 @@ export const REVISE_INSTRUCTION: string;
|
|
|
604
803
|
export const STRUCTURE_INSTRUCTION_TOOL: string;
|
|
605
804
|
export const STRUCTURE_INSTRUCTION_TEXT: string;
|
|
606
805
|
/**
|
|
607
|
-
* THE
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
* the
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
*
|
|
621
|
-
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
806
|
+
* THE UNIFIED INTAKE FORM (PRD item 33 M3 piece 3, `docs/product/ITEM33-BUILD.md`
|
|
807
|
+
* "M3", and the 2026-09-10 signed ruling "The intake form (RULED)" in
|
|
808
|
+
* `docs/product/PRD.md` item 33). Motivated by run `mtv8jihy` (F159): the OLD
|
|
809
|
+
* five-question green set produced a rubric compiled onto doc-comment rules —
|
|
810
|
+
* the wrong bar for what the person actually asked — because Q2 asked in prose
|
|
811
|
+
* for a decision the machine can prove instead, and Q3/Q5 asked the same "what
|
|
812
|
+
* must not go wrong" question twice from two directions.
|
|
813
|
+
*
|
|
814
|
+
* THE SAME SIX FIELDS FOR GREEN AND SOFT-GREEN, in the order a person sees them:
|
|
815
|
+
*
|
|
816
|
+
* Source replaces the read half of the old Q2 — MECHANICAL, proven
|
|
817
|
+
* against the machine ($0), never typed as free prose.
|
|
818
|
+
* Destination replaces the change half of the old Q2 (and, for a repo
|
|
819
|
+
* source, IS the signed `writeScope` fence) — MECHANICAL,
|
|
820
|
+
* same reason.
|
|
821
|
+
* Goal the old Q1, unchanged: "What do you want done?"
|
|
822
|
+
* What success looks like the old Q4, unchanged: a machine-countable check.
|
|
823
|
+
* Guardrails the old Q3 ("must not change") and Q5 ("worse than
|
|
824
|
+
* before") JOINED into one field — they were always one
|
|
825
|
+
* decision answered twice, and Q5 already only mattered for
|
|
826
|
+
* a repo source (the M3 confirm turn, not built in this
|
|
827
|
+
* piece, is where the repo-only half of it gets asked again
|
|
828
|
+
* if needed).
|
|
829
|
+
* Judge examples soft-green only — the old Q7 verbatim ("one you'd pass and
|
|
830
|
+
* one you'd fail, and say why"). The old Q6 ("what separates
|
|
831
|
+
* a pass from a fail") is retired as its own question: the
|
|
832
|
+
* "why" lines of a real pass/fail pair are what the rubric
|
|
833
|
+
* card compiles from (`cardauthor.js`), and asking the
|
|
834
|
+
* differentiator twice — once in the abstract, once against
|
|
835
|
+
* a real example — is the same double-ask Q3/Q5 already were.
|
|
836
|
+
*
|
|
837
|
+
* SOURCE and DESTINATION ARE MECHANICAL FIELDS, not entries in the numbered
|
|
838
|
+
* question record below: `runInterview`'s `answers` dict is what a close's
|
|
839
|
+
* composer prompt quotes verbatim (Q<n>/A<n>), and quoting a machine-proven fact
|
|
840
|
+
* back at the model as if a person had typed it would be the model reading a
|
|
841
|
+
* fabricated conversation. Their WORDING still lives here (`SOURCE_FIELD`,
|
|
842
|
+
* `DESTINATION_FIELD_REPO`, `DESTINATION_FIELD_PLAIN`, immediately below) so
|
|
843
|
+
* `scripts/run-interview.mjs` prints library text and nothing of its own, exactly
|
|
844
|
+
* as ruling 1 requires for the free-text questions.
|
|
845
|
+
*
|
|
846
|
+
* The free-text trio (soon quartet, soft-green only) IS numbered contiguously
|
|
847
|
+
* from 1 — the number a person sees is the key their answer is filed under, and
|
|
848
|
+
* that is what `questionsFor`/`requiredAnswersFor`/`QUESTION_SETS` still expose,
|
|
849
|
+
* unchanged in shape, to every existing caller.
|
|
645
850
|
*/
|
|
646
|
-
export const
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
851
|
+
export const SOURCE_FIELD: Readonly<{
|
|
852
|
+
id: "source";
|
|
853
|
+
kind: "mechanical";
|
|
854
|
+
label: "Source";
|
|
855
|
+
prompt: "A local folder, subfolder or file, or one URL the machine can reach (no login, no setup).";
|
|
856
|
+
}>;
|
|
857
|
+
/** Destination's wording when Source resolved to a git repo: the answer IS the
|
|
858
|
+
* signed `writeScope` fence (ITEM33-BUILD.md M3 ruling 2). */
|
|
859
|
+
export const DESTINATION_FIELD_REPO: Readonly<{
|
|
860
|
+
id: "destination";
|
|
861
|
+
kind: "mechanical";
|
|
862
|
+
label: "Destination";
|
|
863
|
+
prompt: string;
|
|
864
|
+
}>;
|
|
865
|
+
/** Destination's wording for every other kind of Source (a plain folder, a
|
|
866
|
+
* file, a URL): a directory the run may write into, never a filename
|
|
867
|
+
* (2026-09-12 Destination correction, PRD item 33). */
|
|
868
|
+
export const DESTINATION_FIELD_PLAIN: Readonly<{
|
|
869
|
+
id: "destination";
|
|
870
|
+
kind: "mechanical";
|
|
871
|
+
label: "Destination";
|
|
872
|
+
prompt: string;
|
|
652
873
|
}>;
|
|
653
874
|
/**
|
|
654
|
-
* THE
|
|
875
|
+
* THE FREE-TEXT TRIO EVERY CLASS SHARES: Goal, What success looks like,
|
|
876
|
+
* Guardrails — numbered contiguously from 1. This is what `answers[1..3]` are
|
|
877
|
+
* filed under for every class; soft-green appends a fourth
|
|
878
|
+
* (`SOFTGREEN_QUESTIONS`) and hitl appends a different fourth
|
|
879
|
+
* (`HITL_QUESTIONS`), each its own next number rather than a fixed one, so a
|
|
880
|
+
* future trim of this trio renumbers instead of leaving a gap.
|
|
655
881
|
*
|
|
656
|
-
*
|
|
657
|
-
*
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
*
|
|
666
|
-
*
|
|
667
|
-
* thing a human stage must never have done for it. It is the SPREAD's next number
|
|
668
|
-
* rather than a fixed one, so a green-side deletion renumbers it instead of
|
|
669
|
-
* leaving a gap (it was 7 while the green set held six, and is 6 now it holds five).
|
|
882
|
+
* THE TEXT IS THE SIGNED TABLE'S "Holds" COLUMN, VERBATIM (PRD item 33's
|
|
883
|
+
* 2026-09-10 "The intake form (RULED)" ruling, `docs/product/PRD.md`) — not the
|
|
884
|
+
* old worded questions ("What do you want done?", "How do you check today
|
|
885
|
+
* whether it's working?", "...worse than before?"). Motivated by run `mtv8jihy`
|
|
886
|
+
* (F159, `docs/logs/FINDINGS.md`): a rulebook this prompt commit did not touch
|
|
887
|
+
* still had to compile against a card built from a person's actual bar, and the
|
|
888
|
+
* old wording never matched what got signed — this reshape (commit 1ac4d05)
|
|
889
|
+
* trimmed the SET to three slots but left their PROSE unreconciled with the
|
|
890
|
+
* table it was meant to realize. `FIELD_LABELS` (below) carries the matching
|
|
891
|
+
* label for each key, so a caller wanting BOTH shows them together — see
|
|
892
|
+
* `authorPrompt`'s interview block and `scripts/run-interview.mjs`.
|
|
670
893
|
*/
|
|
671
|
-
export const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
894
|
+
export const GREEN_QUESTIONS: Readonly<{
|
|
895
|
+
1: "what you want to achieve";
|
|
896
|
+
2: "checks a machine can count";
|
|
897
|
+
3: "what must not happen or change";
|
|
898
|
+
}>;
|
|
899
|
+
/**
|
|
900
|
+
* The signed table's own label for each of {@link GREEN_QUESTIONS}' keys — "the
|
|
901
|
+
* Field column", where {@link GREEN_QUESTIONS} is "the Holds column". Kept as a
|
|
902
|
+
* SEPARATE map rather than folding the label into the question string itself:
|
|
903
|
+
* every existing caller of `questionsFor`/`requiredAnswersFor`/`QUESTION_SETS`
|
|
904
|
+
* (`src/authorjob.js`, `src/cardauthor.js`, `scripts/run-interview.mjs`) treats
|
|
905
|
+
* a question as a plain string handed verbatim into a prompt or a `Q<n>. `
|
|
906
|
+
* line, and folding a label in would change that shape for every one of them.
|
|
907
|
+
* A caller that wants the label calls {@link labelsFor} exactly the way it
|
|
908
|
+
* calls `questionsFor` — additive, nothing existing breaks.
|
|
909
|
+
*/
|
|
910
|
+
export const FIELD_LABELS: Readonly<{
|
|
911
|
+
1: "Goal";
|
|
912
|
+
2: "What success looks like";
|
|
913
|
+
3: "Guardrails";
|
|
914
|
+
}>;
|
|
915
|
+
/** The soft-green quartet's own key for Judge Examples — exported so
|
|
916
|
+
* `cardauthor.js` reads the SAME number this module files the answer under,
|
|
917
|
+
* rather than a second, hand-typed "6"/"7". */
|
|
918
|
+
export const SOFTGREEN_JUDGE_EXAMPLES_KEY: number;
|
|
919
|
+
/** The Judge Examples question — the signed table's own Holds text, verbatim
|
|
920
|
+
* ("one pass, one fail, and why"), not the old worded Q7 ("Give one example
|
|
921
|
+
* you'd pass and one you'd fail, and say why."). Exported so `cardauthor.js`'s
|
|
922
|
+
* prompt and this module's own `SOFTGREEN_QUESTIONS` render the identical
|
|
923
|
+
* string; its label ("Judge examples") lives in `SOFTGREEN_FIELD_LABELS`. */
|
|
924
|
+
export const JUDGE_EXAMPLES_QUESTION: "one pass, one fail, and why";
|
|
925
|
+
/** {@link FIELD_LABELS} plus Judge Examples' own label, for the soft-green set. */
|
|
926
|
+
export const SOFTGREEN_FIELD_LABELS: Readonly<{
|
|
927
|
+
1: "Goal";
|
|
928
|
+
2: "What success looks like";
|
|
929
|
+
3: "Guardrails";
|
|
678
930
|
}>;
|
|
679
931
|
/**
|
|
680
|
-
* THE SOFTGREEN SET
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
688
|
-
* The two additions are the only things the green set cannot supply, and neither
|
|
689
|
-
* is a flourish — they are the judged floor's two REQUIRED inputs:
|
|
690
|
-
* - Q6 becomes the RUBRIC CARD (§4.3): the person's own pass/fail lines,
|
|
691
|
-
* compiled into enumerated items, signed, and enumerated in the spec hash.
|
|
692
|
-
* The documented ceiling rides with it — the judge catches violations of
|
|
693
|
-
* STATED card items only, and the fix for a miss is a new card line and a
|
|
694
|
-
* re-sign, never a smarter judge.
|
|
695
|
-
* - Q7 becomes the frozen CALIBRATION SET (§4.4): the whole pipe must grade it
|
|
696
|
-
* correctly before the close is signable.
|
|
697
|
-
* Both are asked in the person's own terms — an example they would pass and one
|
|
698
|
-
* they would fail, not a rubric they are asked to write — because compiling a lay
|
|
699
|
-
* answer into extractable items is the LLM's job (D5, proposed-and-signed) and
|
|
700
|
-
* asking the person to do it is the SWE tax this product refuses.
|
|
701
|
-
*
|
|
702
|
-
* What the two answers COMPILE INTO is module 4. This module carries them
|
|
703
|
-
* exactly as the hitl set carries its own last answer: they ride in `answers`,
|
|
704
|
-
* they reach the composer verbatim through the prompt's interview block, and
|
|
705
|
-
* nothing here derives anything from them.
|
|
932
|
+
* THE SOFTGREEN SET — the green trio plus Judge Examples. A judged close needs
|
|
933
|
+
* exactly this one more thing the green set cannot supply: a real pass/fail
|
|
934
|
+
* pair in the person's own words, which module 4 (`cardauthor.js`) compiles
|
|
935
|
+
* into the signed rubric card and the frozen calibration set. It rides in
|
|
936
|
+
* `answers` and reaches the composer verbatim through the prompt's interview
|
|
937
|
+
* block, exactly as every other free-text answer does — this module derives
|
|
938
|
+
* nothing from it.
|
|
706
939
|
*/
|
|
707
940
|
export const SOFTGREEN_QUESTIONS: Readonly<{
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
941
|
+
1: "what you want to achieve";
|
|
942
|
+
2: "checks a machine can count";
|
|
943
|
+
3: "what must not happen or change";
|
|
944
|
+
}>;
|
|
945
|
+
/**
|
|
946
|
+
* THE HITL SET (N4 slice 1, kept in code only — never offered in the form or
|
|
947
|
+
* anywhere customer-facing, PRD item 33 M3 ruling 8) — the green trio plus one.
|
|
948
|
+
* `human-confirms` requires an `ask`, the question the signer answers at the
|
|
949
|
+
* end of the run, and nothing else in the interview names it; without it the
|
|
950
|
+
* composer would have to invent what a person is deciding. It is the green
|
|
951
|
+
* set's next number, not a fixed one, so a green-side trim renumbers it too.
|
|
952
|
+
*/
|
|
953
|
+
export const HITL_QUESTIONS: Readonly<{
|
|
954
|
+
1: "what you want to achieve";
|
|
955
|
+
2: "checks a machine can count";
|
|
956
|
+
3: "what must not happen or change";
|
|
715
957
|
}>;
|
|
716
958
|
/**
|
|
717
959
|
* The three sets, all LIVE as of softgreen module 3. The locked shape stays
|
|
@@ -721,11 +963,17 @@ export const SOFTGREEN_QUESTIONS: Readonly<{
|
|
|
721
963
|
* distinction, at the interview layer) — and a locked class refuses at ADMISSION,
|
|
722
964
|
* before its questions run, so the two readers throw rather than hand back
|
|
723
965
|
* nothing. A fourth class arrives locked, and the machinery is here for it.
|
|
724
|
-
*
|
|
966
|
+
* `labels` travels ALONGSIDE `questions`, one label per key that the signed
|
|
967
|
+
* table names one for (PRD item 33 M3 piece 3's wording fix) — hitl's own
|
|
968
|
+
* fourth question has no table row (it is never customer-facing, ruling 8) and
|
|
969
|
+
* so carries none; a reader finding no label for a key falls back to showing
|
|
970
|
+
* none, never a fabricated one.
|
|
971
|
+
* @type {Record<string, {locked: boolean, questions: Record<string|number, string>|null, labels: Record<string|number, string>, required: readonly number[]|null}>}
|
|
725
972
|
*/
|
|
726
973
|
export const QUESTION_SETS: Record<string, {
|
|
727
974
|
locked: boolean;
|
|
728
975
|
questions: Record<string | number, string> | null;
|
|
976
|
+
labels: Record<string | number, string>;
|
|
729
977
|
required: readonly number[] | null;
|
|
730
978
|
}>;
|
|
731
979
|
/**
|
|
@@ -739,6 +987,69 @@ export const QUESTION_SETS: Record<string, {
|
|
|
739
987
|
* @type {Record<string, string|null>}
|
|
740
988
|
*/
|
|
741
989
|
export const CLASS_STATEMENTS: Record<string, string | null>;
|
|
990
|
+
/**
|
|
991
|
+
* Asked ONLY for a repo source (ruling 2 addendum's D7) — a plain folder or a
|
|
992
|
+
* URL has no "before" a repo's own history gives it to compare against. This
|
|
993
|
+
* is the OLD Q5 wording, verbatim ("What would make you say this came back
|
|
994
|
+
* worse than before?"), which M3 piece 3's reshape folded into Guardrails —
|
|
995
|
+
* it survives here as its OWN field because the confirm turn (ruling 5's
|
|
996
|
+
* 2026-09-13 addendum) includes it as a constraint only when the person
|
|
997
|
+
* actually gave one, and folding it silently into the Guardrails free-text
|
|
998
|
+
* slot would lose that "present or absent" distinction. An empty answer is
|
|
999
|
+
* "nothing beyond what Guardrails already said" and is not required — see
|
|
1000
|
+
* the frozen-wording test below: this phrase appears NOWHERE in
|
|
1001
|
+
* {@link questionsFor}'s own sets, so a caller cannot double-ask it by
|
|
1002
|
+
* reading the wrong table.
|
|
1003
|
+
*/
|
|
1004
|
+
export const WORSE_THAN_BEFORE_FIELD: Readonly<{
|
|
1005
|
+
id: "worseThanBefore";
|
|
1006
|
+
kind: "mechanical";
|
|
1007
|
+
label: "Worse than before";
|
|
1008
|
+
prompt: "What would make you say this came back worse than before?";
|
|
1009
|
+
}>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Asked ONLY when `src/detectlang.js`'s `detectLanguage` reports its
|
|
1012
|
+
* `ambiguous` outcome — two supported languages' manifests at the same
|
|
1013
|
+
* (nearest) directory level (M3 ruling 3, point 3). The candidate list is
|
|
1014
|
+
* NOT embedded here: it travels with the caller's own `ambiguous` result
|
|
1015
|
+
* (`langResult.candidates`), so this module never hand-types a second copy
|
|
1016
|
+
* of the supported-language set. An unsupported pick still goes through the
|
|
1017
|
+
* existing `language-unsupported` refusal — this field only offers a choice
|
|
1018
|
+
* among the candidates `detectLanguage` actually found.
|
|
1019
|
+
*/
|
|
1020
|
+
export const LANGUAGE_PICK_FIELD: Readonly<{
|
|
1021
|
+
id: "language";
|
|
1022
|
+
kind: "mechanical";
|
|
1023
|
+
label: "Language";
|
|
1024
|
+
prompt: "This repo has more than one supported language's manifest at the same level. Which one is this job about?";
|
|
1025
|
+
}>;
|
|
1026
|
+
/**
|
|
1027
|
+
* THE CONFIRM TURN'S MENU — a structured CHOICE the person picks from after
|
|
1028
|
+
* each round, never free text matched against a pattern (ruling 6's "no
|
|
1029
|
+
* hand-authored check matcher" reasoning applies here too: the person's own
|
|
1030
|
+
* reply is read as one of these four keys, never parsed for intent).
|
|
1031
|
+
* confirm — sign the plan and the drafted goal sentence as shown.
|
|
1032
|
+
* fix — free text describing what to change; feeds round r+1, up
|
|
1033
|
+
* to the 2-round cap (ruling 5); after round 2 a "fix" is
|
|
1034
|
+
* passed to the composer verbatim and shown at signing as an
|
|
1035
|
+
* open question rather than spending a 3rd call (D3).
|
|
1036
|
+
* type-goal — the person's own sentence REPLACES the drafted goal,
|
|
1037
|
+
* verbatim (redacted); everything else in the plan stands.
|
|
1038
|
+
* start-over — abandon this confirm turn; the person reruns the
|
|
1039
|
+
* interview from the beginning (`confirm-restart`).
|
|
1040
|
+
* @type {Record<'confirm'|'fix'|'type-goal'|'start-over', string>}
|
|
1041
|
+
*/
|
|
1042
|
+
export const CONFIRM_MENU: Record<"confirm" | "fix" | "type-goal" | "start-over", string>;
|
|
1043
|
+
/**
|
|
1044
|
+
* PLAIN-ENGLISH lines for the guards `classGuards` can compose, keyed by
|
|
1045
|
+
* guard NAME — frozen beside {@link CONFIRM_MENU} because both are constants
|
|
1046
|
+
* the confirm turn shows a person verbatim. One entry per guard that exists
|
|
1047
|
+
* in `MECHANICAL_GUARDS` (`src/authoring.js`); {@link confirmProtections}
|
|
1048
|
+
* throws if a guard `classGuards` hands back has no line here, so a battery
|
|
1049
|
+
* that grows a guard fails loudly instead of showing a blank description.
|
|
1050
|
+
* @type {Record<string, string>}
|
|
1051
|
+
*/
|
|
1052
|
+
export const GUARD_DESCRIPTIONS: Record<string, string>;
|
|
742
1053
|
export const AUTHOR_SYSTEM: string;
|
|
743
1054
|
/**
|
|
744
1055
|
* ONE schema per PARAMETER NAME, composed into kinds by the catalogue's own
|
|
@@ -967,6 +1278,24 @@ export const PARAM_SCHEMAS: Readonly<{
|
|
|
967
1278
|
description: string;
|
|
968
1279
|
};
|
|
969
1280
|
}>;
|
|
1281
|
+
export const CONFIRM_TOOL_NAME: "confirm_plan";
|
|
1282
|
+
/** Acknowledgement text the confirm tool's `execute` returns — mirrors
|
|
1283
|
+
* {@link DECLARATION_ACK}'s role: an output channel that records and
|
|
1284
|
+
* acknowledges, takes no action, and ends the call the moment it fires
|
|
1285
|
+
* (`makeLoopGenerate` stops the loop on any tool execute). */
|
|
1286
|
+
export const CONFIRM_ACK: "plan received";
|
|
1287
|
+
/** the confirm channel's own STRUCTURE_INSTRUCTION_TOOL analogue, shown after
|
|
1288
|
+
* a malformed reply so the retry names the ONE required shape rather than
|
|
1289
|
+
* repeating the whole system prompt */
|
|
1290
|
+
export const CONFIRM_STRUCTURE_INSTRUCTION: string;
|
|
1291
|
+
/**
|
|
1292
|
+
* The confirm turn's system prompt (model-facing, registered — a commit
|
|
1293
|
+
* touching this needs Failure/Addresses/Corrects labels, `src/promptregisters.js`).
|
|
1294
|
+
* States ruling 6 ("a genre never adds a check the goal did not ask for") as
|
|
1295
|
+
* an ORDER to the model itself, the same register {@link AUTHOR_SYSTEM} and
|
|
1296
|
+
* {@link CLASS_STATEMENTS} already use, rather than a code matcher over prose.
|
|
1297
|
+
*/
|
|
1298
|
+
export const CONFIRM_SYSTEM: string;
|
|
970
1299
|
export type Red = {
|
|
971
1300
|
code: string;
|
|
972
1301
|
path: string;
|