@yagni-app/code-staging 0.0.0 → 0.1.0-staging.1002.1
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/LICENSE.md +55 -0
- package/README.md +166 -0
- package/dist/branding.d.ts +25 -0
- package/dist/branding.js +27 -0
- package/dist/claudeCompat.d.ts +78 -0
- package/dist/claudeCompat.js +198 -0
- package/dist/cli.d.ts +55 -0
- package/dist/cli.js +326 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +28 -0
- package/dist/credentials.d.ts +41 -0
- package/dist/credentials.js +75 -0
- package/dist/distribution.d.ts +15 -0
- package/dist/distribution.js +45 -0
- package/dist/doctor.d.ts +94 -0
- package/dist/doctor.js +343 -0
- package/dist/extension/advisor.d.ts +84 -0
- package/dist/extension/advisor.js +101 -0
- package/dist/extension/askAdvisorTool.d.ts +83 -0
- package/dist/extension/askAdvisorTool.js +188 -0
- package/dist/extension/askYagniTool.d.ts +39 -0
- package/dist/extension/askYagniTool.js +63 -0
- package/dist/extension/bless.d.ts +45 -0
- package/dist/extension/bless.js +74 -0
- package/dist/extension/branding.d.ts +48 -0
- package/dist/extension/branding.js +119 -0
- package/dist/extension/chipEditor.d.ts +117 -0
- package/dist/extension/chipEditor.js +369 -0
- package/dist/extension/config.d.ts +112 -0
- package/dist/extension/config.js +108 -0
- package/dist/extension/costHud.d.ts +73 -0
- package/dist/extension/costHud.js +123 -0
- package/dist/extension/decisionCapture.d.ts +52 -0
- package/dist/extension/decisionCapture.js +66 -0
- package/dist/extension/decisions.d.ts +83 -0
- package/dist/extension/decisions.js +200 -0
- package/dist/extension/diagnostics.d.ts +41 -0
- package/dist/extension/diagnostics.js +110 -0
- package/dist/extension/index.d.ts +116 -0
- package/dist/extension/index.js +388 -0
- package/dist/extension/initDone.d.ts +28 -0
- package/dist/extension/initDone.js +66 -0
- package/dist/extension/initPass.d.ts +152 -0
- package/dist/extension/initPass.js +394 -0
- package/dist/extension/nextWorkTool.d.ts +51 -0
- package/dist/extension/nextWorkTool.js +80 -0
- package/dist/extension/permission.d.ts +91 -0
- package/dist/extension/permission.js +236 -0
- package/dist/extension/pipeline/activity.d.ts +37 -0
- package/dist/extension/pipeline/activity.js +151 -0
- package/dist/extension/pipeline/activityFeed.d.ts +59 -0
- package/dist/extension/pipeline/activityFeed.js +175 -0
- package/dist/extension/pipeline/budget.d.ts +48 -0
- package/dist/extension/pipeline/budget.js +68 -0
- package/dist/extension/pipeline/checkpoint.d.ts +31 -0
- package/dist/extension/pipeline/checkpoint.js +176 -0
- package/dist/extension/pipeline/eval.d.ts +168 -0
- package/dist/extension/pipeline/eval.js +182 -0
- package/dist/extension/pipeline/events.d.ts +56 -0
- package/dist/extension/pipeline/events.js +147 -0
- package/dist/extension/pipeline/findings.d.ts +42 -0
- package/dist/extension/pipeline/findings.js +144 -0
- package/dist/extension/pipeline/finish.d.ts +128 -0
- package/dist/extension/pipeline/finish.js +307 -0
- package/dist/extension/pipeline/goCommand.d.ts +128 -0
- package/dist/extension/pipeline/goCommand.js +972 -0
- package/dist/extension/pipeline/goCompareCommand.d.ts +48 -0
- package/dist/extension/pipeline/goCompareCommand.js +184 -0
- package/dist/extension/pipeline/goFlags.d.ts +40 -0
- package/dist/extension/pipeline/goFlags.js +46 -0
- package/dist/extension/pipeline/goStatusCommands.d.ts +59 -0
- package/dist/extension/pipeline/goStatusCommands.js +188 -0
- package/dist/extension/pipeline/invocation.d.ts +45 -0
- package/dist/extension/pipeline/invocation.js +64 -0
- package/dist/extension/pipeline/orchestrator.d.ts +131 -0
- package/dist/extension/pipeline/orchestrator.js +636 -0
- package/dist/extension/pipeline/personas.d.ts +44 -0
- package/dist/extension/pipeline/personas.js +248 -0
- package/dist/extension/pipeline/resilience.d.ts +85 -0
- package/dist/extension/pipeline/resilience.js +166 -0
- package/dist/extension/pipeline/resume.d.ts +18 -0
- package/dist/extension/pipeline/resume.js +106 -0
- package/dist/extension/pipeline/runRegistry.d.ts +112 -0
- package/dist/extension/pipeline/runRegistry.js +202 -0
- package/dist/extension/pipeline/runSession.d.ts +152 -0
- package/dist/extension/pipeline/runSession.js +167 -0
- package/dist/extension/pipeline/runState.d.ts +158 -0
- package/dist/extension/pipeline/runState.js +264 -0
- package/dist/extension/pipeline/runner.d.ts +79 -0
- package/dist/extension/pipeline/runner.js +298 -0
- package/dist/extension/pipeline/scrubSecrets.d.ts +15 -0
- package/dist/extension/pipeline/scrubSecrets.js +32 -0
- package/dist/extension/pipeline/stages.d.ts +51 -0
- package/dist/extension/pipeline/stages.js +113 -0
- package/dist/extension/pipeline/ticketResolution.d.ts +34 -0
- package/dist/extension/pipeline/ticketResolution.js +75 -0
- package/dist/extension/pipeline/types.d.ts +436 -0
- package/dist/extension/pipeline/types.js +48 -0
- package/dist/extension/pipeline/verify.d.ts +277 -0
- package/dist/extension/pipeline/verify.js +758 -0
- package/dist/extension/pipeline/workspace.d.ts +32 -0
- package/dist/extension/pipeline/workspace.js +73 -0
- package/dist/extension/pipeline/worktree.d.ts +107 -0
- package/dist/extension/pipeline/worktree.js +200 -0
- package/dist/extension/provider.d.ts +11 -0
- package/dist/extension/provider.js +26 -0
- package/dist/extension/recall.d.ts +93 -0
- package/dist/extension/recall.js +187 -0
- package/dist/extension/recordContextTool.d.ts +38 -0
- package/dist/extension/recordContextTool.js +85 -0
- package/dist/extension/recordDecisionTool.d.ts +52 -0
- package/dist/extension/recordDecisionTool.js +102 -0
- package/dist/extension/repoDocs.d.ts +81 -0
- package/dist/extension/repoDocs.js +260 -0
- package/dist/extension/resilientFetch.d.ts +60 -0
- package/dist/extension/resilientFetch.js +133 -0
- package/dist/extension/reviewTool.d.ts +34 -0
- package/dist/extension/reviewTool.js +81 -0
- package/dist/extension/spool.d.ts +92 -0
- package/dist/extension/spool.js +266 -0
- package/dist/extension/stateHome.d.ts +2 -0
- package/dist/extension/stateHome.js +6 -0
- package/dist/extension/subagents.d.ts +135 -0
- package/dist/extension/subagents.js +281 -0
- package/dist/extension/surface.d.ts +10 -0
- package/dist/extension/surface.js +12 -0
- package/dist/extension/todos.d.ts +110 -0
- package/dist/extension/todos.js +217 -0
- package/dist/extension/tokenProvider.d.ts +93 -0
- package/dist/extension/tokenProvider.js +234 -0
- package/dist/launch.d.ts +76 -0
- package/dist/launch.js +111 -0
- package/dist/login.d.ts +45 -0
- package/dist/login.js +142 -0
- package/dist/logout.d.ts +14 -0
- package/dist/logout.js +34 -0
- package/dist/paths.d.ts +31 -0
- package/dist/paths.js +87 -0
- package/dist/piPackage.d.ts +33 -0
- package/dist/piPackage.js +71 -0
- package/dist/profiles.d.ts +80 -0
- package/dist/profiles.js +222 -0
- package/dist/refresh.d.ts +70 -0
- package/dist/refresh.js +117 -0
- package/dist/upgrade.d.ts +97 -0
- package/dist/upgrade.js +284 -0
- package/package.json +39 -3
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R3-b - run-level budget / turn ceiling, enforced orchestrator-side.
|
|
3
|
+
*
|
|
4
|
+
* The frontier harnesses bound a run with a turn/budget ceiling; /go had none, so
|
|
5
|
+
* a pathological loop could spend without limit. These PURE helpers aggregate the
|
|
6
|
+
* per-stage usage the runner already records (StageResult.usage) across the whole
|
|
7
|
+
* run (build stages + every review lens + each fix) and report when an aggregate
|
|
8
|
+
* crosses a ceiling. The orchestrator stops honestly with `budget_exceeded` rather
|
|
9
|
+
* than running on.
|
|
10
|
+
*
|
|
11
|
+
* The turn cap is enforced here via aggregated `usage.turns` (not a pi --max-turns
|
|
12
|
+
* flag, which is unverified in the pi flag set; that is on the upstream-pi
|
|
13
|
+
* wishlist). Ceilings are generous safety bounds, not tight budgets, so a normal
|
|
14
|
+
* run never trips them.
|
|
15
|
+
*/
|
|
16
|
+
import type { ReviewRound, StageResult } from "./types.js";
|
|
17
|
+
/** Aggregated usage across a whole run. */
|
|
18
|
+
export interface RunUsage {
|
|
19
|
+
turns: number;
|
|
20
|
+
cost: number;
|
|
21
|
+
input: number;
|
|
22
|
+
output: number;
|
|
23
|
+
}
|
|
24
|
+
/** The run-level ceilings. */
|
|
25
|
+
export interface RunBudget {
|
|
26
|
+
/** Max aggregate assistant turns across all stages. */
|
|
27
|
+
maxTurns: number;
|
|
28
|
+
/** Max aggregate cost (same unit as StageUsage.cost). */
|
|
29
|
+
maxCost: number;
|
|
30
|
+
/** Max aggregate input+output tokens. */
|
|
31
|
+
maxTokens: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generous default ceilings: a 3-round /go fans out review across 3 lenses on top
|
|
35
|
+
* of the build half, so dozens of turns and millions of tokens are normal; these
|
|
36
|
+
* only catch a runaway. Tunable per lane.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DEFAULT_RUN_BUDGET: RunBudget;
|
|
39
|
+
export declare const EMPTY_RUN_USAGE: RunUsage;
|
|
40
|
+
export declare function addRunUsage(a: RunUsage, b: RunUsage): RunUsage;
|
|
41
|
+
/** Sum usage across the build/fix stages AND every review lens result. */
|
|
42
|
+
export declare function aggregateRunUsage(stages: StageResult[], rounds: ReviewRound[]): RunUsage;
|
|
43
|
+
/**
|
|
44
|
+
* Return an honest reason string when an aggregate usage crosses any ceiling, else
|
|
45
|
+
* null. Checked at each stage boundary so the run stops at the first crossing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function exceedsBudget(usage: RunUsage, budget: RunBudget): string | null;
|
|
48
|
+
//# sourceMappingURL=budget.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R3-b - run-level budget / turn ceiling, enforced orchestrator-side.
|
|
3
|
+
*
|
|
4
|
+
* The frontier harnesses bound a run with a turn/budget ceiling; /go had none, so
|
|
5
|
+
* a pathological loop could spend without limit. These PURE helpers aggregate the
|
|
6
|
+
* per-stage usage the runner already records (StageResult.usage) across the whole
|
|
7
|
+
* run (build stages + every review lens + each fix) and report when an aggregate
|
|
8
|
+
* crosses a ceiling. The orchestrator stops honestly with `budget_exceeded` rather
|
|
9
|
+
* than running on.
|
|
10
|
+
*
|
|
11
|
+
* The turn cap is enforced here via aggregated `usage.turns` (not a pi --max-turns
|
|
12
|
+
* flag, which is unverified in the pi flag set; that is on the upstream-pi
|
|
13
|
+
* wishlist). Ceilings are generous safety bounds, not tight budgets, so a normal
|
|
14
|
+
* run never trips them.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Generous default ceilings: a 3-round /go fans out review across 3 lenses on top
|
|
18
|
+
* of the build half, so dozens of turns and millions of tokens are normal; these
|
|
19
|
+
* only catch a runaway. Tunable per lane.
|
|
20
|
+
*/
|
|
21
|
+
export const DEFAULT_RUN_BUDGET = {
|
|
22
|
+
maxTurns: 400,
|
|
23
|
+
maxCost: 50,
|
|
24
|
+
maxTokens: 8_000_000,
|
|
25
|
+
};
|
|
26
|
+
export const EMPTY_RUN_USAGE = { turns: 0, cost: 0, input: 0, output: 0 };
|
|
27
|
+
export function addRunUsage(a, b) {
|
|
28
|
+
return {
|
|
29
|
+
turns: a.turns + b.turns,
|
|
30
|
+
cost: a.cost + b.cost,
|
|
31
|
+
input: a.input + b.input,
|
|
32
|
+
output: a.output + b.output,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Sum usage across the build/fix stages AND every review lens result. */
|
|
36
|
+
export function aggregateRunUsage(stages, rounds) {
|
|
37
|
+
const acc = { ...EMPTY_RUN_USAGE };
|
|
38
|
+
const add = (u) => {
|
|
39
|
+
acc.turns += u.turns;
|
|
40
|
+
acc.cost += u.cost;
|
|
41
|
+
acc.input += u.input;
|
|
42
|
+
acc.output += u.output;
|
|
43
|
+
};
|
|
44
|
+
for (const s of stages)
|
|
45
|
+
add(s.usage);
|
|
46
|
+
for (const r of rounds)
|
|
47
|
+
for (const l of r.lensResults)
|
|
48
|
+
add(l.usage);
|
|
49
|
+
return acc;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Return an honest reason string when an aggregate usage crosses any ceiling, else
|
|
53
|
+
* null. Checked at each stage boundary so the run stops at the first crossing.
|
|
54
|
+
*/
|
|
55
|
+
export function exceedsBudget(usage, budget) {
|
|
56
|
+
if (usage.turns > budget.maxTurns) {
|
|
57
|
+
return `turn ceiling reached (${usage.turns} of ${budget.maxTurns} model turns)`;
|
|
58
|
+
}
|
|
59
|
+
if (usage.cost > budget.maxCost) {
|
|
60
|
+
return `cost ceiling reached (${usage.cost.toFixed(2)} of ${budget.maxCost})`;
|
|
61
|
+
}
|
|
62
|
+
const tokens = usage.input + usage.output;
|
|
63
|
+
if (tokens > budget.maxTokens) {
|
|
64
|
+
return `token ceiling reached (${tokens} of ${budget.maxTokens} tokens)`;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=budget.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fail-soft {@link CheckpointStore} implementations — the durable substrate
|
|
3
|
+
* behind /go resume.
|
|
4
|
+
*
|
|
5
|
+
* Three stores, all sharing the iron contract: NEVER throw, NEVER block /go.
|
|
6
|
+
* - {@link makeFileCheckpointStore} — the durable PRIMARY. An append-only NDJSON
|
|
7
|
+
* file at `~/.yagni-code/runs/<sha1(sessionKey)>.ndjson` (mkdir 0700, file
|
|
8
|
+
* 0600 — mirrors credentials.ts). Session-independent and auth-free, so a
|
|
9
|
+
* LATER pi session (or one started after `/new`) can still read where /go
|
|
10
|
+
* left off, even when the backend was unreachable. A torn final write is
|
|
11
|
+
* harmless: load drops any unparseable line (the classic crash artifact).
|
|
12
|
+
* - {@link makePiJournalCheckpointStore} — a MIRROR into pi's native append-only
|
|
13
|
+
* session journal via `pi.appendEntry` / `sessionManager.getEntries`, the
|
|
14
|
+
* pi-idiomatic persistence the user asked about. Constructed from function
|
|
15
|
+
* seams so it is unit-testable without a pi process.
|
|
16
|
+
* - {@link makeCombinedCheckpointStore} — writes to all stores; reads from the
|
|
17
|
+
* first non-empty (file primary).
|
|
18
|
+
*/
|
|
19
|
+
import type { CheckpointStore } from "./types.js";
|
|
20
|
+
export declare function _setCheckpointHomeForTest(dir: string | null): void;
|
|
21
|
+
export declare function makeFileCheckpointStore(sessionKey: string): CheckpointStore;
|
|
22
|
+
/** The pi customType under which checkpoint records live in the session journal. */
|
|
23
|
+
export declare const PI_CHECKPOINT_CUSTOM_TYPE = "yagni-go-checkpoint";
|
|
24
|
+
/** Function seams onto pi's ExtensionAPI/SessionManager (so this is testable without pi). */
|
|
25
|
+
export interface PiJournalSeams {
|
|
26
|
+
appendEntry: (customType: string, data: unknown) => void;
|
|
27
|
+
getEntries: () => unknown[];
|
|
28
|
+
}
|
|
29
|
+
export declare function makePiJournalCheckpointStore(sessionKey: string, seams: PiJournalSeams): CheckpointStore;
|
|
30
|
+
export declare function makeCombinedCheckpointStore(stores: CheckpointStore[]): CheckpointStore;
|
|
31
|
+
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fail-soft {@link CheckpointStore} implementations — the durable substrate
|
|
3
|
+
* behind /go resume.
|
|
4
|
+
*
|
|
5
|
+
* Three stores, all sharing the iron contract: NEVER throw, NEVER block /go.
|
|
6
|
+
* - {@link makeFileCheckpointStore} — the durable PRIMARY. An append-only NDJSON
|
|
7
|
+
* file at `~/.yagni-code/runs/<sha1(sessionKey)>.ndjson` (mkdir 0700, file
|
|
8
|
+
* 0600 — mirrors credentials.ts). Session-independent and auth-free, so a
|
|
9
|
+
* LATER pi session (or one started after `/new`) can still read where /go
|
|
10
|
+
* left off, even when the backend was unreachable. A torn final write is
|
|
11
|
+
* harmless: load drops any unparseable line (the classic crash artifact).
|
|
12
|
+
* - {@link makePiJournalCheckpointStore} — a MIRROR into pi's native append-only
|
|
13
|
+
* session journal via `pi.appendEntry` / `sessionManager.getEntries`, the
|
|
14
|
+
* pi-idiomatic persistence the user asked about. Constructed from function
|
|
15
|
+
* seams so it is unit-testable without a pi process.
|
|
16
|
+
* - {@link makeCombinedCheckpointStore} — writes to all stores; reads from the
|
|
17
|
+
* first non-empty (file primary).
|
|
18
|
+
*/
|
|
19
|
+
import { appendFileSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { codeStateHome } from "../stateHome.js";
|
|
23
|
+
/**
|
|
24
|
+
* Test seam mirroring credentials.ts `_setYagniCodeHomeForTest`: when set, the
|
|
25
|
+
* runs dir roots here instead of `~/.yagni-code`, so tests hit a tmpdir. Pass
|
|
26
|
+
* `null` to restore.
|
|
27
|
+
*/
|
|
28
|
+
let homeOverride = null;
|
|
29
|
+
export function _setCheckpointHomeForTest(dir) {
|
|
30
|
+
homeOverride = dir;
|
|
31
|
+
}
|
|
32
|
+
function checkpointHome() {
|
|
33
|
+
return codeStateHome(homeOverride);
|
|
34
|
+
}
|
|
35
|
+
function runsDir() {
|
|
36
|
+
return join(checkpointHome(), "runs");
|
|
37
|
+
}
|
|
38
|
+
/** One file per run key; the key is hashed so arbitrary ticket text is path-safe. */
|
|
39
|
+
function keyFile(sessionKey) {
|
|
40
|
+
const hash = createHash("sha1").update(sessionKey).digest("hex");
|
|
41
|
+
return join(runsDir(), `${hash}.ndjson`);
|
|
42
|
+
}
|
|
43
|
+
export function makeFileCheckpointStore(sessionKey) {
|
|
44
|
+
return {
|
|
45
|
+
record(rec) {
|
|
46
|
+
try {
|
|
47
|
+
mkdirSync(runsDir(), { recursive: true, mode: 0o700 });
|
|
48
|
+
const file = keyFile(sessionKey);
|
|
49
|
+
// Self-heal a torn previous write: if the file ends mid-line (a crash
|
|
50
|
+
// dropped the trailing newline), prefix one so OUR record lands on its
|
|
51
|
+
// own line. Otherwise an append would glue onto the torn fragment and
|
|
52
|
+
// load() would drop BOTH as one unparseable line. The fragment itself is
|
|
53
|
+
// still dropped on load; only the next record is protected.
|
|
54
|
+
let prefix = "";
|
|
55
|
+
try {
|
|
56
|
+
const existing = readFileSync(file);
|
|
57
|
+
if (existing.length > 0 && existing[existing.length - 1] !== 0x0a)
|
|
58
|
+
prefix = "\n";
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* no file yet — nothing to heal */
|
|
62
|
+
}
|
|
63
|
+
appendFileSync(file, `${prefix}${JSON.stringify(rec)}\n`, { mode: 0o600 });
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
/* fail-soft: a checkpoint write must never break /go */
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
load() {
|
|
70
|
+
try {
|
|
71
|
+
const raw = readFileSync(keyFile(sessionKey), "utf8");
|
|
72
|
+
const out = [];
|
|
73
|
+
for (const line of raw.split("\n")) {
|
|
74
|
+
if (!line.trim())
|
|
75
|
+
continue;
|
|
76
|
+
try {
|
|
77
|
+
const obj = JSON.parse(line);
|
|
78
|
+
// Drop garbage/torn lines; defensively re-check the key.
|
|
79
|
+
if (obj && obj.sessionKey === sessionKey)
|
|
80
|
+
out.push(obj);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* unparseable (torn final write) — drop this line, keep the rest */
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return []; // missing/unreadable → fresh run
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
clear() {
|
|
93
|
+
try {
|
|
94
|
+
rmSync(keyFile(sessionKey), { force: true });
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
/* fail-soft */
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** The pi customType under which checkpoint records live in the session journal. */
|
|
103
|
+
export const PI_CHECKPOINT_CUSTOM_TYPE = "yagni-go-checkpoint";
|
|
104
|
+
export function makePiJournalCheckpointStore(sessionKey, seams) {
|
|
105
|
+
return {
|
|
106
|
+
record(rec) {
|
|
107
|
+
try {
|
|
108
|
+
seams.appendEntry(PI_CHECKPOINT_CUSTOM_TYPE, rec);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
/* fail-soft */
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
load() {
|
|
115
|
+
try {
|
|
116
|
+
const entries = seams.getEntries() ?? [];
|
|
117
|
+
const out = [];
|
|
118
|
+
for (const e of entries) {
|
|
119
|
+
const entry = e;
|
|
120
|
+
if (entry?.type === "custom" &&
|
|
121
|
+
entry.customType === PI_CHECKPOINT_CUSTOM_TYPE &&
|
|
122
|
+
entry.data?.sessionKey === sessionKey) {
|
|
123
|
+
out.push(entry.data);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
clear() {
|
|
133
|
+
// pi's journal is append-only — it cannot delete. The caller writes a
|
|
134
|
+
// terminal `run_finish` record via record() on completion, which already
|
|
135
|
+
// makes this key read as non-resumable, so clear() is a no-op here.
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export function makeCombinedCheckpointStore(stores) {
|
|
140
|
+
return {
|
|
141
|
+
record(rec) {
|
|
142
|
+
for (const s of stores) {
|
|
143
|
+
try {
|
|
144
|
+
s.record(rec);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* fail-soft */
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
load() {
|
|
152
|
+
for (const s of stores) {
|
|
153
|
+
try {
|
|
154
|
+
const recs = s.load();
|
|
155
|
+
if (recs.length > 0)
|
|
156
|
+
return recs;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
/* try the next store */
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return [];
|
|
163
|
+
},
|
|
164
|
+
clear() {
|
|
165
|
+
for (const s of stores) {
|
|
166
|
+
try {
|
|
167
|
+
s.clear();
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
/* fail-soft */
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M6 - the grounded-vs-blind eval engine (REPORT-ONLY).
|
|
3
|
+
*
|
|
4
|
+
* The Phase-1 grounding GATE: run the SAME ticket twice, once grounded (the real
|
|
5
|
+
* /go) and once blind (grounding tools stripped + grounding-free personas), then
|
|
6
|
+
* score each lane's change for business fit against this company's recorded
|
|
7
|
+
* judgment and report the delta. It validates the entire only-YAGNI thesis: does
|
|
8
|
+
* the weaker grounded model out-ship the stronger guessing one?
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL: this is strictly report-only. Its output is NEVER wired to model
|
|
11
|
+
* selection, the opaque tiers, or any routing decision (FIT auto-routing is an
|
|
12
|
+
* explicitly cut item). It is meaningful only on a context-rich real workspace
|
|
13
|
+
* with real decisions/corrections, so the live run is dogfood, not CI; this module
|
|
14
|
+
* is the pure engine + report formatter, exercised in tests with injected seams.
|
|
15
|
+
*
|
|
16
|
+
* `blindStages` and `formatComparisonReport` are PURE. `makeGroundedVsBlindEval`
|
|
17
|
+
* orchestrates two injected lane runs + an injected fit scorer, so it is unit
|
|
18
|
+
* tested without spawning a child or touching the network.
|
|
19
|
+
*/
|
|
20
|
+
import type { ModelTier, PipelineResult, PipelineStage } from "./types.js";
|
|
21
|
+
/** The grounding tools the blind lane must not be able to call. */
|
|
22
|
+
export declare const GROUNDING_TOOLS: readonly ["ask_yagni", "record_decision", "review_business_match"];
|
|
23
|
+
/** Capture/write-back tools are never exposed in report-only eval lanes. */
|
|
24
|
+
export declare const CAPTURE_TOOLS: readonly ["record_decision", "record_engineering_context"];
|
|
25
|
+
/**
|
|
26
|
+
* Strip the grounding tools from every stage. The blind lane then runs without
|
|
27
|
+
* this company's judgment or retrieved context.
|
|
28
|
+
*/
|
|
29
|
+
export declare function blindStages(stages?: PipelineStage[]): PipelineStage[];
|
|
30
|
+
/** Strip capture/write-back tools so eval lanes can only produce the report. */
|
|
31
|
+
export declare function reportOnlyStages(stages?: PipelineStage[]): PipelineStage[];
|
|
32
|
+
/**
|
|
33
|
+
* The stages whose model choice IS the judgment-tier decision: decide-what
|
|
34
|
+
* (plan) and catch-wrong (review). Kept as data so the transform below and any
|
|
35
|
+
* future lane agree on what "judgment" means.
|
|
36
|
+
*/
|
|
37
|
+
export declare const JUDGMENT_STAGE_IDS: readonly ["plan", "review"];
|
|
38
|
+
/**
|
|
39
|
+
* Set the judgment stages to a given tier, leaving execution stages untouched.
|
|
40
|
+
* PURE: returns new stage objects.
|
|
41
|
+
*
|
|
42
|
+
* This is the seam for answering the question YAG-380 actually poses — not "is
|
|
43
|
+
* K3 good" but "does K3 on plan+review produce better changes than GLM 5.2
|
|
44
|
+
* does". Because it only touches plan and review, a comparison built on it
|
|
45
|
+
* moves exactly one variable.
|
|
46
|
+
*/
|
|
47
|
+
export declare function withJudgmentTier(stages: PipelineStage[] | undefined, tier: ModelTier): PipelineStage[];
|
|
48
|
+
/**
|
|
49
|
+
* Which lane an outcome belongs to.
|
|
50
|
+
*
|
|
51
|
+
* Two comparisons ride this engine today: grounded-vs-blind (does grounding
|
|
52
|
+
* beat guessing) and peak-vs-advanced judgment (does the stronger model on
|
|
53
|
+
* plan+review produce better changes). Both are two-lane A/Bs scored the same
|
|
54
|
+
* way, so the lane is DATA rather than a hardcoded union.
|
|
55
|
+
*/
|
|
56
|
+
export type Lane = "grounded" | "blind" | "peak_judgment" | "advanced_judgment";
|
|
57
|
+
/** A lane's id plus how it is named in the report. */
|
|
58
|
+
export interface LaneSpec {
|
|
59
|
+
id: Lane;
|
|
60
|
+
label: string;
|
|
61
|
+
}
|
|
62
|
+
/** The grounding GATE: the real /go against a grounding-suppressed twin. */
|
|
63
|
+
export declare const GROUNDED_LANES: {
|
|
64
|
+
readonly treatment: {
|
|
65
|
+
readonly id: "grounded";
|
|
66
|
+
readonly label: "Grounded";
|
|
67
|
+
};
|
|
68
|
+
readonly baseline: {
|
|
69
|
+
readonly id: "blind";
|
|
70
|
+
readonly label: "Blind";
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/** The judgment-tier question: peak on plan+review against advanced on plan+review. */
|
|
74
|
+
export declare const JUDGMENT_LANES: {
|
|
75
|
+
readonly treatment: {
|
|
76
|
+
readonly id: "peak_judgment";
|
|
77
|
+
readonly label: "Peak judgment";
|
|
78
|
+
};
|
|
79
|
+
readonly baseline: {
|
|
80
|
+
readonly id: "advanced_judgment";
|
|
81
|
+
readonly label: "Advanced judgment";
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* A lane's business-fit score, produced by running the GROUNDED
|
|
86
|
+
* review_business_match against that lane's final diff (so both lanes are judged
|
|
87
|
+
* by the same recorded company judgment). The /review endpoint returns prose +
|
|
88
|
+
* citations rather than a number, so the qualitative `review` text is the real
|
|
89
|
+
* signal; `conflicts` and `citations` are coarse comparable counts.
|
|
90
|
+
*/
|
|
91
|
+
export interface LaneFit {
|
|
92
|
+
/** review_business_match prose verdict on this lane's diff. */
|
|
93
|
+
review: string;
|
|
94
|
+
/** Count of cited decisions/conventions the review surfaced. */
|
|
95
|
+
citations: number;
|
|
96
|
+
/** Count of flagged conflicts with recorded judgment (lower is better fit). */
|
|
97
|
+
conflicts: number;
|
|
98
|
+
/** Honest note when scoring could not run (fail-soft). */
|
|
99
|
+
note?: string;
|
|
100
|
+
}
|
|
101
|
+
/** One lane's full outcome: the pipeline result plus its fit score. */
|
|
102
|
+
export interface LaneOutcome {
|
|
103
|
+
lane: LaneSpec;
|
|
104
|
+
result: PipelineResult;
|
|
105
|
+
fit: LaneFit;
|
|
106
|
+
}
|
|
107
|
+
/** The full comparison handed back to the command (and rendered into the report). */
|
|
108
|
+
export interface ComparisonReport {
|
|
109
|
+
ticket: string;
|
|
110
|
+
/** The lane under test (grounded / peak judgment). */
|
|
111
|
+
treatment: LaneOutcome;
|
|
112
|
+
/** The lane it is measured against (blind / advanced judgment). */
|
|
113
|
+
baseline: LaneOutcome;
|
|
114
|
+
/** treatment.conflicts - baseline.conflicts; negative means the treatment reduced conflicts. */
|
|
115
|
+
conflictDelta: number;
|
|
116
|
+
/** Rendered markdown report (no em-dashes). */
|
|
117
|
+
report: string;
|
|
118
|
+
}
|
|
119
|
+
/** Injectable seams so the engine is unit-tested without spawning or network. */
|
|
120
|
+
export interface ComparisonSeams {
|
|
121
|
+
/** Run one lane's pipeline end to end and return its result. */
|
|
122
|
+
runLane: (lane: Lane, ticket: string) => Promise<PipelineResult>;
|
|
123
|
+
/** Score one lane's change for business fit against recorded judgment. */
|
|
124
|
+
scoreFit: (lane: Lane, result: PipelineResult) => Promise<LaneFit>;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Per-comparison wording. The engine and the arithmetic are shared, but a
|
|
128
|
+
* grounding result and a judgment-tier result mean different things, so each
|
|
129
|
+
* gets copy that says what its number actually shows.
|
|
130
|
+
*/
|
|
131
|
+
export interface ComparisonCopy {
|
|
132
|
+
title: string;
|
|
133
|
+
/** Labels the headline number, e.g. "FIT delta (blind conflicts minus grounded conflicts)". */
|
|
134
|
+
deltaLabel: string;
|
|
135
|
+
/** Renders the verdict from the signed delta, where positive favours the treatment. */
|
|
136
|
+
verdict: (favor: number) => string;
|
|
137
|
+
/** Closing honesty note about what the report is and is not. */
|
|
138
|
+
footer: string;
|
|
139
|
+
}
|
|
140
|
+
export declare const GROUNDED_COPY: ComparisonCopy;
|
|
141
|
+
export declare const JUDGMENT_COPY: ComparisonCopy;
|
|
142
|
+
/**
|
|
143
|
+
* Render the comparative report a human reads. Leads with the headline conflict
|
|
144
|
+
* delta (the GATE number), then each lane's stop reason, finding tally, and fit
|
|
145
|
+
* verdict. States plainly that this is report-only and never wired to routing.
|
|
146
|
+
*
|
|
147
|
+
* The arithmetic is shared across comparisons; `copy` supplies the wording so a
|
|
148
|
+
* grounding result and a judgment-tier result each say what their number means.
|
|
149
|
+
*/
|
|
150
|
+
export declare function formatComparisonReport(input: Omit<ComparisonReport, "report">, copy?: ComparisonCopy): string;
|
|
151
|
+
/**
|
|
152
|
+
* Build a two-lane eval runner. Runs the treatment lane, then the baseline lane,
|
|
153
|
+
* scores each, and returns the comparison + rendered report. Both lane runs and
|
|
154
|
+
* the scorer are injected, so this is fully deterministic in tests.
|
|
155
|
+
*
|
|
156
|
+
* Lanes run SEQUENTIALLY on purpose: each spawns a full /go pipeline over a real
|
|
157
|
+
* worktree, and running them concurrently would contend for the same machine and
|
|
158
|
+
* muddy any latency signal.
|
|
159
|
+
*/
|
|
160
|
+
export declare function makeComparisonEval(seams: ComparisonSeams, lanes: {
|
|
161
|
+
treatment: LaneSpec;
|
|
162
|
+
baseline: LaneSpec;
|
|
163
|
+
}, copy: ComparisonCopy): (ticket: string) => Promise<ComparisonReport>;
|
|
164
|
+
/** The grounding GATE, named for what it measures. */
|
|
165
|
+
export declare function makeGroundedVsBlindEval(seams: ComparisonSeams): (ticket: string) => Promise<ComparisonReport>;
|
|
166
|
+
/** The judgment-tier question: peak on plan+review against advanced (YAG-380). */
|
|
167
|
+
export declare function makeJudgmentTierEval(seams: ComparisonSeams): (ticket: string) => Promise<ComparisonReport>;
|
|
168
|
+
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M6 - the grounded-vs-blind eval engine (REPORT-ONLY).
|
|
3
|
+
*
|
|
4
|
+
* The Phase-1 grounding GATE: run the SAME ticket twice, once grounded (the real
|
|
5
|
+
* /go) and once blind (grounding tools stripped + grounding-free personas), then
|
|
6
|
+
* score each lane's change for business fit against this company's recorded
|
|
7
|
+
* judgment and report the delta. It validates the entire only-YAGNI thesis: does
|
|
8
|
+
* the weaker grounded model out-ship the stronger guessing one?
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL: this is strictly report-only. Its output is NEVER wired to model
|
|
11
|
+
* selection, the opaque tiers, or any routing decision (FIT auto-routing is an
|
|
12
|
+
* explicitly cut item). It is meaningful only on a context-rich real workspace
|
|
13
|
+
* with real decisions/corrections, so the live run is dogfood, not CI; this module
|
|
14
|
+
* is the pure engine + report formatter, exercised in tests with injected seams.
|
|
15
|
+
*
|
|
16
|
+
* `blindStages` and `formatComparisonReport` are PURE. `makeGroundedVsBlindEval`
|
|
17
|
+
* orchestrates two injected lane runs + an injected fit scorer, so it is unit
|
|
18
|
+
* tested without spawning a child or touching the network.
|
|
19
|
+
*/
|
|
20
|
+
import { selectStages } from "./stages.js";
|
|
21
|
+
/** The grounding tools the blind lane must not be able to call. */
|
|
22
|
+
export const GROUNDING_TOOLS = ["ask_yagni", "record_decision", "review_business_match"];
|
|
23
|
+
/** Capture/write-back tools are never exposed in report-only eval lanes. */
|
|
24
|
+
export const CAPTURE_TOOLS = ["record_decision", "record_engineering_context"];
|
|
25
|
+
/**
|
|
26
|
+
* Strip selected tools from every stage's `--tools` whitelist. The child pi may
|
|
27
|
+
* still have a tool registered, but a tool absent from the stage whitelist cannot
|
|
28
|
+
* be called. Pure: returns new stage objects, leaves the input untouched.
|
|
29
|
+
*/
|
|
30
|
+
function stripStageTools(stages, tools) {
|
|
31
|
+
const drop = new Set(tools);
|
|
32
|
+
return stages.map((s) => ({ ...s, tools: s.tools.filter((t) => !drop.has(t)) }));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Strip the grounding tools from every stage. The blind lane then runs without
|
|
36
|
+
* this company's judgment or retrieved context.
|
|
37
|
+
*/
|
|
38
|
+
export function blindStages(stages = selectStages("full")) {
|
|
39
|
+
return stripStageTools(stages, GROUNDING_TOOLS);
|
|
40
|
+
}
|
|
41
|
+
/** Strip capture/write-back tools so eval lanes can only produce the report. */
|
|
42
|
+
export function reportOnlyStages(stages = selectStages("full")) {
|
|
43
|
+
return stripStageTools(stages, CAPTURE_TOOLS);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The stages whose model choice IS the judgment-tier decision: decide-what
|
|
47
|
+
* (plan) and catch-wrong (review). Kept as data so the transform below and any
|
|
48
|
+
* future lane agree on what "judgment" means.
|
|
49
|
+
*/
|
|
50
|
+
export const JUDGMENT_STAGE_IDS = ["plan", "review"];
|
|
51
|
+
/**
|
|
52
|
+
* Set the judgment stages to a given tier, leaving execution stages untouched.
|
|
53
|
+
* PURE: returns new stage objects.
|
|
54
|
+
*
|
|
55
|
+
* This is the seam for answering the question YAG-380 actually poses — not "is
|
|
56
|
+
* K3 good" but "does K3 on plan+review produce better changes than GLM 5.2
|
|
57
|
+
* does". Because it only touches plan and review, a comparison built on it
|
|
58
|
+
* moves exactly one variable.
|
|
59
|
+
*/
|
|
60
|
+
export function withJudgmentTier(stages = selectStages("full"), tier) {
|
|
61
|
+
const judgment = new Set(JUDGMENT_STAGE_IDS);
|
|
62
|
+
return stages.map((s) => (judgment.has(s.id) ? { ...s, model: tier } : s));
|
|
63
|
+
}
|
|
64
|
+
/** The grounding GATE: the real /go against a grounding-suppressed twin. */
|
|
65
|
+
export const GROUNDED_LANES = {
|
|
66
|
+
treatment: { id: "grounded", label: "Grounded" },
|
|
67
|
+
baseline: { id: "blind", label: "Blind" },
|
|
68
|
+
};
|
|
69
|
+
/** The judgment-tier question: peak on plan+review against advanced on plan+review. */
|
|
70
|
+
export const JUDGMENT_LANES = {
|
|
71
|
+
treatment: { id: "peak_judgment", label: "Peak judgment" },
|
|
72
|
+
baseline: { id: "advanced_judgment", label: "Advanced judgment" },
|
|
73
|
+
};
|
|
74
|
+
export const GROUNDED_COPY = {
|
|
75
|
+
title: "Grounded vs blind eval",
|
|
76
|
+
deltaLabel: "FIT delta (blind conflicts minus grounded conflicts)",
|
|
77
|
+
verdict: (favor) => favor > 0
|
|
78
|
+
? `Grounding REDUCED business-fit conflicts by ${favor} on this ticket.`
|
|
79
|
+
: favor < 0
|
|
80
|
+
? `Grounding showed ${Math.abs(favor)} MORE flagged conflict${Math.abs(favor) === 1 ? "" : "s"} on this ticket (investigate: a thin or noisy corpus can do this).`
|
|
81
|
+
: "Grounding and blind tied on flagged conflicts for this ticket.",
|
|
82
|
+
footer: "Report only. This comparison is never wired to model selection, tiers, or routing. Run it on a context-rich workspace with real recorded decisions for a meaningful number.",
|
|
83
|
+
};
|
|
84
|
+
export const JUDGMENT_COPY = {
|
|
85
|
+
title: "Peak vs advanced judgment eval",
|
|
86
|
+
deltaLabel: "FIT delta (advanced-judgment conflicts minus peak-judgment conflicts)",
|
|
87
|
+
verdict: (favor) => favor > 0
|
|
88
|
+
? `Peak on plan and review REDUCED business-fit conflicts by ${favor} on this ticket.`
|
|
89
|
+
: favor < 0
|
|
90
|
+
? `Peak on plan and review showed ${Math.abs(favor)} MORE flagged conflict${Math.abs(favor) === 1 ? "" : "s"} on this ticket. The judgment upgrade did not pay for itself here.`
|
|
91
|
+
: "Peak and advanced judgment tied on flagged conflicts for this ticket.",
|
|
92
|
+
footer: "Report only. This comparison is never wired to model selection, tiers, or routing. Only plan and review differ between the lanes, so the delta isolates the judgment tier. One ticket is an anecdote; run several before concluding.",
|
|
93
|
+
};
|
|
94
|
+
const blocking = (findings) => findings.filter((f) => f.severity === "critical" || f.severity === "high").length;
|
|
95
|
+
/**
|
|
96
|
+
* Render the comparative report a human reads. Leads with the headline conflict
|
|
97
|
+
* delta (the GATE number), then each lane's stop reason, finding tally, and fit
|
|
98
|
+
* verdict. States plainly that this is report-only and never wired to routing.
|
|
99
|
+
*
|
|
100
|
+
* The arithmetic is shared across comparisons; `copy` supplies the wording so a
|
|
101
|
+
* grounding result and a judgment-tier result each say what their number means.
|
|
102
|
+
*/
|
|
103
|
+
export function formatComparisonReport(input, copy = GROUNDED_COPY) {
|
|
104
|
+
const { ticket, treatment, baseline, conflictDelta } = input;
|
|
105
|
+
const lane = (o) => {
|
|
106
|
+
const total = o.result.findings.length;
|
|
107
|
+
const block = blocking(o.result.findings);
|
|
108
|
+
const fit = o.fit.note
|
|
109
|
+
? `fit scoring skipped (${o.fit.note})`
|
|
110
|
+
: `${o.fit.conflicts} fit conflict${o.fit.conflicts === 1 ? "" : "s"}, ${o.fit.citations} citation${o.fit.citations === 1 ? "" : "s"}`;
|
|
111
|
+
return [
|
|
112
|
+
`### ${o.lane.label} lane`,
|
|
113
|
+
`- stop reason: ${o.result.stopReason}`,
|
|
114
|
+
`- findings: ${total} (${block} blocking)`,
|
|
115
|
+
`- business fit: ${fit}`,
|
|
116
|
+
o.fit.review.trim() ? `\n${o.fit.review.trim()}` : "",
|
|
117
|
+
]
|
|
118
|
+
.filter(Boolean)
|
|
119
|
+
.join("\n");
|
|
120
|
+
};
|
|
121
|
+
// baseline minus treatment: positive favors the treatment. Show an explicit
|
|
122
|
+
// sign, but never render "+0" (a tie reads as 0).
|
|
123
|
+
const favor = -conflictDelta;
|
|
124
|
+
const signed = `${favor > 0 ? "+" : ""}${favor}`;
|
|
125
|
+
return [
|
|
126
|
+
`## ${copy.title}: ${ticket}`,
|
|
127
|
+
"",
|
|
128
|
+
`${copy.deltaLabel}: ${signed}. ${copy.verdict(favor)}`,
|
|
129
|
+
"",
|
|
130
|
+
lane(treatment),
|
|
131
|
+
"",
|
|
132
|
+
lane(baseline),
|
|
133
|
+
"",
|
|
134
|
+
copy.footer,
|
|
135
|
+
].join("\n");
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Build a two-lane eval runner. Runs the treatment lane, then the baseline lane,
|
|
139
|
+
* scores each, and returns the comparison + rendered report. Both lane runs and
|
|
140
|
+
* the scorer are injected, so this is fully deterministic in tests.
|
|
141
|
+
*
|
|
142
|
+
* Lanes run SEQUENTIALLY on purpose: each spawns a full /go pipeline over a real
|
|
143
|
+
* worktree, and running them concurrently would contend for the same machine and
|
|
144
|
+
* muddy any latency signal.
|
|
145
|
+
*/
|
|
146
|
+
export function makeComparisonEval(seams, lanes, copy) {
|
|
147
|
+
return async function compare(ticket) {
|
|
148
|
+
const treatmentResult = await seams.runLane(lanes.treatment.id, ticket);
|
|
149
|
+
const baselineResult = await seams.runLane(lanes.baseline.id, ticket);
|
|
150
|
+
const [treatmentFit, baselineFit] = await Promise.all([
|
|
151
|
+
seams.scoreFit(lanes.treatment.id, treatmentResult),
|
|
152
|
+
seams.scoreFit(lanes.baseline.id, baselineResult),
|
|
153
|
+
]);
|
|
154
|
+
const treatment = {
|
|
155
|
+
lane: lanes.treatment,
|
|
156
|
+
result: treatmentResult,
|
|
157
|
+
fit: treatmentFit,
|
|
158
|
+
};
|
|
159
|
+
const baseline = {
|
|
160
|
+
lane: lanes.baseline,
|
|
161
|
+
result: baselineResult,
|
|
162
|
+
fit: baselineFit,
|
|
163
|
+
};
|
|
164
|
+
const conflictDelta = treatmentFit.conflicts - baselineFit.conflicts;
|
|
165
|
+
return {
|
|
166
|
+
ticket,
|
|
167
|
+
treatment,
|
|
168
|
+
baseline,
|
|
169
|
+
conflictDelta,
|
|
170
|
+
report: formatComparisonReport({ ticket, treatment, baseline, conflictDelta }, copy),
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** The grounding GATE, named for what it measures. */
|
|
175
|
+
export function makeGroundedVsBlindEval(seams) {
|
|
176
|
+
return makeComparisonEval(seams, GROUNDED_LANES, GROUNDED_COPY);
|
|
177
|
+
}
|
|
178
|
+
/** The judgment-tier question: peak on plan+review against advanced (YAG-380). */
|
|
179
|
+
export function makeJudgmentTierEval(seams) {
|
|
180
|
+
return makeComparisonEval(seams, JUDGMENT_LANES, JUDGMENT_COPY);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=eval.js.map
|