@snag-run/core 0.3.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/LICENSE +201 -0
- package/NOTICE +5 -0
- package/README.md +22 -0
- package/dist/anchor.d.ts +58 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +145 -0
- package/dist/anchor.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/lint.d.ts +19 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +153 -0
- package/dist/lint.js.map +1 -0
- package/dist/log.d.ts +81 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +63 -0
- package/dist/log.js.map +1 -0
- package/dist/reconcile.d.ts +66 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +173 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/schema.d.ts +567 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +573 -0
- package/dist/schema.js.map +1 -0
- package/dist/severity.d.ts +5 -0
- package/dist/severity.d.ts.map +1 -0
- package/dist/severity.js +16 -0
- package/dist/severity.js.map +1 -0
- package/package.json +46 -0
package/dist/schema.js
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// failure-map/v1 Zod schema — the interop contract shared by the CLI
|
|
3
|
+
// (generation + render) and, later, the backend. Ported from
|
|
4
|
+
// spikes/failure-map/failure-map.schema.json with the cli-v1.md decisions:
|
|
5
|
+
// - categorical `severity` is DROPPED (scores.severity is the only impact
|
|
6
|
+
// encoding); the band is derived (see severity.ts).
|
|
7
|
+
// - discriminated union on node `type` instead of the spike's if/then.
|
|
8
|
+
// - two schemas: the LLM generation surface ({ nodes, edges }) and the full
|
|
9
|
+
// engine-assembled document (schema + subject + meta envelope).
|
|
10
|
+
// - hard validation via superRefine: unique node ids + edge referential
|
|
11
|
+
// integrity. Soft lint lives in lint.ts.
|
|
12
|
+
const SCHEMA_ID = "failure-map/v1";
|
|
13
|
+
/** The canonical node-id format on the persisted document: lowercase
|
|
14
|
+
* alphanumerics + underscore. Enforced on the final {@link failureMapSchema}
|
|
15
|
+
* (the interop contract a renderer/backend relies on), NOT on the generation
|
|
16
|
+
* surface — see {@link coerceNodeIds}. */
|
|
17
|
+
const NODE_ID_PATTERN = /^[a-z0-9_]+$/;
|
|
18
|
+
const NODE_ID_MESSAGE = "node id must match ^[a-z0-9_]+$";
|
|
19
|
+
/** Node id as the LLM emits it (#280): any non-empty string. The strict
|
|
20
|
+
* `^[a-z0-9_]+$` form is NOT required here — a single malformed id (uppercase,
|
|
21
|
+
* `-`, `.`, a `file:line`-style id, …) used to reject the *entire* generated
|
|
22
|
+
* map at the `generateObject` SDK boundary, and the ~2 retries could not
|
|
23
|
+
* reliably re-roll a clean one (the whole-map-reject brittleness). Ids are
|
|
24
|
+
* mechanical identifiers, so {@link coerceNodeIds} repairs them to
|
|
25
|
+
* {@link NODE_ID_PATTERN} after generation instead of failing. */
|
|
26
|
+
const nodeId = z.string().min(1, "node id must be a non-empty string");
|
|
27
|
+
/**
|
|
28
|
+
* One FMEA risk factor (integer 1-5). `bounded` chooses the JSON-Schema
|
|
29
|
+
* encoding: `minimum`/`maximum` (the natural form) when `true`, or a Zod
|
|
30
|
+
* `.refine()` that carries NO numeric-bound keywords when `false`. The
|
|
31
|
+
* bounds-free form exists for OpenAI-compatible gateways whose structured-output
|
|
32
|
+
* validator rejects `minimum`/`maximum` on integers — AssemblyAI's LLM gateway
|
|
33
|
+
* returns "For 'integer' type, properties maximum, minimum are not supported"
|
|
34
|
+
* (#231). Both forms validate the 1-5 range identically once the model responds;
|
|
35
|
+
* only the schema *hint* sent to the model differs.
|
|
36
|
+
*/
|
|
37
|
+
function riskFactor(bounded) {
|
|
38
|
+
const base = z
|
|
39
|
+
.number()
|
|
40
|
+
.int()
|
|
41
|
+
.describe("FMEA risk factor: integer 1-5 (inclusive)");
|
|
42
|
+
return bounded
|
|
43
|
+
? base.min(1).max(5)
|
|
44
|
+
: base.refine((n) => n >= 1 && n <= 5, {
|
|
45
|
+
message: "FMEA risk factor must be between 1 and 5 (inclusive)",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function buildScores(bounded) {
|
|
49
|
+
const factor = riskFactor(bounded);
|
|
50
|
+
return z.object({ severity: factor, frequency: factor, detection: factor });
|
|
51
|
+
}
|
|
52
|
+
/** FMEA risk factors (each 1-5). RPN = severity * frequency * detection. The
|
|
53
|
+
* default bounded encoding; see {@link generationSchemaNoNumericBounds} for the
|
|
54
|
+
* gateway-safe variant (#231). */
|
|
55
|
+
export const scoresSchema = buildScores(true);
|
|
56
|
+
// Fields shared by every node. `.object()` (not `.strict()`) strips unknown
|
|
57
|
+
// keys — this is what lets the spike fixture's legacy categorical `severity`
|
|
58
|
+
// parse while keeping it out of the derived type.
|
|
59
|
+
const baseNodeShape = {
|
|
60
|
+
id: nodeId,
|
|
61
|
+
label: z.string(),
|
|
62
|
+
group: z.string().optional(),
|
|
63
|
+
sourceRef: z.string().optional(),
|
|
64
|
+
};
|
|
65
|
+
/** A non-failure node on the map (the happy-path spine + branches). */
|
|
66
|
+
export const flowNodeSchema = z.object({
|
|
67
|
+
...baseNodeShape,
|
|
68
|
+
type: z.enum(["step", "decision", "terminal", "recovery"]),
|
|
69
|
+
});
|
|
70
|
+
// The failure-node fields *other than* `scores` — shared by the bounded export
|
|
71
|
+
// below and the bounds-free generation variant (#231) so the two can never
|
|
72
|
+
// drift. `scores` is added separately because it is the only field whose
|
|
73
|
+
// encoding varies by provider.
|
|
74
|
+
const failureNodeShapeSansScores = {
|
|
75
|
+
...baseNodeShape,
|
|
76
|
+
type: z.literal("failure"),
|
|
77
|
+
/** Coarse failure-mode taxonomy for grouping/coverage (#56). Free-form during
|
|
78
|
+
* the discovery phase — required so the model reliably populates it, but NOT
|
|
79
|
+
* an enum yet (the vocabulary is still settling across real maps). */
|
|
80
|
+
class: z.string(),
|
|
81
|
+
silent: z.boolean(),
|
|
82
|
+
handled: z.boolean(),
|
|
83
|
+
reviewWouldMiss: z.boolean(),
|
|
84
|
+
trigger: z.string(),
|
|
85
|
+
manifestation: z.string(),
|
|
86
|
+
suggestedFix: z.string(),
|
|
87
|
+
fixEffort: z.enum(["trivial", "small", "medium", "large"]).optional(),
|
|
88
|
+
/** Engine-stamped stable identity (ADR 0002 seam, #78). A deterministic
|
|
89
|
+
* SHA-256 fingerprint over normalized semantic fields (`class` + `trigger`
|
|
90
|
+
* + `manifestation`). Optional for back-compat with already-committed maps
|
|
91
|
+
* and fixtures; always populated by `assembleDocument` on newly assembled
|
|
92
|
+
* documents. The LLM never produces this field. */
|
|
93
|
+
fingerprint: z.string().optional(),
|
|
94
|
+
};
|
|
95
|
+
/** A failure node / failure mode. Carries the required FMEA fields. */
|
|
96
|
+
export const failureNodeSchema = z.object({
|
|
97
|
+
...failureNodeShapeSansScores,
|
|
98
|
+
scores: scoresSchema,
|
|
99
|
+
});
|
|
100
|
+
/** Discriminated union on `type`: failure vs. flow node. */
|
|
101
|
+
export const nodeSchema = z.discriminatedUnion("type", [
|
|
102
|
+
failureNodeSchema,
|
|
103
|
+
flowNodeSchema,
|
|
104
|
+
]);
|
|
105
|
+
export const edgeSchema = z.object({
|
|
106
|
+
from: z.string(),
|
|
107
|
+
to: z.string(),
|
|
108
|
+
type: z.enum(["happy", "branch", "recovery", "failure"]),
|
|
109
|
+
condition: z.string().optional(),
|
|
110
|
+
});
|
|
111
|
+
// Hard validation shared by the generation schema and the full document:
|
|
112
|
+
// unique node ids + edge referential integrity. Both produce a
|
|
113
|
+
// broken/unrenderable artifact, so they reject rather than warn.
|
|
114
|
+
function refineNodesAndEdges(value, ctx) {
|
|
115
|
+
const seen = new Set();
|
|
116
|
+
value.nodes.forEach((node, i) => {
|
|
117
|
+
if (seen.has(node.id)) {
|
|
118
|
+
ctx.addIssue({
|
|
119
|
+
code: z.ZodIssueCode.custom,
|
|
120
|
+
message: `duplicate node id: ${node.id}`,
|
|
121
|
+
path: ["nodes", i, "id"],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
seen.add(node.id);
|
|
125
|
+
});
|
|
126
|
+
value.edges.forEach((edge, i) => {
|
|
127
|
+
if (!seen.has(edge.from)) {
|
|
128
|
+
ctx.addIssue({
|
|
129
|
+
code: z.ZodIssueCode.custom,
|
|
130
|
+
message: `edge references unknown node id in 'from': ${edge.from}`,
|
|
131
|
+
path: ["edges", i, "from"],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (!seen.has(edge.to)) {
|
|
135
|
+
ctx.addIssue({
|
|
136
|
+
code: z.ZodIssueCode.custom,
|
|
137
|
+
message: `edge references unknown node id in 'to': ${edge.to}`,
|
|
138
|
+
path: ["edges", i, "to"],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const nodesAndEdges = {
|
|
144
|
+
nodes: z.array(nodeSchema).min(1),
|
|
145
|
+
edges: z.array(edgeSchema),
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* The LLM generation surface: the tight { nodes, edges } analysis the model
|
|
149
|
+
* produces. Smallest surface = best structured-output reliability.
|
|
150
|
+
*/
|
|
151
|
+
export const generationSchema = z
|
|
152
|
+
.object(nodesAndEdges)
|
|
153
|
+
.superRefine(refineNodesAndEdges);
|
|
154
|
+
/**
|
|
155
|
+
* The bounds-free generation surface (#231): identical to {@link generationSchema}
|
|
156
|
+
* except the FMEA `scores` carry no JSON-Schema `minimum`/`maximum`. The engine
|
|
157
|
+
* sends this to OpenAI-compatible gateways (AssemblyAI, …) whose structured-output
|
|
158
|
+
* validator rejects numeric bounds on integers. The 1-5 range is still enforced —
|
|
159
|
+
* by the `.refine()` on each factor when this schema parses, and again by the
|
|
160
|
+
* full document schema (which keeps the bounded `scoresSchema`) on assembly — so
|
|
161
|
+
* nothing is lost but the in-schema hint to the model.
|
|
162
|
+
*/
|
|
163
|
+
const failureNodeSchemaNoNumericBounds = z.object({
|
|
164
|
+
...failureNodeShapeSansScores,
|
|
165
|
+
scores: buildScores(false),
|
|
166
|
+
});
|
|
167
|
+
const nodeSchemaNoNumericBounds = z.discriminatedUnion("type", [
|
|
168
|
+
failureNodeSchemaNoNumericBounds,
|
|
169
|
+
flowNodeSchema,
|
|
170
|
+
]);
|
|
171
|
+
export const generationSchemaNoNumericBounds = z
|
|
172
|
+
.object({
|
|
173
|
+
nodes: z.array(nodeSchemaNoNumericBounds).min(1),
|
|
174
|
+
edges: z.array(edgeSchema),
|
|
175
|
+
})
|
|
176
|
+
.superRefine(refineNodesAndEdges);
|
|
177
|
+
// --- #272 fix: REQUIRE sourceRef on code-intake failure nodes ---
|
|
178
|
+
//
|
|
179
|
+
// The code-v3 emit prompt forcefully demands a `file:line` citation on every
|
|
180
|
+
// failure node, yet three prompt variants produced ZERO citations — because
|
|
181
|
+
// `sourceRef` is `.optional()` on the base node and structured-output models
|
|
182
|
+
// drop optional fields regardless of the prose (root cause (a) in
|
|
183
|
+
// codemap-sourceref-grounding). The lever the prompt can't pull is the SCHEMA:
|
|
184
|
+
// making the field required compels the model to emit it.
|
|
185
|
+
//
|
|
186
|
+
// Required ONLY for code intakes (`module`/`capability`) and ONLY on the FAILURE
|
|
187
|
+
// arm — spec/doc maps have no source line, and flow (step/decision/…) nodes keep
|
|
188
|
+
// `sourceRef` optional. The hard `file:line`/in-scope validity check stays SOFT
|
|
189
|
+
// (lint.ts `uncited-code-failure`): a non-empty string is all the schema demands,
|
|
190
|
+
// so a slightly-off citation can't fail the whole map (the brittle gate that broke
|
|
191
|
+
// generation). The soft lint then flags hallucinated/out-of-scope refs. These
|
|
192
|
+
// variants mirror the two discriminated-union surfaces above; the flat/strict
|
|
193
|
+
// surface is deliberately left unchanged (it flattens every node to one shape, so
|
|
194
|
+
// requiring sourceRef there would force flow nodes to cite too — revisit when an
|
|
195
|
+
// OpenAI code-intake eval needs it).
|
|
196
|
+
export const REQUIRED_SOURCEREF_MESSAGE = 'every code-map failure node must cite the file:line it lives on — set sourceRef (e.g. "worktree.go:110")';
|
|
197
|
+
/** The failure-node fields (sans `scores`) with `sourceRef` made required. */
|
|
198
|
+
const failureNodeCodeShapeSansScores = {
|
|
199
|
+
...failureNodeShapeSansScores,
|
|
200
|
+
sourceRef: z.string().min(1, REQUIRED_SOURCEREF_MESSAGE),
|
|
201
|
+
};
|
|
202
|
+
function codeGenerationSchema(bounded) {
|
|
203
|
+
const failureNode = z.object({
|
|
204
|
+
...failureNodeCodeShapeSansScores,
|
|
205
|
+
scores: buildScores(bounded),
|
|
206
|
+
});
|
|
207
|
+
const node = z.discriminatedUnion("type", [failureNode, flowNodeSchema]);
|
|
208
|
+
return z
|
|
209
|
+
.object({ nodes: z.array(node).min(1), edges: z.array(edgeSchema) })
|
|
210
|
+
.superRefine(refineNodesAndEdges);
|
|
211
|
+
}
|
|
212
|
+
/** The bounded code-intake generation surface: {@link generationSchema} with a
|
|
213
|
+
* required `sourceRef` on failure nodes (#272). Sent to providers that accept
|
|
214
|
+
* integer numeric bounds (anthropic). */
|
|
215
|
+
export const generationSchemaCode = codeGenerationSchema(true);
|
|
216
|
+
/** The bounds-free code-intake generation surface: {@link
|
|
217
|
+
* generationSchemaNoNumericBounds} with a required `sourceRef` on failure nodes
|
|
218
|
+
* (#272). Sent to OpenAI-compatible gateways that reject integer bounds. */
|
|
219
|
+
export const generationSchemaCodeNoNumericBounds = codeGenerationSchema(false);
|
|
220
|
+
/**
|
|
221
|
+
* The STRICT-compatible generation surface (#247). OpenAI strict structured
|
|
222
|
+
* output (`response_format: json_schema`, `strict: true`) is the token-level
|
|
223
|
+
* enforcement that stops the model re-emitting nodes — which non-strict gateways
|
|
224
|
+
* (AssemblyAI) otherwise turn into a duplicate-id hard failure. But strict mode
|
|
225
|
+
* forbids `oneOf`, and our node {@link nodeSchema} is a discriminated union
|
|
226
|
+
* (`failure | flow`) which Zod emits as `oneOf` — so strict rejects it outright
|
|
227
|
+
* (`'oneOf' is not permitted`).
|
|
228
|
+
*
|
|
229
|
+
* This surface sidesteps that by FLATTENING the union into a single node object:
|
|
230
|
+
* one `type` enum (incl. `"failure"`) and the failure-only fields made nullable
|
|
231
|
+
* (populated for `type: "failure"`, `null` otherwise). No union → no `oneOf`.
|
|
232
|
+
* It is also bounds-free (strict also rejects integer `minimum`/`maximum`). The
|
|
233
|
+
* flat output is re-projected onto the canonical discriminated union by
|
|
234
|
+
* {@link normalizeFlatGeneration} immediately after generation, so the rest of
|
|
235
|
+
* the engine (envelope, assembly, the full document schema) is unchanged — this
|
|
236
|
+
* is purely the shape we hand the model, not a new internal node type.
|
|
237
|
+
*/
|
|
238
|
+
// Strict mode forbids integer `minimum`/`maximum`, so the flat factor carries no
|
|
239
|
+
// in-schema bound — that leaves the JSON-Schema `description` as the ONLY in-schema
|
|
240
|
+
// 1-5 signal the model gets (the canonical `riskFactor` describe is otherwise lost
|
|
241
|
+
// on this surface). `normalizeFlatGeneration` re-imposes the hard 1-5 bound after
|
|
242
|
+
// generation, where a violation is a no-retry terminal error — so guiding the model
|
|
243
|
+
// up front matters. The text mirrors `riskFactor` for parity (#247).
|
|
244
|
+
const flatBareFactor = z
|
|
245
|
+
.number()
|
|
246
|
+
.int()
|
|
247
|
+
.describe("FMEA risk factor: integer 1-5 (inclusive)");
|
|
248
|
+
const flatNodeSchema = z.object({
|
|
249
|
+
id: nodeId,
|
|
250
|
+
type: z.enum(["step", "decision", "terminal", "recovery", "failure"]),
|
|
251
|
+
label: z.string(),
|
|
252
|
+
// Optional-on-the-union fields, made nullable so strict keeps them `required`.
|
|
253
|
+
group: z.string().nullable(),
|
|
254
|
+
sourceRef: z.string().nullable(),
|
|
255
|
+
// Failure-only fields: present for `type: "failure"`, `null` for flow nodes.
|
|
256
|
+
class: z.string().nullable(),
|
|
257
|
+
silent: z.boolean().nullable(),
|
|
258
|
+
handled: z.boolean().nullable(),
|
|
259
|
+
reviewWouldMiss: z.boolean().nullable(),
|
|
260
|
+
trigger: z.string().nullable(),
|
|
261
|
+
manifestation: z.string().nullable(),
|
|
262
|
+
suggestedFix: z.string().nullable(),
|
|
263
|
+
fixEffort: z.enum(["trivial", "small", "medium", "large"]).nullable(),
|
|
264
|
+
scores: z
|
|
265
|
+
.object({
|
|
266
|
+
severity: flatBareFactor,
|
|
267
|
+
frequency: flatBareFactor,
|
|
268
|
+
detection: flatBareFactor,
|
|
269
|
+
})
|
|
270
|
+
.nullable(),
|
|
271
|
+
});
|
|
272
|
+
const flatEdgeSchema = z.object({
|
|
273
|
+
from: z.string(),
|
|
274
|
+
to: z.string(),
|
|
275
|
+
type: z.enum(["happy", "branch", "recovery", "failure"]),
|
|
276
|
+
condition: z.string().nullable(),
|
|
277
|
+
});
|
|
278
|
+
export const flatGenerationSchema = z.object({
|
|
279
|
+
nodes: z.array(flatNodeSchema).min(1),
|
|
280
|
+
edges: z.array(flatEdgeSchema),
|
|
281
|
+
});
|
|
282
|
+
/**
|
|
283
|
+
* Project a flat strict-mode generation ({@link flatGenerationSchema}) back onto
|
|
284
|
+
* the canonical discriminated-union {@link Generation}: drop the `null`
|
|
285
|
+
* failure-only fields from flow nodes, keep them on failure nodes, strip `null`
|
|
286
|
+
* optionals, then re-validate through {@link generationSchema}. That final parse
|
|
287
|
+
* re-imposes everything the flat surface relaxed for strict's sake — the 1-5
|
|
288
|
+
* `scores` bounds, the per-`type` required fields (a `failure` node missing its
|
|
289
|
+
* `scores`/`class` throws here), unique ids and edge referential integrity — so a
|
|
290
|
+
* malformed flat map fails exactly as a malformed union map would. `input` is
|
|
291
|
+
* `unknown` (defence-in-depth for an injected seam): it is parsed through the flat
|
|
292
|
+
* schema first.
|
|
293
|
+
*/
|
|
294
|
+
export function normalizeFlatGeneration(input) {
|
|
295
|
+
const flat = flatGenerationSchema.parse(input);
|
|
296
|
+
const nodes = flat.nodes.map((n) => {
|
|
297
|
+
const base = {
|
|
298
|
+
id: n.id,
|
|
299
|
+
label: n.label,
|
|
300
|
+
...(n.group != null ? { group: n.group } : {}),
|
|
301
|
+
...(n.sourceRef != null ? { sourceRef: n.sourceRef } : {}),
|
|
302
|
+
};
|
|
303
|
+
if (n.type === "failure") {
|
|
304
|
+
return {
|
|
305
|
+
...base,
|
|
306
|
+
type: "failure",
|
|
307
|
+
class: n.class,
|
|
308
|
+
silent: n.silent,
|
|
309
|
+
handled: n.handled,
|
|
310
|
+
reviewWouldMiss: n.reviewWouldMiss,
|
|
311
|
+
trigger: n.trigger,
|
|
312
|
+
manifestation: n.manifestation,
|
|
313
|
+
suggestedFix: n.suggestedFix,
|
|
314
|
+
...(n.fixEffort != null ? { fixEffort: n.fixEffort } : {}),
|
|
315
|
+
scores: n.scores,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return { ...base, type: n.type };
|
|
319
|
+
});
|
|
320
|
+
const edges = flat.edges.map((e) => ({
|
|
321
|
+
from: e.from,
|
|
322
|
+
to: e.to,
|
|
323
|
+
type: e.type,
|
|
324
|
+
...(e.condition != null ? { condition: e.condition } : {}),
|
|
325
|
+
}));
|
|
326
|
+
return generationSchema.parse({ nodes, edges });
|
|
327
|
+
}
|
|
328
|
+
/** Lowercase + collapse every run of non-`[a-z0-9_]` to a single `_`, then trim
|
|
329
|
+
* leading/trailing `_`. `worktree.go:18` → `worktree_go_18`, `Fail-GitHang` →
|
|
330
|
+
* `fail_githang`. An id that is all punctuation collapses to `""` and the caller
|
|
331
|
+
* substitutes a placeholder. */
|
|
332
|
+
function slugifyNodeId(raw) {
|
|
333
|
+
return raw
|
|
334
|
+
.toLowerCase()
|
|
335
|
+
.replace(/[^a-z0-9_]+/g, "_")
|
|
336
|
+
.replace(/^_+|_+$/g, "");
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Repair LLM-emitted node ids to the canonical {@link NODE_ID_PATTERN} (#280)
|
|
340
|
+
* and rewrite every edge endpoint with the SAME mapping so references stay
|
|
341
|
+
* intact (an un-rewritten endpoint would become a dangling edge). Ids are
|
|
342
|
+
* mechanical identifiers — a bad character should be slugified, never fatal.
|
|
343
|
+
*
|
|
344
|
+
* Identity-preserving by construction:
|
|
345
|
+
* - Distinct raw ids that slugify to the same value are kept distinct (a `_2`,
|
|
346
|
+
* `_3`, … suffix on collision), so two nodes never silently merge.
|
|
347
|
+
* - Equal raw ids map to the same slug, so a genuine duplicate-id still trips
|
|
348
|
+
* {@link refineNodesAndEdges} downstream (this does not paper over duplicates).
|
|
349
|
+
* - An empty slug (all-punctuation id) falls back to `node`.
|
|
350
|
+
* - An edge endpoint with no matching node id is left as-is, so a dangling edge
|
|
351
|
+
* still surfaces as a referential-integrity error rather than being hidden.
|
|
352
|
+
*
|
|
353
|
+
* Does NOT touch the semantic `fingerprint` (over class/trigger/manifestation),
|
|
354
|
+
* so stable identity / reconciliation is unaffected.
|
|
355
|
+
*/
|
|
356
|
+
export function coerceNodeIds(generation) {
|
|
357
|
+
const mapping = new Map();
|
|
358
|
+
const used = new Set();
|
|
359
|
+
// Pass 1: reserve ids ALREADY in canonical form so a valid id is never
|
|
360
|
+
// displaced by an earlier node whose slug happens to collide with it. This
|
|
361
|
+
// keeps the assignment independent of node order and makes #280 a pure repair
|
|
362
|
+
// of the *malformed* ids — the stable ones pass through untouched.
|
|
363
|
+
for (const node of generation.nodes) {
|
|
364
|
+
if (NODE_ID_PATTERN.test(node.id) && !mapping.has(node.id)) {
|
|
365
|
+
used.add(node.id);
|
|
366
|
+
mapping.set(node.id, node.id);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Pass 2: slugify the rest, collision-guarding against the reserved set.
|
|
370
|
+
for (const node of generation.nodes) {
|
|
371
|
+
if (mapping.has(node.id))
|
|
372
|
+
continue; // reserved canonical, or an equal raw id (dup stays a dup)
|
|
373
|
+
const base = slugifyNodeId(node.id) || "node";
|
|
374
|
+
let candidate = base;
|
|
375
|
+
let n = 2;
|
|
376
|
+
while (used.has(candidate))
|
|
377
|
+
candidate = `${base}_${n++}`;
|
|
378
|
+
used.add(candidate);
|
|
379
|
+
mapping.set(node.id, candidate);
|
|
380
|
+
}
|
|
381
|
+
const nodes = generation.nodes.map((node) => ({
|
|
382
|
+
...node,
|
|
383
|
+
id: mapping.get(node.id) ?? node.id,
|
|
384
|
+
}));
|
|
385
|
+
const edges = generation.edges.map((edge) => ({
|
|
386
|
+
...edge,
|
|
387
|
+
from: mapping.get(edge.from) ?? edge.from,
|
|
388
|
+
to: mapping.get(edge.to) ?? edge.to,
|
|
389
|
+
}));
|
|
390
|
+
return { nodes, edges };
|
|
391
|
+
}
|
|
392
|
+
// --- #272: a grounding `sourceRef` on failure nodes for CODE intakes ---
|
|
393
|
+
//
|
|
394
|
+
// `sourceRef` is `optional()` on the base node because spec/PRD maps
|
|
395
|
+
// (`subject.kind: document | process | pull_request`) have no source line to
|
|
396
|
+
// cite. For the code intakes (`module`/`capability`) every FAILURE node SHOULD
|
|
397
|
+
// cite the `file:line` that produces it — the lever against the speculative
|
|
398
|
+
// "false-unaddressed" garbage surfaced by the treetop dogfood (#131): a citation
|
|
399
|
+
// collapses the gap between an imagined guard and the code as built. The code-v2
|
|
400
|
+
// prompt requests it; a missing/invalid citation is surfaced as a SOFT lint
|
|
401
|
+
// warning (see lint.ts `uncited-code-failure`), never a hard rejection — hard
|
|
402
|
+
// gating the whole map on every node proved too brittle to generate (one of ~30
|
|
403
|
+
// failure nodes missing a ref fails the whole map; whole-map retry can't repair a
|
|
404
|
+
// single node). The helpers below are the shared validity check for that lint.
|
|
405
|
+
/** Split a code subject's `ref` ("a.go, dir/b.go") into its discovered path set
|
|
406
|
+
* (#272). Absent/empty ref → empty set (scope unknown: format is still checked,
|
|
407
|
+
* path membership is not). */
|
|
408
|
+
export function scopePathsFromRef(ref) {
|
|
409
|
+
if (!ref)
|
|
410
|
+
return new Set();
|
|
411
|
+
return new Set(ref
|
|
412
|
+
.split(",")
|
|
413
|
+
.map((p) => p.trim())
|
|
414
|
+
.filter((p) => p.length > 0));
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Validate a failure node's `sourceRef` as a concrete, in-scope citation (#272).
|
|
418
|
+
* Returns a human-readable problem (used verbatim as the retry/repair hint the
|
|
419
|
+
* model sees on a re-prompt) or `null` when the ref is acceptable. A valid ref is
|
|
420
|
+
* `file:line` (or `file:line-line`) whose `file` is one of the analyzed-scope
|
|
421
|
+
* paths. When `scopePaths` is empty the path-membership check is skipped (scope
|
|
422
|
+
* unknown) — the `file:line` shape is still enforced.
|
|
423
|
+
*/
|
|
424
|
+
export function sourceRefProblem(ref, scopePaths) {
|
|
425
|
+
if (ref == null || ref.trim() === "") {
|
|
426
|
+
return 'every failure node on a code map must cite the file:line that produces it (set sourceRef, e.g. "worktree.go:110")';
|
|
427
|
+
}
|
|
428
|
+
const lastColon = ref.lastIndexOf(":");
|
|
429
|
+
if (lastColon <= 0 || lastColon === ref.length - 1) {
|
|
430
|
+
return `sourceRef "${ref}" must be "file:line" — a file path and the line the failure lives on (e.g. "worktree.go:110")`;
|
|
431
|
+
}
|
|
432
|
+
const path = ref.slice(0, lastColon);
|
|
433
|
+
const lineSpec = ref.slice(lastColon + 1);
|
|
434
|
+
if (!/^\d+(-\d+)?$/.test(lineSpec)) {
|
|
435
|
+
return `sourceRef "${ref}" must end in a line number ("file:line"); "${lineSpec}" is not a line`;
|
|
436
|
+
}
|
|
437
|
+
if (scopePaths.size > 0 && !scopePaths.has(path)) {
|
|
438
|
+
return `sourceRef "${ref}" cites "${path}", which is not in the analyzed scope — cite one of the files you were given`;
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* The artifact a Snag Map is derived from. `kind` is *what is being analyzed in
|
|
444
|
+
* the world* — `document` (a design) or `process` (a real business process; the
|
|
445
|
+
* intake is reserved, not wired yet), or a code grain: `function` ⊂ `module` ⊂
|
|
446
|
+
* `capability` (the cross-cutting grain spanning modules/boundaries, derived
|
|
447
|
+
* agentically by-name, #85), with `pull_request` the orthogonal change-axis. The
|
|
448
|
+
* enum is *additive* — already-committed maps keep validating as kinds are added.
|
|
449
|
+
*/
|
|
450
|
+
export const subjectSchema = z.object({
|
|
451
|
+
kind: z.enum([
|
|
452
|
+
"pull_request",
|
|
453
|
+
"document",
|
|
454
|
+
"process",
|
|
455
|
+
"function",
|
|
456
|
+
"module",
|
|
457
|
+
"capability",
|
|
458
|
+
]),
|
|
459
|
+
ref: z.string().optional(),
|
|
460
|
+
title: z.string(),
|
|
461
|
+
/** Provenance / staleness anchor (#54): the git blob OID of the exact bytes
|
|
462
|
+
* mapped (`git hash-object <file>`). Optional so docs outside a git repo or
|
|
463
|
+
* untracked still validate. The CLI computes it; the engine only stamps it
|
|
464
|
+
* when provided (the engine stays git-free). */
|
|
465
|
+
sourceSha: z.string().optional(),
|
|
466
|
+
});
|
|
467
|
+
/** The code-intake subject kinds — the grains derived from existing source:
|
|
468
|
+
* `module` (review scope, {@link deriveCodeSubject}) and `capability` (by-name
|
|
469
|
+
* discovery, {@link deriveCapabilitySubject}). These are exactly the kinds for
|
|
470
|
+
* which a failure node MUST cite a `sourceRef` (#272); the spec kinds
|
|
471
|
+
* (`document`/`process`/`pull_request`) have no single source line to anchor.
|
|
472
|
+
* (`function` is in the enum but no intake derives it yet — it joins here when
|
|
473
|
+
* wired.) */
|
|
474
|
+
export function isCodeIntakeKind(kind) {
|
|
475
|
+
return kind === "module" || kind === "capability";
|
|
476
|
+
}
|
|
477
|
+
/** The harnesses that can drive the engine (#297) — pure provenance, nothing
|
|
478
|
+
* branches on the value. `snag` is the native CLI on API tokens; `claude-code`
|
|
479
|
+
* and `codex` are skills/wrappers that drive the same engine on a subscription.
|
|
480
|
+
* Knowing which produced a map is what makes the native-API-vs-via-harness
|
|
481
|
+
* quality comparison (eval / model-support work) possible. Additive: a new
|
|
482
|
+
* harness joins the enum without breaking already-committed maps. */
|
|
483
|
+
export const HARNESSES = ["snag", "claude-code", "codex"];
|
|
484
|
+
/** Default harness when none is declared — the native `snag` CLI. */
|
|
485
|
+
export const DEFAULT_HARNESS = "snag";
|
|
486
|
+
/**
|
|
487
|
+
* Engine-stamped provenance (never produced by the LLM) — the poor-man's
|
|
488
|
+
* observability bridge to a future trace server.
|
|
489
|
+
*/
|
|
490
|
+
export const metaSchema = z.object({
|
|
491
|
+
engineVersion: z.string(),
|
|
492
|
+
generatedAt: z.string(),
|
|
493
|
+
/** Which harness drove the engine for this map (#297). `snag` (native CLI,
|
|
494
|
+
* default) | `claude-code` | `codex`. Provenance only — nothing branches on
|
|
495
|
+
* it. Optional so already-committed maps without it still validate; always
|
|
496
|
+
* stamped on newly generated maps (defaulting to `snag`). */
|
|
497
|
+
harness: z.enum(HARNESSES).optional(),
|
|
498
|
+
/** API protocol/SDK the map was generated against — Langfuse's "Adapter"
|
|
499
|
+
* (#55). `anthropic` | `openai` today (was `provider`). */
|
|
500
|
+
adapter: z.string(),
|
|
501
|
+
/** User-declared vendor/connection label — Langfuse's "Provider Name" (#55,
|
|
502
|
+
* e.g. "AssemblyAI", "OpenRouter", "Anthropic"). The engine can't infer the
|
|
503
|
+
* vendor (it only knows adapter + base URL), so this is optional and
|
|
504
|
+
* user-supplied. */
|
|
505
|
+
providerName: z.string().optional(),
|
|
506
|
+
model: z.string(),
|
|
507
|
+
/** Resolved provider base URL the map was generated against (provenance).
|
|
508
|
+
* Optional so existing maps/fixtures without it still validate; always
|
|
509
|
+
* stamped on newly generated maps. */
|
|
510
|
+
apiUrl: z.string().url().optional(),
|
|
511
|
+
promptVersion: z.string(),
|
|
512
|
+
/** Liveness/degrade flag (#83): TRUE when the agentic gather loop hit its hard
|
|
513
|
+
* step ceiling without converging, so the map was emitted from possibly
|
|
514
|
+
* incomplete gathered context. Optional + only stamped when true, so doc-path
|
|
515
|
+
* maps and already-committed maps omit it and still validate. Surfacing it in
|
|
516
|
+
* the viewer is a separate slice (#B). */
|
|
517
|
+
gatherStoppedAtCap: z.boolean().optional(),
|
|
518
|
+
/** Sampling temperature actually sent to the model (provenance, #173). Optional
|
|
519
|
+
* + only stamped when a temperature was applied: OpenAI reasoning models
|
|
520
|
+
* (gpt-5.x, o-series) reject an explicit `temperature`, so the engine omits it
|
|
521
|
+
* for them and leaves this absent. Already-committed maps without it still
|
|
522
|
+
* validate. */
|
|
523
|
+
temperature: z.number().optional(),
|
|
524
|
+
/** Output-token budget actually sent to the model (provenance, #234). Optional
|
|
525
|
+
* so already-committed maps without it still validate; always stamped on newly
|
|
526
|
+
* generated maps (the engine always sends an explicit budget — the AI SDK only
|
|
527
|
+
* forwards `max_tokens` when we pass it). */
|
|
528
|
+
maxOutputTokens: z.number().int().positive().optional(),
|
|
529
|
+
tokenUsage: z.object({
|
|
530
|
+
input: z.number().int().nonnegative(),
|
|
531
|
+
output: z.number().int().nonnegative(),
|
|
532
|
+
total: z.number().int().nonnegative(),
|
|
533
|
+
}),
|
|
534
|
+
});
|
|
535
|
+
/**
|
|
536
|
+
* Document-level hard validation: everything {@link refineNodesAndEdges} checks,
|
|
537
|
+
* PLUS the strict `^[a-z0-9_]+$` node-id format. The id format is enforced HERE
|
|
538
|
+
* (the persisted contract) rather than on the generation surface so a malformed
|
|
539
|
+
* model id is repaired by {@link coerceNodeIds} during assembly, not fatal at
|
|
540
|
+
* generation (#280). A hand-edited / already-committed map with a bad id still
|
|
541
|
+
* rejects.
|
|
542
|
+
*/
|
|
543
|
+
function refineDocument(value, ctx) {
|
|
544
|
+
value.nodes.forEach((node, i) => {
|
|
545
|
+
if (!NODE_ID_PATTERN.test(node.id)) {
|
|
546
|
+
ctx.addIssue({
|
|
547
|
+
code: z.ZodIssueCode.custom,
|
|
548
|
+
message: NODE_ID_MESSAGE,
|
|
549
|
+
path: ["nodes", i, "id"],
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
refineNodesAndEdges(value, ctx);
|
|
554
|
+
}
|
|
555
|
+
/** The full persisted failure-map/v1 document: envelope + analysis. */
|
|
556
|
+
export const failureMapSchema = z
|
|
557
|
+
.object({
|
|
558
|
+
schema: z.literal(SCHEMA_ID),
|
|
559
|
+
subject: subjectSchema,
|
|
560
|
+
meta: metaSchema,
|
|
561
|
+
...nodesAndEdges,
|
|
562
|
+
})
|
|
563
|
+
.superRefine(refineDocument);
|
|
564
|
+
export { SCHEMA_ID };
|
|
565
|
+
/** Parse + validate the LLM generation surface; throws on invalid input. */
|
|
566
|
+
export function parseGeneration(input) {
|
|
567
|
+
return generationSchema.parse(input);
|
|
568
|
+
}
|
|
569
|
+
/** Parse + validate a full failure-map/v1 document; throws on invalid input. */
|
|
570
|
+
export function parseFailureMap(input) {
|
|
571
|
+
return failureMapSchema.parse(input);
|
|
572
|
+
}
|
|
573
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const SEVERITY_BANDS: readonly ["critical", "high", "medium", "low"];
|
|
2
|
+
export type SeverityBand = (typeof SEVERITY_BANDS)[number];
|
|
3
|
+
/** Derive the categorical band from the 1-5 FMEA severity score. */
|
|
4
|
+
export declare function severityBand(severity: number): SeverityBand;
|
|
5
|
+
//# sourceMappingURL=severity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.d.ts","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,cAAc,gDAAiD,CAAC;AAC7E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAK3D"}
|
package/dist/severity.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Severity band derivation. `scores.severity` (integer 1-5) is the single
|
|
2
|
+
// source of truth for impact (cli-v1.md "Severity — single source of truth").
|
|
3
|
+
// The categorical band is *dropped from the schema* and derived wherever a
|
|
4
|
+
// label is needed: 5 -> critical, 4 -> high, 3 -> medium, 1-2 -> low.
|
|
5
|
+
export const SEVERITY_BANDS = ["critical", "high", "medium", "low"];
|
|
6
|
+
/** Derive the categorical band from the 1-5 FMEA severity score. */
|
|
7
|
+
export function severityBand(severity) {
|
|
8
|
+
if (severity >= 5)
|
|
9
|
+
return "critical";
|
|
10
|
+
if (severity === 4)
|
|
11
|
+
return "high";
|
|
12
|
+
if (severity === 3)
|
|
13
|
+
return "medium";
|
|
14
|
+
return "low";
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=severity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"severity.js","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,sEAAsE;AAEtE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAU,CAAC;AAG7E,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC;IACrC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC"}
|