pi-mega-compact 0.20.2 → 0.20.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/vector-cortex.js +13 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +1 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex-plans.js +49 -0
- package/dist/extensions/dashboard-server/routes-vector-cortex.js +1 -0
- package/dist/extensions/dashboard-server/routes.js +1 -1
- package/dist/extensions/dashboard-server/server.js +29 -22
- package/dist/src/config/vector-cortex.js +13 -0
- package/dist/src/config.js +1 -1
- package/dist/src/vector-cortex/planner/manifest.js +66 -0
- package/dist/src/vector-cortex/planner/portfolio.js +0 -0
- package/dist/src/vector-cortex/planner/types.js +41 -0
- package/dist/src/vector-cortex/prompt-dag/_acceptance-dag.js +347 -0
- package/dist/src/vector-cortex/prompt-dag/_acceptance-fixture.js +59 -0
- package/dist/src/vector-cortex/prompt-dag/_acceptance-helpers.js +17 -0
- package/dist/src/vector-cortex/prompt-dag/_acceptance-planner.js +153 -0
- package/dist/src/vector-cortex/prompt-dag/_acceptance-shuffle.js +24 -0
- package/dist/src/vector-cortex/prompt-dag/builder.js +171 -0
- package/dist/src/vector-cortex/prompt-dag/types.js +33 -0
- package/dist/src/vector-cortex/prompt-dag/validator.js +0 -0
- package/dist/vector-cortex/planner/manifest.js +66 -0
- package/dist/vector-cortex/planner/portfolio.js +0 -0
- package/dist/vector-cortex/planner/types.js +41 -0
- package/dist/vector-cortex/prompt-dag/_acceptance-dag.js +347 -0
- package/dist/vector-cortex/prompt-dag/_acceptance-fixture.js +59 -0
- package/dist/vector-cortex/prompt-dag/_acceptance-helpers.js +17 -0
- package/dist/vector-cortex/prompt-dag/_acceptance-planner.js +153 -0
- package/dist/vector-cortex/prompt-dag/_acceptance-shuffle.js +24 -0
- package/dist/vector-cortex/prompt-dag/builder.js +171 -0
- package/dist/vector-cortex/prompt-dag/types.js +33 -0
- package/dist/vector-cortex/prompt-dag/validator.js +0 -0
- package/extensions/dashboard-client/dist/assets/{AreaChart-XF3jPpvn.js → AreaChart-Cam9-nhT.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-XF3jPpvn.js.map → AreaChart-Cam9-nhT.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-DnYYn0GF.js → BarChart-DzIY8aM1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-DnYYn0GF.js.map → BarChart-DzIY8aM1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-D3bVskCL.js → CacheTab-CKIiYsG_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-D3bVskCL.js.map → CacheTab-CKIiYsG_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CX_8myfc.js → EventsTab-xaaBJLiK.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CX_8myfc.js.map → EventsTab-xaaBJLiK.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-CnVzBQvN.js → HealthTab-BGtUKOqG.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-CnVzBQvN.js.map → HealthTab-BGtUKOqG.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cao--dtV.js → MaintenanceTab-ABgQnTZ9.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Cao--dtV.js.map → MaintenanceTab-ABgQnTZ9.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DZdI-9ig.js → MemoryMapTab-ChR2GAN-.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DZdI-9ig.js.map → MemoryMapTab-ChR2GAN-.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-SlpSmNU4.js → MetricsTab-DdCLAgcR.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-SlpSmNU4.js.map → MetricsTab-DdCLAgcR.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-C_-_4au9.js → OverviewTab-DtemzJt6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-C_-_4au9.js.map → OverviewTab-DtemzJt6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-CyWedWZC.js → ReposTab-B9mvD9Ep.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-CyWedWZC.js.map → ReposTab-B9mvD9Ep.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-wqPBMIJZ.js → SessionsTab-BcO38XLS.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-wqPBMIJZ.js.map → SessionsTab-BcO38XLS.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-MojXmuUf.js → SetupTab-D_TBNP09.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-MojXmuUf.js.map → SetupTab-D_TBNP09.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BxcplEOJ.js → TimeSavedCard-TjHpbUOo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BxcplEOJ.js.map → TimeSavedCard-TjHpbUOo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-D8_qWbjY.js → TurnsTab-DprxndCF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-D8_qWbjY.js.map → TurnsTab-DprxndCF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Bym21yVQ.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-Bym21yVQ.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-Cfd-QZYz.js → WikiTab-OKgSo15G.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-Cfd-QZYz.js.map → WikiTab-OKgSo15G.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-tX5ht0bb.js → button-D_Qz4q7L.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-tX5ht0bb.js.map → button-D_Qz4q7L.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-BT3Z5dDg.js → card-CsI6Jm3p.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-BT3Z5dDg.js.map → card-CsI6Jm3p.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B6p2WnkY.js → generateCategoricalChart-CvHKUdhX.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B6p2WnkY.js.map → generateCategoricalChart-CvHKUdhX.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-CFLekP12.js → index-0Ye_un22.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-CFLekP12.js.map → index-0Ye_un22.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-B52oAMSw.js → switch-VQEoJl8Q.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-B52oAMSw.js.map → switch-VQEoJl8Q.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-VxxVc5Tp.js → toggle-CAPm4HJo.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-VxxVc5Tp.js.map → toggle-CAPm4HJo.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-DAVdZnG7.js → useSSE-pxsNTVkh.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-DAVdZnG7.js.map → useSSE-pxsNTVkh.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/api/vector-cortex.ts +9 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +35 -0
- package/extensions/dashboard-client/src/types/vector-cortex.ts +20 -0
- package/extensions/dashboard-server/api-contracts/vector-cortex.ts +38 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +6 -0
- package/extensions/dashboard-server/routes-vector-cortex-plans.ts +58 -0
- package/extensions/dashboard-server/routes-vector-cortex.ts +1 -0
- package/extensions/dashboard-server/routes.ts +1 -0
- package/extensions/dashboard-server/server.ts +31 -22
- package/package.json +1 -1
- package/src/config/vector-cortex.ts +14 -0
- package/src/config.ts +1 -0
- package/src/vector-cortex/planner/manifest.ts +83 -0
- package/src/vector-cortex/planner/portfolio.ts +0 -0
- package/src/vector-cortex/planner/types.ts +190 -0
- package/src/vector-cortex/prompt-dag/_acceptance-dag.ts +392 -0
- package/src/vector-cortex/prompt-dag/_acceptance-fixture.ts +132 -0
- package/src/vector-cortex/prompt-dag/_acceptance-helpers.ts +39 -0
- package/src/vector-cortex/prompt-dag/_acceptance-planner.ts +188 -0
- package/src/vector-cortex/prompt-dag/_acceptance-shuffle.ts +26 -0
- package/src/vector-cortex/prompt-dag/builder.ts +189 -0
- package/src/vector-cortex/prompt-dag/types.ts +151 -0
- package/src/vector-cortex/prompt-dag/validator.ts +0 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-B3yisAyB.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-B3yisAyB.js.map +0 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt-dag/_acceptance-planner.ts — declarative candidate-set materialization
|
|
3
|
+
* + scenario driver for VC5A planner acceptance rows.
|
|
4
|
+
*
|
|
5
|
+
* Turns named candidate-set scenarios into real `PlanCandidate[]` values and
|
|
6
|
+
* drives them through the REAL portfolio planner (planPortfolio). The
|
|
7
|
+
* `mandatoryTokenEstimate` is the VC4C content-only figure = sum of mandatory
|
|
8
|
+
* content tokens (zero-framing fixtures pin this exactly).
|
|
9
|
+
*/
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import {
|
|
12
|
+
planPortfolio,
|
|
13
|
+
planManifestDigest,
|
|
14
|
+
validatePlanManifest,
|
|
15
|
+
} from "../planner/portfolio.js";
|
|
16
|
+
import { DEFAULT_FRAMING } from "../planner/types.js";
|
|
17
|
+
import type { FramingProfile, PlanCandidate } from "../planner/types.js";
|
|
18
|
+
import type { PlnFixture } from "./_acceptance-fixture.js";
|
|
19
|
+
import { shuffle } from "./_acceptance-shuffle.js";
|
|
20
|
+
|
|
21
|
+
export function materializeCandidates(name: string): PlanCandidate[] {
|
|
22
|
+
const sets: Record<string, PlanCandidate[]> = {
|
|
23
|
+
// m1=10, m2=20 mandatory → 30 content tokens (zero-framing fixtures pin this).
|
|
24
|
+
"mandatory-only": [
|
|
25
|
+
{ nodeId: "m1", tokenEstimate: 10, utility: 100, sourceSeq: 1n, mandatory: true },
|
|
26
|
+
{ nodeId: "m2", tokenEstimate: 20, utility: 200, sourceSeq: 2n, mandatory: true },
|
|
27
|
+
],
|
|
28
|
+
// Two mandatory nodes totalling 101 content tokens → over budget at 100.
|
|
29
|
+
"mandatory-101": [
|
|
30
|
+
{ nodeId: "m1", tokenEstimate: 50, utility: 100, sourceSeq: 1n, mandatory: true },
|
|
31
|
+
{ nodeId: "m2", tokenEstimate: 51, utility: 200, sourceSeq: 2n, mandatory: true },
|
|
32
|
+
],
|
|
33
|
+
// Optional candidates: hi=10t/20u (ratio 2.0), mid=10t/10u (ratio 1.0), lo=10t/5u.
|
|
34
|
+
ratio: [
|
|
35
|
+
{ nodeId: "hi", tokenEstimate: 10, utility: 20, sourceSeq: 1n, mandatory: false },
|
|
36
|
+
{ nodeId: "mid", tokenEstimate: 10, utility: 10, sourceSeq: 2n, mandatory: false },
|
|
37
|
+
{ nodeId: "lo", tokenEstimate: 10, utility: 5, sourceSeq: 3n, mandatory: false },
|
|
38
|
+
],
|
|
39
|
+
// Equal ratios (1.0) → source seq tie-break (early=seq1 wins).
|
|
40
|
+
"tie-seq": [
|
|
41
|
+
{ nodeId: "early", tokenEstimate: 10, utility: 10, sourceSeq: 1n, mandatory: false },
|
|
42
|
+
{ nodeId: "late", tokenEstimate: 10, utility: 10, sourceSeq: 2n, mandatory: false },
|
|
43
|
+
],
|
|
44
|
+
// Equal ratios AND equal source seq → lower ID bytes wins.
|
|
45
|
+
"tie-id": [
|
|
46
|
+
{ nodeId: "bbb", tokenEstimate: 10, utility: 10, sourceSeq: 1n, mandatory: false },
|
|
47
|
+
{ nodeId: "aaa", tokenEstimate: 10, utility: 10, sourceSeq: 1n, mandatory: false },
|
|
48
|
+
],
|
|
49
|
+
// One indivisible optional node of 10t/10u: 0/1 means it is taken whole.
|
|
50
|
+
indivisible: [
|
|
51
|
+
{ nodeId: "one", tokenEstimate: 10, utility: 10, sourceSeq: 1n, mandatory: false },
|
|
52
|
+
],
|
|
53
|
+
// A zero-utility optional node must be omitted.
|
|
54
|
+
"zero-utility": [
|
|
55
|
+
{ nodeId: "zero", tokenEstimate: 5, utility: 0, sourceSeq: 1n, mandatory: false },
|
|
56
|
+
],
|
|
57
|
+
// An optional node incompatible with a mandatory node is omitted (the planner
|
|
58
|
+
// enforces `incompatiblePairs`; here `bad` is mutually exclusive with `m1`).
|
|
59
|
+
incompatible: [
|
|
60
|
+
{ nodeId: "m1", tokenEstimate: 10, utility: 100, sourceSeq: 1n, mandatory: true },
|
|
61
|
+
{ nodeId: "bad", tokenEstimate: 5, utility: 50, sourceSeq: 2n, mandatory: false },
|
|
62
|
+
],
|
|
63
|
+
// Mixed: 2 mandatory + optional candidates exercising closure + selection.
|
|
64
|
+
mixed: [
|
|
65
|
+
{ nodeId: "m1", tokenEstimate: 10, utility: 100, sourceSeq: 1n, mandatory: true },
|
|
66
|
+
{ nodeId: "m2", tokenEstimate: 20, utility: 200, sourceSeq: 2n, mandatory: true },
|
|
67
|
+
{ nodeId: "opt", tokenEstimate: 30, utility: 90, sourceSeq: 3n, mandatory: false },
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
const set = sets[name];
|
|
71
|
+
assert.ok(set, `candidate-set materializer missing for "${name}"`);
|
|
72
|
+
return set;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function framing(zero?: boolean): FramingProfile {
|
|
76
|
+
return zero ? { perNode: 0, overhead: 0 } : DEFAULT_FRAMING;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface PlnResult {
|
|
80
|
+
ok: boolean;
|
|
81
|
+
code?: string;
|
|
82
|
+
selected?: string[];
|
|
83
|
+
tokenTotal?: number;
|
|
84
|
+
firstSelected?: string;
|
|
85
|
+
mandatoryPreserved?: boolean;
|
|
86
|
+
demotesToC?: boolean;
|
|
87
|
+
omittedOverBudget?: boolean;
|
|
88
|
+
omittedZeroUtility?: boolean;
|
|
89
|
+
omittedIncompatible?: boolean;
|
|
90
|
+
noPartialSelection?: boolean;
|
|
91
|
+
withinBudget?: boolean;
|
|
92
|
+
planIsClosed?: boolean;
|
|
93
|
+
permutationInvariant?: boolean;
|
|
94
|
+
manifestStable?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Drive a planner fixture scenario through the REAL portfolio planner. The
|
|
99
|
+
* `mandatoryTokenEstimate` is the VC4C CONTENT-ONLY figure = sum of mandatory
|
|
100
|
+
* content tokens (zero-framing fixtures make that the exact candidate sum).
|
|
101
|
+
*/
|
|
102
|
+
export function runPlannerScenario(fx: PlnFixture): PlnResult {
|
|
103
|
+
const { candidates: setName, tokenBudget, zeroFraming, permute, mutateTokensAfterPlan } = fx.input;
|
|
104
|
+
const cands = materializeCandidates(setName);
|
|
105
|
+
|
|
106
|
+
// VC4C content-only mandatory estimate = sum of mandatory content tokens.
|
|
107
|
+
const mandatoryTokenEstimate = cands
|
|
108
|
+
.filter((c) => c.mandatory)
|
|
109
|
+
.reduce((s, c) => s + c.tokenEstimate, 0);
|
|
110
|
+
|
|
111
|
+
const dagDigest = "deadbeef".repeat(8);
|
|
112
|
+
// The `incompatible` set wires an explicit mutual-exclusion pair (bad ⊥ m1) so
|
|
113
|
+
// the planner's incompatibility gate is exercised end-to-end.
|
|
114
|
+
const incompatiblePairs =
|
|
115
|
+
setName === "incompatible" ? ([["bad", "m1"]] as [string, string][]) : undefined;
|
|
116
|
+
const input = {
|
|
117
|
+
dagDigest,
|
|
118
|
+
candidates: permute ? shuffle([...cands]) : cands,
|
|
119
|
+
mandatoryTokenEstimate,
|
|
120
|
+
tokenBudget,
|
|
121
|
+
dependencyHighWater: 100n,
|
|
122
|
+
framing: framing(zeroFraming),
|
|
123
|
+
...(incompatiblePairs ? { incompatiblePairs } : {}),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const res = planPortfolio(input);
|
|
127
|
+
|
|
128
|
+
if (fx.expected.permutationInvariant) {
|
|
129
|
+
const a = planPortfolio(input);
|
|
130
|
+
const b = planPortfolio({ ...input, candidates: shuffle([...cands]) });
|
|
131
|
+
const ids = (ok: typeof a): string[] => (ok.ok ? [...ok.plan.selectedNodeIds] : []);
|
|
132
|
+
return { ok: true, permutationInvariant: JSON.stringify(ids(a)) === JSON.stringify(ids(b)) };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
// Over-budget failure: mandatory set preserved intact, demotes to C.
|
|
137
|
+
const mandatoryIds = cands.filter((c) => c.mandatory).map((c) => c.nodeId).sort();
|
|
138
|
+
const preserved = res.mandatory.slice().sort().join(",") === mandatoryIds.join(",");
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
code: res.code,
|
|
142
|
+
mandatoryPreserved: preserved,
|
|
143
|
+
demotesToC: res.code === "MANDATORY_CLOSURE_OVER_BUDGET",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ── Accepted-plan assertions ──
|
|
148
|
+
const plan = res.plan;
|
|
149
|
+
const selected = [...plan.selectedNodeIds];
|
|
150
|
+
const out: PlnResult = { ok: true, selected, tokenTotal: plan.tokenTotal };
|
|
151
|
+
if (fx.expected.firstSelected !== undefined) out.firstSelected = selected[0];
|
|
152
|
+
if (fx.expected.withinBudget) out.withinBudget = plan.tokenTotal <= tokenBudget;
|
|
153
|
+
if (fx.expected.noPartialSelection) {
|
|
154
|
+
out.noPartialSelection = cands.every(
|
|
155
|
+
(c) => !c.mandatory || selected.includes(c.nodeId),
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
if (fx.expected.planIsClosed) {
|
|
159
|
+
const mandatoryIds = cands.filter((c) => c.mandatory).map((c) => c.nodeId).sort();
|
|
160
|
+
out.planIsClosed = mandatoryIds.every((id) => selected.includes(id));
|
|
161
|
+
}
|
|
162
|
+
if (fx.expected.omittedOverBudget) {
|
|
163
|
+
const omit = plan.omissions.some((o) => o.reason === "over-budget");
|
|
164
|
+
out.omittedOverBudget = omit;
|
|
165
|
+
}
|
|
166
|
+
if (fx.expected.omittedZeroUtility) {
|
|
167
|
+
out.omittedZeroUtility = plan.omissions.some((o) => o.reason === "zero-utility");
|
|
168
|
+
}
|
|
169
|
+
if (fx.expected.omittedIncompatible) {
|
|
170
|
+
out.omittedIncompatible = plan.omissions.some((o) => o.reason === "incompatible");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Manifest identity: a post-plan token mutation must fail revalidation.
|
|
174
|
+
if (mutateTokensAfterPlan) {
|
|
175
|
+
const pinned = planManifestDigest(plan, cands);
|
|
176
|
+
const mutated = cands.map((c, i) => (i === 0 ? { ...c, tokenEstimate: c.tokenEstimate + 1 } : c));
|
|
177
|
+
const check = validatePlanManifest(plan, mutated, pinned);
|
|
178
|
+
out.ok = check.ok; // false → plan rejected, never reaches provider
|
|
179
|
+
out.code = check.ok ? undefined : check.code;
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
if (fx.expected.manifestStable) {
|
|
183
|
+
const pinned = planManifestDigest(plan, cands);
|
|
184
|
+
const check = validatePlanManifest(plan, cands, pinned);
|
|
185
|
+
out.manifestStable = check.ok;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt-dag/_acceptance-shuffle.ts — small deterministic helpers shared by the
|
|
3
|
+
* VC5A acceptance DAG/planner materializers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Array element equality (length + pairwise). */
|
|
7
|
+
export function eq(a: readonly string[], b: readonly string[]): boolean {
|
|
8
|
+
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Fisher–Yates with a FIXED seed so permutation tests are reproducible across
|
|
13
|
+
* runs and machines (no Math.random in tests).
|
|
14
|
+
*/
|
|
15
|
+
export function shuffle<T>(arr: T[]): T[] {
|
|
16
|
+
const a = [...arr];
|
|
17
|
+
let seed = 0x9e3779b9;
|
|
18
|
+
for (let i = a.length - 1; i > 0; i--) {
|
|
19
|
+
seed = (seed * 1664525 + 1013904223) >>> 0;
|
|
20
|
+
const j = seed % (i + 1);
|
|
21
|
+
const t = a[i]!;
|
|
22
|
+
a[i] = a[j]!;
|
|
23
|
+
a[j] = t;
|
|
24
|
+
}
|
|
25
|
+
return a;
|
|
26
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/prompt-dag/builder.ts — single-session PromptDagV1 construction
|
|
3
|
+
* (VC5A, task 2).
|
|
4
|
+
*
|
|
5
|
+
* The builder is the STRUCTURAL gate: it rejects a graph that could never be
|
|
6
|
+
* planned safely, before any ordering or selection is attempted. Rejections are
|
|
7
|
+
* hard and total (the sprint bar: "cycles/incompatibilities rejected 100%"):
|
|
8
|
+
*
|
|
9
|
+
* - `DAG_MIXED_SESSION` — a span whose sessionId differs from the DAG's.
|
|
10
|
+
* Cross-session evidence MUST be a synthetic
|
|
11
|
+
* node citing a separately validated manifest,
|
|
12
|
+
* never a foreign span (CONTRACTS §PromptDagV1).
|
|
13
|
+
* - `DAG_DUPLICATE_ID` — two nodes sharing an id.
|
|
14
|
+
* - `DAG_MISSING_ENDPOINT` — an edge naming an absent node.
|
|
15
|
+
* - `DAG_INVALID_SPAN` — reversed/negative range, or a synthetic node
|
|
16
|
+
* carrying a span (synthetics have no source
|
|
17
|
+
* position by definition).
|
|
18
|
+
* - `DAG_SPAN_DIGEST_CONFLICT` — two overlapping spans pinning DIFFERENT
|
|
19
|
+
* digests for the same bytes: a corrupted or
|
|
20
|
+
* forged source claim, not a legal overlap.
|
|
21
|
+
* - `DAG_UNKNOWN_INCOMPATIBLE` — `incompatibleWith` naming an absent node.
|
|
22
|
+
* - `DAG_TOOL_PAIR_SPLIT` — a tool-pair edge whose endpoints are not both
|
|
23
|
+
* present (PREVENT-PI-002).
|
|
24
|
+
*
|
|
25
|
+
* Cycle and reversed-`precedes` detection belong to the VALIDATOR, which owns
|
|
26
|
+
* the topological order; the builder only guarantees the graph is structurally
|
|
27
|
+
* well-formed and single-session.
|
|
28
|
+
*
|
|
29
|
+
* Determinism: nodes and edges are emitted in a canonical sorted order so the
|
|
30
|
+
* same inputs always produce byte-identical DAG bytes, whatever order the caller
|
|
31
|
+
* supplied them in. Pure: no storage, no console, no network (PREVENT-PI-004).
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type {
|
|
35
|
+
DagEdge,
|
|
36
|
+
DagFailureCode,
|
|
37
|
+
DagNode,
|
|
38
|
+
DagSpan,
|
|
39
|
+
PromptDagV1,
|
|
40
|
+
} from "./types.js";
|
|
41
|
+
|
|
42
|
+
/** Bytewise string comparison — the universal deterministic tie-break. */
|
|
43
|
+
function byBytes(a: string, b: string): number {
|
|
44
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Canonical node order: source position first (`startSeq`, then `startByte`),
|
|
49
|
+
* synthetics last (they have no span), then `syntheticOrdinal`, then id bytes.
|
|
50
|
+
* This mirrors the validator's queue key so the emitted DAG and its topological
|
|
51
|
+
* order agree on what "earlier" means.
|
|
52
|
+
*/
|
|
53
|
+
export function compareNodes(a: DagNode, b: DagNode): number {
|
|
54
|
+
const aSeq = a.span?.startSeq;
|
|
55
|
+
const bSeq = b.span?.startSeq;
|
|
56
|
+
if (aSeq !== undefined && bSeq !== undefined) {
|
|
57
|
+
if (aSeq !== bSeq) return aSeq < bSeq ? -1 : 1;
|
|
58
|
+
} else if (aSeq !== undefined) {
|
|
59
|
+
return -1; // spanned nodes precede synthetics
|
|
60
|
+
} else if (bSeq !== undefined) {
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
// Contract key: (startSeq, syntheticOrdinal, id bytes) — byte offset is NOT a
|
|
64
|
+
// tie-break, so the emitted DAG and its topological order agree exactly.
|
|
65
|
+
const aOrd = a.syntheticOrdinal ?? 0;
|
|
66
|
+
const bOrd = b.syntheticOrdinal ?? 0;
|
|
67
|
+
if (aOrd !== bOrd) return aOrd < bOrd ? -1 : 1;
|
|
68
|
+
return byBytes(a.id, b.id);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Canonical edge order: from, then to, then kind — a total order. */
|
|
72
|
+
export function compareEdges(a: DagEdge, b: DagEdge): number {
|
|
73
|
+
const f = byBytes(a.from, b.from);
|
|
74
|
+
if (f !== 0) return f;
|
|
75
|
+
const t = byBytes(a.to, b.to);
|
|
76
|
+
if (t !== 0) return t;
|
|
77
|
+
return byBytes(a.kind, b.kind);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Whether two half-open byte ranges in the same session intersect. */
|
|
81
|
+
function spansOverlap(a: DagSpan, b: DagSpan): boolean {
|
|
82
|
+
if (a.sessionId !== b.sessionId) return false;
|
|
83
|
+
return a.startByte < b.endByte && b.startByte < a.endByte;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A span is well-formed when both its seq and byte ranges are non-decreasing. */
|
|
87
|
+
function spanIsValid(span: DagSpan): boolean {
|
|
88
|
+
if (span.startSeq > span.endSeq) return false;
|
|
89
|
+
if (span.startByte < 0 || span.endByte < 0) return false;
|
|
90
|
+
return span.startByte <= span.endByte;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Push a failure code once (codes are a SET, reported in discovery order). */
|
|
94
|
+
function pushCode(codes: DagFailureCode[], code: DagFailureCode): void {
|
|
95
|
+
if (!codes.includes(code)) codes.push(code);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** The inputs a DAG is built from. */
|
|
99
|
+
export interface DagBuildInput {
|
|
100
|
+
readonly sessionId: string;
|
|
101
|
+
/** The durable contiguous authority high-water this DAG is built against. */
|
|
102
|
+
readonly sourceHighWater: bigint;
|
|
103
|
+
readonly nodes: readonly DagNode[];
|
|
104
|
+
readonly edges: readonly DagEdge[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Build outcome: the canonical DAG, or the exact structural failure codes. */
|
|
108
|
+
export type DagBuildResult =
|
|
109
|
+
| { readonly ok: true; readonly dag: PromptDagV1 }
|
|
110
|
+
| { readonly ok: false; readonly codes: readonly DagFailureCode[] };
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Build a canonical single-session `PromptDagV1`, or reject with the exact
|
|
114
|
+
* structural failure codes (task 2).
|
|
115
|
+
*
|
|
116
|
+
* Every check runs before returning so a caller sees ALL structural problems at
|
|
117
|
+
* once rather than fixing them one round-trip at a time; the codes array is
|
|
118
|
+
* deduplicated and ordered by discovery.
|
|
119
|
+
*/
|
|
120
|
+
export function buildPromptDag(input: DagBuildInput): DagBuildResult {
|
|
121
|
+
const codes: DagFailureCode[] = [];
|
|
122
|
+
|
|
123
|
+
// ── Node identity + span validity + single-session enforcement ─────────────
|
|
124
|
+
const byId = new Map<string, DagNode>();
|
|
125
|
+
for (const n of input.nodes) {
|
|
126
|
+
if (byId.has(n.id)) pushCode(codes, "DAG_DUPLICATE_ID");
|
|
127
|
+
else byId.set(n.id, n);
|
|
128
|
+
|
|
129
|
+
if (n.kind === "synthetic") {
|
|
130
|
+
// A synthetic node has no source position by definition; carrying a span
|
|
131
|
+
// would make its ordering ambiguous against real source nodes.
|
|
132
|
+
if (n.span !== undefined) pushCode(codes, "DAG_INVALID_SPAN");
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (n.span === undefined) continue; // a spanless non-synthetic orders last
|
|
136
|
+
if (!spanIsValid(n.span)) pushCode(codes, "DAG_INVALID_SPAN");
|
|
137
|
+
// Single-session: cross-session evidence must be a synthetic citation.
|
|
138
|
+
if (n.span.sessionId !== input.sessionId) pushCode(codes, "DAG_MIXED_SESSION");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── Overlapping spans must agree on the digest of the shared bytes ─────────
|
|
142
|
+
const spanned = input.nodes.filter(
|
|
143
|
+
(n): n is DagNode & { span: DagSpan } => n.span !== undefined,
|
|
144
|
+
);
|
|
145
|
+
for (let i = 0; i < spanned.length; i++) {
|
|
146
|
+
for (let j = i + 1; j < spanned.length; j++) {
|
|
147
|
+
const a = spanned[i]!;
|
|
148
|
+
const b = spanned[j]!;
|
|
149
|
+
if (!spansOverlap(a.span, b.span)) continue;
|
|
150
|
+
if (a.span.digest !== b.span.digest) {
|
|
151
|
+
pushCode(codes, "DAG_SPAN_DIGEST_CONFLICT");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── Incompatibility targets must exist ────────────────────────────────────
|
|
157
|
+
for (const n of input.nodes) {
|
|
158
|
+
for (const other of n.incompatibleWith) {
|
|
159
|
+
if (!byId.has(other)) pushCode(codes, "DAG_UNKNOWN_INCOMPATIBLE");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── Edge endpoints must exist; tool pairs must be whole ───────────────────
|
|
164
|
+
for (const e of input.edges) {
|
|
165
|
+
const hasFrom = byId.has(e.from);
|
|
166
|
+
const hasTo = byId.has(e.to);
|
|
167
|
+
if (!hasFrom || !hasTo) {
|
|
168
|
+
pushCode(codes, "DAG_MISSING_ENDPOINT");
|
|
169
|
+
// A tool pair missing an endpoint is ALSO a split pair (PREVENT-PI-002):
|
|
170
|
+
// the atomic unit cannot be represented, let alone selected whole.
|
|
171
|
+
if (e.kind === "tool-pair") pushCode(codes, "DAG_TOOL_PAIR_SPLIT");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (codes.length > 0) return { ok: false, codes };
|
|
176
|
+
|
|
177
|
+
const nodes = [...input.nodes].sort(compareNodes);
|
|
178
|
+
const edges = [...input.edges].sort(compareEdges);
|
|
179
|
+
return {
|
|
180
|
+
ok: true,
|
|
181
|
+
dag: {
|
|
182
|
+
schema: "prompt-dag-v1",
|
|
183
|
+
sessionId: input.sessionId,
|
|
184
|
+
sourceHighWater: input.sourceHighWater,
|
|
185
|
+
nodes,
|
|
186
|
+
edges,
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vector-cortex/prompt-dag/types.ts — the exact single-session `PromptDagV1`
|
|
3
|
+
* schema (VC5A, task 1).
|
|
4
|
+
*
|
|
5
|
+
* A PromptDagV1 is the STRUCTURE a plan is selected over: nodes are prompt
|
|
6
|
+
* candidates (events, exact spans, semantic renderings, synthetic citations) and
|
|
7
|
+
* edges are the ordering/atomicity/exclusivity constraints among them. It is
|
|
8
|
+
* strictly SINGLE-SESSION (CONTRACTS §PromptDagV1): every node span MUST carry
|
|
9
|
+
* `dag.sessionId`; cross-session evidence is represented by a SYNTHETIC node
|
|
10
|
+
* whose payload cites a separately validated source manifest, never by a foreign
|
|
11
|
+
* span.
|
|
12
|
+
*
|
|
13
|
+
* Ordering is a total order by construction so the same DAG always yields the
|
|
14
|
+
* same Kahn sequence:
|
|
15
|
+
*
|
|
16
|
+
* - event/exact/semantic nodes order by their source span (`startSeq`, then
|
|
17
|
+
* `startByte`);
|
|
18
|
+
* - synthetic nodes have NO span and sort after every prerequisite, then by
|
|
19
|
+
* `syntheticOrdinal`, then by node-ID bytes;
|
|
20
|
+
* - the zero-indegree queue key is `(span.startSeq ?? MAX, syntheticOrdinal ??
|
|
21
|
+
* 0, id bytes)` — never object/map iteration order.
|
|
22
|
+
*
|
|
23
|
+
* Pure types + registered conformance IDs: no storage, no console, no network
|
|
24
|
+
* (PREVENT-PI-004 / PREVENT-011).
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A half-open source span. `startSeq`/`endSeq` are INCLUSIVE event sequence
|
|
29
|
+
* numbers; `startByte`/`endByte` are HALF-OPEN byte offsets (CONTRACTS
|
|
30
|
+
* §PromptDagV1). `digest` is the pinned `sha256:<hex>` of the covered bytes —
|
|
31
|
+
* the builder rejects two overlapping spans whose digests disagree, since that
|
|
32
|
+
* is a corrupted or forged source claim rather than a legitimate overlap.
|
|
33
|
+
*/
|
|
34
|
+
export interface DagSpan {
|
|
35
|
+
readonly sessionId: string;
|
|
36
|
+
readonly startSeq: bigint;
|
|
37
|
+
readonly endSeq: bigint;
|
|
38
|
+
readonly startByte: number;
|
|
39
|
+
readonly endByte: number;
|
|
40
|
+
/** Pinned digest of the covered bytes, `sha256:` prefixed. */
|
|
41
|
+
readonly digest: `sha256:${string}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The kind of a DAG node.
|
|
46
|
+
*
|
|
47
|
+
* - `event` — a whole source event record;
|
|
48
|
+
* - `exact` — authoritative source bytes (verbatim, never paraphrased);
|
|
49
|
+
* - `semantic` — a derived rendering that NEVER claims to recover exact text;
|
|
50
|
+
* - `synthetic` — no source span (a citation/summary); orders after its
|
|
51
|
+
* prerequisites by `syntheticOrdinal` then ID bytes.
|
|
52
|
+
*/
|
|
53
|
+
export type DagNodeKind = "event" | "exact" | "semantic" | "synthetic";
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* One prompt-DAG node. `span` is present for every non-synthetic kind and absent
|
|
57
|
+
* for `synthetic`. `incompatibleWith` lists node IDs that may NOT be selected
|
|
58
|
+
* together with this node (a mutual-exclusion constraint the planner enforces —
|
|
59
|
+
* distinct from a `contradicts` EDGE, which is a source-level disagreement).
|
|
60
|
+
*/
|
|
61
|
+
export interface DagNode {
|
|
62
|
+
readonly id: string;
|
|
63
|
+
readonly kind: DagNodeKind;
|
|
64
|
+
/** Source span; absent (and required to be absent) for `synthetic`. */
|
|
65
|
+
readonly span?: DagSpan;
|
|
66
|
+
/** Tie-break ordinal for synthetic nodes, which have no span. */
|
|
67
|
+
readonly syntheticOrdinal?: number;
|
|
68
|
+
/** Digest of this node's payload (identity for the manifest digest). */
|
|
69
|
+
readonly payloadDigest: string;
|
|
70
|
+
/** Node IDs that must never be co-selected with this node. */
|
|
71
|
+
readonly incompatibleWith: readonly string[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A directed DAG edge, pointing prerequisite/earlier **from → dependent/later
|
|
76
|
+
* to** (CONTRACTS §PromptDagV1).
|
|
77
|
+
*
|
|
78
|
+
* - `precedes` — pure ordering; `from` must appear before `to`;
|
|
79
|
+
* - `depends` — `to` requires `from` (closure pulls `from` in);
|
|
80
|
+
* - `tool-pair` — an atomic tool call/result pair, never split
|
|
81
|
+
* (PREVENT-PI-002);
|
|
82
|
+
* - `contradicts` — mutually exclusive source claims.
|
|
83
|
+
*/
|
|
84
|
+
export type DagEdgeKind = "precedes" | "depends" | "tool-pair" | "contradicts";
|
|
85
|
+
|
|
86
|
+
/** A directed prompt-DAG edge (`from` is the prerequisite/earlier endpoint). */
|
|
87
|
+
export interface DagEdge {
|
|
88
|
+
readonly from: string;
|
|
89
|
+
readonly to: string;
|
|
90
|
+
readonly kind: DagEdgeKind;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The single-session prompt DAG. `sourceHighWater` is the durable contiguous
|
|
95
|
+
* authority high-water this DAG was built against — a derived structure may
|
|
96
|
+
* never claim evidence beyond it (TRIAD_RESILIENCE: derived frontier cannot
|
|
97
|
+
* exceed durable authority high-water).
|
|
98
|
+
*/
|
|
99
|
+
export interface PromptDagV1 {
|
|
100
|
+
readonly schema: "prompt-dag-v1";
|
|
101
|
+
readonly sessionId: string;
|
|
102
|
+
readonly sourceHighWater: bigint;
|
|
103
|
+
readonly nodes: readonly DagNode[];
|
|
104
|
+
readonly edges: readonly DagEdge[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* DAG build/validation failure codes. Every code is a HARD rejection: a DAG that
|
|
109
|
+
* produces any of these never reaches the planner (cycles/incompatibilities are
|
|
110
|
+
* rejected 100%, per the sprint acceptance bar).
|
|
111
|
+
*/
|
|
112
|
+
export type DagFailureCode =
|
|
113
|
+
/** A node span's `sessionId` differs from `dag.sessionId` (single-session). */
|
|
114
|
+
| "DAG_MIXED_SESSION"
|
|
115
|
+
/** Two nodes share an ID. */
|
|
116
|
+
| "DAG_DUPLICATE_ID"
|
|
117
|
+
/** An edge names a node ID absent from the graph. */
|
|
118
|
+
| "DAG_MISSING_ENDPOINT"
|
|
119
|
+
/** A span is malformed (reversed/negative range) or a synthetic node has one. */
|
|
120
|
+
| "DAG_INVALID_SPAN"
|
|
121
|
+
/** Two spans overlap but pin DIFFERENT digests for the shared bytes. */
|
|
122
|
+
| "DAG_SPAN_DIGEST_CONFLICT"
|
|
123
|
+
/** A `precedes` edge points backward against source order. */
|
|
124
|
+
| "DAG_REVERSED_PRECEDES"
|
|
125
|
+
/** The dependency/ordering graph contains a cycle. */
|
|
126
|
+
| "DAG_CYCLE"
|
|
127
|
+
/** A tool-pair edge's endpoints are not both present/whole. */
|
|
128
|
+
| "DAG_TOOL_PAIR_SPLIT"
|
|
129
|
+
/** A node declares `incompatibleWith` naming a node absent from the graph. */
|
|
130
|
+
| "DAG_UNKNOWN_INCOMPATIBLE";
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The validator verdict. `ok:true` carries the STABLE Kahn topological order —
|
|
134
|
+
* the single authoritative sequence downstream consumers (VC5B) replay.
|
|
135
|
+
*/
|
|
136
|
+
export type DagValidation =
|
|
137
|
+
| { readonly ok: true; readonly order: readonly string[] }
|
|
138
|
+
| { readonly ok: false; readonly codes: readonly DagFailureCode[] };
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Registered DAG conformance ID range (DAG-001..030). The acceptance aggregator
|
|
142
|
+
* reads these rows from the v2 manifest and asserts each returns its manifest
|
|
143
|
+
* `ok`/`code`.
|
|
144
|
+
*/
|
|
145
|
+
export const DAG_IDS: readonly string[] = Array.from(
|
|
146
|
+
{ length: 30 },
|
|
147
|
+
(_v, i) => `DAG-${String(i + 1).padStart(3, "0")}`,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
/** Named VC5A DAG conformance assertion (the sprint's headline DAG row). */
|
|
151
|
+
export const DAG_NAMED_IDS = ["DAG-CYCLE-001"] as const;
|
|
Binary file
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{r as o,j as e,B as c}from"./index-CFLekP12.js";import{C as i,a as x,b as h,c as u}from"./card-BT3Z5dDg.js";async function B(){const s=await fetch("/api/vector-cortex/evaluation");if(!s.ok)throw new Error(`vector-cortex evaluation: ${s.status}`);return s.json()}async function S(){const s=await fetch("/api/vector-cortex/health");if(!s.ok)throw new Error(`vector-cortex health: ${s.status}`);return s.json()}async function D(){const s=await fetch("/api/vector-cortex/topology");if(!s.ok)throw new Error(`vector-cortex topology: ${s.status}`);return s.json()}async function O(){const s=await fetch("/api/vector-cortex/query");if(!s.ok)throw new Error(`vector-cortex query: ${s.status}`);return s.json()}async function L(){const s=await fetch("/api/vector-cortex/shards");if(!s.ok)throw new Error(`vector-cortex shards: ${s.status}`);return s.json()}async function H(){const s=await fetch("/api/vector-cortex/reconstruct");if(!s.ok)throw new Error(`vector-cortex reconstruct: ${s.status}`);return s.json()}async function q(s="default"){const n=await fetch(`/api/vector-cortex/ledger?session=${encodeURIComponent(s)}`);if(!n.ok)throw new Error(`vector-cortex ledger: ${n.status}`);return n.json()}async function P(s){const n=await fetch("/api/vector-cortex/breakers/reset",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({subsystem:s})});if(!n.ok)throw new Error(`vector-cortex reset: ${n.status}`);return n.json()}function p({mode:s,count:n}){return e.jsxs("div",{className:"flex items-center justify-between border-b border-border/50 py-1 text-sm",children:[e.jsxs("span",{className:"text-muted-foreground",children:["Mode ",s]}),e.jsx("span",{className:"font-mono",children:n})]})}function r({label:s,value:n}){return e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:s}),e.jsx("div",{className:"font-mono text-sm",children:n})]})}function G(){const[s,n]=o.useState(null),[b,E]=o.useState(null),[V,F]=o.useState(!0),[a,y]=o.useState(null),[N,C]=o.useState(null),[m,$]=o.useState(null),[l,R]=o.useState(null),[v,k]=o.useState(null),[j,T]=o.useState(null),[d,M]=o.useState(null),f=o.useCallback(()=>{B().then(n).catch(t=>E(t instanceof Error?t.message:String(t))).finally(()=>F(!1)),S().then(y).catch(()=>{}),q().then($).catch(()=>{}),D().then(R).catch(()=>{}),O().then(k).catch(()=>{}),L().then(T).catch(()=>{}),H().then(M).catch(()=>{})},[]);o.useEffect(()=>{f();const t=setInterval(f,5e3);return()=>clearInterval(t)},[f]);const A=()=>{P("provider").then(t=>(C(`Breaker "${t.subsystem}" ${t.state}; evidence retained: ${t.failures} failures / ${t.attempts} attempts`),S())).then(y).catch(t=>C(t instanceof Error?t.message:String(t)))};if(V&&!s)return e.jsx("div",{className:"vc-loading",children:"Loading vector-cortex evaluation…"});if(b&&!s)return e.jsxs("div",{className:"vc-error",children:["Error: ",b]});if(!s)return e.jsx("div",{className:"vc-empty",children:"No evaluation data available."});const w=Math.max(1,...s.histogram.cells,s.histogram.overflow);return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("h2",{className:"text-lg font-semibold",children:"Vector Cortex Evaluation"}),s.enabled?e.jsx(c,{variant:"warning",children:"OBSERVER PENDING (A)"}):e.jsx(c,{variant:"danger",children:"MODE C (OFF)"})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-3",children:[e.jsxs(i,{children:[e.jsx(x,{children:e.jsx(h,{children:"Samples"})}),e.jsxs(u,{children:[e.jsx("div",{className:"text-3xl font-bold",children:s.samples}),e.jsxs("div",{className:"mt-2 flex flex-col",children:[e.jsx(p,{mode:"A",count:s.byMode.A}),e.jsx(p,{mode:"B",count:s.byMode.B}),e.jsx(p,{mode:"C",count:s.byMode.C})]})]})]}),e.jsxs(i,{className:"md:col-span-2",children:[e.jsx(x,{children:e.jsx(h,{children:"Latency Histogram (ms, inclusive edges)"})}),e.jsxs(u,{children:[e.jsxs("div",{className:"flex items-end gap-2",style:{height:160},children:[s.histogram.edges.map((t,g)=>{const I=s.histogram.cells[g]/w*140;return e.jsxs("div",{className:"flex flex-1 flex-col items-center gap-1",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s.histogram.cells[g]}),e.jsx("div",{className:"w-full rounded-t",style:{height:Math.max(2,I),background:"#6366f1"}}),e.jsxs("span",{className:"text-[10px] text-muted-foreground",children:["≤",t]})]},t)}),e.jsxs("div",{className:"flex flex-1 flex-col items-center gap-1",children:[e.jsx("span",{className:"text-xs text-muted-foreground",children:s.histogram.overflow}),e.jsx("div",{className:"w-full rounded-t",style:{height:Math.max(2,s.histogram.overflow/w*140),background:"#f87171"}}),e.jsx("span",{className:"text-[10px] text-muted-foreground",children:">250"})]})]}),e.jsxs("div",{className:"mt-1 text-xs text-muted-foreground",children:["Total: ",s.histogram.total," · Rejects: ",s.rejects.length]})]})]})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Live Safety Envelope (VC0C)"}),e.jsxs("div",{className:"flex items-center gap-2",children:[a?.stateSource==="ephemeral"&&e.jsx(c,{variant:"outline",children:"EPHEMERAL (non-live)"}),e.jsx("button",{onClick:A,disabled:!a?.enabled,className:"rounded border border-border px-2 py-1 text-xs disabled:opacity-50",children:"Reset Cooldown"})]})]})}),e.jsxs(u,{children:[N&&e.jsx("div",{className:"mb-2 text-xs text-muted-foreground",children:N}),a?e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(r,{label:"State",value:a.state}),e.jsx(r,{label:"Mode",value:a.mode}),e.jsx(r,{label:"Window",value:`${a.windowMs}ms`}),e.jsx(r,{label:"Probes",value:String(a.probeCount)}),e.jsx(r,{label:"Backoff",value:`${a.backoffDelayMs}ms`}),e.jsx(r,{label:"Failures",value:`${a.failures}/${a.attempts}`}),e.jsx(r,{label:"Frontier",value:a.stateSource==="ephemeral"?"non-live":a.frontierFrozen?"FROZEN":"LIVE"}),e.jsx(r,{label:"Spool lag",value:String(a.spoolLag)}),e.jsx(r,{label:"Encoder mode",value:a.encoderMode}),e.jsx(r,{label:"Encoder asset",value:a.encoderAssetDigest?a.encoderAssetDigest.slice(0,12):"none"})]}):e.jsx("div",{className:"vc-empty",children:"Health unavailable (VC0C off)."})]})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Derived Cortex Store (VC3A)"}),l?.enabled?e.jsx(c,{variant:"success",children:"ACTIVE"}):e.jsx(c,{variant:"danger",children:"OFF"})]})}),e.jsx(u,{children:l?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-3",children:[e.jsx(r,{label:"Generation",value:l.generationId??"—"}),e.jsx(r,{label:"Ordinal",value:l.ordinal??"—"}),e.jsx(r,{label:"Records",value:String(l.recordCount)}),e.jsx(r,{label:"Frontier (HW)",value:l.sourceHighWater}),e.jsx(r,{label:"Root digest",value:l.rootDigest?l.rootDigest.slice(0,16):"—"}),l.nodes!==void 0&&e.jsxs(e.Fragment,{children:[e.jsx(r,{label:"Nodes",value:String(l.nodes?.length??0)}),e.jsx(r,{label:"Edges",value:String(l.edges?.length??0)}),e.jsx(r,{label:"Graph digest",value:l.generationDigest?l.generationDigest.slice(0,16):"—"})]})]}),l.nodes!==void 0&&(l.edges?.length??0)>0&&e.jsxs("div",{className:"mt-4 max-h-56 overflow-y-auto",children:[e.jsx("div",{className:"mb-1 text-xs font-medium text-muted-foreground",children:"Topology edges (VC3B)"}),e.jsxs("table",{className:"w-full text-left text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border/50 text-muted-foreground",children:[e.jsx("th",{className:"py-1 pr-2",children:"source"}),e.jsx("th",{className:"py-1 pr-2",children:"target"}),e.jsx("th",{className:"py-1 pr-2",children:"head"}),e.jsx("th",{className:"py-1 pr-2",children:"dir"}),e.jsx("th",{className:"py-1",children:"score"})]})}),e.jsx("tbody",{children:l.edges?.map((t,g)=>e.jsxs("tr",{className:"border-b border-border/30",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.source}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.target}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.head}),e.jsx("td",{className:"py-1 pr-2",children:t.direction}),e.jsx("td",{className:"py-1 font-mono",children:t.score})]},`${t.source}-${t.target}-${t.head}-${g}`))})]})]})]}):e.jsx("div",{className:"vc-empty",children:"Cortex store disabled (VC3A off)."})})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Topology Query Diagnostics (VC3C)"}),v?.enabled?e.jsx(c,{variant:"success",children:"ACTIVE"}):e.jsx(c,{variant:"danger",children:"OFF"})]})}),e.jsx(u,{children:v?.enabled?e.jsx("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-3",children:e.jsx(r,{label:"Router version",value:String(v.routerVersion)})}):e.jsx("div",{className:"vc-empty",children:"Query diagnostics unavailable (VC3C off)."})})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Dual-Tier Shards (VC4A)"}),j?.enabled?e.jsx(c,{variant:"success",children:"ACTIVE"}):e.jsx(c,{variant:"danger",children:"OFF"})]})}),e.jsx(u,{children:j?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(r,{label:"Semantic shards",value:String(j.semanticCount)}),e.jsx(r,{label:"Exact shards",value:String(j.exactCount)}),e.jsx(r,{label:"Byte total",value:String(j.byteTotal)}),e.jsx(r,{label:"Protected bytes",value:String(j.protectedByteTotal)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only count/byte aggregate; staged in-memory this sprint."})]}):e.jsx("div",{className:"vc-empty",children:"Dual-tier shards disabled (VC4A off)."})})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Reconstruction Fidelity (VC4C)"}),d?.enabled?e.jsx(c,{variant:"success",children:"ACTIVE"}):e.jsx(c,{variant:"danger",children:"OFF"})]})}),e.jsx(u,{children:d?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 md:grid-cols-4",children:[e.jsx(r,{label:"Closure attempts",value:String(d.closureAttempts)}),e.jsx(r,{label:"Closure rejections",value:String(d.closureRejections)}),e.jsx(r,{label:"Validated",value:String(d.validatedCount)}),e.jsx(r,{label:"Invalidated",value:String(d.invalidatedCount)}),e.jsx(r,{label:"Span total",value:String(d.spanTotal)}),e.jsx(r,{label:"Byte total",value:String(d.byteTotal)})]}),e.jsx("div",{className:"mt-3 text-xs text-muted-foreground",children:"Reader-only closure/validation aggregate; staged in-memory this sprint."})]}):e.jsx("div",{className:"vc-empty",children:"Reconstruction fidelity disabled (VC4C off)."})})]}),e.jsxs(i,{children:[e.jsx(x,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(h,{children:"Occurrence Ledger (VC1B)"}),m?.enabled?e.jsx(c,{variant:"success",children:"ACTIVE"}):e.jsx(c,{variant:"danger",children:"OFF"})]})}),e.jsx(u,{children:m?.enabled?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"mb-3 grid grid-cols-2 gap-4 md:grid-cols-3",children:[e.jsx(r,{label:"Session",value:m.session}),e.jsx(r,{label:"High-water",value:m.highWater}),e.jsx(r,{label:"Occurrences",value:String(m.count)})]}),m.occurrences.length===0?e.jsx("div",{className:"vc-empty",children:"No occurrences recorded."}):e.jsx("div",{className:"max-h-64 overflow-y-auto",children:e.jsxs("table",{className:"w-full text-left text-xs",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border/50 text-muted-foreground",children:[e.jsx("th",{className:"py-1 pr-2",children:"seq"}),e.jsx("th",{className:"py-1 pr-2",children:"eventId"}),e.jsx("th",{className:"py-1 pr-2",children:"kind"}),e.jsx("th",{className:"py-1 pr-2",children:"toolCall"}),e.jsx("th",{className:"py-1",children:"digest"})]})}),e.jsx("tbody",{children:m.occurrences.map(t=>e.jsxs("tr",{className:"border-b border-border/30",children:[e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.seq}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.eventId}),e.jsx("td",{className:"py-1 pr-2",children:t.kind}),e.jsx("td",{className:"py-1 pr-2 font-mono",children:t.toolCallId??"—"}),e.jsx("td",{className:"max-w-[180px] truncate font-mono text-muted-foreground",children:t.digest})]},`${t.seq}-${t.eventId}`))})]})})]}):e.jsx("div",{className:"vc-empty",children:"Ledger disabled (VC1B off)."})})]})]})}export{G as default};
|
|
2
|
-
//# sourceMappingURL=VectorCortexTab-B3yisAyB.js.map
|