@mmnto/totem 1.105.0 → 1.107.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/ast-classifier.d.ts +3 -3
  2. package/dist/ast-classifier.js +12 -3
  3. package/dist/ast-classifier.js.map +1 -1
  4. package/dist/ast-classifier.test.js +33 -2
  5. package/dist/ast-classifier.test.js.map +1 -1
  6. package/dist/capability/schema.d.ts +2 -2
  7. package/dist/errors.d.ts +3 -1
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js.map +1 -1
  10. package/dist/index.d.ts +8 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +11 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/ledger.d.ts +92 -4
  15. package/dist/ledger.d.ts.map +1 -1
  16. package/dist/ledger.js +91 -13
  17. package/dist/ledger.js.map +1 -1
  18. package/dist/qbd/compliance.d.ts +216 -0
  19. package/dist/qbd/compliance.d.ts.map +1 -0
  20. package/dist/qbd/compliance.js +490 -0
  21. package/dist/qbd/compliance.js.map +1 -0
  22. package/dist/qbd/compliance.test.d.ts +2 -0
  23. package/dist/qbd/compliance.test.d.ts.map +1 -0
  24. package/dist/qbd/compliance.test.js +539 -0
  25. package/dist/qbd/compliance.test.js.map +1 -0
  26. package/dist/qbd/correlation-id.d.ts +130 -0
  27. package/dist/qbd/correlation-id.d.ts.map +1 -0
  28. package/dist/qbd/correlation-id.js +224 -0
  29. package/dist/qbd/correlation-id.js.map +1 -0
  30. package/dist/qbd/correlation-id.test.d.ts +2 -0
  31. package/dist/qbd/correlation-id.test.d.ts.map +1 -0
  32. package/dist/qbd/correlation-id.test.js +136 -0
  33. package/dist/qbd/correlation-id.test.js.map +1 -0
  34. package/dist/qbd/record.d.ts +140 -0
  35. package/dist/qbd/record.d.ts.map +1 -0
  36. package/dist/qbd/record.js +419 -0
  37. package/dist/qbd/record.js.map +1 -0
  38. package/dist/qbd/record.test.d.ts +27 -0
  39. package/dist/qbd/record.test.d.ts.map +1 -0
  40. package/dist/qbd/record.test.js +607 -0
  41. package/dist/qbd/record.test.js.map +1 -0
  42. package/dist/rule-engine.test.js +85 -0
  43. package/dist/rule-engine.test.js.map +1 -1
  44. package/dist/session-id.d.ts.map +1 -1
  45. package/dist/session-id.js +19 -3
  46. package/dist/session-id.js.map +1 -1
  47. package/dist/session-id.test.js +35 -0
  48. package/dist/session-id.test.js.map +1 -1
  49. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Query-before-derive (QBD) correlation IDs — the join key between a corpus
