sysprom 1.14.0 → 1.16.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 (61) hide show
  1. package/README.md +19 -2
  2. package/dist/schema.json +18 -1
  3. package/dist/src/cli/commands/infer.d.ts +2 -0
  4. package/dist/src/cli/commands/infer.js +235 -0
  5. package/dist/src/cli/program.js +2 -0
  6. package/dist/src/endpoint-types.js +23 -0
  7. package/dist/src/index.d.ts +2 -2
  8. package/dist/src/index.js +2 -2
  9. package/dist/src/mcp/server.js +112 -1
  10. package/dist/src/operations/add-node.d.ts +51 -9
  11. package/dist/src/operations/add-plan-task.d.ts +34 -6
  12. package/dist/src/operations/add-relationship.d.ts +48 -8
  13. package/dist/src/operations/check.d.ts +17 -3
  14. package/dist/src/operations/graph.d.ts +17 -3
  15. package/dist/src/operations/index.d.ts +4 -0
  16. package/dist/src/operations/index.js +5 -0
  17. package/dist/src/operations/infer-completeness.d.ts +428 -0
  18. package/dist/src/operations/infer-completeness.js +131 -0
  19. package/dist/src/operations/infer-derived.d.ts +389 -0
  20. package/dist/src/operations/infer-derived.js +158 -0
  21. package/dist/src/operations/infer-impact.d.ts +2299 -0
  22. package/dist/src/operations/infer-impact.js +262 -0
  23. package/dist/src/operations/infer-lifecycle.d.ts +435 -0
  24. package/dist/src/operations/infer-lifecycle.js +119 -0
  25. package/dist/src/operations/init-document.d.ts +17 -3
  26. package/dist/src/operations/json-to-markdown.d.ts +17 -3
  27. package/dist/src/operations/mark-task-done.d.ts +34 -6
  28. package/dist/src/operations/mark-task-undone.d.ts +34 -6
  29. package/dist/src/operations/markdown-to-json.d.ts +17 -3
  30. package/dist/src/operations/next-id.d.ts +17 -3
  31. package/dist/src/operations/node-history.d.ts +17 -3
  32. package/dist/src/operations/plan-add-task.d.ts +34 -6
  33. package/dist/src/operations/plan-gate.d.ts +17 -3
  34. package/dist/src/operations/plan-init.d.ts +17 -3
  35. package/dist/src/operations/plan-progress.d.ts +17 -3
  36. package/dist/src/operations/plan-status.d.ts +17 -3
  37. package/dist/src/operations/query-node.d.ts +107 -17
  38. package/dist/src/operations/query-nodes.d.ts +34 -6
  39. package/dist/src/operations/query-relationships.d.ts +31 -5
  40. package/dist/src/operations/remove-node.d.ts +51 -9
  41. package/dist/src/operations/remove-relationship.d.ts +36 -7
  42. package/dist/src/operations/rename.d.ts +34 -6
  43. package/dist/src/operations/search.d.ts +34 -6
  44. package/dist/src/operations/speckit-diff.d.ts +17 -3
  45. package/dist/src/operations/speckit-export.d.ts +17 -3
  46. package/dist/src/operations/speckit-import.d.ts +17 -3
  47. package/dist/src/operations/speckit-sync.d.ts +51 -9
  48. package/dist/src/operations/state-at.d.ts +17 -3
  49. package/dist/src/operations/stats.d.ts +17 -3
  50. package/dist/src/operations/sync.d.ts +51 -9
  51. package/dist/src/operations/task-list.d.ts +17 -3
  52. package/dist/src/operations/timeline.d.ts +17 -3
  53. package/dist/src/operations/trace-from-node.d.ts +51 -9
  54. package/dist/src/operations/update-metadata.d.ts +34 -6
  55. package/dist/src/operations/update-node.d.ts +48 -8
  56. package/dist/src/operations/update-plan-task.d.ts +34 -6
  57. package/dist/src/operations/validate.d.ts +17 -3
  58. package/dist/src/schema.d.ts +70 -10
  59. package/dist/src/schema.js +21 -0
  60. package/package.json +1 -1
  61. package/schema.json +18 -1
