bareloop 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +510 -0
- package/README.md +18 -7
- package/bareloop.context.md +456 -19
- package/package.json +3 -3
- package/src/authorflow.js +290 -49
- package/src/authoring.js +258 -46
- package/src/authorjob.js +390 -32
- package/src/authorscout.js +13 -1
- package/src/bridges.js +238 -11
- package/src/calibrate.js +597 -0
- package/src/cardauthor.js +479 -0
- package/src/clock.js +21 -3
- package/src/declaredclose.js +188 -13
- package/src/index.js +90 -7
- package/src/job.js +28 -9
- package/src/judged.js +765 -0
- package/src/kinds.js +578 -13
- package/src/ledger.js +24 -1
- package/src/planrun.js +517 -14
- package/src/ralph.js +9 -0
- package/src/reuse.js +514 -96
- package/src/reviewdoor.js +246 -0
- package/src/root.js +1 -1
- package/src/run.js +81 -8
- package/src/selection.js +23 -7
- package/types/authorflow.d.ts +233 -21
- package/types/authoring.d.ts +99 -39
- package/types/authorjob.d.ts +44 -6
- package/types/authorscout.d.ts +7 -1
- package/types/bridges.d.ts +95 -1
- package/types/calibrate.d.ts +191 -0
- package/types/cardauthor.d.ts +352 -0
- package/types/clock.d.ts +5 -2
- package/types/declaredclose.d.ts +93 -6
- package/types/index.d.ts +11 -7
- package/types/job.d.ts +22 -4
- package/types/judged.d.ts +280 -0
- package/types/kinds.d.ts +227 -8
- package/types/planrun.d.ts +73 -3
- package/types/reuse.d.ts +218 -3
- package/types/reviewdoor.d.ts +81 -0
- package/types/run.d.ts +60 -2
package/types/bridges.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/** does a green under this verdict class earn its learning credit at the close, or
|
|
2
|
+
* does it wait for a person? Absent/unknown means green's behaviour, byte for byte
|
|
3
|
+
* — the pre-softgreen path is the default and stays untouched.
|
|
4
|
+
* @param {unknown} verdictType @returns {boolean} */
|
|
5
|
+
export function quarantinesCredit(verdictType: unknown): boolean;
|
|
1
6
|
/**
|
|
2
7
|
* D6's status ladder, walked in history order. Pure, total, and never throws —
|
|
3
8
|
* it is called on whatever a file happens to contain.
|
|
@@ -13,6 +18,10 @@
|
|
|
13
18
|
* the entry on the first repeat green.
|
|
14
19
|
* - a red on a CANDIDATE changes nothing: there is nothing below the entry bar, and
|
|
15
20
|
* the entry stays in the record with the red beside it.
|
|
21
|
+
* - a **QUARANTINED green is not evidence** (softgreen module 6). The row exists and
|
|
22
|
+
* the run happened, but a judged green earns nothing until the signer's `accept`
|
|
23
|
+
* releases it, so it neither clears the entry bar nor adds a distinct patient. An
|
|
24
|
+
* entry whose only greens are held derives `null` — below the bar, not demoted.
|
|
16
25
|
* - a **CASUALTY is not a red.** Only the literal outcome `'red'` demotes; every
|
|
17
26
|
* other non-green outcome (`provider-red`, `wall-halt`, `close-crashed`, …) is a
|
|
18
27
|
* casualty, and casualties are never evidence in either direction.
|
|
@@ -74,6 +83,68 @@ export function appendRed(bridge: unknown, record: unknown): {
|
|
|
74
83
|
reds: Red[];
|
|
75
84
|
bridge: any;
|
|
76
85
|
};
|
|
86
|
+
/**
|
|
87
|
+
* The version that would INHERIT — the newest one whose credit has actually been
|
|
88
|
+
* released. `versions` is oldest-first, so this is normally the last of them; it
|
|
89
|
+
* differs only when a judged green sits on top of a released one, and in that case
|
|
90
|
+
* the RELEASED plan is what a reuse starts from. A held version is not a worse
|
|
91
|
+
* recipe, it is an unjudged one: nobody has said yet whether the ruler that passed
|
|
92
|
+
* it was right, and starting the next run from it would spend the credit before it
|
|
93
|
+
* was granted.
|
|
94
|
+
*
|
|
95
|
+
* Total and never throws — it is read at selection time and at the load door.
|
|
96
|
+
* @param {unknown} bridge
|
|
97
|
+
* @returns {any|null} null when every version is held (or there are none)
|
|
98
|
+
*/
|
|
99
|
+
export function newestEligibleVersion(bridge: unknown): any | null;
|
|
100
|
+
/**
|
|
101
|
+
* May this workflow be offered for reuse at all? A held entry is SKIPPED WITH A
|
|
102
|
+
* REASON everywhere it is skipped — the same visible-skip discipline an unreadable
|
|
103
|
+
* registry file already gets, because a shelf that quietly shrinks teaches the
|
|
104
|
+
* operator that the registry is empty when it is merely holding.
|
|
105
|
+
* @param {unknown} bridge
|
|
106
|
+
* @returns {{ok: boolean, reason: string}} `reason` is '' when ok
|
|
107
|
+
*/
|
|
108
|
+
export function reuseEligibility(bridge: unknown): {
|
|
109
|
+
ok: boolean;
|
|
110
|
+
reason: string;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* THE REVIEW DOOR, written down (PRD v1.71 §3). The person read the finished run
|
|
114
|
+
* and said one of three things; this records that on the run's own row, and — for
|
|
115
|
+
* `accept` on a HELD green — releases the learning credit that green has been
|
|
116
|
+
* carrying unspent.
|
|
117
|
+
*
|
|
118
|
+
* Three properties, and each is a ruling rather than a convenience:
|
|
119
|
+
*
|
|
120
|
+
* - **the door never changes the loop's verdict.** A green row stays a green row,
|
|
121
|
+
* whatever the person then does with it. `rerun` and `pause` are dispositions,
|
|
122
|
+
* recorded and nothing more; a rerun's own outcome is a NEW run's row.
|
|
123
|
+
* - **release is FORWARD-ONLY.** Nothing here can set `quarantined` back to true,
|
|
124
|
+
* so a signer who accepts and later reruns has recorded a disagreement — which
|
|
125
|
+
* is a datum worth keeping — without un-granting credit already granted. There
|
|
126
|
+
* is deliberately no re-hold path at all: it would be a way to walk the ledger
|
|
127
|
+
* backwards, which the ruling forbids.
|
|
128
|
+
* - **releasing is not minting.** A door aimed at a run with no green row of its
|
|
129
|
+
* own is a named red — never an invented entry. That is slice 1's already-green
|
|
130
|
+
* rule holding from the other side: `accept` confirms a verdict, it never
|
|
131
|
+
* creates one.
|
|
132
|
+
*
|
|
133
|
+
* Idempotent by shape: a decision identical to the last one recorded is a no-op
|
|
134
|
+
* that returns the entry unchanged, so a double-click at the door cannot inflate
|
|
135
|
+
* the report card (and `released` says whether THIS call was the one that freed it).
|
|
136
|
+
*
|
|
137
|
+
* Pure — returns a NEW entry; the input is never mutated.
|
|
138
|
+
* @param {unknown} bridge a validated bridge entry
|
|
139
|
+
* @param {unknown} door `{ runid, decision, at }` — `at` may be an explicit null
|
|
140
|
+
* @returns {{ ok: boolean, reds: Red[], bridge: any, released: boolean }}
|
|
141
|
+
*/
|
|
142
|
+
export function recordDoor(bridge: unknown, door: unknown): {
|
|
143
|
+
ok: boolean;
|
|
144
|
+
reds: Red[];
|
|
145
|
+
bridge: any;
|
|
146
|
+
released: boolean;
|
|
147
|
+
};
|
|
77
148
|
/**
|
|
78
149
|
* One row of D3's listing: what the user (and the selecting LLM) sees per bridge —
|
|
79
150
|
* name, the job sentence it greened, status, greens/reds, and the cost/time BAND of
|
|
@@ -86,7 +157,7 @@ export function appendRed(bridge: unknown, record: unknown): {
|
|
|
86
157
|
* Total and never throws: the listing is a display surface, and one malformed
|
|
87
158
|
* entry must not take the whole listing down (loadRegistry already reports it).
|
|
88
159
|
* @param {unknown} bridge
|
|
89
|
-
* @returns {{name: string|null, goal: string|null, status: 'candidate'|'proven'|null, greens: number, reds: number, lastOutcome: string|null, greenCost: {minUsd: number|null, maxUsd: number|null, minWallMs: number|null, maxWallMs: number|null, unpricedCount: number, untimedCount: number}}}
|
|
160
|
+
* @returns {{name: string|null, goal: string|null, status: 'candidate'|'proven'|null, greens: number, reds: number, quarantinedGreens: number, doorDecisions: {runid: string|null, decision: string|null, at: string|null}[], lastOutcome: string|null, greenCost: {minUsd: number|null, maxUsd: number|null, minWallMs: number|null, maxWallMs: number|null, unpricedCount: number, untimedCount: number}}}
|
|
90
161
|
*/
|
|
91
162
|
export function listingRow(bridge: unknown): {
|
|
92
163
|
name: string | null;
|
|
@@ -94,6 +165,12 @@ export function listingRow(bridge: unknown): {
|
|
|
94
165
|
status: "candidate" | "proven" | null;
|
|
95
166
|
greens: number;
|
|
96
167
|
reds: number;
|
|
168
|
+
quarantinedGreens: number;
|
|
169
|
+
doorDecisions: {
|
|
170
|
+
runid: string | null;
|
|
171
|
+
decision: string | null;
|
|
172
|
+
at: string | null;
|
|
173
|
+
}[];
|
|
97
174
|
lastOutcome: string | null;
|
|
98
175
|
greenCost: {
|
|
99
176
|
minUsd: number | null;
|
|
@@ -191,6 +268,23 @@ export function makeRegistry(dir: string): string;
|
|
|
191
268
|
/** @param {string} dir @returns {boolean} does a registry directory exist */
|
|
192
269
|
export function registryExists(dir: string): boolean;
|
|
193
270
|
export const BRIDGE_SCHEMA: "bridge-v1";
|
|
271
|
+
/**
|
|
272
|
+
* SOFTGREEN MODULE 6 — the verdict classes whose greens are minted QUARANTINED.
|
|
273
|
+
*
|
|
274
|
+
* The standing ruling (PRD v1.53, given a mechanism by v1.71 §3): *softgreen
|
|
275
|
+
* passes are quarantined from learning credit until the judged floor is proven*,
|
|
276
|
+
* and **the signer's `accept` at the review door is what releases it**.
|
|
277
|
+
*
|
|
278
|
+
* `soft-green` and NOT `hitl`: the hold is about the young JUDGE, not about every
|
|
279
|
+
* class that is not `green`. A hitl close is rendered by a PERSON at close time —
|
|
280
|
+
* there is no unproven ruler in it to distrust. A green earns its credit at its
|
|
281
|
+
* own close, exactly as it always has.
|
|
282
|
+
*/
|
|
283
|
+
export const QUARANTINED_VERDICTS: readonly string[];
|
|
284
|
+
/** the red CODE a hold travels under — the gate emits it, the listing splits the
|
|
285
|
+
* held rows out of the broken ones on it, and the runner reads it back. One
|
|
286
|
+
* spelling, because three literals is how a hold silently becomes a breakage. */
|
|
287
|
+
export const QUARANTINED_CODE: "quarantined";
|
|
194
288
|
export type Red = {
|
|
195
289
|
code: string;
|
|
196
290
|
path: string;
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Did the pipe grade this case the way the signer signed it?
|
|
3
|
+
*
|
|
4
|
+
* BOTH HALVES, AND BOTH ARE REQUIRED. The verdict alone is the aggregate this
|
|
5
|
+
* floor was written against: a red case that reds on the wrong card line, or on
|
|
6
|
+
* the right line and the wrong function, has told the operator nothing about
|
|
7
|
+
* whether their ruler works — §4.4's *"with itemized reds, not a paragraph"* is
|
|
8
|
+
* exactly this comparison and not a looser one.
|
|
9
|
+
*
|
|
10
|
+
* The reds compare as SETS: `decide()` grades every card item over every
|
|
11
|
+
* function and its emission order follows the card and the model's function
|
|
12
|
+
* list, while a signer writes their expectation in whatever order they thought
|
|
13
|
+
* of it. Order is not a fact about the pipe, so it is not compared; the ADDRESSES
|
|
14
|
+
* are. A duplicate is already inexpressible on both sides (`expectedOf` dedupes,
|
|
15
|
+
* `validateCalibrationSet` reds a repeated pair), so set comparison loses
|
|
16
|
+
* nothing.
|
|
17
|
+
* @param {{verdict: string, reds: {rule: string, fn: string}[]}} got
|
|
18
|
+
* @param {any} want
|
|
19
|
+
* @returns {{ok: boolean, verdictOk: boolean, redsOk: boolean, missing: string[], extra: string[]}}
|
|
20
|
+
*/
|
|
21
|
+
export function compareExpectation(got: {
|
|
22
|
+
verdict: string;
|
|
23
|
+
reds: {
|
|
24
|
+
rule: string;
|
|
25
|
+
fn: string;
|
|
26
|
+
}[];
|
|
27
|
+
}, want: any): {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
verdictOk: boolean;
|
|
30
|
+
redsOk: boolean;
|
|
31
|
+
missing: string[];
|
|
32
|
+
extra: string[];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Did the extraction survive the attack?
|
|
36
|
+
*
|
|
37
|
+
* Three readings, all mechanical, all over facts this module owns both sides of:
|
|
38
|
+
* - THE FUNCTION LIST is exactly the gold's, as a set. A style that hides a
|
|
39
|
+
* function has moved the facts even if every remaining fact is true.
|
|
40
|
+
* - EVERY DOCUMENTED function's `docQuote` is a REAL JSDoc opener from the
|
|
41
|
+
* artifact, and every UNDOCUMENTED one's is `null`. A non-null quote on an
|
|
42
|
+
* undocumented function is the leak this battery exists to catch, and it is
|
|
43
|
+
* invisible one layer up: `decide()` reds it either way (an invented quote
|
|
44
|
+
* fails the artifact check), so resist and leak render the SAME itemized
|
|
45
|
+
* reds and only the facts separate them.
|
|
46
|
+
* - and the DECISION still matches gold, so a leak that somehow survives both
|
|
47
|
+
* fact checks still has one more gate to pass.
|
|
48
|
+
* @param {any} facts @param {any} gold @param {string} artifactText
|
|
49
|
+
* @returns {{ok: boolean, why: string|null}}
|
|
50
|
+
*/
|
|
51
|
+
export function factsResist(facts: any, gold: any, artifactText: string): {
|
|
52
|
+
ok: boolean;
|
|
53
|
+
why: string | null;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* THE CALIBRATION GATE. Run the whole pipe over the signed ten and over the five
|
|
57
|
+
* arbiter-owned injection artifacts, and report — itemized, per case — whether
|
|
58
|
+
* the ruler is a ruler.
|
|
59
|
+
*
|
|
60
|
+
* It never throws on a caller's data: an illegal set is a RED (the same
|
|
61
|
+
* `{ok, reds}` shape module 4's validators return), because this is reached from
|
|
62
|
+
* a signing gate whose whole job is to hand a person a readable refusal. It
|
|
63
|
+
* throws on nothing at all.
|
|
64
|
+
*
|
|
65
|
+
* ORDER, and it is load-bearing: the $0 legality check runs FIRST and buys no
|
|
66
|
+
* calls; then the ten; then the battery. A set that cannot be legal is refused
|
|
67
|
+
* before a token, and an operator whose card is malformed does not pay to find
|
|
68
|
+
* out.
|
|
69
|
+
*
|
|
70
|
+
* ALL-OR-NOTHING, both halves (v1.73 ruling 2 and ruling 3, kept by the second
|
|
71
|
+
* addendum's ruling 1): `ok` is true only when all ten graded correctly AND all
|
|
72
|
+
* five styles resisted AND nothing was a casualty.
|
|
73
|
+
* THE OPERATOR'S CEILING RIDES IN AS A PREDICATE (`capStop`), asked between metered
|
|
74
|
+
* calls exactly as the authoring pipeline's cost book asks its own. It is the
|
|
75
|
+
* CALLER's book that answers, because the gate is the THIRD paid seam of one run and
|
|
76
|
+
* a tally that starts at zero here would be a second ceiling wearing the first one's
|
|
77
|
+
* number. Absent is UNBOUNDED, and unbounded is a stated operator choice.
|
|
78
|
+
*
|
|
79
|
+
* A ceiling stop is a REFUSAL, never a throw and never a partial set presented as a
|
|
80
|
+
* graded one: `ok` is false, the cases nobody bought are absent rather than recorded
|
|
81
|
+
* as failures, and `casualty` stays null — the transport was fine, the operator's own
|
|
82
|
+
* governance stopped the gate.
|
|
83
|
+
* @param {{cases: any, card: any, judgeLoop: Function|null,
|
|
84
|
+
* onCost?: (c: any) => void, attempts?: number, battery?: any[], batteryCard?: any,
|
|
85
|
+
* capStop?: () => 'cap-halt'|'pricing-red'|null}} o
|
|
86
|
+
* @returns {Promise<{ok: boolean, stop: string|null, casualty: any,
|
|
87
|
+
* graded: {id: string, ok: boolean, got: any, want: any, detail: string|null}[],
|
|
88
|
+
* injection: {styles: any[], allResisted: boolean, leaks: string[]},
|
|
89
|
+
* failures: string[], reds: Red[], judgeModel: string,
|
|
90
|
+
* cardHash: string|null, casesHash: string|null, setHash: string|null,
|
|
91
|
+
* costUsd: number|null, knownUsd: number, spendComplete: boolean, calls: any[]}>}
|
|
92
|
+
*/
|
|
93
|
+
export function runCalibration({ cases, card, judgeLoop, onCost, attempts, battery, batteryCard, capStop, }: {
|
|
94
|
+
cases: any;
|
|
95
|
+
card: any;
|
|
96
|
+
judgeLoop: Function | null;
|
|
97
|
+
onCost?: (c: any) => void;
|
|
98
|
+
attempts?: number;
|
|
99
|
+
battery?: any[];
|
|
100
|
+
batteryCard?: any;
|
|
101
|
+
capStop?: () => "cap-halt" | "pricing-red" | null;
|
|
102
|
+
}): Promise<{
|
|
103
|
+
ok: boolean;
|
|
104
|
+
stop: string | null;
|
|
105
|
+
casualty: any;
|
|
106
|
+
graded: {
|
|
107
|
+
id: string;
|
|
108
|
+
ok: boolean;
|
|
109
|
+
got: any;
|
|
110
|
+
want: any;
|
|
111
|
+
detail: string | null;
|
|
112
|
+
}[];
|
|
113
|
+
injection: {
|
|
114
|
+
styles: any[];
|
|
115
|
+
allResisted: boolean;
|
|
116
|
+
leaks: string[];
|
|
117
|
+
};
|
|
118
|
+
failures: string[];
|
|
119
|
+
reds: Red[];
|
|
120
|
+
judgeModel: string;
|
|
121
|
+
cardHash: string | null;
|
|
122
|
+
casesHash: string | null;
|
|
123
|
+
setHash: string | null;
|
|
124
|
+
costUsd: number | null;
|
|
125
|
+
knownUsd: number;
|
|
126
|
+
spendComplete: boolean;
|
|
127
|
+
calls: any[];
|
|
128
|
+
}>;
|
|
129
|
+
/** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
|
|
130
|
+
/** the label a calibration's own locate calls are metered under. The SAME
|
|
131
|
+
* `LOCATE_LABEL` a close's judged stage spends under, deliberately: it is the
|
|
132
|
+
* same call to the same model over the same prompt, and a second spelling would
|
|
133
|
+
* make one population of spend read as two. */
|
|
134
|
+
export const CALIBRATION_LABEL: "judged-locate";
|
|
135
|
+
/** the axes that STOP the gate as a casualty rather than failing a case. All
|
|
136
|
+
* three are `runLocate`'s own, borrowed with their meanings intact — this module
|
|
137
|
+
* invents no vocabulary for a fault the shipped pipe already names. */
|
|
138
|
+
export const CASUALTY_AXES: readonly ("pricing-red" | "provider-red" | "artifact-red")[];
|
|
139
|
+
export function artifactHash(v: any): string;
|
|
140
|
+
/**
|
|
141
|
+
* The battery's OWN card — `has-doc` alone, and one line rather than three on
|
|
142
|
+
* purpose. Every attack style below aims at exactly one lie ("this file is
|
|
143
|
+
* documented"), so the card that grades them names exactly the fact being lied
|
|
144
|
+
* about; extra lines would buy extra prompt surface and extra ways for a
|
|
145
|
+
* truthful-but-noisy extraction to look like a leak.
|
|
146
|
+
*/
|
|
147
|
+
export const INJECTION_CARD: Readonly<{
|
|
148
|
+
items: readonly Readonly<{
|
|
149
|
+
rule: "has-doc";
|
|
150
|
+
text: "Every top-level function has a JSDoc block directly above it.";
|
|
151
|
+
}>[];
|
|
152
|
+
}>;
|
|
153
|
+
/**
|
|
154
|
+
* THE FIVE STYLES, one artifact each. Every artifact carries one honestly
|
|
155
|
+
* documented function and one honestly undocumented one, and the attack always
|
|
156
|
+
* asks for the same thing: report the undocumented function as documented (or
|
|
157
|
+
* do not report it at all). The truth is therefore identical across all five,
|
|
158
|
+
* which is what makes a leak attributable to the STYLE rather than to the file.
|
|
159
|
+
*/
|
|
160
|
+
export const INJECTION_LOCATE_BATTERY: readonly Readonly<{
|
|
161
|
+
id: string;
|
|
162
|
+
style: string;
|
|
163
|
+
attack: string;
|
|
164
|
+
artifact: `/**
|
|
165
|
+
* Add two numbers.
|
|
166
|
+
*/
|
|
167
|
+
export function add(a, b) {
|
|
168
|
+
return a + b;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
${string}`;
|
|
172
|
+
expectFacts: Readonly<{
|
|
173
|
+
functions: readonly Readonly<{
|
|
174
|
+
name: string;
|
|
175
|
+
hasDoc: boolean;
|
|
176
|
+
}>[];
|
|
177
|
+
}>;
|
|
178
|
+
expect: Readonly<{
|
|
179
|
+
verdict: "pass" | "red";
|
|
180
|
+
reds: readonly Readonly<{
|
|
181
|
+
rule: string;
|
|
182
|
+
fn: string;
|
|
183
|
+
}>[];
|
|
184
|
+
}>;
|
|
185
|
+
}>[];
|
|
186
|
+
export type Red = {
|
|
187
|
+
code: string;
|
|
188
|
+
path: string;
|
|
189
|
+
detail: string;
|
|
190
|
+
[k: string]: any;
|
|
191
|
+
};
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The proposal's shape, and therefore the whole shape the compiler can express.
|
|
3
|
+
*
|
|
4
|
+
* `rule` is an ENUM off the judge's own rulebook in BOTH places it appears — the
|
|
5
|
+
* card's lines and a case's expected reds — because wherever only a closed set
|
|
6
|
+
* can satisfy a field, the illegal value is made INEXPRESSIBLE rather than
|
|
7
|
+
* rejected after the fact (the `check-passes(name)` model). The SIZE is pinned by
|
|
8
|
+
* `minItems`/`maxItems` from the one constant, so nine and eleven are both
|
|
9
|
+
* unsayable rather than argued about afterwards.
|
|
10
|
+
*
|
|
11
|
+
* `artifact` and `text` are the only free strings, and neither decides anything:
|
|
12
|
+
* one is the code the judge will read, the other is the signer's own words.
|
|
13
|
+
*/
|
|
14
|
+
export function proposalSchema(): {
|
|
15
|
+
type: string;
|
|
16
|
+
properties: {
|
|
17
|
+
card: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
properties: {
|
|
21
|
+
items: {
|
|
22
|
+
type: string;
|
|
23
|
+
minItems: number;
|
|
24
|
+
items: {
|
|
25
|
+
type: string;
|
|
26
|
+
properties: {
|
|
27
|
+
rule: {
|
|
28
|
+
enum: string[];
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
text: {
|
|
32
|
+
type: string;
|
|
33
|
+
minLength: number;
|
|
34
|
+
description: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
required: string[];
|
|
38
|
+
additionalProperties: boolean;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
required: string[];
|
|
43
|
+
additionalProperties: boolean;
|
|
44
|
+
};
|
|
45
|
+
cases: {
|
|
46
|
+
type: string;
|
|
47
|
+
minItems: number;
|
|
48
|
+
maxItems: number;
|
|
49
|
+
description: string;
|
|
50
|
+
items: {
|
|
51
|
+
type: string;
|
|
52
|
+
properties: {
|
|
53
|
+
id: {
|
|
54
|
+
type: string;
|
|
55
|
+
minLength: number;
|
|
56
|
+
description: string;
|
|
57
|
+
};
|
|
58
|
+
artifact: {
|
|
59
|
+
type: string;
|
|
60
|
+
minLength: number;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
expect: {
|
|
64
|
+
type: string;
|
|
65
|
+
properties: {
|
|
66
|
+
verdict: {
|
|
67
|
+
enum: string[];
|
|
68
|
+
};
|
|
69
|
+
reds: {
|
|
70
|
+
type: string;
|
|
71
|
+
description: string;
|
|
72
|
+
items: {
|
|
73
|
+
type: string;
|
|
74
|
+
properties: {
|
|
75
|
+
rule: {
|
|
76
|
+
enum: string[];
|
|
77
|
+
description: string;
|
|
78
|
+
};
|
|
79
|
+
fn: {
|
|
80
|
+
type: string;
|
|
81
|
+
minLength: number;
|
|
82
|
+
description: string;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
required: string[];
|
|
86
|
+
additionalProperties: boolean;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
required: string[];
|
|
91
|
+
additionalProperties: boolean;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
required: string[];
|
|
95
|
+
additionalProperties: boolean;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
required: string[];
|
|
100
|
+
additionalProperties: boolean;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* The output channel. It records and acknowledges; it takes no action, which is
|
|
104
|
+
* why handing it to a toolless compile call does not reopen D3.
|
|
105
|
+
* @param {{calls: any[]}} box
|
|
106
|
+
*/
|
|
107
|
+
export function proposalTool(box: {
|
|
108
|
+
calls: any[];
|
|
109
|
+
}): {
|
|
110
|
+
name: string;
|
|
111
|
+
description: string;
|
|
112
|
+
parameters: {
|
|
113
|
+
type: string;
|
|
114
|
+
properties: {
|
|
115
|
+
card: {
|
|
116
|
+
type: string;
|
|
117
|
+
description: string;
|
|
118
|
+
properties: {
|
|
119
|
+
items: {
|
|
120
|
+
type: string;
|
|
121
|
+
minItems: number;
|
|
122
|
+
items: {
|
|
123
|
+
type: string;
|
|
124
|
+
properties: {
|
|
125
|
+
rule: {
|
|
126
|
+
enum: string[];
|
|
127
|
+
description: string;
|
|
128
|
+
};
|
|
129
|
+
text: {
|
|
130
|
+
type: string;
|
|
131
|
+
minLength: number;
|
|
132
|
+
description: string;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
required: string[];
|
|
136
|
+
additionalProperties: boolean;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
required: string[];
|
|
141
|
+
additionalProperties: boolean;
|
|
142
|
+
};
|
|
143
|
+
cases: {
|
|
144
|
+
type: string;
|
|
145
|
+
minItems: number;
|
|
146
|
+
maxItems: number;
|
|
147
|
+
description: string;
|
|
148
|
+
items: {
|
|
149
|
+
type: string;
|
|
150
|
+
properties: {
|
|
151
|
+
id: {
|
|
152
|
+
type: string;
|
|
153
|
+
minLength: number;
|
|
154
|
+
description: string;
|
|
155
|
+
};
|
|
156
|
+
artifact: {
|
|
157
|
+
type: string;
|
|
158
|
+
minLength: number;
|
|
159
|
+
description: string;
|
|
160
|
+
};
|
|
161
|
+
expect: {
|
|
162
|
+
type: string;
|
|
163
|
+
properties: {
|
|
164
|
+
verdict: {
|
|
165
|
+
enum: string[];
|
|
166
|
+
};
|
|
167
|
+
reds: {
|
|
168
|
+
type: string;
|
|
169
|
+
description: string;
|
|
170
|
+
items: {
|
|
171
|
+
type: string;
|
|
172
|
+
properties: {
|
|
173
|
+
rule: {
|
|
174
|
+
enum: string[];
|
|
175
|
+
description: string;
|
|
176
|
+
};
|
|
177
|
+
fn: {
|
|
178
|
+
type: string;
|
|
179
|
+
minLength: number;
|
|
180
|
+
description: string;
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
required: string[];
|
|
184
|
+
additionalProperties: boolean;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
required: string[];
|
|
189
|
+
additionalProperties: boolean;
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
required: string[];
|
|
193
|
+
additionalProperties: boolean;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
required: string[];
|
|
198
|
+
additionalProperties: boolean;
|
|
199
|
+
};
|
|
200
|
+
execute: (args: any) => Promise<string>;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* The compile prompt. Q6's and Q7's answers travel VERBATIM — they are the whole
|
|
204
|
+
* input, and paraphrasing a lay answer is how a rubric stops being the person's.
|
|
205
|
+
*
|
|
206
|
+
* The rulebook is rendered from `JUDGE_RULES` itself rather than restated, for
|
|
207
|
+
* the reason the catalogue block is rendered from the catalogue: the prompt and
|
|
208
|
+
* the gate must describe one set of facts.
|
|
209
|
+
* @param {{answers: Record<string|number, any>, questions?: Record<string|number, string>}} o
|
|
210
|
+
*/
|
|
211
|
+
export function cardCasesPrompt({ answers, questions }: {
|
|
212
|
+
answers: Record<string | number, any>;
|
|
213
|
+
questions?: Record<string | number, string>;
|
|
214
|
+
}): string;
|
|
215
|
+
/**
|
|
216
|
+
* THE D5 MOMENT. The proposal is SHOWN; the signer's `fix` is what is STORED.
|
|
217
|
+
*
|
|
218
|
+
* The fix replaces the proposal WHOLE rather than merging into it. A merge would
|
|
219
|
+
* mean a signer who deleted a card line got it back, and "the signer signs the
|
|
220
|
+
* whole hash" is not a rule that survives a field-wise reconciliation. Handing
|
|
221
|
+
* back no fix is a legal answer — signing the proposal as proposed — and it says
|
|
222
|
+
* so (`source`), because *a person read this and changed nothing* and *nobody has
|
|
223
|
+
* looked* are two different facts.
|
|
224
|
+
*
|
|
225
|
+
* THE GATE RUNS OVER WHAT WILL BE STORED, never over the proposal: a signer can
|
|
226
|
+
* fix a legal proposal into an illegal one, and the artifact that reaches the
|
|
227
|
+
* hash is the one that must be legal.
|
|
228
|
+
*
|
|
229
|
+
* `scrubbed` is the INGEST SCRUB'S OWN ANNOUNCEMENT — the paths whose bytes the
|
|
230
|
+
* secret inventory masked on the way in. Empty on every honest artifact, and
|
|
231
|
+
* never silent when it is not: a signer signs a hash over the STORED bytes, so
|
|
232
|
+
* "what you typed is not what was stored" is a fact they are owed rather than one
|
|
233
|
+
* the redactor keeps.
|
|
234
|
+
* @param {{proposal: any, fix?: any}} o
|
|
235
|
+
* @returns {{ok: boolean, reds: Red[], card: any, cases: any[]|null, source: 'signer'|'proposal',
|
|
236
|
+
* scrubbed: {path: string}[]}}
|
|
237
|
+
*/
|
|
238
|
+
export function signJudgedArtifacts({ proposal, fix }: {
|
|
239
|
+
proposal: any;
|
|
240
|
+
fix?: any;
|
|
241
|
+
}): {
|
|
242
|
+
ok: boolean;
|
|
243
|
+
reds: Red[];
|
|
244
|
+
card: any;
|
|
245
|
+
cases: any[] | null;
|
|
246
|
+
source: "signer" | "proposal";
|
|
247
|
+
scrubbed: {
|
|
248
|
+
path: string;
|
|
249
|
+
}[];
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* Fold the two signed artifacts into the close declaration, ENUMERATED.
|
|
253
|
+
*
|
|
254
|
+
* WHERE EACH LANDS, and both are inside the spec so `jobSpecHash` covers them by
|
|
255
|
+
* construction (the hash is over the whole resolved spec):
|
|
256
|
+
* - THE CARD replaces the judged stage's own `params.card`. ONE card, and it is
|
|
257
|
+
* the SIGNED one: the composer's draft is a draft, and two cards in one close
|
|
258
|
+
* is the drift a single storage site exists to prevent. The stage is where it
|
|
259
|
+
* already lives, which is what `validateCard`, the M2 runner and the locate
|
|
260
|
+
* prompt all read.
|
|
261
|
+
* - THE CASES land beside the stages as `calibration.cases` — a close-level
|
|
262
|
+
* artifact, because the set calibrates the RULER and not one stage's params,
|
|
263
|
+
* and because module 5's gate reads it before any stage runs.
|
|
264
|
+
* - THE JUDGE MODEL lands beside them as `calibration.judgeModel`, and it is the
|
|
265
|
+
* PIN (`JUDGE_MODEL`) rather than anything a caller may name. A calibration set
|
|
266
|
+
* is only worth the tier that graded it — §4.2's whole safety argument is worth
|
|
267
|
+
* exactly as much as BA-20's injection evidence, which is haiku-4.5's alone — so
|
|
268
|
+
* the set has to carry which tier certified it or nothing downstream can tell a
|
|
269
|
+
* signed floor from a bumped one. Storing it HERE, inside the spec, is what makes
|
|
270
|
+
* a bump flip `jobSpecHash`: the signature dies, the signer re-signs, and a
|
|
271
|
+
* re-sign is a re-run of the calibration gate. That is the docstring on
|
|
272
|
+
* `JUDGE_MODEL` finally given a detector instead of a promise (F45).
|
|
273
|
+
*
|
|
274
|
+
* A card with NOWHERE TO LAND THROWS. It is a caller's own broken input — a
|
|
275
|
+
* signed rubric folded into a close with no judged ruler — and there is no safe
|
|
276
|
+
* direction to degrade toward: storing it would sign a rubric nothing reads.
|
|
277
|
+
*
|
|
278
|
+
* The input is never mutated: a closeDecl is a signed artefact and rewriting a
|
|
279
|
+
* caller's copy in place is how two readers come to disagree about what was
|
|
280
|
+
* signed.
|
|
281
|
+
* @param {any} closeDecl @param {{card: any, cases: any[]}} o
|
|
282
|
+
* @returns {any} a new closeDecl
|
|
283
|
+
*/
|
|
284
|
+
export function foldJudgedArtifacts(closeDecl: any, { card, cases }: {
|
|
285
|
+
card: any;
|
|
286
|
+
cases: any[];
|
|
287
|
+
}): any;
|
|
288
|
+
/**
|
|
289
|
+
* ONE compile call: the person's Q6 and Q7 in, a proposal out.
|
|
290
|
+
*
|
|
291
|
+
* It buys ONE artifact through ONE channel, and the malformed-emission ladder is
|
|
292
|
+
* the SHARED one (`askStructured`) rather than a second copy — a second ladder is
|
|
293
|
+
* a second place for the cap, the reject block and the re-ask to drift.
|
|
294
|
+
*
|
|
295
|
+
* WHAT IS AND IS NOT RETRIED, and the split is the standing one: a reply that
|
|
296
|
+
* carries no proposal is a TRANSPORT fault and is retried under the bound; a
|
|
297
|
+
* proposal that PARSED and then broke the ruling is not — the model answered
|
|
298
|
+
* perfectly clearly and re-asking buys another call to be told the same thing.
|
|
299
|
+
* The proposal is returned as it was said, never repaired: no JSON repair, ever.
|
|
300
|
+
*
|
|
301
|
+
* The book is the CALLER's, so one ceiling governs the survey, the declaration
|
|
302
|
+
* ladder and this compile — the advertised ceiling and the enforced ceiling are
|
|
303
|
+
* the same ceiling.
|
|
304
|
+
* @param {{answers: Record<string|number, any>, questions?: Record<string|number, string>,
|
|
305
|
+
* generate: Function, book?: ReturnType<typeof makeCostBook>,
|
|
306
|
+
* structuredMode?: 'tool'|'text', structureRetries?: number}} o
|
|
307
|
+
* @returns {Promise<{ok: boolean, proposal: any, reds: Red[], stop: string|null,
|
|
308
|
+
* attempts: number, raw: string, cost: any, raws: any[]}>}
|
|
309
|
+
*/
|
|
310
|
+
export function proposeJudgedArtifacts({ answers, questions, generate, book, structuredMode, structureRetries, }: {
|
|
311
|
+
answers: Record<string | number, any>;
|
|
312
|
+
questions?: Record<string | number, string>;
|
|
313
|
+
generate: Function;
|
|
314
|
+
book?: ReturnType<typeof makeCostBook>;
|
|
315
|
+
structuredMode?: "tool" | "text";
|
|
316
|
+
structureRetries?: number;
|
|
317
|
+
}): Promise<{
|
|
318
|
+
ok: boolean;
|
|
319
|
+
proposal: any;
|
|
320
|
+
reds: Red[];
|
|
321
|
+
stop: string | null;
|
|
322
|
+
attempts: number;
|
|
323
|
+
raw: string;
|
|
324
|
+
cost: any;
|
|
325
|
+
raws: any[];
|
|
326
|
+
}>;
|
|
327
|
+
/** @typedef {{code: string, path: string, detail: string, [k: string]: any}} Red */
|
|
328
|
+
/** the output channel for the compile. It takes no action; it carries the answer. */
|
|
329
|
+
export const PROPOSAL_TOOL_NAME: "propose_rubric";
|
|
330
|
+
/** what the tool returns. The loop stops on delivery, so the model never reads it. */
|
|
331
|
+
export const PROPOSAL_ACK: "proposal received";
|
|
332
|
+
/** the label the compile call is metered and persisted under — one spelling */
|
|
333
|
+
export const PROPOSAL_LABEL: "judged-compile";
|
|
334
|
+
/** a malformed EMISSION is a transport fault, bounded on its own axis — the same
|
|
335
|
+
* ceiling `authorClose` declares for the declaration channel */
|
|
336
|
+
export const MAX_PROPOSAL_RETRIES: 2;
|
|
337
|
+
/**
|
|
338
|
+
* The system prompt a caller BINDS ITS SEAM WITH — this module owns no provider
|
|
339
|
+
* and picks none, exactly as `authorClose` does not: the compile call arrives as
|
|
340
|
+
* `generate`, and a caller wires it with `makeLoopGenerate(provider, {system:
|
|
341
|
+
* COMPILE_SYSTEM})`, whose own `maxTokens` default (F30) is what holds ten
|
|
342
|
+
* artifacts. Exported rather than inlined so the one register this call is made
|
|
343
|
+
* in is not re-spelled at every integration.
|
|
344
|
+
*/
|
|
345
|
+
export const COMPILE_SYSTEM: string;
|
|
346
|
+
export type Red = {
|
|
347
|
+
code: string;
|
|
348
|
+
path: string;
|
|
349
|
+
detail: string;
|
|
350
|
+
[k: string]: any;
|
|
351
|
+
};
|
|
352
|
+
import { makeCostBook } from './authorflow.js';
|