3
+ * query event and the derive-class action it grounded (mmnto-ai/totem#2510).
4
+ *
5
+ * ## Why a bespoke ID and not `correlation_id`
6
+ *
7
+ * `LedgerEvent.correlation_id` is ADR-014's orchestrator→MCP trace ID and is a
8
+ * plain UUID. #2510 is explicitly NOT chartered to build the ADR-014 telemetry
9
+ * stack, so this slice carries its own field (`qbd_correlation_id`) with its
10
+ * own format. A UUID carries no mint instant, and the mint instant is exactly
11
+ * what makes falsifier 2 (post-hoc correlation) mechanically checkable.
12
+ *
13
+ * ## Format
14
+ *
15
+ * `qbd1-<mintInstantMs base36>-<16 hex random>` — e.g.
16
+ * `qbd1-2h1s4kbqr-9f2c0a7e51d34b60`.
17
+ *
18
+ * The ID is **self-dating**: it embeds the wall-clock instant at which it was
19
+ * minted. That is the whole point. Validation (below) cross-checks the embedded
20
+ * instant against the timestamp of the row carrying the ID, which turns
21
+ * "IDs must be minted at event-write time" from a convention into a schema
22
+ * constraint (#2510 falsifier 2: "a backfilled ID is a schema violation, not a
23
+ * data point").
24
+ *
25
+ * ## What the validation actually catches — and what it does not
26
+ *
27
+ * Catches (mechanically, at parse time, for every reader and writer):
28
+ * - a query row whose ID predates or postdates its own write instant beyond
29
+ * `QBD_MINT_TOLERANCE_MS` — i.e. an ID minted anywhere other than at the
30
+ * moment the row was written;
31
+ * - a derive row carrying an ID minted *after* the derive happened (an ID that
32
+ * did not exist when the derive ran cannot have grounded it);
33
+ * - a derive row carrying an ID minted longer ago than the correlation window
34
+ * (retroactively dressing an ancient query as this derive's grounding);
35
+ * - `qbd_correlation_id` stamped on an event type that has no query→derive
36
+ * semantics at all.
37
+ *
38
+ * On the tolerance: the checks are "beyond tolerance", NOT categorical. A
39
+ * mismatch inside `QBD_MINT_TOLERANCE_MS` passes in both directions, including
40
+ * a mint instant slightly in the future of its row. That window exists for
41
+ * clock granularity between two reads of the same clock, and it is small
42
+ * relative to the correlation window — but it is a real gap, and calling these
43
+ * checks categorical would overstate them.
44
+ *
45
+ * ## What this does NOT catch, stated precisely
46
+ *
47
+ * This is a per-row consistency check, so it cannot see relationships BETWEEN
48
+ * rows. Two attacks live in that gap:
49
+ *
50
+ * 1. **Backdated appends.** `mintQbdCorrelationId` takes its instant as an
51
+ * argument and is public API, and the ledger is append-only — so coherent
52
+ * query/derive pairs stamped in the past can simply be appended. No
53
+ * whole-file rewrite is needed. Each row passes this check individually.
54
+ * That attack is caught one layer up, by the append-only monotonicity check
55
+ * in `compliance.ts`, which degrades a scan whose timestamps regress. That
56
+ * check takes its reference from EVERY row in the file, not just QBD rows,
57
+ * so an adopted ledger's existing history is the baseline.
58
+ * 2. **A coherent whole-file rewrite** — and its degenerate case, an EMPTY or
59
+ * QBD-only ledger authored wholesale. With no prior history there is no
60
+ * monotonicity reference to violate, so internally consistent fake rows
61
+ * read clean. This is the same adversary as the rewrite: whoever authors
62
+ * the entire file controls its whole timeline. Conceded scope for v1 —
63
+ * nothing short of signing or an append-only server addresses it, and
64
+ * neither is chartered here.
65
+ *
66
+ * The realistic threat — a script or agent attaching correlation IDs to rows
67
+ * already on disk — is caught here. The other two are named rather than
68
+ * claimed solved, per the #2510 discipline.
69
+ */
70
+ /**
71
+ * Correlation window: a derive-class action counts as grounded by a query only
72
+ * if that query was minted within this window before it.
73
+ *
74
+ * The VALUE is borrowed from ADR-029 § 2's two-hour session window so this
75
+ * slice does not invent a second time constant. The DECISION to treat that
76
+ * span as a grounding-validity window is this slice's own, not the ADR's —
77
+ * ADR-029 § 2 defines a session-GROUPING heuristic for the recall metric, which
78
+ * is a different question, and it should not be cited as authority for this
79
+ * choice. Owned here as a design call: a shorter window would be a strictly
80
+ * harder test of the same claim, and the value is pinned so the pre-registered
81
+ * threshold is evaluated against a fixed rule rather than a tunable one.
82
+ *
83
+ * Note that consume-on-use (see `record.ts`) does most of the real work: the
84
+ * window bounds how STALE a grounding may be, but a query grounds only one
85
+ * derive regardless, so a generous window cannot inflate the numerator.
86
+ */
87
+ export declare const QBD_CORRELATION_WINDOW_MS: number;
88
+ /**
89
+ * Tolerance for clock jitter between minting an ID and stamping the row's
90
+ * `timestamp`. These happen microseconds apart in the same function, so this is
91
+ * generous; it exists so a coarse clock or a slow filesystem never manufactures
92
+ * a spurious schema violation.
93
+ */
94
+ export declare const QBD_MINT_TOLERANCE_MS = 2000;
95
+ /** Why a correlation ID failed validation. Rendered verbatim in accounting. */
96
+ export type QbdIdViolation = 'malformed-shape' | 'undecodable-mint-instant' | 'query-id-not-self-minted' | 'derive-id-minted-after-derive' | 'derive-id-older-than-window' | 'id-on-non-qbd-event';
97
+ export interface QbdIdCheckResult {
98
+ ok: boolean;
99
+ /** Populated when `ok` is false. */
100
+ violation?: QbdIdViolation;
101
+ /** Human-readable detail for accounting output. */
102
+ detail?: string;
103
+ }
104
+ /**
105
+ * Mint a correlation ID stamped with `mintedAtMs`.
106
+ *
107
+ * Callers MUST pass the same instant they stamp on the event row — see
108
+ * `record.ts`, which derives both from one `Date.now()` read. Every writer path
109
+ * in this slice goes through that module precisely so the two cannot drift.
110
+ */
111
+ export declare function mintQbdCorrelationId(mintedAtMs: number): string;
112
+ /**
113
+ * Decode the mint instant embedded in a correlation ID.
114
+ * Returns `undefined` when the ID is not a well-formed QBD ID.
115
+ */
116
+ export declare function decodeQbdMintInstant(id: string): number | undefined;
117
+ /**
118
+ * The minted-at-write-time contract, enforced structurally.
119
+ *
120
+ * `eventType` is the ledger row's `type`; `eventMs` is `Date.parse(row.timestamp)`.
121
+ *
122
+ * - `corpus_query`: the ID must be minted at the row's own instant (± tolerance).
123
+ * A query row is the ID's birth certificate; any other mint instant means the
124
+ * ID was attached later.
125
+ * - `derive_action`: the ID must be minted at or before the derive (± tolerance)
126
+ * and no earlier than one correlation window before it.
127
+ * - any other type: carrying the field at all is a violation.
128
+ */
129
+ export declare function checkQbdCorrelationId(id: string, eventType: string, eventMs: number): QbdIdCheckResult;
130
+ //# sourceMappingURL=correlation-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-id.d.ts","sourceRoot":"","sources":["../../src/qbd/correlation-id.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAeH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,QAAqB,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAqB1C,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,0BAA0B,GAC1B,0BAA0B,GAC1B,+BAA+B,GAC/B,6BAA6B,GAC7B,qBAAqB,CAAC;AAE1B,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,OAAO,CAAC;IACZ,oCAAoC;IACpC,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAO/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUnE;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,gBAAgB,CAgElB"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Query-before-derive (QBD) correlation IDs — the join key between a corpus
3
+ * query event and the derive-class action it grounded (mmnto-ai/totem#2510).
4
+ *
5
+ * ## Why a bespoke ID and not `correlation_id`
6
+ *
7
+ * `LedgerEvent.correlation_id` is ADR-014's orchestrator→MCP trace ID and is a
8
+ * plain UUID. #2510 is explicitly NOT chartered to build the ADR-014 telemetry
9
+ * stack, so this slice carries its own field (`qbd_correlation_id`) with its
10
+ * own format. A UUID carries no mint instant, and the mint instant is exactly
11
+ * what makes falsifier 2 (post-hoc correlation) mechanically checkable.
12
+ *
13
+ * ## Format
14
+ *
15
+ * `qbd1-<mintInstantMs base36>-<16 hex random>` — e.g.
16
+ * `qbd1-2h1s4kbqr-9f2c0a7e51d34b60`.
17
+ *
18
+ * The ID is **self-dating**: it embeds the wall-clock instant at which it was
19
+ * minted. That is the whole point. Validation (below) cross-checks the embedded
20
+ * instant against the timestamp of the row carrying the ID, which turns
21
+ * "IDs must be minted at event-write time" from a convention into a schema
22
+ * constraint (#2510 falsifier 2: "a backfilled ID is a schema violation, not a
23
+ * data point").
24
+ *
25
+ * ## What the validation actually catches — and what it does not
26
+ *
27
+ * Catches (mechanically, at parse time, for every reader and writer):
28
+ * - a query row whose ID predates or postdates its own write instant beyond
29
+ * `QBD_MINT_TOLERANCE_MS` — i.e. an ID minted anywhere other than at the
30
+ * moment the row was written;
31
+ * - a derive row carrying an ID minted *after* the derive happened (an ID that
32
+ * did not exist when the derive ran cannot have grounded it);
33
+ * - a derive row carrying an ID minted longer ago than the correlation window
34
+ * (retroactively dressing an ancient query as this derive's grounding);
35
+ * - `qbd_correlation_id` stamped on an event type that has no query→derive
36
+ * semantics at all.
37
+ *
38
+ * On the tolerance: the checks are "beyond tolerance", NOT categorical. A
39
+ * mismatch inside `QBD_MINT_TOLERANCE_MS` passes in both directions, including
40
+ * a mint instant slightly in the future of its row. That window exists for
41
+ * clock granularity between two reads of the same clock, and it is small
42
+ * relative to the correlation window — but it is a real gap, and calling these
43
+ * checks categorical would overstate them.
44
+ *
45
+ * ## What this does NOT catch, stated precisely
46
+ *
47
+ * This is a per-row consistency check, so it cannot see relationships BETWEEN
48
+ * rows. Two attacks live in that gap:
49
+ *
50
+ * 1. **Backdated appends.** `mintQbdCorrelationId` takes its instant as an
51
+ * argument and is public API, and the ledger is append-only — so coherent
52
+ * query/derive pairs stamped in the past can simply be appended. No
53
+ * whole-file rewrite is needed. Each row passes this check individually.
54
+ * That attack is caught one layer up, by the append-only monotonicity check
55
+ * in `compliance.ts`, which degrades a scan whose timestamps regress. That
56
+ * check takes its reference from EVERY row in the file, not just QBD rows,
57
+ * so an adopted ledger's existing history is the baseline.
58
+ * 2. **A coherent whole-file rewrite** — and its degenerate case, an EMPTY or
59
+ * QBD-only ledger authored wholesale. With no prior history there is no
60
+ * monotonicity reference to violate, so internally consistent fake rows
61
+ * read clean. This is the same adversary as the rewrite: whoever authors
62
+ * the entire file controls its whole timeline. Conceded scope for v1 —
63
+ * nothing short of signing or an append-only server addresses it, and
64
+ * neither is chartered here.
65
+ *
66
+ * The realistic threat — a script or agent attaching correlation IDs to rows
67
+ * already on disk — is caught here. The other two are named rather than
68
+ * claimed solved, per the #2510 discipline.
69
+ */
70
+ import * as crypto from 'node:crypto';
71
+ // ─── Constants ──────────────────────────────────────────
72
+ /** Format version prefix — bump if the encoding ever changes. */
73
+ const QBD_ID_PREFIX = 'qbd1';
74
+ /** Bytes of randomness in the ID suffix (16 hex chars). */
75
+ const QBD_ID_RANDOM_BYTES = 8;
76
+ /** Radix for the embedded mint instant. */
77
+ const MINT_RADIX = 36;
78
+ /**
79
+ * Correlation window: a derive-class action counts as grounded by a query only
80
+ * if that query was minted within this window before it.
81
+ *
82
+ * The VALUE is borrowed from ADR-029 § 2's two-hour session window so this
83
+ * slice does not invent a second time constant. The DECISION to treat that
84
+ * span as a grounding-validity window is this slice's own, not the ADR's —
85
+ * ADR-029 § 2 defines a session-GROUPING heuristic for the recall metric, which
86
+ * is a different question, and it should not be cited as authority for this
87
+ * choice. Owned here as a design call: a shorter window would be a strictly
88
+ * harder test of the same claim, and the value is pinned so the pre-registered
89
+ * threshold is evaluated against a fixed rule rather than a tunable one.
90
+ *
91
+ * Note that consume-on-use (see `record.ts`) does most of the real work: the
92
+ * window bounds how STALE a grounding may be, but a query grounds only one
93
+ * derive regardless, so a generous window cannot inflate the numerator.
94
+ */
95
+ export const QBD_CORRELATION_WINDOW_MS = 2 * 60 * 60 * 1000;
96
+ /**
97
+ * Tolerance for clock jitter between minting an ID and stamping the row's
98
+ * `timestamp`. These happen microseconds apart in the same function, so this is
99
+ * generous; it exists so a coarse clock or a slow filesystem never manufactures
100
+ * a spurious schema violation.
101
+ */
102
+ export const QBD_MINT_TOLERANCE_MS = 2000;
103
+ /** Structural shape of a QBD correlation ID. */
104
+ const QBD_ID_PATTERN = /^qbd1-([0-9a-z]{1,11})-[0-9a-f]{16}$/;
105
+ /**
106
+ * Largest instant a `Date` can represent (±8.64e15 ms). The ID pattern admits
107
+ * up to 11 base36 digits, i.e. ~1.3e17 — comfortably past this bound.
108
+ *
109
+ * That gap was a crash, not a cosmetic issue: an ID like
110
+ * `qbd1-zzzzzzzzzzz-<16 hex>` decoded to a finite, non-negative number, passed
111
+ * every guard, and then reached `new Date(mintedAtMs).toISOString()` in a
112
+ * violation-detail string, which throws `RangeError`. Those details are built
113
+ * inside `LedgerEventSchema`'s refinement, and Zod does NOT trap throws from
114
+ * refinements — so `safeParse` threw rather than returning a failure, and one
115
+ * forged line killed the entire scan. Reject the ID before any `Date` sees it.
116
+ */
117
+ const MAX_TIME_VALUE_MS = 8.64e15;
118
+ // ─── Mint ───────────────────────────────────────────────
119
+ /**
120
+ * Mint a correlation ID stamped with `mintedAtMs`.
121
+ *
122
+ * Callers MUST pass the same instant they stamp on the event row — see
123
+ * `record.ts`, which derives both from one `Date.now()` read. Every writer path
124
+ * in this slice goes through that module precisely so the two cannot drift.
125
+ */
126
+ export function mintQbdCorrelationId(mintedAtMs) {
127
+ if (!Number.isFinite(mintedAtMs) || mintedAtMs < 0 || mintedAtMs > MAX_TIME_VALUE_MS) {
128
+ throw new RangeError(`mintQbdCorrelationId: invalid mint instant ${String(mintedAtMs)}`);
129
+ }
130
+ const stamp = Math.floor(mintedAtMs).toString(MINT_RADIX);
131
+ const random = crypto.randomBytes(QBD_ID_RANDOM_BYTES).toString('hex');
132
+ return `${QBD_ID_PREFIX}-${stamp}-${random}`;
133
+ }
134
+ /**
135
+ * Decode the mint instant embedded in a correlation ID.
136
+ * Returns `undefined` when the ID is not a well-formed QBD ID.
137
+ */
138
+ export function decodeQbdMintInstant(id) {
139
+ const match = QBD_ID_PATTERN.exec(id);
140
+ if (match === null)
141
+ return undefined;
142
+ const decoded = parseInt(match[1], MINT_RADIX);
143
+ // The upper bound is load-bearing, not defensive: past it, every downstream
144
+ // `new Date(...)` throws. Returning `undefined` routes such an ID to
145
+ // `undecodable-mint-instant`, which is counted and degrades the read — a data
146
+ // point rather than a crash.
147
+ if (!Number.isFinite(decoded) || decoded < 0 || decoded > MAX_TIME_VALUE_MS)
148
+ return undefined;
149
+ return decoded;
150
+ }
151
+ // ─── Validate (the anti-backfill contract) ──────────────
152
+ /**
153
+ * The minted-at-write-time contract, enforced structurally.
154
+ *
155
+ * `eventType` is the ledger row's `type`; `eventMs` is `Date.parse(row.timestamp)`.
156
+ *
157
+ * - `corpus_query`: the ID must be minted at the row's own instant (± tolerance).
158
+ * A query row is the ID's birth certificate; any other mint instant means the
159
+ * ID was attached later.
160
+ * - `derive_action`: the ID must be minted at or before the derive (± tolerance)
161
+ * and no earlier than one correlation window before it.
162
+ * - any other type: carrying the field at all is a violation.
163
+ */
164
+ export function checkQbdCorrelationId(id, eventType, eventMs) {
165
+ // Self-contained on its own argument: callers inside this package already
166
+ // validate `eventMs`, but this is public API and the detail strings below
167
+ // feed it straight to `new Date(...)`. An unusable instant is a violation to
168
+ // report, never a throw to leak out of a validation function.
169
+ if (!Number.isFinite(eventMs) || Math.abs(eventMs) > MAX_TIME_VALUE_MS) {
170
+ return {
171
+ ok: false,
172
+ violation: 'undecodable-mint-instant',
173
+ detail: `event timestamp ${String(eventMs)} is not a usable instant`,
174
+ };
175
+ }
176
+ if (QBD_ID_PATTERN.exec(id) === null) {
177
+ return {
178
+ ok: false,
179
+ violation: 'malformed-shape',
180
+ detail: `'${id}' is not a qbd1-<base36 instant>-<16 hex> correlation ID`,
181
+ };
182
+ }
183
+ const mintedAtMs = decodeQbdMintInstant(id);
184
+ if (mintedAtMs === undefined) {
185
+ return {
186
+ ok: false,
187
+ violation: 'undecodable-mint-instant',
188
+ detail: `'${id}' has no readable mint instant`,
189
+ };
190
+ }
191
+ if (eventType === 'corpus_query') {
192
+ if (Math.abs(eventMs - mintedAtMs) > QBD_MINT_TOLERANCE_MS) {
193
+ return {
194
+ ok: false,
195
+ violation: 'query-id-not-self-minted',
196
+ detail: `query row stamped ${new Date(eventMs).toISOString()} carries an ID minted ${new Date(mintedAtMs).toISOString()} — a query event's ID is minted as the row is written, so this ID was attached after the fact`,
197
+ };
198
+ }
199
+ return { ok: true };
200
+ }
201
+ if (eventType === 'derive_action') {
202
+ if (mintedAtMs - eventMs > QBD_MINT_TOLERANCE_MS) {
203
+ return {
204
+ ok: false,
205
+ violation: 'derive-id-minted-after-derive',
206
+ detail: `derive row stamped ${new Date(eventMs).toISOString()} carries an ID minted ${new Date(mintedAtMs).toISOString()} — a query that had not happened yet cannot have grounded this derive`,
207
+ };
208
+ }
209
+ if (eventMs - mintedAtMs > QBD_CORRELATION_WINDOW_MS) {
210
+ return {
211
+ ok: false,
212
+ violation: 'derive-id-older-than-window',
213
+ detail: `derive row stamped ${new Date(eventMs).toISOString()} carries an ID minted ${new Date(mintedAtMs).toISOString()}, older than the ${QBD_CORRELATION_WINDOW_MS}ms correlation window`,
214
+ };
215
+ }
216
+ return { ok: true };
217
+ }
218
+ return {
219
+ ok: false,
220
+ violation: 'id-on-non-qbd-event',
221
+ detail: `event type '${eventType}' has no query→derive semantics but carries a qbd_correlation_id`,
222
+ };
223
+ }
224
+ //# sourceMappingURL=correlation-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-id.js","sourceRoot":"","sources":["../../src/qbd/correlation-id.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=correlation-id.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-id.test.d.ts","sourceRoot":"","sources":["../../src/qbd/correlation-id.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,136 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { LedgerEventSchema } from '../ledger.js';
3
+ import { checkQbdCorrelationId, decodeQbdMintInstant, mintQbdCorrelationId, QBD_CORRELATION_WINDOW_MS, QBD_MINT_TOLERANCE_MS, } from './correlation-id.js';
4
+ const T0 = Date.parse('2026-07-28T12:00:00.000Z');
5
+ describe('mintQbdCorrelationId', () => {
6
+ it('embeds the mint instant so the ID is self-dating', () => {
7
+ const id = mintQbdCorrelationId(T0);
8
+ expect(decodeQbdMintInstant(id)).toBe(T0);
9
+ });
10
+ it('is unique across calls at the same instant', () => {
11
+ const a = mintQbdCorrelationId(T0);
12
+ const b = mintQbdCorrelationId(T0);
13
+ expect(a).not.toBe(b);
14
+ expect(decodeQbdMintInstant(a)).toBe(decodeQbdMintInstant(b));
15
+ });
16
+ it('rejects a nonsense mint instant rather than emitting a bad ID', () => {
17
+ expect(() => mintQbdCorrelationId(Number.NaN)).toThrow(RangeError);
18
+ expect(() => mintQbdCorrelationId(-1)).toThrow(RangeError);
19
+ });
20
+ it('returns undefined decoding a non-QBD string', () => {
21
+ expect(decodeQbdMintInstant('not-an-id')).toBeUndefined();
22
+ expect(decodeQbdMintInstant('550e8400-e29b-41d4-a716-446655440000')).toBeUndefined();
23
+ });
24
+ it('returns undefined for an instant past the max Date value', () => {
25
+ // The ID pattern admits 11 base36 digits (~1.3e17), well past 8.64e15.
26
+ // Decoding must refuse rather than hand a poison number downstream, where
27
+ // every `new Date(...)` would throw.
28
+ expect(decodeQbdMintInstant(`qbd1-zzzzzzzzzzz-${'a'.repeat(16)}`)).toBeUndefined();
29
+ });
30
+ it('refuses to MINT an instant past the max Date value', () => {
31
+ expect(() => mintQbdCorrelationId(8.64e15 + 1)).toThrow(RangeError);
32
+ });
33
+ });
34
+ describe('checkQbdCorrelationId — the minted-at-write-time contract', () => {
35
+ it('accepts a query ID minted at its own row instant', () => {
36
+ const id = mintQbdCorrelationId(T0);
37
+ expect(checkQbdCorrelationId(id, 'corpus_query', T0).ok).toBe(true);
38
+ });
39
+ it('REJECTS a query row whose ID was minted earlier — the backfill shape', () => {
40
+ // The falsifier-2 case: an ID minted at some past moment, attached later to
41
+ // a query row that was already on disk.
42
+ const id = mintQbdCorrelationId(T0 - 60_000);
43
+ const result = checkQbdCorrelationId(id, 'corpus_query', T0);
44
+ expect(result.ok).toBe(false);
45
+ expect(result.violation).toBe('query-id-not-self-minted');
46
+ });
47
+ it('accepts a derive ID minted earlier, inside the correlation window', () => {
48
+ const id = mintQbdCorrelationId(T0 - 60_000);
49
+ expect(checkQbdCorrelationId(id, 'derive_action', T0).ok).toBe(true);
50
+ });
51
+ it('REJECTS a derive ID minted after the derive it claims to have grounded', () => {
52
+ const id = mintQbdCorrelationId(T0 + 60_000);
53
+ const result = checkQbdCorrelationId(id, 'derive_action', T0);
54
+ expect(result.ok).toBe(false);
55
+ expect(result.violation).toBe('derive-id-minted-after-derive');
56
+ });
57
+ it('REJECTS a derive ID older than the correlation window', () => {
58
+ const id = mintQbdCorrelationId(T0 - QBD_CORRELATION_WINDOW_MS - 1000);
59
+ const result = checkQbdCorrelationId(id, 'derive_action', T0);
60
+ expect(result.ok).toBe(false);
61
+ expect(result.violation).toBe('derive-id-older-than-window');
62
+ });
63
+ it('tolerates sub-tolerance clock jitter on a query row', () => {
64
+ const id = mintQbdCorrelationId(T0 - (QBD_MINT_TOLERANCE_MS - 1));
65
+ expect(checkQbdCorrelationId(id, 'corpus_query', T0).ok).toBe(true);
66
+ });
67
+ it('reports an out-of-range ID as undecodable rather than throwing', () => {
68
+ const result = checkQbdCorrelationId(`qbd1-zzzzzzzzzzz-${'a'.repeat(16)}`, 'derive_action', T0);
69
+ expect(result.ok).toBe(false);
70
+ expect(result.violation).toBe('undecodable-mint-instant');
71
+ });
72
+ it('reports an unusable EVENT timestamp rather than throwing (public API)', () => {
73
+ const id = mintQbdCorrelationId(T0);
74
+ expect(checkQbdCorrelationId(id, 'derive_action', Number.NaN).ok).toBe(false);
75
+ expect(checkQbdCorrelationId(id, 'derive_action', Number.POSITIVE_INFINITY).ok).toBe(false);
76
+ });
77
+ it('REJECTS a malformed ID', () => {
78
+ const result = checkQbdCorrelationId('qbd1-nope', 'corpus_query', T0);
79
+ expect(result.ok).toBe(false);
80
+ expect(result.violation).toBe('malformed-shape');
81
+ });
82
+ it('REJECTS the field on an event type with no query→derive semantics', () => {
83
+ const id = mintQbdCorrelationId(T0);
84
+ const result = checkQbdCorrelationId(id, 'mcp_call', T0);
85
+ expect(result.ok).toBe(false);
86
+ expect(result.violation).toBe('id-on-non-qbd-event');
87
+ });
88
+ });
89
+ describe('LedgerEventSchema enforces the contract at the schema layer', () => {
90
+ const baseRow = {
91
+ timestamp: new Date(T0).toISOString(),
92
+ type: 'derive_action',
93
+ activity_name: 'spec',
94
+ source: 'lint',
95
+ justification: '',
96
+ };
97
+ it('parses a contract-valid correlated derive row', () => {
98
+ const row = { ...baseRow, qbd_correlation_id: mintQbdCorrelationId(T0 - 60_000) };
99
+ expect(LedgerEventSchema.safeParse(row).success).toBe(true);
100
+ });
101
+ it('parses an UNcorrelated derive row — it is a data point, not an error', () => {
102
+ // Falsifier 1: a derive with no query behind it must survive parsing so it
103
+ // can land in the denominator.
104
+ expect(LedgerEventSchema.safeParse(baseRow).success).toBe(true);
105
+ });
106
+ it('REJECTS a backfilled ID — a schema violation, not a data point', () => {
107
+ const row = { ...baseRow, qbd_correlation_id: mintQbdCorrelationId(T0 + 60_000) };
108
+ const result = LedgerEventSchema.safeParse(row);
109
+ expect(result.success).toBe(false);
110
+ if (!result.success) {
111
+ expect(result.error.issues[0]?.message).toContain('derive-id-minted-after-derive');
112
+ }
113
+ });
114
+ it('REJECTS a correlation ID stapled onto an unrelated event type', () => {
115
+ const row = {
116
+ timestamp: new Date(T0).toISOString(),
117
+ type: 'mcp_call',
118
+ source: 'bot',
119
+ justification: '',
120
+ qbd_correlation_id: mintQbdCorrelationId(T0),
121
+ };
122
+ expect(LedgerEventSchema.safeParse(row).success).toBe(false);
123
+ });
124
+ it('leaves pre-existing event types untouched', () => {
125
+ const legacy = {
126
+ timestamp: new Date(T0).toISOString(),
127
+ type: 'suppress',
128
+ ruleId: 'abc123',
129
+ file: 'packages/core/src/logger.ts',
130
+ source: 'lint',
131
+ justification: 'logger module',
132
+ };
133
+ expect(LedgerEventSchema.safeParse(legacy).success).toBe(true);
134
+ });
135
+ });
136
+ //# sourceMappingURL=correlation-id.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlation-id.test.js","sourceRoot":"","sources":["../../src/qbd/correlation-id.test.ts"],"names":[],"mappings":"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"}