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
@@ -230,6 +230,72 @@ export interface VectorCortexResidualView {
230
230
  readonly updatedAt: string;
231
231
  }
232
232
 
233
+ /**
234
+ * Reader-only reconstruction-fidelity aggregate for GET /api/vector-cortex/reconstruct
235
+ * (VC4C). Purely an enabled-flag + COUNT/BYTE aggregate — closure attempts,
236
+ * rejections, validated/invalidated counts, span total, and byte total.
237
+ * Reader-only: NEVER exposes reconstructed spans, exact bytes, or prompt text.
238
+ * The reconstruction validator is pure in-memory logic in this sprint (no
239
+ * durable metrics store), so when no closure has been staged the aggregates are
240
+ * truthfully zero. Non-fatal: a missing state dir degrades to `enabled:false`.
241
+ */
242
+ export interface VectorCortexReconstructView {
243
+ /** Whether the VC4C reconstruction fidelity flag is enabled in this process. */
244
+ readonly enabled: boolean;
245
+ /** Number of closure attempts observed by the process emitter. */
246
+ readonly closureAttempts: number;
247
+ /** Number of closures rejected (events vector_cortex_closure_rejected). */
248
+ readonly closureRejections: number;
249
+ /** Number of reconstructions validated (events vector_cortex_reconstruction_validated). */
250
+ readonly validatedCount: number;
251
+ /** Number of reconstructions invalidated (failed validation). */
252
+ readonly invalidatedCount: number;
253
+ /** Total reconstructed spans across validated reconstructions. */
254
+ readonly spanTotal: number;
255
+ /** Total reconstructed bytes across validated reconstructions. */
256
+ readonly byteTotal: number;
257
+ /** ISO timestamp of the snapshot. */
258
+ readonly updatedAt: string;
259
+ }
260
+
261
+ /**
262
+ * Reader-only plan manifest view for GET /api/vector-cortex/plans (VC5A).
263
+ *
264
+ * Exposes ONLY plan manifests — the VC5A PromptDagV1 + budgeted-planner output:
265
+ * registered DAG/plan identifiers, the mandatory-closure status, selected-node
266
+ * manifests, and the mandatory-overflow signal. NEVER exposes session payloads,
267
+ * prompt text, byte spans, or source bytes (reader-only, SECURITY_PRIVACY).
268
+ *
269
+ * Flag-gated on MEGACOMPACT_VC5A: `enabled:false` when off (byte-identical to the
270
+ * pre-VC5A predecessor). Non-fatal: a missing manifest store degrades to
271
+ * `enabled:false` with empty arrays.
272
+ */
273
+ export interface VectorCortexPlanManifest {
274
+ /** Stable plan id (e.g. "PLN-009"). */
275
+ readonly id: string;
276
+ /** Whether the mandatory dependency/tool/anchor closure fit within budget. */
277
+ readonly mandatoryInBudget: boolean;
278
+ /** Selected optional node ids under the budgeted portfolio (sorted by id bytes). */
279
+ readonly selectedNodeIds: readonly string[];
280
+ /** Total planned token estimate (mandatory framed + selected framed). */
281
+ readonly tokenTotal: number;
282
+ /** true when the mandatory closure exceeded budget (demoted to mode C). */
283
+ readonly demotedToC: boolean;
284
+ }
285
+
286
+ export interface VectorCortexPlansView {
287
+ /** Whether the VC5A PromptDagV1 + budgeted-planner flag is enabled. */
288
+ readonly enabled: boolean;
289
+ /** Count of registered PromptDagV1 fixtures (DAG-001..). */
290
+ readonly dagCount: number;
291
+ /** Count of registered plan fixtures (PLN-001..). */
292
+ readonly plannerCount: number;
293
+ /** Plan manifests (reader-only, no payloads). */
294
+ readonly plans: readonly VectorCortexPlanManifest[];
295
+ /** ISO timestamp of the snapshot. */
296
+ readonly updatedAt: string;
297
+ }
298
+
233
299
  /**
234
300
  * Reader-only occurrence-ledger view for GET /api/vector-cortex/ledger (VC1B).
235
301
  * Built on the LedgerReader capability surface. Exposes occurrence IDENTITY
@@ -361,6 +361,18 @@ export const SETTINGS: ReadonlyArray<{
361
361
  "Residual codec: orthonormal DCT-II basis + int16 block quantization + block-scoped exact correction stream + (9,6) Reed-Solomon parity shards with SHA-256 corruption detection; admission gates on encodedSize <= 95% of exact-compressed size. OFF = mode C, no residual artifact produced, byte-identical predecessor.",
362
362
  true,
363
363
  ),
364
+ boolDirect(
365
+ "MEGACOMPACT_VC4C",
366
+ "VC4C Reconstruction Fidelity",
367
+ "Conservative closure + source-order assembly + reconstruction validator: recursively closes dependencies and whole tool pairs to a fixed point, resolves contradictions by retaining the later exact source resolution, assembles spans solely by source range, and rejects missing anchors / split pairs / digest mismatch / unresolved contradiction. Mandatory token estimate is content-only and handed unchanged to VC5A. OFF = mode C, no closure/validator, byte-identical predecessor (VC4B).",
368
+ true,
369
+ ),
370
+ boolDirect(
371
+ "MEGACOMPACT_VC5A",
372
+ "VC5A PromptDagV1 + Budgeted Planner",
373
+ "Single-session DAG (PromptDagV1) + budgeted 0/1 portfolio planner: builds a stable Kahn-ordered DAG, computes the mandatory dependency/tool/anchor closure before optional selection, returns MANDATORY_CLOSURE_OVER_BUDGET with evidence preserved on overflow, and runs a utility-per-token portfolio that never exceeds the remaining budget. Framing is owned here, not in VC4C. OFF = byte-identical predecessor (VC4C).",
374
+ true,
375
+ ),
364
376
  ],
365
377
  },
366
378
  {
@@ -0,0 +1,58 @@
1
+ /**
2
+ * dashboard-server/routes-vector-cortex-plans.ts — VC5A PromptDagV1 + budgeted
3
+ * planner dashboard route.
4
+ *
5
+ * Reader-only GET /api/vector-cortex/plans returning ONLY plan manifests — the
6
+ * registered PromptDagV1 (DAG-001..030) and budgeted-planner (PLN-001..020)
7
+ * identifier counts, plus a reader-only plans array. NEVER exposes session
8
+ * payloads, prompt text, byte spans, or source bytes (reader-only,
9
+ * SECURITY_PRIVACY). Flag-gated on MEGACOMPACT_VC5A: `enabled:false` when off
10
+ * (byte-identical to the pre-VC5A predecessor).
11
+ *
12
+ * The VC5A planner is PURE IN-MEMORY logic in this sprint (it has no durable plan
13
+ * store yet), so the per-run plan outputs are not persisted. The route reports
14
+ * the registered manifest layout truthfully: `enabled` reflects the flag, the
15
+ * dag/planner counts come from the registered conformance ID range, and `plans`
16
+ * is empty until a future sprint persists selected plans. Non-fatal: an internal
17
+ * error degrades to `enabled:false` with empty arrays.
18
+ *
19
+ * Guardrails: PREVENT-PI-004 (local filesystem / in-process state only),
20
+ * PREVENT-011 (no `any`), reader-only aggregate (counts + manifests only).
21
+ */
22
+
23
+ import type { IncomingMessage, ServerResponse } from "node:http";
24
+ import type { RouteContext } from "./routes-core.js";
25
+ import { VC5A_ENABLED } from "../../src/config.js";
26
+ import { DAG_IDS } from "../../src/vector-cortex/prompt-dag/types.js";
27
+ import { PLN_IDS } from "../../src/vector-cortex/planner/types.js";
28
+ import { sendJson } from "./routes-vector-cortex-shared.js";
29
+ import type { VectorCortexPlansView } from "./api-contracts/vector-cortex.js";
30
+
31
+ /**
32
+ * Reader-only GET /api/vector-cortex/plans (VC5A).
33
+ */
34
+ export function handleVectorCortexPlans(
35
+ req: IncomingMessage,
36
+ res: ServerResponse,
37
+ _ctx: RouteContext,
38
+ ): boolean {
39
+ const url = req.url ?? "";
40
+ const path = url.split("?")[0] ?? url;
41
+ if (path !== "/api/vector-cortex/plans") return false;
42
+ if (req.method !== "GET") {
43
+ // Reader-only path: cannot be "off" without a GET; it is genuinely read-only.
44
+ sendJson(res, 405, { error: "method_not_allowed" });
45
+ return true;
46
+ }
47
+
48
+ const enabled = VC5A_ENABLED();
49
+ const body: VectorCortexPlansView = {
50
+ enabled,
51
+ dagCount: enabled ? DAG_IDS.length : 0,
52
+ plannerCount: enabled ? PLN_IDS.length : 0,
53
+ plans: [],
54
+ updatedAt: new Date().toISOString(),
55
+ };
56
+ sendJson(res, 200, body);
57
+ return true;
58
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Dashboard handler: GET /api/vector-cortex/reconstruct (VC4C).
3
+ *
4
+ * Reader-only reconstruction-fidelity aggregate. Mirrors the VC4B residual
5
+ * handler: path guard + 405 on non-GET, gated on the sprint flag, returns a
6
+ * zero-valued view when disabled (byte-identical predecessor contract). Never
7
+ * returns reconstructed spans, exact bytes, or prompt text.
8
+ */
9
+
10
+ import type { IncomingMessage, ServerResponse } from "node:http";
11
+ import type { RouteContext } from "./routes-core.js";
12
+ import { VC4C_ENABLED } from "../../src/config.js";
13
+ import { sendJson } from "./routes-vector-cortex-shared.js";
14
+ import type { VectorCortexReconstructView } from "./api-contracts/vector-cortex.js";
15
+
16
+ export function handleVectorCortexReconstruct(
17
+ req: IncomingMessage,
18
+ res: ServerResponse,
19
+ _ctx: RouteContext,
20
+ ): boolean {
21
+ const url = req.url ?? "";
22
+ const path = url.split("?")[0] ?? url;
23
+ if (path !== "/api/vector-cortex/reconstruct") return false;
24
+ if (req.method !== "GET") {
25
+ sendJson(res, 405, { error: "method_not_allowed" });
26
+ return true;
27
+ }
28
+ const enabled = VC4C_ENABLED();
29
+ const body: VectorCortexReconstructView = {
30
+ enabled,
31
+ closureAttempts: 0,
32
+ closureRejections: 0,
33
+ validatedCount: 0,
34
+ invalidatedCount: 0,
35
+ spanTotal: 0,
36
+ byteTotal: 0,
37
+ updatedAt: new Date().toISOString(),
38
+ };
39
+ sendJson(res, 200, body);
40
+ return true;
41
+ }
@@ -21,3 +21,5 @@ export { handleVectorCortexTopology } from "./routes-vector-cortex-topology.js";
21
21
  export { handleVectorCortexQuery } from "./routes-vector-cortex-query.js";
22
22
  export { handleVectorCortexShards } from "./routes-vector-cortex-shards.js";
23
23
  export { handleVectorCortexResidual } from "./routes-vector-cortex-residual.js";
24
+ export { handleVectorCortexReconstruct } from "./routes-vector-cortex-reconstruct.js";
25
+ export { handleVectorCortexPlans } from "./routes-vector-cortex-plans.js";
@@ -49,4 +49,6 @@ export {
49
49
  handleVectorCortexQuery,
50
50
  handleVectorCortexShards,
51
51
  handleVectorCortexResidual,
52
+ handleVectorCortexReconstruct,
53
+ handleVectorCortexPlans,
52
54
  } from "./routes-vector-cortex.js";
@@ -65,6 +65,8 @@ import {
65
65
  handleVectorCortexQuery,
66
66
  handleVectorCortexShards,
67
67
  handleVectorCortexResidual,
68
+ handleVectorCortexReconstruct,
69
+ handleVectorCortexPlans,
68
70
  handleStatic,
69
71
  } from "./routes.js";
70
72
 
@@ -308,6 +310,8 @@ export async function launchDashboardServer(
308
310
  if (handleVectorCortexQuery(req, res, ctx)) return;
309
311
  if (handleVectorCortexShards(req, res, ctx)) return;
310
312
  if (handleVectorCortexResidual(req, res, ctx)) return;
313
+ if (handleVectorCortexReconstruct(req, res, ctx)) return;
314
+ if (handleVectorCortexPlans(req, res, ctx)) return;
311
315
  handleStatic(req, res, ctx);
312
316
  });
