@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.
- package/dist/ast-classifier.d.ts +3 -3
- package/dist/ast-classifier.js +12 -3
- package/dist/ast-classifier.js.map +1 -1
- package/dist/ast-classifier.test.js +33 -2
- package/dist/ast-classifier.test.js.map +1 -1
- package/dist/capability/schema.d.ts +2 -2
- package/dist/errors.d.ts +3 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +92 -4
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +91 -13
- package/dist/ledger.js.map +1 -1
- package/dist/qbd/compliance.d.ts +216 -0
- package/dist/qbd/compliance.d.ts.map +1 -0
- package/dist/qbd/compliance.js +490 -0
- package/dist/qbd/compliance.js.map +1 -0
- package/dist/qbd/compliance.test.d.ts +2 -0
- package/dist/qbd/compliance.test.d.ts.map +1 -0
- package/dist/qbd/compliance.test.js +539 -0
- package/dist/qbd/compliance.test.js.map +1 -0
- package/dist/qbd/correlation-id.d.ts +130 -0
- package/dist/qbd/correlation-id.d.ts.map +1 -0
- package/dist/qbd/correlation-id.js +224 -0
- package/dist/qbd/correlation-id.js.map +1 -0
- package/dist/qbd/correlation-id.test.d.ts +2 -0
- package/dist/qbd/correlation-id.test.d.ts.map +1 -0
- package/dist/qbd/correlation-id.test.js +136 -0
- package/dist/qbd/correlation-id.test.js.map +1 -0
- package/dist/qbd/record.d.ts +140 -0
- package/dist/qbd/record.d.ts.map +1 -0
- package/dist/qbd/record.js +419 -0
- package/dist/qbd/record.js.map +1 -0
- package/dist/qbd/record.test.d.ts +27 -0
- package/dist/qbd/record.test.d.ts.map +1 -0
- package/dist/qbd/record.test.js +607 -0
- package/dist/qbd/record.test.js.map +1 -0
- package/dist/rule-engine.test.js +85 -0
- package/dist/rule-engine.test.js.map +1 -1
- package/dist/session-id.d.ts.map +1 -1
- package/dist/session-id.js +19 -3
- package/dist/session-id.js.map +1 -1
- package/dist/session-id.test.js +35 -0
- package/dist/session-id.test.js.map +1 -1
- package/package.json +1 -1
package/dist/ledger.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { checkQbdCorrelationId } from './qbd/correlation-id.js';
|
|
4
5
|
// ─── Schema ─────────────────────────────────────────
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Every ledger event type, in one place.
|
|
8
|
+
*
|
|
9
|
+
* Consumers that need to partition the type space (e.g. the query-before-derive
|
|
10
|
+
* scanner, which must tell "another subsystem's row" from "a row that concerns
|
|
11
|
+
* me") MUST derive their sets from this constant rather than hand-mirroring it.
|
|
12
|
+
* A hand-copied list silently rots the moment a type is added here, and for the
|
|
13
|
+
* QBD scanner that rot changes a DEGRADED verdict — see `qbd/compliance.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export const LEDGER_EVENT_TYPES = [
|
|
16
|
+
'suppress',
|
|
17
|
+
'override',
|
|
18
|
+
'exemption',
|
|
19
|
+
'mcp_call',
|
|
20
|
+
'tool_call_first_significant',
|
|
21
|
+
'hook_fire',
|
|
22
|
+
'session_start',
|
|
23
|
+
'compile_run',
|
|
24
|
+
'claim_discipline_finding',
|
|
25
|
+
'compile_cache_decision',
|
|
26
|
+
'corpus_query',
|
|
27
|
+
'derive_action',
|
|
28
|
+
];
|
|
29
|
+
/** Ledger event types that belong to the query-before-derive metric (#2510). */
|
|
30
|
+
export const QBD_EVENT_TYPES = ['corpus_query', 'derive_action'];
|
|
31
|
+
const LedgerEventShape = z.object({
|
|
6
32
|
/** ISO 8601 timestamp */
|
|
7
33
|
timestamp: z.string().datetime(),
|
|
8
34
|
/**
|
|
@@ -31,22 +57,21 @@ export const LedgerEventSchema = z.object({
|
|
|
31
57
|
* `cache_miss_fingerprint_changed` / `cache_miss_force` /
|
|
32
58
|
* `cache_miss_no_prior_record`) per Proposal 281.
|
|
33
59
|
*
|
|
60
|
+
* Query-before-derive events (mmnto-ai/totem#2510; see `qbd/`):
|
|
61
|
+
* - `corpus_query` — a corpus query fired (`totem search` CLI or the MCP `search_knowledge`
|
|
62
|
+
* tool); `activity_name` carries which surface. Mints a fresh
|
|
63
|
+
* `qbd_correlation_id` at write time.
|
|
64
|
+
* - `derive_action` — a derive-class action ran (`totem spec` synthesis, `totem orient`
|
|
65
|
+
* derivation, `totem review` grounding); `activity_name` carries which.
|
|
66
|
+
* Carries the `qbd_correlation_id` of the query that grounded it, or
|
|
67
|
+
* NO id when nothing grounded it — an uncorrelated derive is a real,
|
|
68
|
+
* countable data point, never a dropped row (#2510 falsifier 1).
|
|
69
|
+
*
|
|
34
70
|
* Schema-level: `ruleId` + `file` are optional to accommodate activity events. Writer-side
|
|
35
71
|
* discipline enforces required-by-type. Promotion to `z.discriminatedUnion` deferred to A.3.c
|
|
36
72
|
* per design doc OQ-1 (.handoff/_shared/2026-05-15-a3a-schema-extension-design.md).
|
|
37
73
|
*/
|
|
38
|
-
type: z.enum(
|
|
39
|
-
'suppress',
|
|
40
|
-
'override',
|
|
41
|
-
'exemption',
|
|
42
|
-
'mcp_call',
|
|
43
|
-
'tool_call_first_significant',
|
|
44
|
-
'hook_fire',
|
|
45
|
-
'session_start',
|
|
46
|
-
'compile_run',
|
|
47
|
-
'claim_discipline_finding',
|
|
48
|
-
'compile_cache_decision',
|
|
49
|
-
]),
|
|
74
|
+
type: z.enum(LEDGER_EVENT_TYPES),
|
|
50
75
|
/** Rule ID (lessonHash) for override events. Optional; required by writer for suppress/override/exemption. */
|
|
51
76
|
ruleId: z.string().trim().min(1).optional(),
|
|
52
77
|
/** File where the suppression/override occurred. Optional; required by writer for suppress/override/exemption. */
|
|
@@ -122,6 +147,59 @@ export const LedgerEventSchema = z.object({
|
|
|
122
147
|
* writer convention even though the field lives on the base schema.
|
|
123
148
|
*/
|
|
124
149
|
addressed_in_pr: z.boolean().optional(),
|
|
150
|
+
/**
|
|
151
|
+
* Query-before-derive correlation ID (mmnto-ai/totem#2510) — the join key
|
|
152
|
+
* between a `corpus_query` row and the `derive_action` rows that query
|
|
153
|
+
* grounded. Distinct from `correlation_id` (ADR-014 orchestrator→MCP trace),
|
|
154
|
+
* which this slice is explicitly not chartered to build on.
|
|
155
|
+
*
|
|
156
|
+
* Self-dating by construction: the ID embeds its own mint instant, and
|
|
157
|
+
* `LedgerEventSchema`'s refinement below cross-checks that instant against
|
|
158
|
+
* this row's `timestamp`. That is what makes "minted at event-write time" a
|
|
159
|
+
* schema constraint rather than a convention — see `qbd/correlation-id.ts`
|
|
160
|
+
* for the exact contract and its honest limits.
|
|
161
|
+
*
|
|
162
|
+
* Absent on a `derive_action` = that derive was not grounded by a query. That
|
|
163
|
+
* is the metric's most important signal, not a gap: it must be counted in the
|
|
164
|
+
* denominator (#2510 falsifier 1, denominator gaming).
|
|
165
|
+
*/
|
|
166
|
+
qbd_correlation_id: z.string().trim().min(1).optional(),
|
|
167
|
+
});
|
|
168
|
+
/**
|
|
169
|
+
* The Trap Ledger event schema.
|
|
170
|
+
*
|
|
171
|
+
* The refinement enforces the #2510 minted-at-write-time contract structurally:
|
|
172
|
+
* a row whose `qbd_correlation_id` could not have been minted when the row was
|
|
173
|
+
* written fails to parse. Per the charter, "a backfilled ID is a schema
|
|
174
|
+
* violation, not a data point" — so such a row is never counted as compliant by
|
|
175
|
+
* anyone reading through this schema.
|
|
176
|
+
*
|
|
177
|
+
* Note for readers: `readLedgerEvents` SKIPS schema-invalid lines, so a
|
|
178
|
+
* violating row silently disappears from generic consumers. The compliance
|
|
179
|
+
* scanner (`qbd/compliance.ts`) therefore does NOT read through that helper —
|
|
180
|
+
* it counts every rejected row per-item so a tampered or torn ledger renders as
|
|
181
|
+
* DEGRADED instead of as a clean number (ADR-115 § 2).
|
|
182
|
+
*/
|
|
183
|
+
export const LedgerEventSchema = LedgerEventShape.superRefine((event, ctx) => {
|
|
184
|
+
if (event.qbd_correlation_id === undefined)
|
|
185
|
+
return;
|
|
186
|
+
const eventMs = Date.parse(event.timestamp);
|
|
187
|
+
if (!Number.isFinite(eventMs)) {
|
|
188
|
+
ctx.addIssue({
|
|
189
|
+
code: z.ZodIssueCode.custom,
|
|
190
|
+
path: ['qbd_correlation_id'],
|
|
191
|
+
message: 'qbd_correlation_id present on a row with an unparseable timestamp',
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const check = checkQbdCorrelationId(event.qbd_correlation_id, event.type, eventMs);
|
|
196
|
+
if (!check.ok) {
|
|
197
|
+
ctx.addIssue({
|
|
198
|
+
code: z.ZodIssueCode.custom,
|
|
199
|
+
path: ['qbd_correlation_id'],
|
|
200
|
+
message: `${check.violation ?? 'invalid'}: ${check.detail ?? 'invalid qbd_correlation_id'}`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
125
203
|
});
|
|
126
204
|
// ─── Constants ──────────────────────────────────────
|
|
127
205
|
const LEDGER_DIR = 'ledger';
|
package/dist/ledger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,uDAAuD;AAEvD,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,uDAAuD;AAEvD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,UAAU;IACV,UAAU;IACV,WAAW;IACX,UAAU;IACV,6BAA6B;IAC7B,WAAW;IACX,eAAe;IACf,aAAa;IACb,0BAA0B;IAC1B,wBAAwB;IACxB,cAAc;IACd,eAAe;CACP,CAAC;AAEX,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,cAAc,EAAE,eAAe,CAAU,CAAC;AAE1E,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,yBAAyB;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuCG;IACH,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC;IAChC,8GAA8G;IAC9G,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3C,kHAAkH;IAClH,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACzC,8BAA8B;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC5C,gHAAgH;IAChH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC;;;OAGG;IACH,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACzC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC;;;;;;;;;;;;;;;OAeG;IACH,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACjD;;;;;;OAMG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IACxC;;;;OAIG;IACH,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;IAC5C;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAClD;;;;;OAKG;IACH,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAChD;;;;;;OAMG;IACH,eAAe,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACvC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACxD,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC3E,IAAI,KAAK,CAAC,kBAAkB,KAAK,SAAS;QAAE,OAAO;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,OAAO,EAAE,mEAAmE;SAC7E,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,kBAAkB,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACnF,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM;YAC3B,IAAI,EAAE,CAAC,oBAAoB,CAAC;YAC5B,OAAO,EAAE,GAAG,KAAK,CAAC,SAAS,IAAI,SAAS,KAAK,KAAK,CAAC,MAAM,IAAI,4BAA4B,EAAE;SAC5F,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC,CAAC;AAIH,uDAAuD;AAEvD,MAAM,UAAU,GAAG,QAAQ,CAAC;AAC5B,MAAM,WAAW,GAAG,eAAe,CAAC;AAEpC,uDAAuD;AAEvD;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,KAAkB,EAClB,MAA8B;IAE9B,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClD,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QACnD,mEAAmE;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;QAC1C,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,MAA8B;IAC/E,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrE,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChC,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACnD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAChE,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,EAAE,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;QAC5C,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query-before-derive compliance — the metric (mmnto-ai/totem#2510).
|
|
3
|
+
*
|
|
4
|
+
* ## The number
|
|
5
|
+
*
|
|
6
|
+
* Of the derive-class actions in an agent session (spec synthesis, orientation
|
|
7
|
+
* derivation, review grounding), what fraction was preceded by a corpus query
|
|
8
|
+
* correlated to that action?
|
|
9
|
+
*
|
|
10
|
+
* compliance = correlated derive events / ALL derive events
|
|
11
|
+
*
|
|
12
|
+
* ## Denominator discipline (#2510 falsifier 1)
|
|
13
|
+
*
|
|
14
|
+
* The denominator is **every** derive-class event in the evaluated sessions,
|
|
15
|
+
* including sessions that fired zero queries. A session that derived without
|
|
16
|
+
* ever querying is the exact behaviour this metric exists to catch, so it must
|
|
17
|
+
* pull the number DOWN, not vanish from it. Two places this could have been
|
|
18
|
+
* gamed, and how each is closed:
|
|
19
|
+
*
|
|
20
|
+
* - *at the ratio level* — counting only derives that carry an ID. Closed: the
|
|
21
|
+
* denominator counts derive rows, correlated or not.
|
|
22
|
+
* - *at the window level* — enumerating only sessions that contain queries.
|
|
23
|
+
* Closed: session selection keys on "carries ≥1 derive-class event,
|
|
24
|
+
* regardless of query count", which is the operator-pinned window phrasing.
|
|
25
|
+
*
|
|
26
|
+
* ## Numerator discipline (#2510 falsifier 2)
|
|
27
|
+
*
|
|
28
|
+
* A derive counts as correlated only when its `qbd_correlation_id` resolves to
|
|
29
|
+
* a `corpus_query` row that actually appears earlier in the ledger, in the same
|
|
30
|
+
* session and from the same seat. Ways that check fails, all counted as
|
|
31
|
+
* anomalies and none as compliant: a schema-rejected ID (see
|
|
32
|
+
* `correlation-id.ts`), an ID with no matching query row (orphan — a truncated
|
|
33
|
+
* or tampered ledger), an ID whose query row belongs to a different session or
|
|
34
|
+
* a different seat, and a row whose timestamp regresses in an append-only file
|
|
35
|
+
* (a backdated append trying to seize the evaluation window).
|
|
36
|
+
*
|
|
37
|
+
* One query grounds exactly ONE derive — the pointer is consumed on use (see
|
|
38
|
+
* `record.ts`). Without that, a single query would credit every derive for the
|
|
39
|
+
* rest of the correlation window.
|
|
40
|
+
*
|
|
41
|
+
* ## What this metric CANNOT see (#2510 falsifier 4, ritual query)
|
|
42
|
+
*
|
|
43
|
+
* A query fired purely to satisfy the metric, whose results the following
|
|
44
|
+
* derive never reads, is indistinguishable here from a query that genuinely
|
|
45
|
+
* grounded the derive. Both produce a query row and a correlated derive row.
|
|
46
|
+
* v1 senses adjacency, not influence. This is named, not solved — the honest
|
|
47
|
+
* statement is that the number measures whether querying happened before
|
|
48
|
+
* deriving, NOT whether the derive used what the query returned. Any reading
|
|
49
|
+
* that treats it as the latter is over-claiming.
|
|
50
|
+
*
|
|
51
|
+
* ## Degraded reads (ADR-115 § 2)
|
|
52
|
+
*
|
|
53
|
+
* `readLedgerEvents` skips schema-invalid lines silently, which would let a torn
|
|
54
|
+
* or tampered ledger render as a confident 100% or a confident 0%. This scanner
|
|
55
|
+
* therefore parses the NDJSON itself and counts every rejected line by class. A
|
|
56
|
+
* scan with any integrity anomaly is `degraded`, and the render must announce
|
|
57
|
+
* that rather than print a bare number.
|
|
58
|
+
*/
|
|
59
|
+
/** Pre-registered floor. Below this at the checkpoint, the claim is falsified. */
|
|
60
|
+
export declare const QBD_PRE_REGISTERED_THRESHOLD = 0.5;
|
|
61
|
+
/** Pre-registered evaluation window, in sessions. */
|
|
62
|
+
export declare const QBD_PRE_REGISTERED_WINDOW_SESSIONS = 20;
|
|
63
|
+
/**
|
|
64
|
+
* The pre-registration, verbatim as pinned by the operator ruling 2026-07-28 on
|
|
65
|
+
* mmnto-ai/totem#2510. Rendered verbatim by the doctor section — the exact
|
|
66
|
+
* phrasing is load-bearing: an earlier "first 20 correlated sessions" wording
|
|
67
|
+
* was post-hoc-interpretable as excluding zero-query sessions, which would have
|
|
68
|
+
* enacted falsifier 1 at the window level. Do not paraphrase this string.
|
|
69
|
+
*/
|
|
70
|
+
export declare const QBD_PRE_REGISTRATION_STATEMENT = "compliance \u2265 0.50, evaluated over the first 20 instrumented sessions carrying \u22651 derive-class event, regardless of query count";
|
|
71
|
+
export type QbdEventType = 'corpus_query' | 'derive_action';
|
|
72
|
+
/** A QBD row lifted out of the ledger. */
|
|
73
|
+
export interface QbdRow {
|
|
74
|
+
ms: number;
|
|
75
|
+
type: QbdEventType;
|
|
76
|
+
activityName?: string;
|
|
77
|
+
sessionId?: string;
|
|
78
|
+
correlationId?: string;
|
|
79
|
+
agentSource?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Per-item anomaly accounting — every rejected or unjoinable item, by class. */
|
|
82
|
+
export interface QbdAnomalies {
|
|
83
|
+
/** Lines that were not valid JSON (a torn append, a hand-edit). */
|
|
84
|
+
malformedJson: number;
|
|
85
|
+
/**
|
|
86
|
+
* Lines that parsed as JSON but were rejected by the ledger schema while
|
|
87
|
+
* looking like QBD rows — this is where a backfilled correlation ID lands.
|
|
88
|
+
*/
|
|
89
|
+
correlationContractViolations: number;
|
|
90
|
+
/** Lines rejected by the schema whose event type could not be classified. */
|
|
91
|
+
unclassifiedInvalid: number;
|
|
92
|
+
/** Derive rows whose correlation ID matches no earlier query row. */
|
|
93
|
+
orphanCorrelations: number;
|
|
94
|
+
/** Derive rows whose correlated query row belongs to a different session. */
|
|
95
|
+
crossSessionCorrelations: number;
|
|
96
|
+
/**
|
|
97
|
+
* Derive rows citing a correlation ID an earlier derive already spent. One
|
|
98
|
+
* query grounds one derive; a re-citation means the write-side consume
|
|
99
|
+
* failed, raced, or was bypassed.
|
|
100
|
+
*/
|
|
101
|
+
duplicateCorrelations: number;
|
|
102
|
+
/**
|
|
103
|
+
* Uncorrelated derives that had an in-window query from a DIFFERENT seat —
|
|
104
|
+
* the signature of one-sided seat plumbing. A diagnostic hint, never an
|
|
105
|
+
* integrity anomaly, so it does not degrade the read.
|
|
106
|
+
*/
|
|
107
|
+
seatMismatchHints: number;
|
|
108
|
+
/**
|
|
109
|
+
* Rows whose timestamp regresses behind the newest already seen in this
|
|
110
|
+
* append-only file — the backdated-append attack on the evaluation window.
|
|
111
|
+
*/
|
|
112
|
+
backdatedRows: number;
|
|
113
|
+
/**
|
|
114
|
+
* Rows carrying an event type this build does not know. An ADVISORY, not an
|
|
115
|
+
* integrity anomaly: the ordinary cause is version skew, and it deliberately
|
|
116
|
+
* does NOT flip `degraded`.
|
|
117
|
+
*/
|
|
118
|
+
unknownTypeRows: number;
|
|
119
|
+
/** Human-readable detail lines, capped, for the render. */
|
|
120
|
+
details: string[];
|
|
121
|
+
}
|
|
122
|
+
export interface QbdScanResult {
|
|
123
|
+
rows: QbdRow[];
|
|
124
|
+
/** Non-empty lines examined. */
|
|
125
|
+
linesScanned: number;
|
|
126
|
+
anomalies: QbdAnomalies;
|
|
127
|
+
/**
|
|
128
|
+
* True when any integrity anomaly fired. A degraded scan must never render as
|
|
129
|
+
* a clean number (ADR-115 § 2) — the number it would print is not trustworthy
|
|
130
|
+
* because rows are known to be missing or rejected.
|
|
131
|
+
*/
|
|
132
|
+
degraded: boolean;
|
|
133
|
+
}
|
|
134
|
+
export interface QbdRateStat {
|
|
135
|
+
/** Derive-class events counted (the denominator). */
|
|
136
|
+
derives: number;
|
|
137
|
+
/** Of `derives`, how many were correlated to a preceding query. */
|
|
138
|
+
correlated: number;
|
|
139
|
+
}
|
|
140
|
+
export type QbdVerdict = 'PENDING' | 'PASS' | 'FAIL';
|
|
141
|
+
export interface QbdComplianceReport {
|
|
142
|
+
/** Sessions carrying ≥1 derive-class event, in first-seen order. */
|
|
143
|
+
instrumentedSessions: number;
|
|
144
|
+
/** Sessions actually evaluated (capped at the pre-registered window). */
|
|
145
|
+
evaluatedSessions: number;
|
|
146
|
+
/** The pre-registration window's rate. */
|
|
147
|
+
window: QbdRateStat;
|
|
148
|
+
/** The rate, or null when there is nothing to divide. */
|
|
149
|
+
compliance: number | null;
|
|
150
|
+
/**
|
|
151
|
+
* `PENDING` until the window fills — the pre-registered threshold is not
|
|
152
|
+
* evaluable before then, and calling it early in either direction would be
|
|
153
|
+
* exactly the post-hoc reinterpretation the registration forbids.
|
|
154
|
+
*/
|
|
155
|
+
verdict: QbdVerdict;
|
|
156
|
+
/** Trend across all instrumented sessions, earlier half vs recent half. */
|
|
157
|
+
trend: {
|
|
158
|
+
earlier: QbdRateStat;
|
|
159
|
+
recent: QbdRateStat;
|
|
160
|
+
} | null;
|
|
161
|
+
anomalies: QbdAnomalies;
|
|
162
|
+
degraded: boolean;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Parse the raw `events.ndjson` contents, lifting out QBD rows and counting
|
|
166
|
+
* every line this metric could not trust.
|
|
167
|
+
*
|
|
168
|
+
* Deliberately does NOT use `readLedgerEvents`: that helper drops schema-invalid
|
|
169
|
+
* lines without telling anyone, which is precisely how a tampered ledger would
|
|
170
|
+
* render as a clean number.
|
|
171
|
+
*/
|
|
172
|
+
export declare function scanQbdLedger(content: string): QbdScanResult;
|
|
173
|
+
/**
|
|
174
|
+
* One instrumented session: the unit the pre-registered evaluation window
|
|
175
|
+
* counts in. Exported because `groupQbdSessions` returns it through the package
|
|
176
|
+
* barrel — a consumer could call that function but not name its return type.
|
|
177
|
+
*/
|
|
178
|
+
export interface QbdSession {
|
|
179
|
+
/** Stable identity: `sid:<agent>:<session_id>` or `win:<agent>:<n>`. */
|
|
180
|
+
key: string;
|
|
181
|
+
/** Earliest row instant in the session; sessions are ordered by this. */
|
|
182
|
+
firstMs: number;
|
|
183
|
+
/** The session's rows, in time order. */
|
|
184
|
+
rows: QbdRow[];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Group rows into sessions.
|
|
188
|
+
*
|
|
189
|
+
* Rows carrying a `session_id` group by it. Rows without one (hookless agents,
|
|
190
|
+
* pre-hook runs) fall back to a rolling-window roll-up, applied among
|
|
191
|
+
* themselves and PARTITIONED BY `agent_source`. Both are "instrumented
|
|
192
|
+
* sessions"; neither is privileged.
|
|
193
|
+
*
|
|
194
|
+
* The agent partition matters concretely: cohort seats share one working tree
|
|
195
|
+
* per repo, so two seats writing to the same ledger inside the same two-hour
|
|
196
|
+
* span would otherwise be rolled into a single "session", letting one seat's
|
|
197
|
+
* query sit in the same session as another seat's derive. Sessions are
|
|
198
|
+
* per-agent, so the fallback is too.
|
|
199
|
+
*
|
|
200
|
+
* Note on provenance: preferring an explicit session id over a time heuristic
|
|
201
|
+
* follows the `.session-id` primitive's own documented contract
|
|
202
|
+
* (`session-id.ts`), not ADR-029 § 2 — that section defines a session-GROUPING
|
|
203
|
+
* heuristic for the recall metric, which is a different question.
|
|
204
|
+
*/
|
|
205
|
+
export declare function groupQbdSessions(rows: QbdRow[]): QbdSession[];
|
|
206
|
+
/**
|
|
207
|
+
* Compute the compliance report from a scan.
|
|
208
|
+
*
|
|
209
|
+
* The verdict stays `PENDING` until the pre-registered window fills. That is
|
|
210
|
+
* deliberate: declaring PASS at n=3 would be as much a post-hoc reinterpretation
|
|
211
|
+
* of the registration as moving the threshold would be.
|
|
212
|
+
*/
|
|
213
|
+
export declare function computeQbdCompliance(scan: QbdScanResult): QbdComplianceReport;
|
|
214
|
+
/** Format a rate as a fixed-2 fraction, or `n/a` when there is nothing to divide. */
|
|
215
|
+
export declare function formatQbdRate(stat: QbdRateStat): string;
|
|
216
|
+
//# sourceMappingURL=compliance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.d.ts","sourceRoot":"","sources":["../../src/qbd/compliance.ts"],"names":[],"mappings":"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"}
|