pi-mega-compact 0.20.1 → 0.20.3

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 (120) hide show
  1. package/dist/config/vector-cortex.js +26 -0
  2. package/dist/config.js +1 -1
  3. package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +2 -0
  4. package/dist/extensions/dashboard-server/routes-vector-cortex-plans.js +49 -0
  5. package/dist/extensions/dashboard-server/routes-vector-cortex-reconstruct.js +33 -0
  6. package/dist/extensions/dashboard-server/routes-vector-cortex.js +2 -0
  7. package/dist/extensions/dashboard-server/routes.js +1 -1
  8. package/dist/extensions/dashboard-server/server.js +5 -1
  9. package/dist/src/config/vector-cortex.js +26 -0
  10. package/dist/src/config.js +1 -1
  11. package/dist/src/vector-cortex/planner/manifest.js +66 -0
  12. package/dist/src/vector-cortex/planner/portfolio.js +0 -0
  13. package/dist/src/vector-cortex/planner/types.js +41 -0
  14. package/dist/src/vector-cortex/prompt-dag/_acceptance-dag.js +347 -0
  15. package/dist/src/vector-cortex/prompt-dag/_acceptance-fixture.js +59 -0
  16. package/dist/src/vector-cortex/prompt-dag/_acceptance-helpers.js +17 -0
  17. package/dist/src/vector-cortex/prompt-dag/_acceptance-planner.js +153 -0
  18. package/dist/src/vector-cortex/prompt-dag/_acceptance-shuffle.js +24 -0
  19. package/dist/src/vector-cortex/prompt-dag/builder.js +171 -0
  20. package/dist/src/vector-cortex/prompt-dag/types.js +33 -0
  21. package/dist/src/vector-cortex/prompt-dag/validator.js +0 -0
  22. package/dist/src/vector-cortex/reconstruct/_acceptance-helpers.js +365 -0
  23. package/dist/src/vector-cortex/reconstruct/assemble.js +137 -0
  24. package/dist/src/vector-cortex/reconstruct/closure.js +268 -0
  25. package/dist/src/vector-cortex/reconstruct/types.js +46 -0
  26. package/dist/src/vector-cortex/reconstruct/validate.js +152 -0
  27. package/dist/vector-cortex/planner/manifest.js +66 -0
  28. package/dist/vector-cortex/planner/portfolio.js +0 -0
  29. package/dist/vector-cortex/planner/types.js +41 -0
  30. package/dist/vector-cortex/prompt-dag/_acceptance-dag.js +347 -0
  31. package/dist/vector-cortex/prompt-dag/_acceptance-fixture.js +59 -0
  32. package/dist/vector-cortex/prompt-dag/_acceptance-helpers.js +17 -0
  33. package/dist/vector-cortex/prompt-dag/_acceptance-planner.js +153 -0
  34. package/dist/vector-cortex/prompt-dag/_acceptance-shuffle.js +24 -0
  35. package/dist/vector-cortex/prompt-dag/builder.js +171 -0
  36. package/dist/vector-cortex/prompt-dag/types.js +33 -0
  37. package/dist/vector-cortex/prompt-dag/validator.js +0 -0
  38. package/dist/vector-cortex/reconstruct/_acceptance-helpers.js +365 -0
  39. package/dist/vector-cortex/reconstruct/assemble.js +137 -0
  40. package/dist/vector-cortex/reconstruct/closure.js +268 -0
  41. package/dist/vector-cortex/reconstruct/types.js +46 -0
  42. package/dist/vector-cortex/reconstruct/validate.js +152 -0
  43. package/extensions/dashboard-client/dist/assets/{AreaChart-n4z5w9Ox.js → AreaChart-Cam9-nhT.js} +2 -2
  44. package/extensions/dashboard-client/dist/assets/{AreaChart-n4z5w9Ox.js.map → AreaChart-Cam9-nhT.js.map} +1 -1
  45. package/extensions/dashboard-client/dist/assets/{BarChart-BLGjWWBr.js → BarChart-DzIY8aM1.js} +2 -2
  46. package/extensions/dashboard-client/dist/assets/{BarChart-BLGjWWBr.js.map → BarChart-DzIY8aM1.js.map} +1 -1
  47. package/extensions/dashboard-client/dist/assets/{CacheTab-CAnrKKVK.js → CacheTab-CKIiYsG_.js} +2 -2
  48. package/extensions/dashboard-client/dist/assets/{CacheTab-CAnrKKVK.js.map → CacheTab-CKIiYsG_.js.map} +1 -1
  49. package/extensions/dashboard-client/dist/assets/{EventsTab-D-GL7Ngq.js → EventsTab-xaaBJLiK.js} +2 -2
  50. package/extensions/dashboard-client/dist/assets/{EventsTab-D-GL7Ngq.js.map → EventsTab-xaaBJLiK.js.map} +1 -1
  51. package/extensions/dashboard-client/dist/assets/{HealthTab-C4x5qQ8s.js → HealthTab-BGtUKOqG.js} +2 -2
  52. package/extensions/dashboard-client/dist/assets/{HealthTab-C4x5qQ8s.js.map → HealthTab-BGtUKOqG.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BSPs0eq5.js → MaintenanceTab-ABgQnTZ9.js} +2 -2
  54. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-BSPs0eq5.js.map → MaintenanceTab-ABgQnTZ9.js.map} +1 -1
  55. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BWEUtTSu.js → MemoryMapTab-ChR2GAN-.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BWEUtTSu.js.map → MemoryMapTab-ChR2GAN-.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/{MetricsTab-Dhm1c3Cx.js → MetricsTab-DdCLAgcR.js} +2 -2
  58. package/extensions/dashboard-client/dist/assets/{MetricsTab-Dhm1c3Cx.js.map → MetricsTab-DdCLAgcR.js.map} +1 -1
  59. package/extensions/dashboard-client/dist/assets/{OverviewTab-Cm6cySiQ.js → OverviewTab-DtemzJt6.js} +2 -2
  60. package/extensions/dashboard-client/dist/assets/{OverviewTab-Cm6cySiQ.js.map → OverviewTab-DtemzJt6.js.map} +1 -1
  61. package/extensions/dashboard-client/dist/assets/{ReposTab-DxLN1N4K.js → ReposTab-B9mvD9Ep.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{ReposTab-DxLN1N4K.js.map → ReposTab-B9mvD9Ep.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{SessionsTab-CZuI4ISW.js → SessionsTab-BcO38XLS.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{SessionsTab-CZuI4ISW.js.map → SessionsTab-BcO38XLS.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/{SetupTab-C_0VOomm.js → SetupTab-D_TBNP09.js} +2 -2
  66. package/extensions/dashboard-client/dist/assets/{SetupTab-C_0VOomm.js.map → SetupTab-D_TBNP09.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BhbaRLmi.js → TimeSavedCard-TjHpbUOo.js} +2 -2
  68. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BhbaRLmi.js.map → TimeSavedCard-TjHpbUOo.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/assets/{TurnsTab-CXJmbjje.js → TurnsTab-DprxndCF.js} +2 -2
  70. package/extensions/dashboard-client/dist/assets/{TurnsTab-CXJmbjje.js.map → TurnsTab-DprxndCF.js.map} +1 -1
  71. package/extensions/dashboard-client/dist/assets/VectorCortexTab-Bym21yVQ.js +2 -0
  72. package/extensions/dashboard-client/dist/assets/VectorCortexTab-Bym21yVQ.js.map +1 -0
  73. package/extensions/dashboard-client/dist/assets/{WikiTab-C5uvMCzp.js → WikiTab-OKgSo15G.js} +2 -2
  74. package/extensions/dashboard-client/dist/assets/{WikiTab-C5uvMCzp.js.map → WikiTab-OKgSo15G.js.map} +1 -1
  75. package/extensions/dashboard-client/dist/assets/{button-Cl_fxJcg.js → button-D_Qz4q7L.js} +2 -2
  76. package/extensions/dashboard-client/dist/assets/{button-Cl_fxJcg.js.map → button-D_Qz4q7L.js.map} +1 -1
  77. package/extensions/dashboard-client/dist/assets/{card-BH8Le5YM.js → card-CsI6Jm3p.js} +2 -2
  78. package/extensions/dashboard-client/dist/assets/{card-BH8Le5YM.js.map → card-CsI6Jm3p.js.map} +1 -1
  79. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-sZ6ZNtBi.js → generateCategoricalChart-CvHKUdhX.js} +2 -2
  80. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-sZ6ZNtBi.js.map → generateCategoricalChart-CvHKUdhX.js.map} +1 -1
  81. package/extensions/dashboard-client/dist/assets/{index-CX9zv8cJ.js → index-0Ye_un22.js} +3 -3
  82. package/extensions/dashboard-client/dist/assets/{index-CX9zv8cJ.js.map → index-0Ye_un22.js.map} +1 -1
  83. package/extensions/dashboard-client/dist/assets/{switch-CXJhcjhM.js → switch-VQEoJl8Q.js} +2 -2
  84. package/extensions/dashboard-client/dist/assets/{switch-CXJhcjhM.js.map → switch-VQEoJl8Q.js.map} +1 -1
  85. package/extensions/dashboard-client/dist/assets/{toggle-CoLtIc6y.js → toggle-CAPm4HJo.js} +2 -2
  86. package/extensions/dashboard-client/dist/assets/{toggle-CoLtIc6y.js.map → toggle-CAPm4HJo.js.map} +1 -1
  87. package/extensions/dashboard-client/dist/assets/{useSSE-fSXho606.js → useSSE-pxsNTVkh.js} +2 -2
  88. package/extensions/dashboard-client/dist/assets/{useSSE-fSXho606.js.map → useSSE-pxsNTVkh.js.map} +1 -1
  89. package/extensions/dashboard-client/dist/index.html +1 -1
  90. package/extensions/dashboard-client/src/api/vector-cortex.ts +18 -0
  91. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +72 -0
  92. package/extensions/dashboard-client/src/types/vector-cortex.ts +36 -0
  93. package/extensions/dashboard-server/api-contracts/vector-cortex.ts +66 -0
  94. package/extensions/dashboard-server/routes-rag-settings-helpers.ts +12 -0
  95. package/extensions/dashboard-server/routes-vector-cortex-plans.ts +58 -0
  96. package/extensions/dashboard-server/routes-vector-cortex-reconstruct.ts +41 -0
  97. package/extensions/dashboard-server/routes-vector-cortex.ts +2 -0
  98. package/extensions/dashboard-server/routes.ts +2 -0
  99. package/extensions/dashboard-server/server.ts +4 -0
  100. package/package.json +1 -1
  101. package/src/config/vector-cortex.ts +28 -0
  102. package/src/config.ts +2 -0
  103. package/src/vector-cortex/planner/manifest.ts +83 -0
  104. package/src/vector-cortex/planner/portfolio.ts +0 -0
  105. package/src/vector-cortex/planner/types.ts +190 -0
  106. package/src/vector-cortex/prompt-dag/_acceptance-dag.ts +392 -0
  107. package/src/vector-cortex/prompt-dag/_acceptance-fixture.ts +132 -0
  108. package/src/vector-cortex/prompt-dag/_acceptance-helpers.ts +39 -0
  109. package/src/vector-cortex/prompt-dag/_acceptance-planner.ts +188 -0
  110. package/src/vector-cortex/prompt-dag/_acceptance-shuffle.ts +26 -0
  111. package/src/vector-cortex/prompt-dag/builder.ts +189 -0
  112. package/src/vector-cortex/prompt-dag/types.ts +151 -0
  113. package/src/vector-cortex/prompt-dag/validator.ts +0 -0
  114. package/src/vector-cortex/reconstruct/_acceptance-helpers.ts +455 -0
  115. package/src/vector-cortex/reconstruct/assemble.ts +170 -0
  116. package/src/vector-cortex/reconstruct/closure.ts +299 -0
  117. package/src/vector-cortex/reconstruct/types.ts +330 -0
  118. package/src/vector-cortex/reconstruct/validate.ts +184 -0
  119. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js +0 -2
  120. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js.map +0 -1
@@ -0,0 +1,392 @@
1
+ /**
2
+ * prompt-dag/_acceptance-dag.ts — declarative DAG materialization + scenario
3
+ * driver for VC5A acceptance rows.
4
+ *
5
+ * Turns named graph scenarios into real `PromptDagV1` values and drives them
6
+ * through the REAL build/validate logic. Deterministic helpers (eq/shuffle)
7
+ * live in `_acceptance-shuffle.ts`.
8
+ */
9
+ import assert from "node:assert/strict";
10
+ import { buildPromptDag, compareNodes, compareEdges } from "./builder.js";
11
+ import { validatePromptDag, dagDigest } from "./validator.js";
12
+ import type { DagEdge, DagNode, DagSpan, PromptDagV1 } from "./types.js";
13
+ import type { DagFixture } from "./_acceptance-fixture.js";
14
+ import { eq, shuffle } from "./_acceptance-shuffle.js";
15
+
16
+ function span(
17
+ sessionId: string,
18
+ startSeq: bigint,
19
+ endSeq: bigint,
20
+ startByte: number,
21
+ endByte: number,
22
+ digest: string,
23
+ ): DagSpan {
24
+ return { sessionId, startSeq, endSeq, startByte, endByte, digest: `sha256:${digest}` as `sha256:${string}` };
25
+ }
26
+ function node(
27
+ id: string,
28
+ kind: DagNode["kind"],
29
+ opts: Partial<DagNode> = {},
30
+ ): DagNode {
31
+ return {
32
+ id,
33
+ kind,
34
+ payloadDigest: opts.payloadDigest ?? `pd:${id}`,
35
+ incompatibleWith: opts.incompatibleWith ?? [],
36
+ ...(opts.span !== undefined ? { span: opts.span } : {}),
37
+ ...(opts.syntheticOrdinal !== undefined ? { syntheticOrdinal: opts.syntheticOrdinal } : {}),
38
+ };
39
+ }
40
+ function edge(from: string, to: string, kind: DagEdge["kind"]): DagEdge {
41
+ return { from, to, kind };
42
+ }
43
+
44
+ const D0 = "a".repeat(64);
45
+ const D1 = "b".repeat(64);
46
+
47
+ export interface MaterializedDag {
48
+ dag: PromptDagV1;
49
+ buildOk: boolean;
50
+ buildCodes: readonly string[];
51
+ }
52
+
53
+ /** Materialize a named graph into a built PromptDagV1 + a validator order. */
54
+ export function materializeDag(name: string): MaterializedDag {
55
+ const cases: Record<string, { sessionId: string; nodes: DagNode[]; edges: DagEdge[] }> = {
56
+ linear: {
57
+ sessionId: "s",
58
+ nodes: [
59
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
60
+ node("b", "exact", { span: span("s", 2n, 2n, 3, 6, D0) }),
61
+ node("c", "semantic", { span: span("s", 3n, 3n, 6, 9, D0) }),
62
+ ],
63
+ edges: [edge("a", "b", "depends"), edge("b", "c", "depends")],
64
+ },
65
+ "mixed-session": {
66
+ sessionId: "s",
67
+ nodes: [
68
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
69
+ // A span claiming a foreign session — single-session violation.
70
+ node("b", "exact", { span: span("OTHER", 2n, 2n, 0, 3, D0) }),
71
+ ],
72
+ edges: [],
73
+ },
74
+ "duplicate-id": {
75
+ sessionId: "s",
76
+ nodes: [
77
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
78
+ node("a", "exact", { span: span("s", 2n, 2n, 0, 3, D1) }),
79
+ ],
80
+ edges: [],
81
+ },
82
+ "missing-endpoint": {
83
+ sessionId: "s",
84
+ nodes: [node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) })],
85
+ edges: [edge("a", "ghost", "depends")],
86
+ },
87
+ "invalid-span": {
88
+ sessionId: "s",
89
+ nodes: [node("a", "event", { span: span("s", 3n, 1n, 9, 0, D0) })],
90
+ edges: [],
91
+ },
92
+ "synthetic-span": {
93
+ sessionId: "s",
94
+ nodes: [
95
+ node("a", "synthetic", { syntheticOrdinal: 0, span: span("s", 1n, 1n, 0, 3, D0) }),
96
+ ],
97
+ edges: [],
98
+ },
99
+ "digest-conflict": {
100
+ sessionId: "s",
101
+ nodes: [
102
+ node("a", "exact", { span: span("s", 1n, 1n, 0, 6, D0) }),
103
+ node("b", "exact", { span: span("s", 2n, 2n, 3, 9, D1) }),
104
+ ],
105
+ edges: [],
106
+ },
107
+ "digest-agree": {
108
+ sessionId: "s",
109
+ nodes: [
110
+ node("a", "exact", { span: span("s", 1n, 1n, 0, 6, D0) }),
111
+ node("b", "exact", { span: span("s", 2n, 2n, 3, 9, D0) }),
112
+ ],
113
+ edges: [],
114
+ },
115
+ "unknown-incompatible": {
116
+ sessionId: "s",
117
+ nodes: [
118
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0), incompatibleWith: ["ghost"] }),
119
+ node("b", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
120
+ ],
121
+ edges: [],
122
+ },
123
+ "tool-pair-split": {
124
+ sessionId: "s",
125
+ nodes: [node("toolcall", "event", { span: span("s", 1n, 1n, 0, 3, D0) })],
126
+ edges: [edge("toolcall", "toolresult", "tool-pair")],
127
+ },
128
+ cycle: {
129
+ sessionId: "s",
130
+ nodes: [
131
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
132
+ node("b", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
133
+ node("c", "event", { span: span("s", 3n, 3n, 0, 3, D0) }),
134
+ ],
135
+ edges: [edge("b", "a", "depends"), edge("c", "b", "depends"), edge("a", "c", "depends")],
136
+ },
137
+ selfloop: {
138
+ sessionId: "s",
139
+ nodes: [node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) })],
140
+ edges: [edge("a", "a", "depends")],
141
+ },
142
+ "id-tie": {
143
+ sessionId: "s",
144
+ nodes: [
145
+ node("aa", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
146
+ node("bb", "event", { span: span("s", 1n, 1n, 3, 6, D1) }),
147
+ node("cc", "event", { span: span("s", 1n, 1n, 6, 9, D0) }),
148
+ ],
149
+ edges: [],
150
+ },
151
+ "seq-before-id": {
152
+ sessionId: "s",
153
+ // Earlier seq sorts first even though IDs sort the other way.
154
+ nodes: [
155
+ node("z", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
156
+ node("y", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
157
+ node("x", "event", { span: span("s", 3n, 3n, 0, 3, D0) }),
158
+ ],
159
+ edges: [],
160
+ },
161
+ "synthetic-last": {
162
+ sessionId: "s",
163
+ nodes: [
164
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
165
+ node("b", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
166
+ node("syn", "synthetic", { syntheticOrdinal: 0 }),
167
+ ],
168
+ edges: [],
169
+ },
170
+ "synthetic-ordinal": {
171
+ sessionId: "s",
172
+ nodes: [
173
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
174
+ node("s1", "synthetic", { syntheticOrdinal: 1 }),
175
+ node("s2", "synthetic", { syntheticOrdinal: 2 }),
176
+ ],
177
+ edges: [],
178
+ },
179
+ diamond: {
180
+ sessionId: "s",
181
+ nodes: [
182
+ node("top", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
183
+ node("l", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
184
+ node("r", "event", { span: span("s", 3n, 3n, 0, 3, D0) }),
185
+ node("bottom", "event", { span: span("s", 4n, 4n, 0, 3, D1) }),
186
+ ],
187
+ edges: [
188
+ edge("top", "l", "depends"),
189
+ edge("top", "r", "depends"),
190
+ edge("l", "bottom", "depends"),
191
+ edge("r", "bottom", "depends"),
192
+ ],
193
+ },
194
+ contradicts: {
195
+ sessionId: "s",
196
+ nodes: [
197
+ node("a", "exact", { span: span("s", 1n, 1n, 0, 3, D0) }),
198
+ node("b", "exact", { span: span("s", 2n, 2n, 0, 3, D1) }),
199
+ ],
200
+ edges: [edge("a", "b", "contradicts")],
201
+ },
202
+ "contradicts-cycle": {
203
+ sessionId: "s",
204
+ nodes: [
205
+ node("a", "exact", { span: span("s", 1n, 1n, 0, 3, D0) }),
206
+ node("b", "exact", { span: span("s", 2n, 2n, 0, 3, D1) }),
207
+ ],
208
+ // A contradicts edge plus a depends edge: a real cycle would need the
209
+ // depends to form a loop, but here only `a->b` depends, so no cycle.
210
+ edges: [edge("a", "b", "contradicts"), edge("a", "b", "depends")],
211
+ },
212
+ "reversed-precedes": {
213
+ sessionId: "s",
214
+ nodes: [
215
+ node("a", "event", { span: span("s", 2n, 2n, 0, 3, D0) }),
216
+ node("b", "event", { span: span("s", 1n, 1n, 0, 3, D1) }),
217
+ ],
218
+ // b's source position is EARLIER than a's, so a->b precedes is backward.
219
+ edges: [edge("a", "b", "precedes")],
220
+ },
221
+ scrambled: {
222
+ sessionId: "s",
223
+ nodes: [
224
+ node("c", "event", { span: span("s", 3n, 3n, 6, 9, D0) }),
225
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
226
+ node("b", "event", { span: span("s", 2n, 2n, 3, 6, D1) }),
227
+ ],
228
+ edges: [edge("a", "b", "depends"), edge("b", "c", "depends")],
229
+ },
230
+ empty: { sessionId: "s", nodes: [], edges: [] },
231
+ single: {
232
+ sessionId: "s",
233
+ nodes: [node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) })],
234
+ edges: [],
235
+ },
236
+ disconnected: {
237
+ sessionId: "s",
238
+ nodes: [
239
+ node("a", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
240
+ node("b", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
241
+ node("x", "event", { span: span("s", 1n, 1n, 3, 6, D0) }),
242
+ node("y", "event", { span: span("s", 2n, 2n, 3, 6, D1) }),
243
+ ],
244
+ edges: [],
245
+ },
246
+ toolpair: {
247
+ sessionId: "s",
248
+ nodes: [
249
+ node("toolcall", "event", { span: span("s", 1n, 1n, 0, 3, D0) }),
250
+ node("toolresult", "event", { span: span("s", 2n, 2n, 0, 3, D1) }),
251
+ ],
252
+ edges: [edge("toolcall", "toolresult", "tool-pair")],
253
+ },
254
+ chain8: {
255
+ sessionId: "s",
256
+ nodes: [0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) =>
257
+ node(`n${i}`, "event", { span: span("s", BigInt(i + 1), BigInt(i + 1), 0, 3, D0) }),
258
+ ),
259
+ edges: [0, 1, 2, 3, 4, 5, 6, 7].map((i) => edge(`n${i + 1}`, `n${i}`, "depends")),
260
+ },
261
+ };
262
+ const g = cases[name];
263
+ assert.ok(g, `dag materializer missing for "${name}"`);
264
+ // Give every node a DISTINCT, non-overlapping byte window so the builder's
265
+ // digest-conflict rule (which only fires on genuinely shared bytes) does not
266
+ // misfire on adjacent ordering-test nodes. The two digest-* graphs intentionally
267
+ // KEEP overlapping spans to exercise that rule, so they are excluded here.
268
+ const overlapIntentional = name === "digest-conflict" || name === "digest-agree";
269
+ const nodes = overlapIntentional
270
+ ? g.nodes
271
+ : g.nodes.map((n, i) =>
272
+ n.span === undefined
273
+ ? n
274
+ : { ...n, span: { ...n.span, startByte: i * 4, endByte: i * 4 + 4 } },
275
+ );
276
+ const built = buildPromptDag({
277
+ sessionId: g.sessionId,
278
+ sourceHighWater: 100n,
279
+ nodes,
280
+ edges: g.edges,
281
+ });
282
+ return {
283
+ buildOk: built.ok,
284
+ buildCodes: built.ok ? [] : built.codes,
285
+ dag: built.ok
286
+ ? built.dag
287
+ : {
288
+ schema: "prompt-dag-v1",
289
+ sessionId: g.sessionId,
290
+ sourceHighWater: 100n,
291
+ nodes: [...g.nodes].sort(compareNodes),
292
+ edges: [...g.edges].sort(compareEdges),
293
+ },
294
+ };
295
+ }
296
+
297
+ /** Validate a materialized DAG, returning order / failure codes / digest. */
298
+ export function runDagScenario(fx: DagFixture): {
299
+ ok: boolean;
300
+ code?: string;
301
+ order?: string[];
302
+ orderLength?: number;
303
+ permutationInvariant?: boolean;
304
+ digestStable?: boolean;
305
+ digestSensitive?: boolean;
306
+ orderIsTotal?: boolean;
307
+ } {
308
+ const { scenario, graph, mutateDigest } = fx.input;
309
+ const base = materializeDag(graph ?? "linear");
310
+
311
+ // Structural REJECTION scenarios stop at the builder (no validation). Build
312
+ // ACCEPTANCE scenarios (build-linear / build-digest-agree) succeed and must
313
+ // still be validated for their topological order.
314
+ const structuralReject = [
315
+ "build-mixed-session",
316
+ "build-duplicate-id",
317
+ "build-missing-endpoint",
318
+ "build-invalid-span",
319
+ "build-synthetic-with-span",
320
+ "build-digest-conflict",
321
+ "build-unknown-incompatible",
322
+ "build-tool-pair-split",
323
+ ];
324
+ if (structuralReject.includes(scenario)) {
325
+ // Prefer the more specific tool-pair rejection when both it and a generic
326
+ // missing-endpoint code are present (a split tool pair is also missing an
327
+ // endpoint, but the tool-pair split is the precise failure).
328
+ const codes = base.buildCodes;
329
+ const code = codes.includes("DAG_TOOL_PAIR_SPLIT")
330
+ ? "DAG_TOOL_PAIR_SPLIT"
331
+ : codes[0];
332
+ return { ok: base.buildOk, code };
333
+ }
334
+
335
+ // A built DAG is required for validation scenarios.
336
+ assert.ok(base.buildOk, `${fx.id}: builder must succeed before validation`);
337
+ const dag = base.dag;
338
+ const v = validatePromptDag(dag);
339
+ const digest = dagDigest(dag);
340
+
341
+ if (fx.expected.permutationInvariant) {
342
+ // Re-run with a shuffled node/edge array; order + digest must be identical.
343
+ const permNodes = shuffle([...dag.nodes]);
344
+ const permEdges = shuffle([...dag.edges]);
345
+ const perm = buildPromptDag({
346
+ sessionId: dag.sessionId,
347
+ sourceHighWater: dag.sourceHighWater,
348
+ nodes: permNodes,
349
+ edges: permEdges,
350
+ });
351
+ assert.ok(perm.ok, `${fx.id}: permuted build must succeed`);
352
+ const vPerm = validatePromptDag(perm.dag);
353
+ const orderSame = v.ok && vPerm.ok && eq(v.order, vPerm.order);
354
+ const digestSame = dagDigest(perm.dag) === digest;
355
+ return { ok: true, permutationInvariant: orderSame, digestStable: digestSame };
356
+ }
357
+
358
+ if (fx.expected.digestStable) {
359
+ const perm = buildPromptDag({
360
+ sessionId: dag.sessionId,
361
+ sourceHighWater: dag.sourceHighWater,
362
+ nodes: shuffle([...dag.nodes]),
363
+ edges: shuffle([...dag.edges]),
364
+ });
365
+ assert.ok(perm.ok);
366
+ return { ok: true, digestStable: dagDigest(perm.dag) === digest };
367
+ }
368
+
369
+ if (fx.expected.digestSensitive) {
370
+ const mutated = {
371
+ ...dag,
372
+ nodes: dag.nodes.map((n, i) =>
373
+ i === 0 ? { ...n, payloadDigest: `pd:mutated-${n.id}` } : n,
374
+ ),
375
+ };
376
+ return { ok: true, digestSensitive: dagDigest(mutated) !== digest };
377
+ }
378
+
379
+ if (fx.expected.orderIsTotal) {
380
+ const ok = v.ok && v.order.length === dag.nodes.length && new Set(v.order).size === dag.nodes.length;
381
+ return { ok, orderIsTotal: ok };
382
+ }
383
+
384
+ if (fx.expected.orderLength !== undefined) {
385
+ return { ok: v.ok, orderLength: v.ok ? v.order.length : 0 };
386
+ }
387
+
388
+ // Plain order / failure-code scenarios.
389
+ if (!v.ok) return { ok: false, code: v.codes[0] };
390
+ void mutateDigest;
391
+ return { ok: true, order: [...v.order] };
392
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * prompt-dag/_acceptance-fixture.ts — conformance fixture I/O for VC5A DAG +
3
+ * planner acceptance rows.
4
+ *
5
+ * Reads the v2 conformance manifest + the per-sprint fixture files, and exposes
6
+ * the `DagFixture` / `PlnFixture` shapes the acceptance aggregator drives. No
7
+ * mocks/stubs: the fixtures are the committed canonical corpus.
8
+ */
9
+ import { readFileSync, existsSync } from "node:fs";
10
+ import { join, dirname } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ import assert from "node:assert/strict";
13
+
14
+ const HERE = dirname(fileURLToPath(import.meta.url));
15
+
16
+ function repoRoot(from: string): string {
17
+ let dir = from;
18
+ for (let i = 0; i < 8; i++) {
19
+ if (existsSync(join(dir, "conformance", "vector-cortex"))) return dir;
20
+ const next = dirname(dir);
21
+ if (next === dir) break;
22
+ dir = next;
23
+ }
24
+ throw new Error("conformance corpus not found above " + from);
25
+ }
26
+ export const REPO_ROOT = repoRoot(HERE);
27
+ export const V2 = join(REPO_ROOT, "conformance", "vector-cortex", "v2");
28
+
29
+ export interface ManifestRow {
30
+ id: string;
31
+ path: string;
32
+ algorithm: string;
33
+ expected: string;
34
+ }
35
+ export interface Manifest {
36
+ fixtures: ManifestRow[];
37
+ }
38
+
39
+ export function readManifest(): Manifest {
40
+ return JSON.parse(readFileSync(join(V2, "manifest.json"), "utf8")) as Manifest;
41
+ }
42
+
43
+ /** Resolve a fixture row by ID, restricting to one of this sprint's two roots. */
44
+ function readFixture(id: string, prefix: "prompt-dag" | "planner"): unknown {
45
+ const m = readManifest();
46
+ const row = m.fixtures.find((f) => f.id === id && f.path.startsWith(`${prefix}/`));
47
+ assert.ok(row, `fixture ${id} registered under ${prefix}/ in manifest`);
48
+ return JSON.parse(readFileSync(join(V2, row.path), "utf8"));
49
+ }
50
+
51
+ // ── DAG fixture shape ──
52
+ export interface DagFxInput {
53
+ scenario: string;
54
+ graph?: string;
55
+ permute?: boolean;
56
+ mutateDigest?: boolean;
57
+ }
58
+ export interface DagFxExpected {
59
+ ok: boolean;
60
+ code?: string;
61
+ order?: string[];
62
+ orderLength?: number;
63
+ permutationInvariant?: boolean;
64
+ digestStable?: boolean;
65
+ digestSensitive?: boolean;
66
+ orderIsTotal?: boolean;
67
+ }
68
+ export interface DagFixture {
69
+ id: string;
70
+ schema: string;
71
+ producer: string;
72
+ assertion: string;
73
+ kind: string;
74
+ input: DagFxInput;
75
+ expected: DagFxExpected;
76
+ }
77
+ export function dagFixture(id: string): DagFixture {
78
+ return readFixture(id, "prompt-dag") as DagFixture;
79
+ }
80
+
81
+ // ── Planner fixture shape ──
82
+ export interface PlnFxInput {
83
+ scenario: string;
84
+ candidates: string;
85
+ tokenBudget: number;
86
+ zeroFraming?: boolean;
87
+ permute?: boolean;
88
+ mutateTokensAfterPlan?: boolean;
89
+ }
90
+ export interface PlnFxExpected {
91
+ ok: boolean;
92
+ code?: string;
93
+ selected?: string[];
94
+ tokenTotal?: number;
95
+ firstSelected?: string;
96
+ mandatoryPreserved?: boolean;
97
+ demotesToC?: boolean;
98
+ omittedOverBudget?: boolean;
99
+ omittedZeroUtility?: boolean;
100
+ omittedIncompatible?: boolean;
101
+ noPartialSelection?: boolean;
102
+ withinBudget?: boolean;
103
+ planIsClosed?: boolean;
104
+ permutationInvariant?: boolean;
105
+ manifestStable?: boolean;
106
+ }
107
+ export interface PlnFixture {
108
+ id: string;
109
+ schema: string;
110
+ producer: string;
111
+ assertion: string;
112
+ kind: string;
113
+ input: PlnFxInput;
114
+ expected: PlnFxExpected;
115
+ }
116
+ export function plnFixture(id: string): PlnFixture {
117
+ return readFixture(id, "planner") as PlnFixture;
118
+ }
119
+
120
+ /** Flag-pinned wrapper: VC5A gated by MEGACOMPACT_VC5A (defaults ON). */
121
+ export function withFlagsOn(fn: () => void): () => void {
122
+ return (): void => {
123
+ const saved = process.env.MEGACOMPACT_VC5A;
124
+ process.env.MEGACOMPACT_VC5A = "1";
125
+ try {
126
+ fn();
127
+ } finally {
128
+ if (saved === undefined) delete process.env.MEGACOMPACT_VC5A;
129
+ else process.env.MEGACOMPACT_VC5A = saved;
130
+ }
131
+ };
132
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * prompt-dag/_acceptance-helpers.ts — barrel re-export for the VC5A DAG +
3
+ * planner acceptance rows.
4
+ *
5
+ * The implementation is split across focused sibling files to keep each under
6
+ * the src/ 500-line hard limit; this file is the single import surface the
7
+ * acceptance aggregator uses:
8
+ * - `_acceptance-fixture.ts` — manifest I/O + DagFixture/PlnFixture shapes + withFlagsOn
9
+ * - `_acceptance-dag.ts` — declarative DAG materialization + runDagScenario
10
+ * - `_acceptance-planner.ts` — candidate-set materialization + runPlannerScenario
11
+ * - `_acceptance-shuffle.ts` — deterministic eq/shuffle helpers
12
+ *
13
+ * Every function drives the REAL prompt-dag / planner logic — no mocks, no stubs.
14
+ */
15
+
16
+ export {
17
+ REPO_ROOT,
18
+ V2,
19
+ readManifest,
20
+ dagFixture,
21
+ plnFixture,
22
+ withFlagsOn,
23
+ } from "./_acceptance-fixture.js";
24
+ export type {
25
+ ManifestRow,
26
+ Manifest,
27
+ DagFxInput,
28
+ DagFxExpected,
29
+ DagFixture,
30
+ PlnFxInput,
31
+ PlnFxExpected,
32
+ PlnFixture,
33
+ } from "./_acceptance-fixture.js";
34
+
35
+ export { materializeDag, runDagScenario } from "./_acceptance-dag.js";
36
+ export type { MaterializedDag } from "./_acceptance-dag.js";
37
+
38
+ export { materializeCandidates, runPlannerScenario } from "./_acceptance-planner.js";
39
+ export type { PlnResult } from "./_acceptance-planner.js";