313
317
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.20.1",
3
+ "version": "0.20.3",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -160,6 +160,34 @@ export const VC4A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC4A");
160
160
  */
161
161
  export const VC4B_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC4B");
162
162
 
163
+ /**
164
+ * VC4C — reconstruction fidelity (closure + assemble + validate). Default ON.
165
+ * `MEGACOMPACT_VC4C=0` disables and is byte-identical to the predecessor
166
+ * (VC4B): no conservative closure is computed, the reconstruction validator's
167
+ * `vector_cortex_reconstruction_validated` / `vector_cortex_closure_rejected`
168
+ * events are never emitted, and the assembled reconstruction is never produced
169
+ * (the prompt continues to be built by the legacy VC4B exact/residual path and
170
+ * the VC4A shard goldens are unchanged). The closure/assemble/validate
171
+ * functions are PURE — flag OFF gates the reporter seam, never the arithmetic.
172
+ * This flag MUST also be a dashboard SETTINGS toggle (visible in config UI,
173
+ * never in EXCLUDED_SETTINGS), mirroring VC4A/VC4B.
174
+ */
175
+ export const VC4C_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC4C");
176
+
177
+ /**
178
+ * VC5A — PromptDagV1 + budgeted portfolio planner. Default ON.
179
+ * `MEGACOMPACT_VC5A=0` disables and is byte-identical to the predecessor
180
+ * (VC4C): no prompt DAG is built or validated, no budgeted plan is selected,
181
+ * the `vector_cortex_plan_selected` / `vector_cortex_plan_mandatory_overflow`
182
+ * events are never emitted, and the prompt continues to be built by the
183
+ * predecessor VC4C closure/reconstruction path (its goldens are unchanged).
184
+ * The builder/validator/portfolio functions are PURE — flag OFF gates the
185
+ * reporter + dashboard seam, never the arithmetic. This flag MUST also be a
186
+ * dashboard SETTINGS toggle (visible in config UI, never in EXCLUDED_SETTINGS),
187
+ * mirroring VC4A/VC4B/VC4C.
188
+ */
189
+ export const VC5A_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_VC5A");
190
+
163
191
  // ---------------------------------------------------------------------------
