@ramplab/generator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/agentSdkRunner.d.ts +64 -0
  4. package/dist/agentSdkRunner.d.ts.map +1 -0
  5. package/dist/agentSdkRunner.js +158 -0
  6. package/dist/agentSdkRunner.js.map +1 -0
  7. package/dist/assembleStage.d.ts +41 -0
  8. package/dist/assembleStage.d.ts.map +1 -0
  9. package/dist/assembleStage.js +33 -0
  10. package/dist/assembleStage.js.map +1 -0
  11. package/dist/authorStage.d.ts +123 -0
  12. package/dist/authorStage.d.ts.map +1 -0
  13. package/dist/authorStage.js +284 -0
  14. package/dist/authorStage.js.map +1 -0
  15. package/dist/cloneRepo.d.ts +72 -0
  16. package/dist/cloneRepo.d.ts.map +1 -0
  17. package/dist/cloneRepo.js +104 -0
  18. package/dist/cloneRepo.js.map +1 -0
  19. package/dist/flagship.d.ts +62 -0
  20. package/dist/flagship.d.ts.map +1 -0
  21. package/dist/flagship.js +216 -0
  22. package/dist/flagship.js.map +1 -0
  23. package/dist/generateLab.d.ts +151 -0
  24. package/dist/generateLab.d.ts.map +1 -0
  25. package/dist/generateLab.js +291 -0
  26. package/dist/generateLab.js.map +1 -0
  27. package/dist/index.d.ts +22 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +21 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/intake.d.ts +31 -0
  32. package/dist/intake.d.ts.map +1 -0
  33. package/dist/intake.js +45 -0
  34. package/dist/intake.js.map +1 -0
  35. package/dist/live.d.ts +2 -0
  36. package/dist/live.d.ts.map +1 -0
  37. package/dist/live.js +213 -0
  38. package/dist/live.js.map +1 -0
  39. package/dist/mapStage.d.ts +84 -0
  40. package/dist/mapStage.d.ts.map +1 -0
  41. package/dist/mapStage.js +241 -0
  42. package/dist/mapStage.js.map +1 -0
  43. package/dist/pass1.d.ts +85 -0
  44. package/dist/pass1.d.ts.map +1 -0
  45. package/dist/pass1.js +81 -0
  46. package/dist/pass1.js.map +1 -0
  47. package/dist/pipeline.d.ts +73 -0
  48. package/dist/pipeline.d.ts.map +1 -0
  49. package/dist/pipeline.js +70 -0
  50. package/dist/pipeline.js.map +1 -0
  51. package/dist/planStage.d.ts +141 -0
  52. package/dist/planStage.d.ts.map +1 -0
  53. package/dist/planStage.js +275 -0
  54. package/dist/planStage.js.map +1 -0
  55. package/dist/progress.d.ts +45 -0
  56. package/dist/progress.d.ts.map +1 -0
  57. package/dist/progress.js +2 -0
  58. package/dist/progress.js.map +1 -0
  59. package/dist/repoCommit.d.ts +41 -0
  60. package/dist/repoCommit.d.ts.map +1 -0
  61. package/dist/repoCommit.js +84 -0
  62. package/dist/repoCommit.js.map +1 -0
  63. package/dist/repoSize.d.ts +23 -0
  64. package/dist/repoSize.d.ts.map +1 -0
  65. package/dist/repoSize.js +74 -0
  66. package/dist/repoSize.js.map +1 -0
  67. package/dist/resolveAnchors.d.ts +142 -0
  68. package/dist/resolveAnchors.d.ts.map +1 -0
  69. package/dist/resolveAnchors.js +242 -0
  70. package/dist/resolveAnchors.js.map +1 -0
  71. package/dist/verifyStage.d.ts +150 -0
  72. package/dist/verifyStage.d.ts.map +1 -0
  73. package/dist/verifyStage.js +461 -0
  74. package/dist/verifyStage.js.map +1 -0
  75. package/package.json +47 -0
