@specverse/engines 6.32.0 → 6.33.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 (59) hide show
  1. package/dist/ai/analyse-runner.d.ts.map +1 -1
  2. package/dist/ai/analyse-runner.js +8 -1
  3. package/dist/ai/analyse-runner.js.map +1 -1
  4. package/dist/ai/behaviours-runner.d.ts.map +1 -1
  5. package/dist/ai/behaviours-runner.js +35 -7
  6. package/dist/ai/behaviours-runner.js.map +1 -1
  7. package/dist/ai/create-runner.d.ts.map +1 -1
  8. package/dist/ai/create-runner.js +6 -0
  9. package/dist/ai/create-runner.js.map +1 -1
  10. package/dist/ai/deployment-emitter.d.ts +3 -0
  11. package/dist/ai/deployment-emitter.d.ts.map +1 -1
  12. package/dist/ai/deployment-emitter.js +145 -0
  13. package/dist/ai/deployment-emitter.js.map +1 -1
  14. package/dist/ai/manifest-emitter.d.ts +35 -10
  15. package/dist/ai/manifest-emitter.d.ts.map +1 -1
  16. package/dist/ai/manifest-emitter.js +140 -54
  17. package/dist/ai/manifest-emitter.js.map +1 -1
  18. package/dist/ai/skeleton-emitter.d.ts +1 -1
  19. package/dist/ai/skeleton-emitter.d.ts.map +1 -1
  20. package/dist/ai/skeleton-emitter.js +152 -14
  21. package/dist/ai/skeleton-emitter.js.map +1 -1
  22. package/dist/analyse-prepass/imports-graph.d.ts +407 -0
  23. package/dist/analyse-prepass/imports-graph.d.ts.map +1 -0
  24. package/dist/analyse-prepass/imports-graph.js +1200 -0
  25. package/dist/analyse-prepass/imports-graph.js.map +1 -0
  26. package/dist/analyse-prepass/index.d.ts +33 -0
  27. package/dist/analyse-prepass/index.d.ts.map +1 -1
  28. package/dist/analyse-prepass/index.js +35 -0
  29. package/dist/analyse-prepass/index.js.map +1 -1
  30. package/dist/inference/logical/generators/view-generator.d.ts +10 -0
  31. package/dist/inference/logical/generators/view-generator.d.ts.map +1 -1
  32. package/dist/inference/logical/generators/view-generator.js +20 -0
  33. package/dist/inference/logical/generators/view-generator.js.map +1 -1
  34. package/dist/libs/instance-factories/orms/templates/prisma/schema-generator.js +66 -4
  35. package/dist/parser/unified-parser.d.ts.map +1 -1
  36. package/dist/parser/unified-parser.js +103 -0
  37. package/dist/parser/unified-parser.js.map +1 -1
  38. package/dist/realize/index.d.ts.map +1 -1
  39. package/dist/realize/index.js +73 -148
  40. package/dist/realize/index.js.map +1 -1
  41. package/dist/realize/per-action-emitter.d.ts +235 -0
  42. package/dist/realize/per-action-emitter.d.ts.map +1 -0
  43. package/dist/realize/per-action-emitter.js +229 -0
  44. package/dist/realize/per-action-emitter.js.map +1 -0
  45. package/dist/realize/per-action-llm-emit.d.ts +87 -0
  46. package/dist/realize/per-action-llm-emit.d.ts.map +1 -0
  47. package/dist/realize/per-action-llm-emit.js +427 -0
  48. package/dist/realize/per-action-llm-emit.js.map +1 -0
  49. package/dist/realize/per-action-runner.d.ts +127 -0
  50. package/dist/realize/per-action-runner.d.ts.map +1 -0
  51. package/dist/realize/per-action-runner.js +269 -0
  52. package/dist/realize/per-action-runner.js.map +1 -0
  53. package/dist/realize/structural-validator.d.ts +71 -0
  54. package/dist/realize/structural-validator.d.ts.map +1 -0
  55. package/dist/realize/structural-validator.js +167 -0
  56. package/dist/realize/structural-validator.js.map +1 -0
  57. package/libs/instance-factories/orms/templates/prisma/__tests__/schema-generator.test.ts +416 -0
  58. package/libs/instance-factories/orms/templates/prisma/schema-generator.ts +182 -5
  59. package/package.json +3 -3
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Per-action realize runner — Phase 3 of the L3 redesign.
3
+ *
4
+ * The orchestration glue between the spec walker (controllers + services
5
+ * + their actions/operations) and the per-action emitter. This is the
6
+ * call site that REPLACES the legacy `generateAiBehaviors` step in
7
+ * `realize/index.ts` when the per-action path is enabled.
8
+ *
9
+ * Responsibilities:
10
+ * 1. Walk the spec's controllers + services and collect every custom
11
+ * action (controller actions + service operations) along with the
12
+ * owning entity name + step list + spec metadata.
13
+ * 2. For each action, build an ActionSpec + RealizeContext and call
14
+ * emitActionBody. The matcher (prisma / mongo-native / pg-native)
15
+ * and conventions array are passed through as injected
16
+ * dependencies — same shape the legacy ai-behaviors path uses.
17
+ * 3. Group results by owner and emit one `<Owner>.ai.ts` file per
18
+ * owner, containing one exported async function per action with
19
+ * the LLM-emitted (or stub-γ-emitted) body inline.
20
+ *
21
+ * Concurrency: the LLM call site (when a real LLM is configured) is
22
+ * sequential per owner — keeps surgical-retry's parse-error feedback
23
+ * clean and bounds the API spend in the worst case. A future Phase
24
+ * could parallelise across owners; not the default in V1.
25
+ *
26
+ * The legacy `<Owner>.ai.ts` emitted by `ai-behaviors-generator.ts`
27
+ * contains per-STEP helpers; the new file contains per-ACTION pure
28
+ * functions. DR2 says keep the filename, repurpose the content shape.
29
+ * Both shapes co-exist when this runner runs alongside the legacy
30
+ * generator (gated by env flag); the new file overwrites the legacy
31
+ * output when both are run for the same owner. The integration test
32
+ * pins the new shape; the env flag governs which runs in realize.
33
+ */
34
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
35
+ import { dirname, join } from 'path';
36
+ import { emitActionBody, } from './per-action-emitter.js';
37
+ /**
38
+ * Walk the spec, dispatch each custom action through the per-action
39
+ * emitter, and write per-owner `.ai.ts` files.
40
+ *
41
+ * Collection rules:
42
+ * - Controllers: every entry under `controller.actions` becomes a
43
+ * CollectedAction. CURVED ops (`controller.cured.{create,...}`)
44
+ * are skipped — the L1 instance-factory templates handle those
45
+ * deterministically.
46
+ * - Services: every entry under `service.operations` becomes a
47
+ * CollectedAction. Service operations don't have CURVED kinship.
48
+ * - Model behaviours (`model.behaviors.<name>`) are NOT collected by
49
+ * this runner — the controller / service is the realized surface;
50
+ * model behaviours flow through controllers via the inference
51
+ * pipeline before realize sees them. A future phase could collect
52
+ * them directly if needed.
53
+ */
54
+ export async function runPerActionEmission(opts) {
55
+ const collected = collectActions(opts.spec);
56
+ const ownerGroups = groupByOwner(collected);
57
+ const owners = [];
58
+ const filesWritten = [];
59
+ const totals = {
60
+ actionCount: 0,
61
+ ownerCount: 0,
62
+ stubCount: 0,
63
+ llmCount: 0,
64
+ fullyMatchedCount: 0,
65
+ };
66
+ for (const [ownerName, actions] of ownerGroups) {
67
+ const bodies = new Map();
68
+ const specs = new Map();
69
+ for (const collectedAction of actions) {
70
+ const realizeCtx = {
71
+ componentName: ownerName,
72
+ modelName: collectedAction.modelName,
73
+ matcher: opts.matcher,
74
+ conventions: opts.conventions,
75
+ aiArgsExpr: opts.aiArgsExpr,
76
+ llmEmit: opts.llmEmit,
77
+ canCallLLM: opts.canCallLLM,
78
+ };
79
+ const body = await emitActionBody(collectedAction.spec, realizeCtx);
80
+ bodies.set(collectedAction.actionName, body);
81
+ specs.set(collectedAction.actionName, collectedAction.spec);
82
+ totals.actionCount++;
83
+ // Heuristic counters — body shape tells us which branch fired.
84
+ if (body.includes('throw new Error(') && body.includes(': not implemented")')) {
85
+ totals.stubCount++;
86
+ }
87
+ else if (collectedAction.spec.steps.length > 0) {
88
+ // No way to distinguish LLM vs full-convention from here, but
89
+ // we can spot the "stub" branch above; everything else is a
90
+ // composed body.
91
+ totals.fullyMatchedCount++;
92
+ }
93
+ }
94
+ const result = { ownerName, bodies, specs };
95
+ owners.push(result);
96
+ totals.ownerCount++;
97
+ if (!opts.dryRun) {
98
+ const filePath = writeOwnerAiFile(opts.outputDir, result);
99
+ filesWritten.push(filePath);
100
+ if (!opts.silent) {
101
+ console.log(` ✅ Per-action AI behaviors: ${ownerName}.ai.ts (${actions.length} action${actions.length === 1 ? '' : 's'})`);
102
+ }
103
+ }
104
+ }
105
+ return { owners, filesWritten, totals };
106
+ }
107
+ // ─── Spec walking ────────────────────────────────────────────────────
108
+ /**
109
+ * Walk the spec and collect every custom controller action + service
110
+ * operation that has a non-empty `steps:` block. Without steps, the
111
+ * per-action emitter has no work to do — those actions stay as
112
+ * placeholder methods on the controller / service.
113
+ */
114
+ export function collectActions(spec) {
115
+ const out = [];
116
+ // Controllers — accept either {Name: {...}} object or [{name, ...}] array.
117
+ // When keyed by name (the canonical spec shape), the entries don't
118
+ // necessarily carry a `name` field; we fall back to the map key.
119
+ const controllerEntries = Array.isArray(spec.controllers)
120
+ ? spec.controllers.map((c) => [c?.name ?? '', c])
121
+ : Object.entries(spec.controllers || {});
122
+ for (const [keyName, controller] of controllerEntries) {
123
+ if (!controller?.actions)
124
+ continue;
125
+ const ownerName = controller.name || keyName;
126
+ if (!ownerName)
127
+ continue;
128
+ const modelName = controller.model || controller.modelReference || ownerName.replace(/Controller$/, '');
129
+ for (const [actionName, actionRaw] of Object.entries(controller.actions)) {
130
+ const action = normalizeActionSpec(actionRaw, actionName);
131
+ if (action.steps.length === 0)
132
+ continue;
133
+ out.push({
134
+ ownerKind: 'controller',
135
+ ownerName,
136
+ modelName,
137
+ actionName,
138
+ spec: { ...action, ownerName, ownerKind: 'controller' },
139
+ });
140
+ }
141
+ }
142
+ // Services — accept either {Name: {...}} object or [{name, ...}] array.
143
+ const serviceEntries = Array.isArray(spec.services)
144
+ ? spec.services.map((s) => [s?.name ?? '', s])
145
+ : Object.entries(spec.services || {});
146
+ for (const [keyName, service] of serviceEntries) {
147
+ if (!service?.operations)
148
+ continue;
149
+ const ownerName = service.name || keyName;
150
+ if (!ownerName)
151
+ continue;
152
+ const modelName = ownerName.replace(/Service$/, '');
153
+ const operationEntries = Array.isArray(service.operations)
154
+ ? service.operations.map((op) => [op.name, op])
155
+ : Object.entries(service.operations);
156
+ for (const [actionName, opRaw] of operationEntries) {
157
+ const action = normalizeActionSpec(opRaw, actionName);
158
+ if (action.steps.length === 0)
159
+ continue;
160
+ out.push({
161
+ ownerKind: 'service',
162
+ ownerName,
163
+ modelName,
164
+ actionName,
165
+ spec: { ...action, ownerName, ownerKind: 'service' },
166
+ });
167
+ }
168
+ }
169
+ return out;
170
+ }
171
+ /** Coerce a raw action / operation spec object into the ActionSpec shape. */
172
+ function normalizeActionSpec(raw, actionName) {
173
+ const stepsRaw = raw?.steps ?? raw?.implementation?.steps ?? [];
174
+ const steps = Array.isArray(stepsRaw)
175
+ ? stepsRaw.map((s) => (typeof s === 'string' ? s : s?.step)).filter((s) => typeof s === 'string')
176
+ : [];
177
+ return {
178
+ name: actionName,
179
+ ownerName: '', // filled in by caller
180
+ ownerKind: 'controller', // overwritten by caller
181
+ steps,
182
+ description: raw?.description,
183
+ parameters: raw?.parameters,
184
+ returns: typeof raw?.returns === 'string' ? raw.returns : raw?.returns ? JSON.stringify(raw.returns) : undefined,
185
+ requires: raw?.requires ?? raw?.preconditions,
186
+ ensures: raw?.ensures ?? raw?.postconditions,
187
+ publishes: raw?.publishes ?? raw?.events,
188
+ };
189
+ }
190
+ /** Group collected actions by owner so we emit one .ai.ts file per owner. */
191
+ function groupByOwner(actions) {
192
+ const groups = new Map();
193
+ for (const a of actions) {
194
+ const list = groups.get(a.ownerName) ?? [];
195
+ list.push(a);
196
+ groups.set(a.ownerName, list);
197
+ }
198
+ return groups;
199
+ }
200
+ // ─── File emission ───────────────────────────────────────────────────
201
+ /**
202
+ * Write a single owner's `.ai.ts` file to disk. Returns the file path.
203
+ *
204
+ * The file is structured as:
205
+ * - Header docstring (DR2 framing — repurposed from per-step to per-action).
206
+ * - One `export async function <actionName>(input): Promise<...>` per
207
+ * action, with the body produced by emitActionBody.
208
+ *
209
+ * Signatures are intentionally loose (`input: any`) for V1; Phase 4 /
210
+ * 5 will tighten them using the spec's `parameters:` types. The per-step
211
+ * `.ai.ts` files used the same loose signature, so we don't regress.
212
+ */
213
+ function writeOwnerAiFile(outputDir, owner) {
214
+ const filePath = join(outputDir, 'backend', 'src', 'behaviors', `${owner.ownerName}.ai.ts`);
215
+ const dir = dirname(filePath);
216
+ if (!existsSync(dir))
217
+ mkdirSync(dir, { recursive: true });
218
+ writeFileSync(filePath, renderOwnerAiFile(owner), 'utf-8');
219
+ return filePath;
220
+ }
221
+ /**
222
+ * Render the `.ai.ts` content for one owner. Exported so tests can
223
+ * assert on the produced shape without going to disk.
224
+ */
225
+ export function renderOwnerAiFile(owner) {
226
+ const blocks = [];
227
+ blocks.push(`/**
228
+ * ${owner.ownerName} — Per-action AI behaviors (Realize L3 per-action emission).
229
+ *
230
+ * One exported async function per spec action / operation. Each body
231
+ * was emitted by the per-action realize pipeline:
232
+ *
233
+ * - L2 convention matcher pre-baked deterministic snippets for known
234
+ * step patterns. Those snippets are present verbatim in the body.
235
+ * - The LLM (when available) wove the [WRITE]-step code around the
236
+ * pre-baked snippets to produce one coherent method body per action.
237
+ * - When neither convention nor LLM produced a coherent body, the
238
+ * function throws a "not implemented" stub at runtime and preserves
239
+ * the convention-matched scaffolding as a code-block comment for
240
+ * reviewer context (DR4-γ shape).
241
+ *
242
+ * REVIEW SURFACE — anything in this file that ISN'T deterministic
243
+ * convention output came from an LLM. Inspect carefully before
244
+ * deploying production logic.
245
+ *
246
+ * Generated: ${new Date().toISOString().split('T')[0]}
247
+ */
248
+ `);
249
+ for (const [actionName, spec] of owner.specs) {
250
+ const body = owner.bodies.get(actionName) ?? ` throw new Error('${actionName}: missing body');`;
251
+ blocks.push(renderActionFunction(actionName, spec, body));
252
+ }
253
+ return blocks.join('\n');
254
+ }
255
+ /** Render a single per-action `export async function ...` block. */
256
+ function renderActionFunction(actionName, spec, body) {
257
+ const description = spec.description ? ` * ${spec.description}\n *` : '';
258
+ const stepsDoc = spec.steps.length > 0
259
+ ? ` *\n * Spec steps:\n${spec.steps.map((s) => ` * - ${s}`).join('\n')}\n`
260
+ : '';
261
+ return `/**
262
+ * ${actionName}
263
+ ${description}${stepsDoc} */
264
+ export async function ${actionName}(input: any): Promise<any> {
265
+ ${body}
266
+ }
267
+ `;
268
+ }
269
+ //# sourceMappingURL=per-action-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-action-runner.js","sourceRoot":"","sources":["../../src/realize/per-action-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EACL,cAAc,GAOf,MAAM,yBAAyB,CAAC;AAoEjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAiC;IAEjC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IAE5C,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG;QACb,WAAW,EAAE,CAAC;QACd,UAAU,EAAE,CAAC;QACb,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,iBAAiB,EAAE,CAAC;KACrB,CAAC;IAEF,KAAK,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,WAAW,EAAE,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;QAE5C,KAAK,MAAM,eAAe,IAAI,OAAO,EAAE,CAAC;YACtC,MAAM,UAAU,GAAmB;gBACjC,aAAa,EAAE,SAAS;gBACxB,SAAS,EAAE,eAAe,CAAC,SAAS;gBACpC,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC;YAEF,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,eAAe,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YACpE,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC7C,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,EAAE,eAAe,CAAC,IAAI,CAAC,CAAC;YAC5D,MAAM,CAAC,WAAW,EAAE,CAAC;YACrB,+DAA+D;YAC/D,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBAC9E,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,CAAC;iBAAM,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjD,8DAA8D;gBAC9D,4DAA4D;gBAC5D,iBAAiB;gBACjB,MAAM,CAAC,iBAAiB,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAwB,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACjE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,UAAU,EAAE,CAAC;QAEpB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC1D,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,iCAAiC,SAAS,WAAW,OAAO,CAAC,MAAM,UAAU,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YAC/H,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;AAC1C,CAAC;AAED,wEAAwE;AAExE;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAS;IACtC,MAAM,GAAG,GAAsB,EAAE,CAAC;IAElC,2EAA2E;IAC3E,mEAAmE;IACnE,iEAAiE;IACjE,MAAM,iBAAiB,GAAyB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QAC7E,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,iBAAiB,EAAE,CAAC;QACtD,IAAI,CAAC,UAAU,EAAE,OAAO;YAAE,SAAS;QACnC,MAAM,SAAS,GAAI,UAAU,CAAC,IAAe,IAAI,OAAO,CAAC;QACzD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,SAAS,GAAI,UAAU,CAAC,KAAgB,IAAK,UAAU,CAAC,cAAyB,IAAI,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAChI,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAoB,EAAE,CAAC;YAC5F,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;YAC1D,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACxC,GAAG,CAAC,IAAI,CAAC;gBACP,SAAS,EAAE,YAAY;gBACvB,SAAS;gBACT,SAAS;gBACT,UAAU;gBACV,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,MAAM,cAAc,GAAyB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;QACvE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IACxC,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,cAAc,EAAE,CAAC;QAChD,IAAI,CAAC,OAAO,EAAE,UAAU;YAAE,SAAS;QACnC,MAAM,SAAS,GAAI,OAAO,CAAC,IAAe,IAAI,OAAO,CAAC;QACtD,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACpD,MAAM,gBAAgB,GAAoB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC;YACzE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAO,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpD,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACvC,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,gBAAgB,EAAE,CAAC;YACnD,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YACtD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACxC,GAAG,CAAC,IAAI,CAAC;gBACP,SAAS,EAAE,SAAS;gBACpB,SAAS;gBACT,SAAS;gBACT,UAAU;gBACV,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE;aACrD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAC7E,SAAS,mBAAmB,CAAC,GAAQ,EAAE,UAAkB;IACvD,MAAM,QAAQ,GAAG,GAAG,EAAE,KAAK,IAAI,GAAG,EAAE,cAAc,EAAE,KAAK,IAAI,EAAE,CAAC;IAChE,MAAM,KAAK,GAAa,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC7C,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;QAC3G,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,SAAS,EAAE,EAAE,EAAE,sBAAsB;QACrC,SAAS,EAAE,YAAY,EAAE,wBAAwB;QACjD,KAAK;QACL,WAAW,EAAE,GAAG,EAAE,WAAW;QAC7B,UAAU,EAAE,GAAG,EAAE,UAAU;QAC3B,OAAO,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;QAChH,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,GAAG,EAAE,aAAa;QAC7C,OAAO,EAAE,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,cAAc;QAC5C,SAAS,EAAE,GAAG,EAAE,SAAS,IAAI,GAAG,EAAE,MAAM;KACzC,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,SAAS,YAAY,CAAC,OAA0B;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACb,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wEAAwE;AAExE;;;;;;;;;;;GAWG;AACH,SAAS,gBAAgB,CAAC,SAAiB,EAAE,KAA0B;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC,SAAS,QAAQ,CAAC,CAAC;IAC5F,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,aAAa,CAAC,QAAQ,EAAE,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAA0B;IAC1D,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,CAAC,IAAI,CAAC;KACT,KAAK,CAAC,SAAS;;;;;;;;;;;;;;;;;;gBAkBJ,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;;CAErD,CAAC,CAAC;IAED,KAAK,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,wBAAwB,UAAU,mBAAmB,CAAC;QACnG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,oEAAoE;AACpE,SAAS,oBAAoB,CAAC,UAAkB,EAAE,IAAgB,EAAE,IAAY;IAC9E,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QACpC,CAAC,CAAC,uBAAuB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC5E,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;KACJ,UAAU;EACb,WAAW,GAAG,QAAQ;wBACA,UAAU;EAChC,IAAI;;CAEL,CAAC;AACF,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Structural validator for per-action LLM output (DR3 of the L3 proposal).
3
+ *
4
+ * The L2 convention matcher produces deterministic TypeScript snippets
5
+ * for spec steps it can match. Those pre-baked snippets are passed to the
6
+ * LLM as scaffolding (DR3-A). The LLM emits a coherent method body that
7
+ * weaves the pre-baked snippets together with [WRITE]-step code it
8
+ * authors itself.
9
+ *
10
+ * The structural validator is the trust-but-verify counterpart to that
11
+ * pattern: after the LLM emits, we diff the output against the pre-baked
12
+ * snippets. Every pre-baked snippet must appear in the LLM's body
13
+ * verbatim (modulo whitespace + trailing punctuation). If a snippet is
14
+ * missing — i.e. the LLM rewrote a deterministic piece — the realize
15
+ * pipeline fails loudly with a diff showing what was preserved + what
16
+ * was dropped.
17
+ *
18
+ * Why "verbatim modulo whitespace": pre-baked snippets are already
19
+ * idiomatic TS. Letting the LLM reformat them silently undermines
20
+ * "deterministic" — we'd lose reproducibility across runs. But forcing
21
+ * exact byte-for-byte match would fail on innocuous LLM behaviours
22
+ * (re-indenting a single line of pre-baked code to match the surrounding
23
+ * indentation it adopted). We compare on the canonical form: the
24
+ * snippet's "code essence" stripped of leading whitespace and trailing
25
+ * comment-only lines.
26
+ *
27
+ * This validator is orthogonal to the parse-check (esbuild) and the
28
+ * tsc-check (per-action-llm-emit's surgical retry loop). All three
29
+ * gates compose: parse-fail → surgical retry; structural-fail → loud
30
+ * fail (LLM rewrote a deterministic piece); tsc-fail → fall through to
31
+ * γ stub.
32
+ */
33
+ /** A single pre-baked snippet to verify is preserved in the LLM output. */
34
+ export interface PrebakedSnippet {
35
+ /** Step number (1-indexed) the snippet came from — for error messages. */
36
+ stepNum: number;
37
+ /** Human-readable step text — for error messages. */
38
+ stepText: string;
39
+ /** The pre-baked TypeScript snippet. The matcher's `.call` string. */
40
+ snippet: string;
41
+ }
42
+ /** Outcome of the structural-preservation check. */
43
+ export type StructuralValidationResult = {
44
+ ok: true;
45
+ } | {
46
+ ok: false;
47
+ missing: MissingSnippet[];
48
+ reason: string;
49
+ };
50
+ /** Per-snippet failure detail. */
51
+ export interface MissingSnippet {
52
+ stepNum: number;
53
+ stepText: string;
54
+ /** The original pre-baked snippet (canonicalised). */
55
+ expected: string;
56
+ /** The closest match found in the LLM body, or null when no near-match. */
57
+ closestMatch: string | null;
58
+ }
59
+ /**
60
+ * Validate that every pre-baked snippet appears in the LLM-emitted body.
61
+ *
62
+ * The check is substring containment on the canonical form (whitespace +
63
+ * leading-comment normalised). For each missing snippet we surface the
64
+ * step number, step text, and the closest near-match found in the body
65
+ * (or `null` if there's no token-overlap candidate).
66
+ *
67
+ * Empty `prebakedSnippets` is a vacuous pass — when no convention
68
+ * matched, there's nothing to preserve.
69
+ */
70
+ export declare function validateLlmOutputPreservesConventions(llmBody: string, prebakedSnippets: PrebakedSnippet[]): StructuralValidationResult;
71
+ //# sourceMappingURL=structural-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-validator.d.ts","sourceRoot":"","sources":["../../src/realize/structural-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oDAAoD;AACpD,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,kCAAkC;AAClC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAuBD;;;;;;;;;;GAUG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,eAAe,EAAE,GAClC,0BAA0B,CAiD5B"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Structural validator for per-action LLM output (DR3 of the L3 proposal).
3
+ *
4
+ * The L2 convention matcher produces deterministic TypeScript snippets
5
+ * for spec steps it can match. Those pre-baked snippets are passed to the
6
+ * LLM as scaffolding (DR3-A). The LLM emits a coherent method body that
7
+ * weaves the pre-baked snippets together with [WRITE]-step code it
8
+ * authors itself.
9
+ *
10
+ * The structural validator is the trust-but-verify counterpart to that
11
+ * pattern: after the LLM emits, we diff the output against the pre-baked
12
+ * snippets. Every pre-baked snippet must appear in the LLM's body
13
+ * verbatim (modulo whitespace + trailing punctuation). If a snippet is
14
+ * missing — i.e. the LLM rewrote a deterministic piece — the realize
15
+ * pipeline fails loudly with a diff showing what was preserved + what
16
+ * was dropped.
17
+ *
18
+ * Why "verbatim modulo whitespace": pre-baked snippets are already
19
+ * idiomatic TS. Letting the LLM reformat them silently undermines
20
+ * "deterministic" — we'd lose reproducibility across runs. But forcing
21
+ * exact byte-for-byte match would fail on innocuous LLM behaviours
22
+ * (re-indenting a single line of pre-baked code to match the surrounding
23
+ * indentation it adopted). We compare on the canonical form: the
24
+ * snippet's "code essence" stripped of leading whitespace and trailing
25
+ * comment-only lines.
26
+ *
27
+ * This validator is orthogonal to the parse-check (esbuild) and the
28
+ * tsc-check (per-action-llm-emit's surgical retry loop). All three
29
+ * gates compose: parse-fail → surgical retry; structural-fail → loud
30
+ * fail (LLM rewrote a deterministic piece); tsc-fail → fall through to
31
+ * γ stub.
32
+ */
33
+ /**
34
+ * Canonicalise a code chunk for comparison: strip leading whitespace per
35
+ * line, drop pure-comment lines (the matcher prepends `// Step N: ...`
36
+ * markers that the LLM is allowed to reword or absorb into prose), and
37
+ * collapse internal whitespace runs to a single space.
38
+ *
39
+ * The result is a fingerprint of the snippet's executable shape — enough
40
+ * to spot rewrites (different identifier, different control flow) but
41
+ * loose enough to tolerate harmless reformatting (alignment, spacing
42
+ * around operators).
43
+ */
44
+ function canonicalise(code) {
45
+ return code
46
+ .split('\n')
47
+ .map((line) => line.trim())
48
+ .filter((line) => line.length > 0 && !line.startsWith('//'))
49
+ .join(' ')
50
+ .replace(/\s+/g, ' ')
51
+ .trim();
52
+ }
53
+ /**
54
+ * Validate that every pre-baked snippet appears in the LLM-emitted body.
55
+ *
56
+ * The check is substring containment on the canonical form (whitespace +
57
+ * leading-comment normalised). For each missing snippet we surface the
58
+ * step number, step text, and the closest near-match found in the body
59
+ * (or `null` if there's no token-overlap candidate).
60
+ *
61
+ * Empty `prebakedSnippets` is a vacuous pass — when no convention
62
+ * matched, there's nothing to preserve.
63
+ */
64
+ export function validateLlmOutputPreservesConventions(llmBody, prebakedSnippets) {
65
+ if (prebakedSnippets.length === 0) {
66
+ return { ok: true };
67
+ }
68
+ const llmCanonical = canonicalise(llmBody);
69
+ const missing = [];
70
+ for (const snippet of prebakedSnippets) {
71
+ const expected = canonicalise(snippet.snippet);
72
+ if (expected.length === 0)
73
+ continue; // skip comment-only snippets
74
+ if (llmCanonical.includes(expected)) {
75
+ continue;
76
+ }
77
+ // Near-match heuristic: extract a list of progressively-shorter
78
+ // dotted tokens from the snippet (e.g. `prisma.customer.findUnique`,
79
+ // `prisma.customer`, `prisma`) and search the LLM body for any of
80
+ // them. Surfaces the closest line to the reviewer — so when the LLM
81
+ // rewrote `findUnique` to `findFirst` (kept the `prisma.customer`
82
+ // prefix), we find the rewritten line rather than reporting "no
83
+ // near-match found".
84
+ const distinctiveTokens = extractDistinctiveTokens(snippet.snippet);
85
+ let closestMatch = null;
86
+ for (const tok of distinctiveTokens) {
87
+ for (const line of llmBody.split('\n')) {
88
+ if (line.includes(tok)) {
89
+ closestMatch = line.trim();
90
+ break;
91
+ }
92
+ }
93
+ if (closestMatch)
94
+ break;
95
+ }
96
+ missing.push({
97
+ stepNum: snippet.stepNum,
98
+ stepText: snippet.stepText,
99
+ expected: snippet.snippet.trim(),
100
+ closestMatch,
101
+ });
102
+ }
103
+ if (missing.length === 0) {
104
+ return { ok: true };
105
+ }
106
+ const reason = formatMissingReport(missing);
107
+ return { ok: false, missing, reason };
108
+ }
109
+ /**
110
+ * Extract a list of progressively-shorter distinctive identifier
111
+ * tokens from a snippet, ordered most-specific first. Used by the
112
+ * closest-match heuristic to surface a rewritten line even when the
113
+ * LLM changed the trailing call shape (e.g. `findUnique → findFirst`)
114
+ * but kept the prefix.
115
+ *
116
+ * Returns the empty array when the snippet has no dotted identifiers.
117
+ */
118
+ function extractDistinctiveTokens(snippet) {
119
+ // Collect every dotted identifier (foo.bar, prisma.order.create, etc.)
120
+ const rawMatches = snippet.match(/[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+/g);
121
+ const matches = rawMatches ? Array.from(rawMatches) : [];
122
+ if (matches.length === 0)
123
+ return [];
124
+ const out = [];
125
+ // Start with the longest dotted identifier, then walk back along
126
+ // its prefix segments (one fewer dot each step) so we have a series
127
+ // of fall-back queries to match against the LLM body.
128
+ matches.sort((a, b) => b.length - a.length);
129
+ const longest = matches[0];
130
+ out.push(longest);
131
+ const segments = longest.split('.');
132
+ for (let i = segments.length - 1; i >= 2; i--) {
133
+ out.push(segments.slice(0, i).join('.'));
134
+ }
135
+ // Add any other dotted identifiers from the snippet, in case the
136
+ // longest one was a transient (e.g. variable assignment) and the
137
+ // distinguishing call sits later.
138
+ for (const m of matches.slice(1)) {
139
+ if (!out.includes(m))
140
+ out.push(m);
141
+ }
142
+ return out;
143
+ }
144
+ /**
145
+ * Format a human-readable diff report for the realize pipeline to print
146
+ * when the structural validator rejects an LLM output.
147
+ */
148
+ function formatMissingReport(missing) {
149
+ const lines = [];
150
+ lines.push(`LLM output dropped or rewrote ${missing.length} pre-baked convention snippet${missing.length === 1 ? '' : 's'}:`);
151
+ for (const m of missing) {
152
+ lines.push('');
153
+ lines.push(` Step ${m.stepNum}: ${m.stepText}`);
154
+ lines.push(` Expected (verbatim): ${m.expected.replace(/\n/g, '\n ')}`);
155
+ if (m.closestMatch) {
156
+ lines.push(` Closest in LLM body: ${m.closestMatch}`);
157
+ }
158
+ else {
159
+ lines.push(` Closest in LLM body: (no near-match found)`);
160
+ }
161
+ }
162
+ lines.push('');
163
+ lines.push('The convention matcher is deterministic; pre-baked snippets must be preserved verbatim. ' +
164
+ 'If you believe the matcher is wrong for this case, fix the convention pattern in step-conventions.ts.');
165
+ return lines.join('\n');
166
+ }
167
+ //# sourceMappingURL=structural-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structural-validator.js","sourceRoot":"","sources":["../../src/realize/structural-validator.ts"],"names":[],"mappings":"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"}