@@ -0,0 +1,428 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Completeness result for a single node.
4
+ */
5
+ declare const CompletenessResult: z.ZodObject<{
6
+ id: z.ZodString;
7
+ type: z.ZodEnum<{
8
+ intent: "intent";
9
+ concept: "concept";
10
+ capability: "capability";
11
+ element: "element";
12
+ realisation: "realisation";
13
+ invariant: "invariant";
14
+ principle: "principle";
15
+ policy: "policy";
16
+ protocol: "protocol";
17
+ stage: "stage";
18
+ role: "role";
19
+ gate: "gate";
20
+ mode: "mode";
21
+ artefact: "artefact";
22
+ artefact_flow: "artefact_flow";
23
+ decision: "decision";
24
+ change: "change";
25
+ view: "view";
26
+ milestone: "milestone";
27
+ version: "version";
28
+ }> & {
29
+ is(value: unknown): value is "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
30
+ };
31
+ name: z.ZodString;
32
+ score: z.ZodNumber;
33
+ issues: z.ZodArray<z.ZodString>;
34
+ }, z.core.$strip>;
35
+ /** Completeness result for a single node with score and issues. */
36
+ export type CompletenessResult = z.infer<typeof CompletenessResult>;
37
+ /**
38
+ * Output schema for inferCompletenessOp.
39
+ */
40
+ declare const CompletenessOutput: z.ZodObject<{
41
+ nodes: z.ZodArray<z.ZodObject<{
42
+ id: z.ZodString;
43
+ type: z.ZodEnum<{
44
+ intent: "intent";
45
+ concept: "concept";
46
+ capability: "capability";
47
+ element: "element";
48
+ realisation: "realisation";
49
+ invariant: "invariant";
50
+ principle: "principle";
51
+ policy: "policy";
52
+ protocol: "protocol";
53
+ stage: "stage";
54
+ role: "role";
55
+ gate: "gate";
56
+ mode: "mode";
57
+ artefact: "artefact";
58
+ artefact_flow: "artefact_flow";
59
+ decision: "decision";
60
+ change: "change";
61
+ view: "view";
62
+ milestone: "milestone";
63
+ version: "version";
64
+ }> & {
65
+ is(value: unknown): value is "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
66
+ };
67
+ name: z.ZodString;
68
+ score: z.ZodNumber;
69
+ issues: z.ZodArray<z.ZodString>;
70
+ }, z.core.$strip>>;
71
+ averageScore: z.ZodNumber;
72
+ completeNodes: z.ZodNumber;
73
+ incompleteNodes: z.ZodNumber;
74
+ }, z.core.$strip>;
75
+ /** Output of completeness inference operation. */
76
+ export type CompletenessOutput = z.infer<typeof CompletenessOutput>;
77
+ /**
78
+ * Infer completeness of nodes based on expected relationships.
79
+ *
80
+ * Analyses each node to determine if it has expected refinements or
81
+ * relationships, returning a score (0-1) and list of issues for incomplete nodes.
82
+ */
83
+ export declare const inferCompletenessOp: import("./define-operation.js").DefinedOperation<z.ZodObject<{
84
+ doc: z.ZodObject<{
85
+ $schema: z.ZodOptional<z.ZodString>;
86
+ metadata: z.ZodOptional<z.ZodObject<{
87
+ title: z.ZodOptional<z.ZodString>;
88
+ doc_type: z.ZodOptional<z.ZodString>;
89
+ scope: z.ZodOptional<z.ZodString>;
90
+ status: z.ZodOptional<z.ZodString>;
91
+ version: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodInt]>>;
92
+ }, z.core.$loose> & {
93
+ is(value: unknown): value is {
94
+ [x: string]: unknown;
95
+ title?: string | undefined;
96
+ doc_type?: string | undefined;
97
+ scope?: string | undefined;
98
+ status?: string | undefined;
99
+ version?: string | number | undefined;
100
+ };
101
+ }>;
102
+ nodes: z.ZodArray<z.ZodObject<{
103
+ id: z.ZodString;
104
+ type: z.ZodEnum<{
105
+ intent: "intent";
106
+ concept: "concept";
107
+ capability: "capability";
108
+ element: "element";
109
+ realisation: "realisation";
110
+ invariant: "invariant";
111
+ principle: "principle";
112
+ policy: "policy";
113
+ protocol: "protocol";
114
+ stage: "stage";
115
+ role: "role";
116
+ gate: "gate";
117
+ mode: "mode";
118
+ artefact: "artefact";
119
+ artefact_flow: "artefact_flow";
120
+ decision: "decision";
121
+ change: "change";
122
+ view: "view";
123
+ milestone: "milestone";
124
+ version: "version";
125
+ }> & {
126
+ is(value: unknown): value is "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
127
+ };
128
+ name: z.ZodString;
129
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
130
+ is(value: unknown): value is string | string[];
131
+ }>;
132
+ status: z.ZodOptional<z.ZodEnum<{
133
+ deprecated: "deprecated";
134
+ proposed: "proposed";
135
+ accepted: "accepted";
136
+ active: "active";
137
+ implemented: "implemented";
138
+ adopted: "adopted";
139
+ defined: "defined";
140
+ introduced: "introduced";
141
+ in_progress: "in_progress";
142
+ complete: "complete";
143
+ consolidated: "consolidated";
144
+ experimental: "experimental";
145
+ retired: "retired";
146
+ superseded: "superseded";
147
+ abandoned: "abandoned";
148
+ deferred: "deferred";
149
+ }> & {
150
+ is(value: unknown): value is "deprecated" | "proposed" | "accepted" | "active" | "implemented" | "adopted" | "defined" | "introduced" | "in_progress" | "complete" | "consolidated" | "experimental" | "retired" | "superseded" | "abandoned" | "deferred";
151
+ }>;
152
+ lifecycle: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>>;
153
+ context: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
154
+ is(value: unknown): value is string | string[];
155
+ }>;
156
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
157
+ id: z.ZodString;
158
+ description: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
159
+ is(value: unknown): value is string | string[];
160
+ };
161
+ }, z.core.$loose> & {
162
+ is(value: unknown): value is {
163
+ [x: string]: unknown;
164
+ id: string;
165
+ description: string | string[];
166
+ };
167
+ }>>;
168
+ selected: z.ZodOptional<z.ZodString>;
169
+ rationale: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
170
+ is(value: unknown): value is string | string[];
171
+ }>;
172
+ scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
173
+ operations: z.ZodOptional<z.ZodArray<z.ZodObject<{
174
+ type: z.ZodEnum<{
175
+ link: "link";
176
+ add: "add";
177
+ update: "update";
178
+ remove: "remove";
179
+ }>;
180
+ target: z.ZodOptional<z.ZodString>;
181
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
182
+ is(value: unknown): value is string | string[];
183
+ }>;
184
+ }, z.core.$loose> & {
185
+ is(value: unknown): value is {
186
+ [x: string]: unknown;
187
+ type: "link" | "add" | "update" | "remove";
188
+ target?: string | undefined;
189
+ description?: string | string[] | undefined;
190
+ };
191
+ }>>;
192
+ plan: z.ZodOptional<z.ZodArray<z.ZodObject<{
193
+ description: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
194
+ is(value: unknown): value is string | string[];
195
+ };
196
+ done: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
197
+ }, z.core.$loose> & {
198
+ is(value: unknown): value is {
199
+ [x: string]: unknown;
200
+ description: string | string[];
201
+ done?: boolean | undefined;
202
+ };
203
+ }>>;
204
+ propagation: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
205
+ includes: z.ZodOptional<z.ZodArray<z.ZodString>>;
206
+ input: z.ZodOptional<z.ZodString>;
207
+ output: z.ZodOptional<z.ZodString>;
208
+ external_references: z.ZodOptional<z.ZodArray<z.ZodObject<{
209
+ role: z.ZodEnum<{
210
+ output: "output";
211
+ input: "input";
212
+ context: "context";
213
+ evidence: "evidence";
214
+ source: "source";
215
+ standard: "standard";
216
+ prior_art: "prior_art";
217
+ }> & {
218
+ is(value: unknown): value is "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
219
+ };
220
+ identifier: z.ZodString;
221
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
222
+ is(value: unknown): value is string | string[];
223
+ }>;
224
+ node_id: z.ZodOptional<z.ZodString>;
225
+ internalised: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
226
+ is(value: unknown): value is string | string[];
227
+ }>;
228
+ }, z.core.$strip> & {
229
+ is(value: unknown): value is {
230
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
231
+ identifier: string;
232
+ description?: string | string[] | undefined;
233
+ node_id?: string | undefined;
234
+ internalised?: string | string[] | undefined;
235
+ };
236
+ }>>;
237
+ readonly subsystem: z.ZodOptional<z.ZodObject</*elided*/ any, z.core.$strip>>;
238
+ }, z.core.$loose>>;
239
+ relationships: z.ZodOptional<z.ZodArray<z.ZodObject<{
240
+ from: z.ZodString;
241
+ to: z.ZodString;
242
+ type: z.ZodEnum<{
243
+ refines: "refines";
244
+ realises: "realises";
245
+ implements: "implements";
246
+ depends_on: "depends_on";
247
+ constrained_by: "constrained_by";
248
+ affects: "affects";
249
+ supersedes: "supersedes";
250
+ must_preserve: "must_preserve";
251
+ performs: "performs";
252
+ part_of: "part_of";
253
+ precedes: "precedes";
254
+ must_follow: "must_follow";
255
+ blocks: "blocks";
256
+ routes_to: "routes_to";
257
+ governed_by: "governed_by";
258
+ modifies: "modifies";
259
+ triggered_by: "triggered_by";
260
+ applies_to: "applies_to";
261
+ produces: "produces";
262
+ consumes: "consumes";
263
+ transforms_into: "transforms_into";
264
+ selects: "selects";
265
+ requires: "requires";
266
+ disables: "disables";
267
+ influence: "influence";
268
+ }> & {
269
+ is(value: unknown): value is "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence";
270
+ };
271
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
272
+ is(value: unknown): value is string | string[];
273
+ }>;
274
+ polarity: z.ZodOptional<z.ZodEnum<{
275
+ positive: "positive";
276
+ negative: "negative";
277
+ neutral: "neutral";
278
+ uncertain: "uncertain";
279
+ }> & {
280
+ is(value: unknown): value is "positive" | "negative" | "neutral" | "uncertain";
281
+ }>;
282
+ strength: z.ZodOptional<z.ZodNumber>;
283
+ }, z.core.$loose> & {
284
+ is(value: unknown): value is {
285
+ [x: string]: unknown;
286
+ from: string;
287
+ to: string;
288
+ type: "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence";
289
+ description?: string | string[] | undefined;
290
+ polarity?: "positive" | "negative" | "neutral" | "uncertain" | undefined;
291
+ strength?: number | undefined;
292
+ };
293
+ }>>;
294
+ external_references: z.ZodOptional<z.ZodArray<z.ZodObject<{
295
+ role: z.ZodEnum<{
296
+ output: "output";
297
+ input: "input";
298
+ context: "context";
299
+ evidence: "evidence";
300
+ source: "source";
301
+ standard: "standard";
302
+ prior_art: "prior_art";
303
+ }> & {
304
+ is(value: unknown): value is "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
305
+ };
306
+ identifier: z.ZodString;
307
+ description: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
308
+ is(value: unknown): value is string | string[];
309
+ }>;
310
+ node_id: z.ZodOptional<z.ZodString>;
311
+ internalised: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]> & {
312
+ is(value: unknown): value is string | string[];
313
+ }>;
314
+ }, z.core.$strip> & {
315
+ is(value: unknown): value is {
316
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
317
+ identifier: string;
318
+ description?: string | string[] | undefined;
319
+ node_id?: string | undefined;
320
+ internalised?: string | string[] | undefined;
321
+ };
322
+ }>>;
323
+ }, z.core.$strip> & {
324
+ is(value: unknown): value is {
325
+ nodes: {
326
+ [x: string]: unknown;
327
+ id: string;
328
+ type: "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
329
+ name: string;
330
+ description?: string | string[] | undefined;
331
+ status?: "deprecated" | "proposed" | "accepted" | "active" | "implemented" | "adopted" | "defined" | "introduced" | "in_progress" | "complete" | "consolidated" | "experimental" | "retired" | "superseded" | "abandoned" | "deferred" | undefined;
332
+ lifecycle?: Record<string, string | boolean> | undefined;
333
+ context?: string | string[] | undefined;
334
+ options?: {
335
+ [x: string]: unknown;
336
+ id: string;
337
+ description: string | string[];
338
+ }[] | undefined;
339
+ selected?: string | undefined;
340
+ rationale?: string | string[] | undefined;
341
+ scope?: string[] | undefined;
342
+ operations?: {
343
+ [x: string]: unknown;
344
+ type: "link" | "add" | "update" | "remove";
345
+ target?: string | undefined;
346
+ description?: string | string[] | undefined;
347
+ }[] | undefined;
348
+ plan?: {
349
+ [x: string]: unknown;
350
+ description: string | string[];
351
+ done?: boolean | undefined;
352
+ }[] | undefined;
353
+ propagation?: Record<string, boolean> | undefined;
354
+ includes?: string[] | undefined;
355
+ input?: string | undefined;
356
+ output?: string | undefined;
357
+ external_references?: {
358
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
359
+ identifier: string;
360
+ description?: string | string[] | undefined;
361
+ node_id?: string | undefined;
362
+ internalised?: string | string[] | undefined;
363
+ }[] | undefined;
364
+ subsystem?: /*elided*/ any | undefined;
365
+ }[];
366
+ $schema?: string | undefined;
367
+ metadata?: {
368
+ [x: string]: unknown;
369
+ title?: string | undefined;
370
+ doc_type?: string | undefined;
371
+ scope?: string | undefined;
372
+ status?: string | undefined;
373
+ version?: string | number | undefined;
374
+ } | undefined;
375
+ relationships?: {
376
+ [x: string]: unknown;
377
+ from: string;
378
+ to: string;
379
+ type: "refines" | "realises" | "implements" | "depends_on" | "constrained_by" | "affects" | "supersedes" | "must_preserve" | "performs" | "part_of" | "precedes" | "must_follow" | "blocks" | "routes_to" | "governed_by" | "modifies" | "triggered_by" | "applies_to" | "produces" | "consumes" | "transforms_into" | "selects" | "requires" | "disables" | "influence";
380
+ description?: string | string[] | undefined;
381
+ polarity?: "positive" | "negative" | "neutral" | "uncertain" | undefined;
382
+ strength?: number | undefined;
383
+ }[] | undefined;
384
+ external_references?: {
385
+ role: "output" | "input" | "context" | "evidence" | "source" | "standard" | "prior_art";
386
+ identifier: string;
387
+ description?: string | string[] | undefined;
388
+ node_id?: string | undefined;
389
+ internalised?: string | string[] | undefined;
390
+ }[] | undefined;
391
+ };
392
+ };
393
+ }, z.core.$strip>, z.ZodObject<{
394
+ nodes: z.ZodArray<z.ZodObject<{
395
+ id: z.ZodString;
396
+ type: z.ZodEnum<{
397
+ intent: "intent";
398
+ concept: "concept";
399
+ capability: "capability";
400
+ element: "element";
401
+ realisation: "realisation";
402
+ invariant: "invariant";
403
+ principle: "principle";
404
+ policy: "policy";
405
+ protocol: "protocol";
406
+ stage: "stage";
407
+ role: "role";
408
+ gate: "gate";
409
+ mode: "mode";
410
+ artefact: "artefact";
411
+ artefact_flow: "artefact_flow";
412
+ decision: "decision";
413
+ change: "change";
414
+ view: "view";
415
+ milestone: "milestone";
416
+ version: "version";
417
+ }> & {
418
+ is(value: unknown): value is "intent" | "concept" | "capability" | "element" | "realisation" | "invariant" | "principle" | "policy" | "protocol" | "stage" | "role" | "gate" | "mode" | "artefact" | "artefact_flow" | "decision" | "change" | "view" | "milestone" | "version";
419
+ };
420
+ name: z.ZodString;
421
+ score: z.ZodNumber;
422
+ issues: z.ZodArray<z.ZodString>;
423
+ }, z.core.$strip>>;
424
+ averageScore: z.ZodNumber;
425
+ completeNodes: z.ZodNumber;
426
+ incompleteNodes: z.ZodNumber;
427
+ }, z.core.$strip>>;
428
+ export {};
@@ -0,0 +1,131 @@
1
+ import * as z from "zod";
2
+ import { defineOperation } from "./define-operation.js";
3
+ import { SysProMDocument, NodeType } from "../schema.js";
4
+ /**
5
+ * Completeness result for a single node.
6
+ */
7
+ const CompletenessResult = z.object({
8
+ id: z.string(),
9
+ type: NodeType,
10
+ name: z.string(),
11
+ score: z.number().min(0).max(1),
12
+ issues: z.array(z.string()),
13
+ });
14
+ /**
15
+ * Output schema for inferCompletenessOp.
16
+ */
17
+ const CompletenessOutput = z.object({
18
+ nodes: z.array(CompletenessResult),
19
+ averageScore: z.number(),
20
+ completeNodes: z.number(),
21
+ incompleteNodes: z.number(),
22
+ });
23
+ /**
24
+ * Node types that are expected to have downward refinement relationships.
25
+ */
26
+ const REFINEMENT_HIERARCHY = {
27
+ intent: { expectedChildren: ["concept", "capability"], relType: "refines" },
28
+ concept: { expectedChildren: ["capability", "element"], relType: "refines" },
29
+ capability: {
30
+ expectedChildren: ["element", "realisation"],
31
+ relType: "realises",
32
+ },
33
+ element: { expectedChildren: ["realisation"], relType: "implements" },
34
+ decision: { expectedChildren: ["invariant"], relType: "must_preserve" },
35
+ change: { expectedChildren: ["decision"], relType: "implements" },
36
+ };
37
+ /**
38
+ * Infer completeness of nodes based on expected relationships.
39
+ *
40
+ * Analyses each node to determine if it has expected refinements or
41
+ * relationships, returning a score (0-1) and list of issues for incomplete nodes.
42
+ */
43
+ export const inferCompletenessOp = defineOperation({
44
+ name: "infer-completeness",
45
+ description: "Infer completeness of nodes based on expected refinement relationships",
46
+ input: z.object({
47
+ doc: SysProMDocument,
48
+ }),
49
+ output: CompletenessOutput,
50
+ fn: (input) => {
51
+ const typeMap = new Map(input.doc.nodes.map((n) => [n.id, n.type]));
52
+ const results = [];
53
+ for (const node of input.doc.nodes) {
54
+ const issues = [];
55
+ let score = 1.0;
56
+ if (node.type in REFINEMENT_HIERARCHY) {
57
+ const expected = REFINEMENT_HIERARCHY[node.type];
58
+ // For decision: find relationships FROM decision TO invariant (must_preserve)
59
+ // For change: find relationships FROM change TO decision (implements)
60
+ // For others: find relationships TO this node (refines, realises, implements)
61
+ const isOutgoingRel = ["decision", "change"].includes(node.type);
62
+ const children = (input.doc.relationships ?? [])
63
+ .filter((r) => {
64
+ if (isOutgoingRel) {
65
+ return r.from === node.id && r.type === expected.relType;
66
+ }
67
+ return r.to === node.id && r.type === expected.relType;
68
+ })
69
+ .map((r) => ({
70
+ id: isOutgoingRel ? r.to : r.from,
71
+ type: typeMap.get(isOutgoingRel ? r.to : r.from),
72
+ }));
73
+ // Check if any children match expected types
74
+ const validChildren = children.filter((c) => expected.expectedChildren.includes(c.type ?? ""));
75
+ if (validChildren.length === 0) {
76
+ issues.push(`No ${expected.relType} relationships ${isOutgoingRel ? "to" : "from"} ${expected.expectedChildren.join("/")} nodes`);
77
+ score -= 0.5;
78
+ }
79
+ }
80
+ // Check for required fields based on node type
81
+ if (node.type === "decision") {
82
+ if (!node.options || node.options.length === 0) {
83
+ issues.push("Decision has no options");
84
+ score -= 0.25;
85
+ }
86
+ if (!node.selected) {
87
+ issues.push("Decision has no selected option");
88
+ score -= 0.25;
89
+ }
90
+ if (!node.rationale) {
91
+ issues.push("Decision has no rationale");
92
+ score -= 0.1;
93
+ }
94
+ }
95
+ if (node.type === "change") {
96
+ if (!node.scope || node.scope.length === 0) {
97
+ issues.push("Change has no scope");
98
+ score -= 0.2;
99
+ }
100
+ if (!node.plan || node.plan.length === 0) {
101
+ issues.push("Change has no plan");
102
+ score -= 0.1;
103
+ }
104
+ }
105
+ if (node.type === "invariant") {
106
+ if (!node.description) {
107
+ issues.push("Invariant has no description");
108
+ score -= 0.3;
109
+ }
110
+ }
111
+ // Clamp score to [0, 1]
112
+ score = Math.max(0, Math.min(1, score));
113
+ results.push({
114
+ id: node.id,
115
+ type: node.type,
116
+ name: node.name,
117
+ score,
118
+ issues,
119
+ });
120
+ }
121
+ const completeNodes = results.filter((r) => r.score === 1).length;
122
+ const incompleteNodes = results.filter((r) => r.score < 1).length;
123
+ const averageScore = results.reduce((sum, r) => sum + r.score, 0) / results.length;
124
+ return {
125
+ nodes: results,
126
+ averageScore,
127
+ completeNodes,
128
+ incompleteNodes,
129
+ };
130
+ },
131
+ });