pi-mega-compact 0.19.3 → 0.20.1

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 (114) hide show
  1. package/dist/config/vector-cortex.js +24 -0
  2. package/dist/config.js +1 -1
  3. package/dist/extensions/dashboard-server/routes-cache.test/_helpers.js +2 -0
  4. package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +2 -0
  5. package/dist/extensions/dashboard-server/routes-vector-cortex-helpers.js +100 -0
  6. package/dist/extensions/dashboard-server/routes-vector-cortex-residual.js +51 -0
  7. package/dist/extensions/dashboard-server/routes-vector-cortex-shards.js +48 -0
  8. package/dist/extensions/dashboard-server/routes-vector-cortex.js +2 -0
  9. package/dist/extensions/dashboard-server/routes.js +1 -1
  10. package/dist/extensions/dashboard-server/server.js +41 -16
  11. package/dist/extensions/dashboard-server/tailscale.js +32 -0
  12. package/dist/src/config/vector-cortex.js +24 -0
  13. package/dist/src/config.js +1 -1
  14. package/dist/src/vector-cortex/residual/codec.js +224 -0
  15. package/dist/src/vector-cortex/residual/dct.js +158 -0
  16. package/dist/src/vector-cortex/residual/fixture-payload.js +77 -0
  17. package/dist/src/vector-cortex/residual/gf256.js +182 -0
  18. package/dist/src/vector-cortex/residual/parity.js +245 -0
  19. package/dist/src/vector-cortex/residual/quantize.js +200 -0
  20. package/dist/src/vector-cortex/residual/stream.js +124 -0
  21. package/dist/src/vector-cortex/residual/types.js +55 -0
  22. package/dist/src/vector-cortex/shards/exact.js +134 -0
  23. package/dist/src/vector-cortex/shards/manifest.js +237 -0
  24. package/dist/src/vector-cortex/shards/semantic.js +137 -0
  25. package/dist/src/vector-cortex/shards/types.js +51 -0
  26. package/dist/vector-cortex/residual/codec.js +224 -0
  27. package/dist/vector-cortex/residual/dct.js +158 -0
  28. package/dist/vector-cortex/residual/fixture-payload.js +77 -0
  29. package/dist/vector-cortex/residual/gf256.js +182 -0
  30. package/dist/vector-cortex/residual/parity.js +245 -0
  31. package/dist/vector-cortex/residual/quantize.js +200 -0
  32. package/dist/vector-cortex/residual/stream.js +124 -0
  33. package/dist/vector-cortex/residual/types.js +55 -0
  34. package/dist/vector-cortex/shards/exact.js +134 -0
  35. package/dist/vector-cortex/shards/manifest.js +237 -0
  36. package/dist/vector-cortex/shards/semantic.js +137 -0
  37. package/dist/vector-cortex/shards/types.js +51 -0
  38. package/extensions/dashboard-client/dist/assets/{AreaChart-DqiFSnDx.js → AreaChart-n4z5w9Ox.js} +2 -2
  39. package/extensions/dashboard-client/dist/assets/{AreaChart-DqiFSnDx.js.map → AreaChart-n4z5w9Ox.js.map} +1 -1
  40. package/extensions/dashboard-client/dist/assets/{BarChart-Cqg-PQMK.js → BarChart-BLGjWWBr.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{BarChart-Cqg-PQMK.js.map → BarChart-BLGjWWBr.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/{CacheTab-BPNs0xIF.js → CacheTab-CAnrKKVK.js} +2 -2
  43. package/extensions/dashboard-client/dist/assets/{CacheTab-BPNs0xIF.js.map → CacheTab-CAnrKKVK.js.map} +1 -1
  44. package/extensions/dashboard-client/dist/assets/{EventsTab-BQf7OGkf.js → EventsTab-D-GL7Ngq.js} +2 -2
  45. package/extensions/dashboard-client/dist/assets/{EventsTab-BQf7OGkf.js.map → EventsTab-D-GL7Ngq.js.map} +1 -1
  46. package/extensions/dashboard-client/dist/assets/{HealthTab-B14TaSPN.js → HealthTab-C4x5qQ8s.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{HealthTab-B14TaSPN.js.map → HealthTab-C4x5qQ8s.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-D8lkRoa1.js → MaintenanceTab-BSPs0eq5.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-D8lkRoa1.js.map → MaintenanceTab-BSPs0eq5.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BOWtGfpx.js → MemoryMapTab-BWEUtTSu.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-BOWtGfpx.js.map → MemoryMapTab-BWEUtTSu.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/{MetricsTab-7XI9cWaX.js → MetricsTab-Dhm1c3Cx.js} +2 -2
  53. package/extensions/dashboard-client/dist/assets/{MetricsTab-7XI9cWaX.js.map → MetricsTab-Dhm1c3Cx.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{OverviewTab-C9KaGYvh.js → OverviewTab-Cm6cySiQ.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{OverviewTab-C9KaGYvh.js.map → OverviewTab-Cm6cySiQ.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/{ReposTab-BwESNhox.js → ReposTab-DxLN1N4K.js} +2 -2
  57. package/extensions/dashboard-client/dist/assets/{ReposTab-BwESNhox.js.map → ReposTab-DxLN1N4K.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{SessionsTab-DKH55Rda.js → SessionsTab-CZuI4ISW.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{SessionsTab-DKH55Rda.js.map → SessionsTab-CZuI4ISW.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{SetupTab-zDxf-nJd.js → SetupTab-C_0VOomm.js} +2 -2
  61. package/extensions/dashboard-client/dist/assets/{SetupTab-zDxf-nJd.js.map → SetupTab-C_0VOomm.js.map} +1 -1
  62. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-C9isog4L.js → TimeSavedCard-BhbaRLmi.js} +2 -2
  63. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-C9isog4L.js.map → TimeSavedCard-BhbaRLmi.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/{TurnsTab-ciI6ydvj.js → TurnsTab-CXJmbjje.js} +2 -2
  65. package/extensions/dashboard-client/dist/assets/{TurnsTab-ciI6ydvj.js.map → TurnsTab-CXJmbjje.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js +2 -0
  67. package/extensions/dashboard-client/dist/assets/VectorCortexTab-BGe9hu3r.js.map +1 -0
  68. package/extensions/dashboard-client/dist/assets/{WikiTab-DcYHc734.js → WikiTab-C5uvMCzp.js} +2 -2
  69. package/extensions/dashboard-client/dist/assets/{WikiTab-DcYHc734.js.map → WikiTab-C5uvMCzp.js.map} +1 -1
  70. package/extensions/dashboard-client/dist/assets/{button-DF8lx4bt.js → button-Cl_fxJcg.js} +2 -2
  71. package/extensions/dashboard-client/dist/assets/{button-DF8lx4bt.js.map → button-Cl_fxJcg.js.map} +1 -1
  72. package/extensions/dashboard-client/dist/assets/{card-DIoDheSZ.js → card-BH8Le5YM.js} +2 -2
  73. package/extensions/dashboard-client/dist/assets/{card-DIoDheSZ.js.map → card-BH8Le5YM.js.map} +1 -1
  74. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BFRzeYX3.js → generateCategoricalChart-sZ6ZNtBi.js} +2 -2
  75. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-BFRzeYX3.js.map → generateCategoricalChart-sZ6ZNtBi.js.map} +1 -1
  76. package/extensions/dashboard-client/dist/assets/{index-DSZON0Yi.js → index-CX9zv8cJ.js} +3 -3
  77. package/extensions/dashboard-client/dist/assets/{index-DSZON0Yi.js.map → index-CX9zv8cJ.js.map} +1 -1
  78. package/extensions/dashboard-client/dist/assets/{switch-l4qo22mU.js → switch-CXJhcjhM.js} +2 -2
  79. package/extensions/dashboard-client/dist/assets/{switch-l4qo22mU.js.map → switch-CXJhcjhM.js.map} +1 -1
  80. package/extensions/dashboard-client/dist/assets/{toggle-DPn6td1_.js → toggle-CoLtIc6y.js} +2 -2
  81. package/extensions/dashboard-client/dist/assets/{toggle-DPn6td1_.js.map → toggle-CoLtIc6y.js.map} +1 -1
  82. package/extensions/dashboard-client/dist/assets/{useSSE-BLmolqTJ.js → useSSE-fSXho606.js} +2 -2
  83. package/extensions/dashboard-client/dist/assets/{useSSE-BLmolqTJ.js.map → useSSE-fSXho606.js.map} +1 -1
  84. package/extensions/dashboard-client/dist/index.html +1 -1
  85. package/extensions/dashboard-client/src/api/vector-cortex.ts +9 -0
  86. package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +35 -0
  87. package/extensions/dashboard-client/src/types/vector-cortex.ts +13 -0
  88. package/extensions/dashboard-server/api-contracts/vector-cortex.ts +53 -0
  89. package/extensions/dashboard-server/routes-cache.test/_helpers.ts +2 -0
  90. package/extensions/dashboard-server/routes-rag-settings-helpers.ts +12 -0
  91. package/extensions/dashboard-server/routes-vector-cortex-helpers.ts +110 -0
  92. package/extensions/dashboard-server/routes-vector-cortex-residual.ts +60 -0
  93. package/extensions/dashboard-server/routes-vector-cortex-shards.ts +57 -0
  94. package/extensions/dashboard-server/routes-vector-cortex.ts +2 -0
  95. package/extensions/dashboard-server/routes.ts +2 -0
  96. package/extensions/dashboard-server/server.ts +46 -17
  97. package/extensions/dashboard-server/tailscale.ts +32 -0
  98. package/package.json +1 -1
  99. package/src/config/vector-cortex.ts +26 -0
  100. package/src/config.ts +2 -0
  101. package/src/vector-cortex/residual/codec.ts +292 -0
  102. package/src/vector-cortex/residual/dct.ts +166 -0
  103. package/src/vector-cortex/residual/fixture-payload.ts +90 -0
  104. package/src/vector-cortex/residual/gf256.ts +196 -0
  105. package/src/vector-cortex/residual/parity.ts +283 -0
  106. package/src/vector-cortex/residual/quantize.ts +230 -0
  107. package/src/vector-cortex/residual/stream.ts +135 -0
  108. package/src/vector-cortex/residual/types.ts +236 -0
  109. package/src/vector-cortex/shards/exact.ts +141 -0
  110. package/src/vector-cortex/shards/manifest.ts +276 -0
  111. package/src/vector-cortex/shards/semantic.ts +156 -0
  112. package/src/vector-cortex/shards/types.ts +212 -0
  113. package/extensions/dashboard-client/dist/assets/VectorCortexTab-qTZ7NWng.js +0 -2
  114. package/extensions/dashboard-client/dist/assets/VectorCortexTab-qTZ7NWng.js.map +0 -1
@@ -0,0 +1,135 @@
1
+ /**
2
+ * vector-cortex/residual/stream.ts — canonical PROTECTED STREAM serialization
3
+ * for the VC4B residual codec.
4
+ *
5
+ * The protected stream is `header + all block scales/coefficient arrays +
6
+ * corrections` (RESIDUAL_CODEC §erasure parity), serialized in exactly this
7
+ * canonical order so encode and decode are byte-symmetric:
8
+ *
9
+ * header (46 bytes) magic `VCR1` | u32 LE originalLength | 32-byte SHA-256
10
+ * | u16 LE blockSize | u16 LE k | u16 LE m
11
+ * blocks for each block in ascending index:
12
+ * float32 LE scale | 4096 * int16 LE coefficient
13
+ * corrections varint blockCount, then per non-empty block
14
+ * u32 LE blockIndex | varint count
15
+ * | count * (u16 LE offset, u8 original)
16
+ *
17
+ * Pure serialization: no storage, no console, no network (PREVENT-PI-004 /
18
+ * PREVENT-011).
19
+ */
20
+
21
+ import {
22
+ parseCorrections,
23
+ serializeCorrections,
24
+ } from "./quantize.js";
25
+ import {
26
+ RESIDUAL_BLOCK_SIZE,
27
+ RESIDUAL_HEADER_BYTES,
28
+ RESIDUAL_MAGIC,
29
+ RS_DATA_SHARDS,
30
+ RS_PARITY_SHARDS,
31
+ type QuantizedBlockV1,
32
+ type ResidualCodecV1,
33
+ type ResidualHeaderV1,
34
+ } from "./types.js";
35
+
36
+ /** Per-block serialized size: float32 scale + n int16 coefficients. */
37
+ export function blockBytes(blockSize: number = RESIDUAL_BLOCK_SIZE): number {
38
+ return 4 + blockSize * 2;
39
+ }
40
+
41
+ /** Serialize the canonical 46-byte header. */
42
+ export function serializeHeader(header: ResidualHeaderV1): Uint8Array {
43
+ const out = new Uint8Array(RESIDUAL_HEADER_BYTES);
44
+ const view = new DataView(out.buffer);
45
+ for (let i = 0; i < 4; i++) out[i] = RESIDUAL_MAGIC.charCodeAt(i);
46
+ view.setUint32(4, header.originalLength, true);
47
+ const digest = Buffer.from(header.payloadDigest, "hex");
48
+ out.set(digest.subarray(0, 32), 8);
49
+ view.setUint16(40, header.blockSize, true);
50
+ view.setUint16(42, header.dataShards, true);
51
+ view.setUint16(44, header.parityShards, true);
52
+ return out;
53
+ }
54
+
55
+ /** Parse the canonical header. Returns null on magic/geometry mismatch. */
56
+ export function parseHeader(bytes: Uint8Array): ResidualHeaderV1 | null {
57
+ if (bytes.length < RESIDUAL_HEADER_BYTES) return null;
58
+ for (let i = 0; i < 4; i++) {
59
+ if (bytes[i] !== RESIDUAL_MAGIC.charCodeAt(i)) return null;
60
+ }
61
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
62
+ const originalLength = view.getUint32(4, true);
63
+ const payloadDigest = Buffer.from(bytes.subarray(8, 40)).toString("hex");
64
+ const blockSize = view.getUint16(40, true);
65
+ const dataShards = view.getUint16(42, true);
66
+ const parityShards = view.getUint16(44, true);
67
+ if (blockSize !== RESIDUAL_BLOCK_SIZE) return null;
68
+ if (dataShards !== RS_DATA_SHARDS || parityShards !== RS_PARITY_SHARDS) return null;
69
+ return {
70
+ magic: RESIDUAL_MAGIC,
71
+ originalLength,
72
+ payloadDigest,
73
+ blockSize: RESIDUAL_BLOCK_SIZE,
74
+ dataShards: RS_DATA_SHARDS,
75
+ parityShards: RS_PARITY_SHARDS,
76
+ };
77
+ }
78
+
79
+ /** Serialize the full protected stream for one encoded artifact. */
80
+ export function serializeStream(codec: ResidualCodecV1): Uint8Array {
81
+ const head = serializeHeader(codec.header);
82
+ const perBlock = blockBytes(codec.header.blockSize);
83
+ const corrections = serializeCorrections(codec.corrections);
84
+ const out = new Uint8Array(
85
+ head.length + codec.blocks.length * perBlock + corrections.length,
86
+ );
87
+ out.set(head, 0);
88
+ const view = new DataView(out.buffer);
89
+ let pos = head.length;
90
+ for (const block of codec.blocks) {
91
+ view.setFloat32(pos, block.scale, true);
92
+ pos += 4;
93
+ for (let i = 0; i < block.coefficients.length; i++) {
94
+ view.setInt16(pos, block.coefficients[i]!, true);
95
+ pos += 2;
96
+ }
97
+ }
98
+ out.set(corrections, pos);
99
+ return out;
100
+ }
101
+
102
+ /** Parse a protected stream back into the codec artifact. Null on malformed. */
103
+ export function parseStream(stream: Uint8Array): ResidualCodecV1 | null {
104
+ const header = parseHeader(stream);
105
+ if (!header) return null;
106
+ const perBlock = blockBytes(header.blockSize);
107
+ const blockCount = Math.ceil(header.originalLength / header.blockSize);
108
+ const bodyEnd = RESIDUAL_HEADER_BYTES + blockCount * perBlock;
109
+ if (stream.length < bodyEnd) return null;
110
+ const view = new DataView(stream.buffer, stream.byteOffset, stream.byteLength);
111
+ const blocks: QuantizedBlockV1[] = [];
112
+ let pos = RESIDUAL_HEADER_BYTES;
113
+ for (let b = 0; b < blockCount; b++) {
114
+ const scale = view.getFloat32(pos, true);
115
+ pos += 4;
116
+ const coefficients = new Int16Array(header.blockSize);
117
+ for (let i = 0; i < header.blockSize; i++) {
118
+ coefficients[i] = view.getInt16(pos, true);
119
+ pos += 2;
120
+ }
121
+ blocks.push({ scale, coefficients });
122
+ }
123
+ const parsed = parseCorrections(stream, pos);
124
+ if (!parsed) return null;
125
+ // Every correction must name a block that exists.
126
+ for (const block of parsed.blocks) {
127
+ if (block.blockIndex >= blockCount) return null;
128
+ }
129
+ return {
130
+ schema: "residual-codec-v1",
131
+ header,
132
+ blocks,
133
+ corrections: parsed.blocks,
134
+ };
135
+ }
@@ -0,0 +1,236 @@
1
+ /**
2
+ * vector-cortex/residual/types.ts — reversible residual payload codec (VC4B).
3
+ *
4
+ * Owns `ResidualCodecV1` / `ParityShardV1` — the contract of the sprint failure
5
+ * triad:
6
+ *
7
+ * A = admitted residual (DCT + int16 + exact corrections) + RS(9,6) parity;
8
+ * B = exact compressed bytes (forced when the >95% accounting rejects A);
9
+ * C = ledger bytes (forced when A/B decode fails).
10
+ *
11
+ * Semantic vectors NEVER claim to recover exact text. Exact bytes come only from
12
+ * exact payload shards (VC4A `ExactShardV1`) or this REVERSIBLE codec: a block
13
+ * DCT-II analysis, int16 quantization, and a block-scoped exact correction
14
+ * stream that makes post-decode byte error exactly zero for admitted artifacts.
15
+ * Numeric erasure parity protects the codec bytes; it is not a substitute for
16
+ * the exact payload (RESIDUAL_CODEC.md).
17
+ *
18
+ * Consumes only reviewer-accepted predecessor contracts (VC1A EventV2 bytes via
19
+ * VC4A shard ranges) and the common contracts. Pure types + registered
20
+ * conformance IDs: no storage, no console, no network (PREVENT-PI-004 /
21
+ * PREVENT-011).
22
+ */
23
+
24
+ /** Fixed transform block length (RESIDUAL_CODEC §byte scope: 4096). */
25
+ export const RESIDUAL_BLOCK_SIZE = 4096;
26
+
27
+ /** Reed–Solomon shard geometry: k=6 data shards, m=3 parity shards. */
28
+ export const RS_DATA_SHARDS = 6;
29
+ export const RS_PARITY_SHARDS = 3;
30
+ export const RS_TOTAL_SHARDS = RS_DATA_SHARDS + RS_PARITY_SHARDS;
31
+
32
+ /** GF(2^8) primitive polynomial for the parity field (0x11d). */
33
+ export const GF_PRIMITIVE_POLYNOMIAL = 0x11d;
34
+
35
+ /** Header magic bytes `VCR1`. */
36
+ export const RESIDUAL_MAGIC = "VCR1";
37
+
38
+ /**
39
+ * Admission ratio: residual is admitted only when its FULL encoded size is at
40
+ * most `floor(0.95 * exactCompressedSize)` (RESIDUAL_CODEC §admission). The
41
+ * accounting counts every persisted byte — header, scales, coefficients,
42
+ * corrections, shard metadata, all 9 shards, and digests.
43
+ */
44
+ export const ADMISSION_NUMERATOR = 95;
45
+ export const ADMISSION_DENOMINATOR = 100;
46
+
47
+ /**
48
+ * Canonical header of an encoded residual artifact. Serialized (little-endian)
49
+ * as: magic `VCR1` (4 bytes), u32 original length, 32-byte SHA-256 of the
50
+ * ORIGINAL payload, u16 block size, u16 data shard count `k`, u16 parity count
51
+ * `m` — 46 bytes total.
52
+ */
53
+ export interface ResidualHeaderV1 {
54
+ readonly magic: typeof RESIDUAL_MAGIC;
55
+ /** Original (pre-padding) payload length in bytes. */
56
+ readonly originalLength: number;
57
+ /** SHA-256 of the original payload bytes, lowercase hex (64 chars). */
58
+ readonly payloadDigest: string;
59
+ readonly blockSize: typeof RESIDUAL_BLOCK_SIZE;
60
+ readonly dataShards: typeof RS_DATA_SHARDS;
61
+ readonly parityShards: typeof RS_PARITY_SHARDS;
62
+ }
63
+
64
+ /** Serialized header byte length: 4 + 4 + 32 + 2 + 2 + 2. */
65
+ export const RESIDUAL_HEADER_BYTES = 46;
66
+
67
+ /**
68
+ * One transform block's quantized coefficients. `scale` is the per-block float32
69
+ * scale `max(abs(c))/32767` (exactly 0 for an all-zero block); `coefficients`
70
+ * are the int16 quantized DCT-II coefficients in ascending frequency order.
71
+ */
72
+ export interface QuantizedBlockV1 {
73
+ /** Per-block float32 LE scale. Zero for an all-zero coefficient block. */
74
+ readonly scale: number;
75
+ /** Int16 coefficients, length exactly `RESIDUAL_BLOCK_SIZE`. */
76
+ readonly coefficients: Int16Array;
77
+ }
78
+
79
+ /**
80
+ * One exact byte correction inside a block: the reconstruction differed from
81
+ * the original at `offset`, and `original` is the authoritative byte.
82
+ */
83
+ export interface CorrectionV1 {
84
+ /** Offset within the block, 0..4095. */
85
+ readonly offset: number;
86
+ /** The original (authoritative) byte value, 0..255. */
87
+ readonly original: number;
88
+ }
89
+
90
+ /**
91
+ * The block-scoped exact correction stream. Blocks appear in ascending
92
+ * `blockIndex`; each block's corrections are sorted by ascending offset with no
93
+ * duplicate offset. Omitted blocks have an implicit count of zero.
94
+ */
95
+ export interface BlockCorrectionsV1 {
96
+ readonly blockIndex: number;
97
+ readonly corrections: readonly CorrectionV1[];
98
+ }
99
+
100
+ /**
101
+ * A fully encoded residual artifact before shard splitting: the header plus the
102
+ * per-block quantization and the exact correction stream. Serializing this in
103
+ * canonical order produces the PROTECTED STREAM that the parity layer splits.
104
+ */
105
+ export interface ResidualCodecV1 {
106
+ readonly schema: "residual-codec-v1";
107
+ readonly header: ResidualHeaderV1;
108
+ readonly blocks: readonly QuantizedBlockV1[];
109
+ readonly corrections: readonly BlockCorrectionsV1[];
110
+ }
111
+
112
+ /**
113
+ * One Reed–Solomon shard over the protected stream. Shards 0..5 are the
114
+ * systematic data shards (the protected stream split into `k=6` equal,
115
+ * zero-padded pieces); shards 6..8 are the parity shards, in that order. Every
116
+ * shard carries its own SHA-256 so an unknown corruption is DETECTED (and can
117
+ * then be marked as a known erasure) even though it is never blindly corrected.
118
+ */
119
+ export interface ParityShardV1 {
120
+ readonly schema: "parity-shard-v1";
121
+ /** Shard index 0..8 (0..5 data, 6..8 parity). */
122
+ readonly index: number;
123
+ readonly kind: "data" | "parity";
124
+ /** Shard payload bytes; every shard has the same length. */
125
+ readonly bytes: Uint8Array;
126
+ /** SHA-256 of `bytes`, lowercase hex. */
127
+ readonly digest: string;
128
+ /** Length of the UNPADDED protected stream (needed to truncate on recovery). */
129
+ readonly streamLength: number;
130
+ }
131
+
132
+ /** Byte accounting handed forward to VC4C (spec §next handoff). */
133
+ export interface ResidualAccountingV1 {
134
+ /** Every persisted residual byte: header + scales + coefficients + corrections + shards + digests. */
135
+ readonly encodedSize: number;
136
+ /** Size of the competing exact compressed representation. */
137
+ readonly exactCompressedSize: number;
138
+ /** `floor(0.95 * exactCompressedSize)` — the inclusive admission ceiling. */
139
+ readonly admissionCeiling: number;
140
+ /** Number of correction entries across every block (density numerator). */
141
+ readonly correctionCount: number;
142
+ /** Number of transform blocks. */
143
+ readonly blockCount: number;
144
+ }
145
+
146
+ /** Failure codes the residual codec / parity layer can return. */
147
+ export type ResidualFailureCode =
148
+ | "RES_QUANTIZE_RANGE"
149
+ | "RES_TOO_MANY_ERASURES"
150
+ | "RES_DUPLICATE_SHARD_INDEX"
151
+ | "RES_SHARD_DIGEST_MISMATCH"
152
+ | "RES_SHARD_LENGTH_MISMATCH"
153
+ | "RES_SINGULAR_MATRIX"
154
+ | "RES_PAYLOAD_DIGEST_MISMATCH"
155
+ | "RES_HEADER_INVALID"
156
+ | "RES_CORRECTION_DUPLICATE_OFFSET"
157
+ | "RES_CORRECTION_RANGE"
158
+ | "RES_NOT_ADMITTED";
159
+
160
+ /** Encode result: an admitted artifact, or the exact reason it was not admitted. */
161
+ export type ResidualEncodeResult =
162
+ | {
163
+ ok: true;
164
+ /** Mode A: the residual was admitted. */
165
+ admitted: true;
166
+ codec: ResidualCodecV1;
167
+ shards: readonly ParityShardV1[];
168
+ accounting: ResidualAccountingV1;
169
+ }
170
+ | {
171
+ ok: true;
172
+ /** Mode B: encode succeeded but accounting rejected it; store exact bytes. */
173
+ admitted: false;
174
+ code: "RES_NOT_ADMITTED";
175
+ accounting: ResidualAccountingV1;
176
+ }
177
+ | { ok: false; code: ResidualFailureCode };
178
+
179
+ /** Decode result: the exact original bytes, or the exact failure code. */
180
+ export type ResidualDecodeResult =
181
+ | { ok: true; bytes: Uint8Array }
182
+ | { ok: false; code: ResidualFailureCode };
183
+
184
+ /** Parity reconstruction result over a (possibly partial) shard set. */
185
+ export type ParityRecoveryResult =
186
+ | { ok: true; stream: Uint8Array; recoveredIndices: readonly number[] }
187
+ | { ok: false; code: ResidualFailureCode };
188
+
189
+ /** The two structured events the VC4B reporter emits. */
190
+ export type ResidualEventName =
191
+ | "vector_cortex_residual_admitted"
192
+ | "vector_cortex_parity_recovery_failed";
193
+
194
+ /** Injected emit callback — same (event, fields) shape as the other VC seams. */
195
+ export type ResidualEmitter = (
196
+ event: ResidualEventName,
197
+ fields: Record<string, unknown>,
198
+ ) => void;
199
+
200
+ /** Typed, best-effort reporter bound to the two residual event names. */
201
+ export interface ResidualReporter {
202
+ readonly residualAdmitted: (fields: Record<string, unknown>) => void;
203
+ readonly parityRecoveryFailed: (fields: Record<string, unknown>) => void;
204
+ }
205
+
206
+ /**
207
+ * Aggregate-only residual metrics exposed to the dashboard. NEVER payload:
208
+ * counts, byte totals and ratios only (SECURITY_PRIVACY — the exact ledger is
209
+ * not training data and residual payloads are never rendered).
210
+ */
211
+ export interface ResidualMetricsV1 {
212
+ readonly encodeAttempts: number;
213
+ readonly admittedCount: number;
214
+ readonly rejectedCount: number;
215
+ readonly recoveryFailures: number;
216
+ readonly encodedByteTotal: number;
217
+ readonly exactByteTotal: number;
218
+ }
219
+
220
+ /**
221
+ * Registered RES conformance ID range (RES-001..050). The acceptance test reads
222
+ * these rows from the v2 manifest and asserts each returns its manifest
223
+ * `ok`/`code`. The three named assertions (RES-DCT-001 / RES-RS-002 /
224
+ * RES-ADMIT-003) live alongside them.
225
+ */
226
+ export const RES_IDS: readonly string[] = Array.from(
227
+ { length: 50 },
228
+ (_v, i) => `RES-${String(i + 1).padStart(3, "0")}`,
229
+ );
230
+
231
+ /** Named RES conformance assertions (the sprint's headline rows). */
232
+ export const RES_NAMED_IDS = [
233
+ "RES-DCT-001",
234
+ "RES-RS-002",
235
+ "RES-ADMIT-003",
236
+ ] as const;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * vector-cortex/shards/exact.ts — exact tier partition (VC4A).
3
+ *
4
+ * Carves the session's PROTECTED spans — every tool call/result pair, every
5
+ * anchor, every invalid UTF-8 event — into `ExactShardV1` payloads of the
6
+ * ORIGINAL bytes, verbatim and never normalized (SHD-UTF8-002: invalid bytes
7
+ * are exact-only and preserved unchanged — the codec's strict-fatal classifier
8
+ * means an invalid event has no lossy text to re-encode; we copy `originalBytes`
9
+ * directly). Each protected span is ATOMIC: a tool call/result pair is one
10
+ * `ProtectedSpan`, so no exact shard EVER splits a pair, even when the pair
11
+ * straddles the target-size boundary (SHD-PAIR-001).
12
+ *
13
+ * The partition walks the protected spans in canonical stream order (ascending
14
+ * first-seq), accrues each span's bytes, and closes an exact shard the moment
15
+ * adding the next atomic span would exceed `targetSize`. A single span over the
16
+ * budget still occupies exactly one shard — the pair case never splits.
17
+ *
18
+ * Triad: A = used with the semantic tier; B = the same exact spans preserved
19
+ * alongside extractive-derived semantic content; C = exact anchors/current
20
+ * transcript ONLY (this partition alone, with zero semantic shards).
21
+ *
22
+ * Pure/deterministic: hashes + array walking only, no storage, no console, no
23
+ * network (PREVENT-PI-004 / PREVENT-011).
24
+ */
25
+ import { createHash } from "node:crypto";
26
+ import type { EventV2 } from "../ledger/types.js";
27
+ import { cumulativeOffsets } from "./semantic.js";
28
+ import type { ExactPartitionInput, ExactPartitionResult, ExactShardCase, ExactShardV1, ProtectedSpan } from "./types.js";
29
+
30
+ /** Deterministic exact-shard digest over the verbatim original bytes. */
31
+ function sealExactDigest(sessionId: string, bytes: Uint8Array): string {
32
+ const h = createHash("sha256");
33
+ h.update(`exact-shard-v1|${sessionId}|`);
34
+ h.update(bytes);
35
+ return `sha256:${h.digest("hex")}`;
36
+ }
37
+
38
+ /** Combine per-span cases into one shard case (invalid dominates, then tool-pair). */
39
+ function combineCase(span: ProtectedSpan, acc: ExactShardCase): ExactShardCase {
40
+ if (span.case === "invalid-utf8" || acc === "invalid-utf8") return "invalid-utf8";
41
+ if (span.case === "tool-pair" || acc === "tool-pair") return "tool-pair";
42
+ return "anchor";
43
+ }
44
+
45
+ /** Concatenate an ordered group of events' original bytes, verbatim. */
46
+ function concatBytes(events: readonly EventV2[]): Uint8Array {
47
+ let len = 0;
48
+ for (const e of events) len += e.originalBytes.length;
49
+ const out = new Uint8Array(len);
50
+ let off = 0;
51
+ for (const e of events) {
52
+ out.set(e.originalBytes, off);
53
+ off += e.originalBytes.length;
54
+ }
55
+ return out;
56
+ }
57
+
58
+ /**
59
+ * Partition the exact tier (task 3). Returns `ok:true` with a list of
60
+ * `ExactShardV1` whose (sorted) ranges are contiguous, non-overlapping and
61
+ * jointly cover every protected span exactly once, each preserving the original
62
+ * bytes verbatim. Defensive failures mirror the semantic tier: a bad target size
63
+ * rejects with `SHD_INVALID_TARGET_SIZE`; a protected span referencing an event
64
+ * outside the session's stream, or a mixed-session span, rejects with
65
+ * `SHD_CROSS_SESSION`.
66
+ */
67
+ export function partitionExact(input: ExactPartitionInput): ExactPartitionResult {
68
+ const { sessionId, events, protectedSpans, targetSize } = input;
69
+ if (!Number.isFinite(targetSize) || targetSize <= 0) {
70
+ return { ok: false, code: "SHD_INVALID_TARGET_SIZE" };
71
+ }
72
+ const stream = new Set(events.map((e) => e.seq.toString()));
73
+ for (const span of protectedSpans) {
74
+ if (span.events.some((e) => e.sessionId !== sessionId || !stream.has(e.seq.toString()))) {
75
+ return { ok: false, code: "SHD_CROSS_SESSION" };
76
+ }
77
+ }
78
+ const offsets = cumulativeOffsets(events);
79
+ if (protectedSpans.length === 0) return { ok: true, shards: [] };
80
+
81
+ // Process protected spans in canonical stream order (ascending first-seq;
82
+ // equal first-seq preserves input order for determinism).
83
+ const ordered = [...protectedSpans].sort((a, b) => {
84
+ const as = a.events.length ? a.events[0].seq : 0n;
85
+ const bs = b.events.length ? b.events[0].seq : 0n;
86
+ return as < bs ? -1 : as > bs ? 1 : 0;
87
+ });
88
+
89
+ const shards: ExactShardV1[] = [];
90
+ let batch: ProtectedSpan[] = [];
91
+ let batchBytes = 0;
92
+ let batchCase: ExactShardCase = "anchor";
93
+
94
+ const spanBytes = (s: ProtectedSpan): number =>
95
+ s.events.reduce((n, e) => n + e.originalBytes.length, 0);
96
+
97
+ const flush = (): void => {
98
+ if (batch.length === 0) return;
99
+ const first = batch[0];
100
+ const last = batch[batch.length - 1];
101
+ const firstEv = first.events[0];
102
+ const lastEv = last.events[last.events.length - 1];
103
+ const start = offsets.of(firstEv.seq);
104
+ const end = offsets.of(lastEv.seq);
105
+ const byteStart = start ? start.byteStart : 0;
106
+ const byteEnd = end ? end.byteEnd : byteStart;
107
+ const bytes = concatBytes(batch.flatMap((s) => s.events));
108
+ shards.push({
109
+ schema: "exact-shard-v1",
110
+ sessionId,
111
+ range: {
112
+ sessionId,
113
+ seqStart: firstEv.seq,
114
+ seqEnd: lastEv.seq,
115
+ byteStart,
116
+ byteEnd,
117
+ },
118
+ kind: "exact",
119
+ originalBytes: bytes,
120
+ digest: sealExactDigest(sessionId, bytes),
121
+ byteCount: batchBytes,
122
+ case: batchCase,
123
+ });
124
+ batch = [];
125
+ batchBytes = 0;
126
+ batchCase = "anchor";
127
+ };
128
+
129
+ for (const span of ordered) {
130
+ const sz = spanBytes(span);
131
+ // Close at a complete-span boundary when adding this atomic span would
132
+ // exceed the budget and we already hold at least one complete span.
133
+ if (batch.length > 0 && batchBytes + sz > targetSize) flush();
134
+ batch.push(span);
135
+ batchBytes += sz;
136
+ batchCase = combineCase(span, batchCase);
137
+ }
138
+ flush();
139
+
140
+ return { ok: true, shards };
141
+ }