@@ -0,0 +1,142 @@
1
+ import type { Anchor, LabSpec } from '@ramplab/spec';
2
+ /**
3
+ * Anchor resolution — mechanical grounding enforcement (PLAN.md §3).
4
+ *
5
+ * `resolveAnchors(spec, repoDir)` checks every anchor in the spec's base
6
+ * content against the actual repository directory:
7
+ *
8
+ * - the anchored file exists (repo-relative; paths that escape `repoDir`
9
+ * never resolve),
10
+ * - the line range, if given, is valid against the file's real line count,
11
+ * - the symbol, if given, matches textually inside the anchored region.
12
+ *
13
+ * v1 is deliberately textual and language-agnostic — no parsers, no
14
+ * tree-sitter. A "symbol match" is a token-boundary substring match, which
15
+ * works uniformly across TS, Ruby, Go, Python, Java, C#, Dart, Kotlin,
16
+ * Swift, ... (tree-sitter-backed resolution is a v2 option).
17
+ *
18
+ * The function is deterministic and pure over `(spec, directory)`: no
19
+ * globals, no clock, no mutation of the input spec. Given the same spec and
20
+ * the same directory contents it always returns the same result.
21
+ */
22
+ /** Why an individual anchor did or did not resolve. */
23
+ export type AnchorStatus = 'resolved' | 'file-missing' | 'lines-out-of-range' | 'symbol-not-found';
24
+ /**
25
+ * What to do with teachable units whose anchors fail to resolve:
26
+ * - `drop` (default): remove the unit from the returned base spec — the
27
+ * grounding constraint is enforced structurally.
28
+ * - `flag`: keep the spec intact and only report — for review flows where
29
+ * a human decides.
30
+ */
31
+ export type ResolutionPolicy = 'drop' | 'flag';
32
+ /** Per-teachable-unit outcome, reflecting the active policy. */
33
+ export type UnitOutcome = 'resolved' | 'dropped' | 'flagged';
34
+ /** The resolution verdict for one anchor of one base widget. */
35
+ export interface AnchorResolution {
36
+ moduleId: string;
37
+ widgetId: string;
38
+ /**
39
+ * Ordinal of the anchor within its widget, in deterministic walk order.
40
+ * For widgets with a single top-level `anchors` array (callouts) this is
41
+ * the array index; nested carriers (system-map nodes/edges, data-model
42
+ * annotations) are walked depth-first in spec order.
43
+ */
44
+ anchorIndex: number;
45
+ /** JSON path of the anchor within its widget (e.g. `["nodes", 0, "anchors", 1]`). */
46
+ anchorPath: (string | number)[];
47
+ /** The anchor as checked (fingerprint populated when resolved). */
48
+ anchor: Anchor;
49
+ status: AnchorStatus;
50
+ /** Human-readable explanation of the status. */
51
+ detail: string;
52
+ /**
53
+ * `sha256:<hex>` content hash of the anchored region (the line range if
54
+ * given, otherwise the whole file), only present when resolved. Line
55
+ * endings are normalized to `\n` before hashing so fingerprints are
56
+ * stable across checkout conventions.
57
+ */
58
+ fingerprint?: string;
59
+ }
60
+ /**
61
+ * The verdict for one teachable unit (a base widget). A unit is resolved
62
+ * only if *every* one of its anchors resolved — each claim's grounding must
63
+ * check out.
64
+ */
65
+ export interface UnitResolution {
66
+ moduleId: string;
67
+ widgetId: string;
68
+ outcome: UnitOutcome;
69
+ anchors: AnchorResolution[];
70
+ }
71
+ export interface ResolutionSummary {
72
+ totalAnchors: number;
73
+ resolvedAnchors: number;
74
+ totalUnits: number;
75
+ resolvedUnits: number;
76
+ /** Units dropped or flagged, depending on policy. */
77
+ unresolvedUnits: number;
78
+ }
79
+ /** Structured report of a full resolution pass over a spec's base content. */
80
+ export interface ResolutionReport {
81
+ policy: ResolutionPolicy;
82
+ /** Every anchor checked, in spec order. */
83
+ anchors: AnchorResolution[];
84
+ /** Every teachable unit (base widget), in spec order. */
85
+ units: UnitResolution[];
86
+ summary: ResolutionSummary;
87
+ }
88
+ export interface ResolveAnchorsOptions {
89
+ /** @default 'drop' */
90
+ policy?: ResolutionPolicy;
91
+ }
92
+ export interface ResolveAnchorsResult {
93
+ /**
94
+ * The spec after resolution. Resolved anchors carry fingerprints. Under
95
+ * the `drop` policy, unresolved units are removed from their modules;
96
+ * under `flag` the structure is untouched. The human overlay is never
97
+ * modified — only the machine-owned base is subject to grounding
98
+ * enforcement.
99
+ */
100
+ spec: LabSpec;
101
+ report: ResolutionReport;
102
+ }
103
+ /**
104
+ * Resolve every base-content anchor in `spec` against the repository at
105
+ * `repoDir`, enforcing the grounding constraint per the chosen policy.
106
+ */
107
+ export declare function resolveAnchors(spec: LabSpec, repoDir: string, options?: ResolveAnchorsOptions): ResolveAnchorsResult;
108
+ /**
109
+ * The content an anchor points at, or why it could not be read. The failure
110
+ * kinds mirror the mechanical {@link AnchorStatus} values (symbol matching is
111
+ * a separate concern layered on top by `resolveAnchor`).
112
+ */
113
+ export type AnchorRegion = {
114
+ kind: 'ok';
115
+ text: string;
116
+ } | {
117
+ kind: 'file-missing';
118
+ detail: string;
119
+ } | {
120
+ kind: 'lines-out-of-range';
121
+ detail: string;
122
+ };
123
+ /** Share one cache across many {@link readAnchorRegion} calls over one repo. */
124
+ export declare function createAnchorFileCache(): AnchorFileCache;
125
+ export type AnchorFileCache = Map<string, LoadedFile>;
126
+ /**
127
+ * Read the actual repository content an anchor points at: the line range if
128
+ * given, otherwise the whole file. Line endings are normalized to `\n`. This
129
+ * is the single anchor-region reader — anchor resolution fingerprints what it
130
+ * returns, and the verify stage shows it to the adversarial verifier — so
131
+ * both stages are guaranteed to be looking at the same bytes.
132
+ */
133
+ export declare function readAnchorRegion(anchor: Pick<Anchor, 'file' | 'lines'>, repoDir: string, cache?: AnchorFileCache): AnchorRegion;
134
+ export type LoadedFile = {
135
+ kind: 'ok';
136
+ lines: string[];
137
+ lineCount: number;
138
+ } | {
139
+ kind: 'missing';
140
+ detail: string;
141
+ };
142
+ //# sourceMappingURL=resolveAnchors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveAnchors.d.ts","sourceRoot":"","sources":["../src/resolveAnchors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,242 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync, statSync } from 'node:fs';
3
+ import { isAbsolute, resolve, sep } from 'node:path';
4
+ /**
5
+ * Resolve every base-content anchor in `spec` against the repository at
6
+ * `repoDir`, enforcing the grounding constraint per the chosen policy.
7
+ */
8
+ export function resolveAnchors(spec, repoDir, options = {}) {
9
+ const policy = options.policy ?? 'drop';
10
+ const repoRoot = resolve(repoDir);
11
+ const fileCache = new Map();
12
+ const units = [];
13
+ const allAnchors = [];
14
+ for (const module of spec.base.modules) {
15
+ for (const widget of module.widgets) {
16
+ const anchors = collectAnchorRefs(widget).map((ref, anchorIndex) => resolveAnchor(ref.anchor, {
17
+ repoRoot,
18
+ fileCache,
19
+ moduleId: module.id,
20
+ widgetId: widget.id,
21
+ anchorIndex,
22
+ anchorPath: ref.path,
23
+ }));
24
+ const unitResolved = anchors.every((a) => a.status === 'resolved');
25
+ units.push({
26
+ moduleId: module.id,
27
+ widgetId: widget.id,
28
+ outcome: unitResolved ? 'resolved' : policy === 'drop' ? 'dropped' : 'flagged',
29
+ anchors,
30
+ });
31
+ allAnchors.push(...anchors);
32
+ }
33
+ }
34
+ const report = {
35
+ policy,
36
+ anchors: allAnchors,
37
+ units,
38
+ summary: {
39
+ totalAnchors: allAnchors.length,
40
+ resolvedAnchors: allAnchors.filter((a) => a.status === 'resolved').length,
41
+ totalUnits: units.length,
42
+ resolvedUnits: units.filter((u) => u.outcome === 'resolved').length,
43
+ unresolvedUnits: units.filter((u) => u.outcome !== 'resolved').length,
44
+ },
45
+ };
46
+ return { spec: buildOutputSpec(spec, report), report };
47
+ }
48
+ function resolveAnchor(anchor, ctx) {
49
+ const base = {
50
+ moduleId: ctx.moduleId,
51
+ widgetId: ctx.widgetId,
52
+ anchorIndex: ctx.anchorIndex,
53
+ anchorPath: ctx.anchorPath,
54
+ };
55
+ const fail = (status, detail) => ({
56
+ ...base,
57
+ anchor: cloneAnchor(anchor),
58
+ status,
59
+ detail,
60
+ });
61
+ const loaded = readAnchorRegion(anchor, ctx.repoRoot, ctx.fileCache);
62
+ if (loaded.kind !== 'ok') {
63
+ return fail(loaded.kind, loaded.detail);
64
+ }
65
+ const region = loaded.text;
66
+ if (anchor.symbol !== undefined && !symbolPattern(anchor.symbol).test(region)) {
67
+ const where = anchor.lines
68
+ ? `lines ${anchor.lines.start}-${anchor.lines.end} of "${anchor.file}"`
69
+ : `"${anchor.file}"`;
70
+ return fail('symbol-not-found', `Symbol "${anchor.symbol}" not found in ${where}.`);
71
+ }
72
+ const fingerprint = `sha256:${createHash('sha256').update(region, 'utf8').digest('hex')}`;
73
+ const resolvedAnchor = cloneAnchor(anchor);
74
+ resolvedAnchor.fingerprint = fingerprint;
75
+ return {
76
+ ...base,
77
+ anchor: resolvedAnchor,
78
+ status: 'resolved',
79
+ detail: anchor.lines
80
+ ? `Resolved lines ${anchor.lines.start}-${anchor.lines.end} of "${anchor.file}".`
81
+ : `Resolved "${anchor.file}".`,
82
+ fingerprint,
83
+ };
84
+ }
85
+ /**
86
+ * Textual, language-agnostic symbol matching: the symbol must appear in the
87
+ * region as a whole token — not embedded inside a longer identifier (so
88
+ * "greet" never matches "greeting"). Symbols containing punctuation (Ruby's
89
+ * `empty?`, operators, etc.) are matched literally.
90
+ */
91
+ function symbolPattern(symbol) {
92
+ const escaped = symbol.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
93
+ return new RegExp(`(?<![A-Za-z0-9_$])${escaped}(?![A-Za-z0-9_$])`);
94
+ }
95
+ /** Share one cache across many {@link readAnchorRegion} calls over one repo. */
96
+ export function createAnchorFileCache() {
97
+ return new Map();
98
+ }
99
+ /**
100
+ * Read the actual repository content an anchor points at: the line range if
101
+ * given, otherwise the whole file. Line endings are normalized to `\n`. This
102
+ * is the single anchor-region reader — anchor resolution fingerprints what it
103
+ * returns, and the verify stage shows it to the adversarial verifier — so
104
+ * both stages are guaranteed to be looking at the same bytes.
105
+ */
106
+ export function readAnchorRegion(anchor, repoDir, cache = createAnchorFileCache()) {
107
+ const repoRoot = resolve(repoDir);
108
+ const file = loadFile(anchor.file, repoRoot, cache);
109
+ if (file.kind === 'missing') {
110
+ return { kind: 'file-missing', detail: file.detail };
111
+ }
112
+ let regionLines = file.lines;
113
+ if (anchor.lines) {
114
+ const { start, end } = anchor.lines;
115
+ if (end > file.lineCount || start > file.lineCount) {
116
+ return {
117
+ kind: 'lines-out-of-range',
118
+ detail: `Line range ${start}-${end} exceeds "${anchor.file}" (${file.lineCount} line${file.lineCount === 1 ? '' : 's'}).`,
119
+ };
120
+ }
121
+ regionLines = file.lines.slice(start - 1, end);
122
+ }
123
+ return { kind: 'ok', text: regionLines.join('\n') };
124
+ }
125
+ function loadFile(relPath, repoRoot, cache) {
126
+ const cached = cache.get(relPath);
127
+ if (cached)
128
+ return cached;
129
+ const loaded = loadFileUncached(relPath, repoRoot);
130
+ cache.set(relPath, loaded);
131
+ return loaded;
132
+ }
133
+ function loadFileUncached(relPath, repoRoot) {
134
+ if (isAbsolute(relPath)) {
135
+ return { kind: 'missing', detail: `Anchor file "${relPath}" must be repo-relative, not absolute.` };
136
+ }
137
+ const absPath = resolve(repoRoot, relPath);
138
+ if (absPath !== repoRoot && !absPath.startsWith(repoRoot + sep)) {
139
+ return { kind: 'missing', detail: `Anchor file "${relPath}" escapes the repository root.` };
140
+ }
141
+ let raw;
142
+ try {
143
+ const stat = statSync(absPath);
144
+ if (!stat.isFile()) {
145
+ return { kind: 'missing', detail: `Anchor path "${relPath}" is not a regular file.` };
146
+ }
147
+ raw = readFileSync(absPath, 'utf8');
148
+ }
149
+ catch {
150
+ return { kind: 'missing', detail: `Anchor file "${relPath}" does not exist in the repository.` };
151
+ }
152
+ // Normalize line endings so line counts and fingerprints are identical
153
+ // across CRLF/LF checkouts of the same content.
154
+ const normalized = raw.replace(/\r\n?/g, '\n');
155
+ const lines = normalized.split('\n');
156
+ // A trailing newline does not start an extra line ("a\n" is one line).
157
+ const lineCount = lines[lines.length - 1] === '' ? lines.length - 1 : lines.length;
158
+ return { kind: 'ok', lines, lineCount };
159
+ }
160
+ // ---------------------------------------------------------------------------
161
+ // Output spec construction
162
+ // ---------------------------------------------------------------------------
163
+ /**
164
+ * Build the returned spec without mutating the input: fingerprints stamped
165
+ * onto resolved anchors, and (under `drop`) unresolved units filtered out of
166
+ * their modules. Module and overlay structure is otherwise preserved.
167
+ */
168
+ function buildOutputSpec(spec, report) {
169
+ const out = structuredClone(spec);
170
+ const outcomeByUnit = new Map();
171
+ for (const unit of report.units) {
172
+ outcomeByUnit.set(unitKey(unit.moduleId, unit.widgetId), unit.outcome);
173
+ }
174
+ const fingerprintByAnchor = new Map();
175
+ for (const res of report.anchors) {
176
+ if (res.fingerprint !== undefined) {
177
+ fingerprintByAnchor.set(anchorKey(res.moduleId, res.widgetId, res.anchorIndex), res.fingerprint);
178
+ }
179
+ }
180
+ for (const module of out.base.modules) {
181
+ if (report.policy === 'drop') {
182
+ module.widgets = module.widgets.filter((widget) => outcomeByUnit.get(unitKey(module.id, widget.id)) !== 'dropped');
183
+ }
184
+ for (const widget of module.widgets) {
185
+ // Same deterministic walk as during resolution, so ordinals line up.
186
+ collectAnchorRefs(widget).forEach((ref, index) => {
187
+ const fingerprint = fingerprintByAnchor.get(anchorKey(module.id, widget.id, index));
188
+ if (fingerprint !== undefined) {
189
+ ref.anchor.fingerprint = fingerprint;
190
+ }
191
+ });
192
+ }
193
+ }
194
+ return out;
195
+ }
196
+ function unitKey(moduleId, widgetId) {
197
+ return `${moduleId}${widgetId}`;
198
+ }
199
+ function anchorKey(moduleId, widgetId, anchorIndex) {
200
+ return `${unitKey(moduleId, widgetId)}${anchorIndex}`;
201
+ }
202
+ function cloneAnchor(anchor) {
203
+ return structuredClone(anchor);
204
+ }
205
+ function isAnchorLike(value) {
206
+ return (typeof value === 'object' &&
207
+ value !== null &&
208
+ typeof value.file === 'string');
209
+ }
210
+ /**
211
+ * Collect every anchor a widget carries, wherever it lives: top-level
212
+ * `anchors` arrays (callouts), nested carriers (system-map nodes/edges,
213
+ * data-model annotations at any depth), and single-anchor `source` fields.
214
+ * Structural rather than per-widget-type, so new widget shapes are covered
215
+ * automatically as long as they keep the schema's `anchors`/`source` naming.
216
+ * Depth-first in spec order — deterministic for a given spec.
217
+ */
218
+ function collectAnchorRefs(value, path = [], out = []) {
219
+ if (Array.isArray(value)) {
220
+ value.forEach((item, index) => collectAnchorRefs(item, [...path, index], out));
221
+ return out;
222
+ }
223
+ if (value === null || typeof value !== 'object') {
224
+ return out;
225
+ }
226
+ for (const [key, child] of Object.entries(value)) {
227
+ if (key === 'anchors' && Array.isArray(child)) {
228
+ child.forEach((anchor, index) => {
229
+ if (isAnchorLike(anchor))
230
+ out.push({ anchor, path: [...path, key, index] });
231
+ });
232
+ }
233
+ else if (key === 'source' && isAnchorLike(child)) {
234
+ out.push({ anchor: child, path: [...path, key] });
235
+ }
236
+ else {
237
+ collectAnchorRefs(child, [...path, key], out);
238
+ }
239
+ }
240
+ return out;
241
+ }
242
+ //# sourceMappingURL=resolveAnchors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveAnchors.js","sourceRoot":"","sources":["../src/resolveAnchors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ import { type Anchor, type LabModule, type LabSpec } from '@ramplab/spec';
2
+ import { type ModelRunner } from './pipeline.js';
3
+ /**
4
+ * The verify stage (PLAN.md §3–§4): adversarial grounding enforcement.
5
+ *
6
+ * Anchor resolution proves a claim *points at real code*; this stage proves
7
+ * the claim is *true of that code*. An independent verifier agent receives
8
+ * each machine-generated claim together with the ACTUAL content of its
9
+ * anchored regions (read via the same `readAnchorRegion` that resolution
10
+ * fingerprints, so verifier and resolver see identical bytes) and tries to
11
+ * REFUTE it. Per-claim verdicts: `verified` | `refuted` | `unverifiable`,
12
+ * each with a reason. Anything not verified is dropped from the base spec —
13
+ * the overlay (human tribal knowledge) is never touched.
14
+ *
15
+ * **Batching (deliberate):** one verifier call per module, covering every
16
+ * claim in that module's widgets. Per-claim calls would cost one agent
17
+ * invocation per sentence of the lab; per-module batches keep the call count
18
+ * at the same order as the author fan-out (which produced the claims in the
19
+ * first place), keep each prompt's code context focused on one subsystem's
20
+ * files, and still yield strictly per-claim verdicts because the output
21
+ * contract demands exactly one verdict per listed claim id. Batches run in
22
+ * parallel under the same worker-pool/concurrency cap as authoring.
23
+ *
24
+ * **Drop semantics:** the unit of removal is the whole teachable widget —
25
+ * consistent with `UnitResolution` granularity in anchor resolution — with
26
+ * one refinement: a quiz drops only the failed question, and the quiz widget
27
+ * itself only when no questions remain. A module emptied by drops is removed
28
+ * (the spec schema demands ≥1 widget-bearing structure stays parseable) and
29
+ * recorded in the report.
30
+ *
31
+ * **Failure policy (consistent with the author stage):** a batch whose
32
+ * verifier output is still invalid after bounded retries fails the whole
33
+ * stage with an error naming the module — verification is a grounding
34
+ * guarantee, so there is no silent-skip mode. Other in-flight batches finish
35
+ * first so all failures are reported at once.
36
+ */
37
+ /** Default cap on concurrent verifier agents. */
38
+ export declare const DEFAULT_VERIFY_CONCURRENCY = 4;
39
+ /** The three per-claim verdicts. Only `verified` keeps a claim in the lab. */
40
+ export type ClaimVerdictValue = 'verified' | 'refuted' | 'unverifiable';
41
+ /** One machine-generated claim, extracted from a base widget. */
42
+ export interface VerificationClaim {
43
+ moduleId: string;
44
+ widgetId: string;
45
+ /**
46
+ * Stable claim id, unique within its module batch:
47
+ * `<widgetId>#<part>` (e.g. `greet-walkthrough#step-1`,
48
+ * `greetings-quiz#question-q-greet-return`).
49
+ */
50
+ claimId: string;
51
+ /** For quiz claims: the question id, so drops can target the question. */
52
+ questionId?: string;
53
+ /** The claim text shown to the verifier. */
54
+ claim: string;
55
+ /** The anchors grounding the claim, as they appear in the spec. */
56
+ anchors: Anchor[];
57
+ }
58
+ /** A claim plus its verdict — one row of the verification report. */
59
+ export interface ClaimVerdict extends VerificationClaim {
60
+ verdict: ClaimVerdictValue;
61
+ /** The verifier's justification (or the mechanical reason). */
62
+ reason: string;
63
+ }
64
+ export interface VerificationDroppedWidget {
65
+ moduleId: string;
66
+ widgetId: string;
67
+ /** One entry per failed claim: `<claimId>: <verdict> — <reason>`. */
68
+ reasons: string[];
69
+ }
70
+ export interface VerificationDroppedQuestion {
71
+ moduleId: string;
72
+ widgetId: string;
73
+ questionId: string;
74
+ reason: string;
75
+ }
76
+ export interface VerificationDrops {
77
+ /** Whole widgets removed (any failed claim; quizzes only when emptied). */
78
+ widgets: VerificationDroppedWidget[];
79
+ /** Individual quiz questions removed. */
80
+ questions: VerificationDroppedQuestion[];
81
+ /** Modules removed because verification left them without widgets. */
82
+ modules: string[];
83
+ }
84
+ export interface VerificationSummary {
85
+ totalClaims: number;
86
+ verified: number;
87
+ refuted: number;
88
+ unverifiable: number;
89
+ /** `verified / totalClaims`; 1 when there were no claims to check. */
90
+ passRate: number;
91
+ }
92
+ /** Structured report of a full verification pass over a spec's base content. */
93
+ export interface VerificationReport {
94
+ /** Every claim checked, in spec order, with its verdict and reason. */
95
+ claims: ClaimVerdict[];
96
+ drops: VerificationDrops;
97
+ summary: VerificationSummary;
98
+ }
99
+ export interface VerifyStageOptions {
100
+ model: string;
101
+ /** The assembled, anchor-resolved spec whose base content is on trial. */
102
+ spec: LabSpec;
103
+ /**
104
+ * Units already flagged by anchor resolution (the `flag` policy keeps
105
+ * them for human review). Verification skips them: their grounding failed
106
+ * mechanically, so there is no anchored code to check the claim against,
107
+ * and dropping them here would defeat the review-flow policy.
108
+ */
109
+ flaggedUnits?: readonly {
110
+ moduleId: string;
111
+ widgetId: string;
112
+ }[];
113
+ /**
114
+ * How many times to re-prompt a batch after invalid verifier output.
115
+ * @default 1
116
+ */
117
+ maxRetries?: number;
118
+ /**
119
+ * Max verifier agents in flight at once.
120
+ * @default 4
121
+ */
122
+ concurrency?: number;
123
+ }
124
+ export interface VerifyStageResult {
125
+ /** The spec with every non-verified unit dropped, revalidated. */
126
+ spec: LabSpec;
127
+ report: VerificationReport;
128
+ /**
129
+ * Verifier attempts per module batch (1 = first output was valid).
130
+ * Modules whose claims never needed a model call are absent.
131
+ */
132
+ attempts: Record<string, number>;
133
+ /** Summed cost across all batches and attempts, if the runner reports it. */
134
+ costUsd: number | undefined;
135
+ }
136
+ /** One batch's terminal failure inside the verify stage. */
137
+ export interface VerifyBatchFailure {
138
+ moduleId: string;
139
+ attempts: number;
140
+ lastFailure: string;
141
+ }
142
+ /** Raised when at least one module batch never produced valid verdicts. */
143
+ export declare class VerifyStageError extends Error {
144
+ readonly failures: readonly VerifyBatchFailure[];
145
+ constructor(failures: readonly VerifyBatchFailure[]);
146
+ }
147
+ export declare function runVerifyStage(runner: ModelRunner, repoDir: string, options: VerifyStageOptions): Promise<VerifyStageResult>;
148
+ /** Extract every claim carried by a module's widgets, in spec order. */
149
+ export declare function collectModuleClaims(module: LabModule): VerificationClaim[];
150
+ //# sourceMappingURL=verifyStage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifyStage.d.ts","sourceRoot":"","sources":["../src/verifyStage.ts"],"names":[],"mappings":"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"}