164
192
  // Breaker state machine constants (TRIAD_RESILIENCE.md §breaker).
165
193
  // Rolled numbers for one 60s window; VC0C consumes these at its breaker seam.
package/src/config.ts CHANGED
@@ -165,6 +165,8 @@ export {
165
165
  VC3C_ENABLED,
166
166
  VC4A_ENABLED,
167
167
  VC4B_ENABLED,
168
+ VC4C_ENABLED,
169
+ VC5A_ENABLED,
168
170
  BREAKER_WINDOW_MS,
169
171
  BREAKER_MIN_ATTEMPTS,
170
172
  BREAKER_PERF_FAILURES,
@@ -0,0 +1,83 @@
1
+ /**
2
+ * vector-cortex/planner/manifest.ts — plan manifest identity + pre-provider
3
+ * revalidation (VC5A).
4
+ *
5
+ * Split from `portfolio.ts` (which owns SELECTION) so each file keeps one
6
+ * concern and stays under the 300-line soft limit: this module owns the plan's
7
+ * IDENTITY and the last gate before a provider call.
8
+ *
9
+ * The manifest digest deliberately covers PER-NODE TOKEN COUNTS, which the DAG
10
+ * digest does not: token counts are a planner input rather than DAG structure.
11
+ * That is exactly what makes the sprint's unique failure injection detectable —
12
+ * mutating a node's token count after planning but before validation changes the
13
+ * recomputed manifest digest, so `validatePlanManifest` returns
14
+ * `PLN_MANIFEST_DIGEST_MISMATCH` and the plan never reaches the provider.
15
+ *
16
+ * Pure/deterministic: no storage, no console, no network (PREVENT-PI-004).
17
+ */
18
+
19
+ import { createHash } from "node:crypto";
20
+
21
+ import type { PlanCandidate, PlanV1 } from "./types.js";
22
+
23
+ /**
24
+ * Deterministic digest over a plan AND the token counts/utilities it was
25
+ * selected with. Hashing walks `selectedNodeIds` in its stored (sorted) order,
26
+ * so the digest is a pure function of the plan and the candidate facts.
27
+ *
28
+ * A node missing from `candidates` hashes as `-1`, so dropping a candidate is
29
+ * itself a detectable mutation rather than a silently-skipped field.
30
+ */
31
+ export function planManifestDigest(
32
+ plan: PlanV1,
33
+ candidates: readonly PlanCandidate[],
34
+ ): string {
35
+ const h = createHash("sha256");
36
+ h.update(plan.schema);
37
+ h.update(" ");
38
+ h.update(plan.dagDigest);
39
+ h.update(" ");
40
+ h.update(String(plan.tokenBudget));
41
+ h.update(" ");
42
+ h.update(String(plan.tokenTotal));
43
+ h.update(" ");
44
+ h.update(String(plan.dependencyHighWater));
45
+ const byId = new Map(candidates.map((c) => [c.nodeId, c]));
46
+ for (const id of plan.selectedNodeIds) {
47
+ const c = byId.get(id);
48
+ h.update("");
49
+ h.update(id);
50
+ h.update(" ");
51
+ // Token count is part of the identity — a post-plan mutation breaks it.
52
+ h.update(String(c?.tokenEstimate ?? -1));
53
+ h.update(" ");
54
+ h.update(String(c?.utility ?? -1));
55
+ }
56
+ return h.digest("hex");
57
+ }
58
+
59
+ /** The verdict of the pre-provider manifest revalidation. */
60
+ export type PlanManifestValidation =
61
+ | { readonly ok: true }
62
+ | { readonly ok: false; readonly code: "PLN_MANIFEST_DIGEST_MISMATCH" };
63
+
64
+ /**
65
+ * Re-validate a plan against the candidates AS THEY STAND NOW, immediately
66
+ * before a provider call. Returns `PLN_MANIFEST_DIGEST_MISMATCH` when the
67
+ * recomputed manifest digest disagrees with the digest pinned at planning time.
68
+ *
69
+ * This is the sprint's unique failure injection: a node token count mutated
70
+ * after planning but before validation is caught here, BEFORE the provider is
71
+ * invoked, rather than producing a prompt whose real cost differs from the
72
+ * admitted budget.
73
+ */
74
+ export function validatePlanManifest(
75
+ plan: PlanV1,
76
+ candidates: readonly PlanCandidate[],
77
+ pinnedDigest: string,
78
+ ): PlanManifestValidation {
79
+ if (planManifestDigest(plan, candidates) !== pinnedDigest) {
80
+ return { ok: false, code: "PLN_MANIFEST_DIGEST_MISMATCH" };
81
+ }
82
+ return { ok: true };
83
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * vector-cortex/planner/types.ts — `PlanV1` + the budget admission contract
3
+ * (VC5A, task 1).
4
+ *
5
+ * VC5A EXCLUSIVELY OWNS FRAMING + BUDGET ADMISSION (CONTRACTS §plan and
6
+ * closure). VC4C hands over `ClosureResult.mandatoryTokenEstimate`, a
7
+ * CONTENT-ONLY count with no prompt framing, no role tags and no separators, and
8
+ * VC4C never truncates a mandatory node nor reasons about a budget. This module
9
+ * adds the framing cost on top of that content estimate and decides admission:
10
+ *
11
+ * framed(node) = tokenEstimate + framingPerNode
12
+ * mandatoryCost = mandatoryTokenEstimate + framingPerNode * |mandatory|
13
+ * + framingOverhead
14
+ *
15
+ * If `mandatoryCost > tokenBudget` the planner returns
16
+ * `MANDATORY_CLOSURE_OVER_BUDGET` and the adapter demotes to C. Crucially it
17
+ * does so WITHOUT DROPPING EVIDENCE: the mandatory set is returned intact on the
18
+ * failure so the caller can report exactly what did not fit (the sprint bar:
19
+ * "over-budget mandatory closure never drops evidence and always demotes").
20
+ *
21
+ * The framing constants are CONFIGURABLE, never invented magic numbers: a caller
22
+ * supplies the profile it is actually rendering with, and the defaults below are
23
+ * documented as a conservative baseline rather than a measured provider fact.
24
+ *
25
+ * Pure types + registered conformance IDs: no storage, no console, no network
26
+ * (PREVENT-PI-004 / PREVENT-011).
27
+ */
28
+
29
+ /**
30
+ * The prompt framing cost model. These are the ONLY places framing enters the
31
+ * budget, keeping the VC4C content-only estimate cleanly separable.
32
+ *
33
+ * `perNode` is the per-node envelope (role tag + separator) a renderer adds
34
+ * around one node's content. `overhead` is the whole-prompt fixed cost (system
35
+ * preamble scaffolding, closing delimiters) charged once.
36
+ *
37
+ * Both DEFAULT to a conservative baseline and are overridable per call, so a
38
+ * provider profile with a measured framing cost (VC5B) supplies its own numbers
39
+ * rather than inheriting a guess.
40
+ */
41
+ export interface FramingProfile {
42
+ /** Tokens added around each selected node (role tag + separator). */
43
+ readonly perNode: number;
44
+ /** Fixed whole-prompt framing tokens charged once. */
45
+ readonly overhead: number;
46
+ }
47
+
48
+ /**
49
+ * Conservative default framing baseline. Documented as a BASELINE, not a
50
+ * measured provider constant: a real provider profile (VC5B) overrides it. Kept
51
+ * small and explicit so a default-driven plan is never silently over-optimistic.
52
+ */
53
+ export const DEFAULT_FRAMING: FramingProfile = { perNode: 4, overhead: 8 };
54
+
55
+ /**
56
+ * One candidate offered to the 0/1 portfolio. `mandatory` candidates are the
57
+ * closed set from VC4C and are admitted before any optional selection; optional
58
+ * candidates compete for the REMAINING budget.
59
+ *
60
+ * `sourceSeq` is the source ordering fact used as the FIRST tie-break after
61
+ * utility-per-token, so two equally efficient candidates resolve by source
62
+ * position (earlier wins) and then by ID bytes — a total, deterministic order.
63
+ */
64
+ export interface PlanCandidate {
65
+ readonly nodeId: string;
66
+ /** CONTENT-ONLY token estimate (framing is added by the planner). */
67
+ readonly tokenEstimate: number;
68
+ /** Selection value; higher is better. Ratio is `utility / framedTokens`. */
69
+ readonly utility: number;
70
+ /** Source sequence position, the first tie-break after the ratio. */
71
+ readonly sourceSeq: bigint;
72
+ /** True when the candidate is part of the mandatory closure. */
73
+ readonly mandatory: boolean;
74
+ }
75
+
76
+ /** Why a candidate was left out of the plan (recorded, never silent). */
77
+ export interface PlanOmission {
78
+ readonly nodeId: string;
79
+ readonly reason: "over-budget" | "incompatible" | "zero-utility";
80
+ }
81
+
82
+ /** Planner failure codes (registered PLN codes). */
83
+ export type PlanFailureCode =
84
+ /**
85
+ * The mandatory closure alone (with framing) exceeds `tokenBudget`. Evidence
86
+ * is NOT dropped — the mandatory set is returned intact and the adapter
87
+ * demotes to C.
88
+ */
89
+ | "MANDATORY_CLOSURE_OVER_BUDGET"
90
+ /** A candidate names a node absent from the DAG. */
91
+ | "PLN_UNKNOWN_NODE"
92
+ /** Two selected nodes declare mutual incompatibility. */
93
+ | "PLN_INCOMPATIBLE_SELECTION"
94
+ /** The DAG digest recorded in the plan no longer matches the DAG. */
95
+ | "PLN_MANIFEST_DIGEST_MISMATCH"
96
+ /** The budget itself is invalid (negative or non-finite). */
97
+ | "PLN_INVALID_BUDGET";
98
+
99
+ /**
100
+ * The accepted plan (CONTRACTS §plan and closure). `selectedNodeIds` is sorted
101
+ * for a stable manifest; `tokenTotal` is the FRAMED total and is guaranteed
102
+ * `<= tokenBudget` for every accepted plan.
103
+ */
104
+ export interface PlanV1 {
105
+ readonly schema: "plan-v1";
106
+ /** Digest of the DAG this plan was selected over (binds plan to structure). */
107
+ readonly dagDigest: string;
108
+ /** The selected node IDs, sorted by ID bytes. */
109
+ readonly selectedNodeIds: readonly string[];
110
+ /** The budget this plan was admitted against. */
111
+ readonly tokenBudget: number;
112
+ /** Framed token total of the selection; always `<= tokenBudget`. */
113
+ readonly tokenTotal: number;
114
+ /** Summed utility of the selection. */
115
+ readonly utilityTotal: number;
116
+ /** The durable authority high-water the plan's evidence depends on. */
117
+ readonly dependencyHighWater: bigint;
118
+ /** Candidates deliberately left out, with the reason. */
119
+ readonly omissions: readonly PlanOmission[];
120
+ }
121
+
122
+ /**
123
+ * The planner verdict. On failure the mandatory set is preserved so an
124
+ * over-budget closure can be reported WITHOUT dropping evidence.
125
+ */
126
+ export type PlanResult =
127
+ | { readonly ok: true; readonly plan: PlanV1 }
128
+ | {
129
+ readonly ok: false;
130
+ readonly code: PlanFailureCode;
131
+ /** The intact mandatory node IDs (never dropped on failure). */
132
+ readonly mandatory: readonly string[];
133
+ /** The framed cost of the mandatory set that could not be admitted. */
134
+ readonly mandatoryCost: number;
135
+ /** The budget the mandatory cost was measured against. */
136
+ readonly tokenBudget: number;
137
+ };
138
+
139
+ /**
140
+ * The triad mode VC5A selects (TRIAD_RESILIENCE). A/B/C are INDEPENDENT
141
+ * algorithms:
142
+ *
143
+ * A = the 0/1 portfolio optimizer (ratio-ordered admission);
144
+ * B = a stable greedy closed planner, forced by an A exception — it shares no
145
+ * ratio ordering with A and admits strictly in source order;
146
+ * C = the predecessor prompt, forced by mandatory overflow; it states its loss
147
+ * of old semantic context (continuity, NOT completeness).
148
+ */
149
+ export type PlanMode = "A" | "B" | "C";
150
+
151
+ /** The two structured events the VC5A reporter emits. */
152
+ export type PlanEventName =
153
+ | "vector_cortex_plan_selected"
154
+ | "vector_cortex_plan_mandatory_overflow";
155
+
156
+ /** Injected emit callback — same (event, fields) shape as the other VC seams. */
157
+ export type PlanEmitter = (
158
+ event: PlanEventName,
159
+ fields: Record<string, unknown>,
160
+ ) => void;
161
+
162
+ /** Typed, best-effort reporter bound to the two plan event names. */
163
+ export interface PlanReporter {
164
+ readonly planSelected: (fields: Record<string, unknown>) => void;
165
+ readonly planMandatoryOverflow: (fields: Record<string, unknown>) => void;
166
+ }
167
+
168
+ /**
169
+ * Aggregate-only plan metrics for the dashboard (counts/tokens only, never
170
+ * prompt text or node payloads).
171
+ */
172
+ export interface PlanMetricsV1 {
173
+ readonly plansSelected: number;
174
+ readonly mandatoryOverflows: number;
175
+ readonly nodesSelected: number;
176
+ readonly tokenTotal: number;
177
+ }
178
+
179
+ /**
180
+ * Registered PLN conformance ID range (PLN-001..020). The acceptance aggregator
181
+ * reads these rows from the v2 manifest and asserts each returns its manifest
182
+ * `ok`/`code`.
183
+ */
184
+ export const PLN_IDS: readonly string[] = Array.from(
185
+ { length: 20 },
186
+ (_v, i) => `PLN-${String(i + 1).padStart(3, "0")}`,
187
+ );
188
+
189
+ /** Named VC5A planner conformance assertions (the sprint's headline rows). */
190
+ export const PLAN_NAMED_IDS = ["PLN-MANDATORY-002", "PLN-TIE-003"] as const;