@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
|
@@ -0,0 +1,490 @@
|
|
|
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
|
+
import { LEDGER_EVENT_TYPES, LedgerEventSchema, QBD_EVENT_TYPES } from '../ledger.js';
|
|
60
|
+
import { QBD_CORRELATION_WINDOW_MS } from './correlation-id.js';
|
|
61
|
+
// ─── Pre-registration (fixed before the sensor first emitted) ───
|
|
62
|
+
/** Pre-registered floor. Below this at the checkpoint, the claim is falsified. */
|
|
63
|
+
export const QBD_PRE_REGISTERED_THRESHOLD = 0.5;
|
|
64
|
+
/** Pre-registered evaluation window, in sessions. */
|
|
65
|
+
export const QBD_PRE_REGISTERED_WINDOW_SESSIONS = 20;
|
|
66
|
+
/**
|
|
67
|
+
* The pre-registration, verbatim as pinned by the operator ruling 2026-07-28 on
|
|
68
|
+
* mmnto-ai/totem#2510. Rendered verbatim by the doctor section — the exact
|
|
69
|
+
* phrasing is load-bearing: an earlier "first 20 correlated sessions" wording
|
|
70
|
+
* was post-hoc-interpretable as excluding zero-query sessions, which would have
|
|
71
|
+
* enacted falsifier 1 at the window level. Do not paraphrase this string.
|
|
72
|
+
*/
|
|
73
|
+
export const QBD_PRE_REGISTRATION_STATEMENT = 'compliance ≥ 0.50, evaluated over the first 20 instrumented sessions carrying ≥1 derive-class event, regardless of query count';
|
|
74
|
+
/**
|
|
75
|
+
* Window for the id-less rolling-window session fallback. Same span as the
|
|
76
|
+
* correlation window so the slice carries one time constant rather than two;
|
|
77
|
+
* see `correlation-id.ts` for why that value is this slice's design call and
|
|
78
|
+
* not something ADR-029 § 2 authorises.
|
|
79
|
+
*/
|
|
80
|
+
const SESSION_ROLLUP_WINDOW_MS = QBD_CORRELATION_WINDOW_MS;
|
|
81
|
+
/** Minimum instrumented sessions per side before a trend is worth printing. */
|
|
82
|
+
const MIN_SESSIONS_PER_TREND_SIDE = 2;
|
|
83
|
+
// ─── Scan ───────────────────────────────────────────────
|
|
84
|
+
/**
|
|
85
|
+
* Event types that exist in the ledger and are not part of this metric.
|
|
86
|
+
*
|
|
87
|
+
* DERIVED from the ledger schema's own type list, never hand-mirrored: a copied
|
|
88
|
+
* list rots the moment a type is added to `ledger.ts`, and here that rot is not
|
|
89
|
+
* cosmetic — an unrecognised type used to flip the whole scan to DEGRADED.
|
|
90
|
+
* `ledger-type-parity` in the tests pins this to the schema.
|
|
91
|
+
*/
|
|
92
|
+
const NON_QBD_TYPES = new Set(LEDGER_EVENT_TYPES.filter((t) => !QBD_EVENT_TYPES.includes(t)));
|
|
93
|
+
/**
|
|
94
|
+
* How far a row's timestamp may regress behind the newest timestamp seen so far
|
|
95
|
+
* before the scan calls it backdated.
|
|
96
|
+
*
|
|
97
|
+
* The ledger is append-only, so timestamps should march forward. Small
|
|
98
|
+
* regressions are legitimate — concurrent writers in one repo, sub-second clock
|
|
99
|
+
* jitter, a cohort seat whose clock drifts slightly — so the tolerance is
|
|
100
|
+
* generous. What it catches is the real attack: APPENDING rows stamped far in
|
|
101
|
+
* the past to seize the pre-registered first-20-session window.
|
|
102
|
+
*/
|
|
103
|
+
const BACKDATE_TOLERANCE_MS = 5 * 60 * 1000;
|
|
104
|
+
/** Cap on stored detail strings so a pathological ledger cannot balloon memory. */
|
|
105
|
+
const MAX_ANOMALY_DETAILS = 20;
|
|
106
|
+
function emptyAnomalies() {
|
|
107
|
+
return {
|
|
108
|
+
malformedJson: 0,
|
|
109
|
+
correlationContractViolations: 0,
|
|
110
|
+
unclassifiedInvalid: 0,
|
|
111
|
+
orphanCorrelations: 0,
|
|
112
|
+
crossSessionCorrelations: 0,
|
|
113
|
+
duplicateCorrelations: 0,
|
|
114
|
+
seatMismatchHints: 0,
|
|
115
|
+
backdatedRows: 0,
|
|
116
|
+
unknownTypeRows: 0,
|
|
117
|
+
details: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function pushDetail(anomalies, detail) {
|
|
121
|
+
if (anomalies.details.length < MAX_ANOMALY_DETAILS)
|
|
122
|
+
anomalies.details.push(detail);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Parse the raw `events.ndjson` contents, lifting out QBD rows and counting
|
|
126
|
+
* every line this metric could not trust.
|
|
127
|
+
*
|
|
128
|
+
* Deliberately does NOT use `readLedgerEvents`: that helper drops schema-invalid
|
|
129
|
+
* lines without telling anyone, which is precisely how a tampered ledger would
|
|
130
|
+
* render as a clean number.
|
|
131
|
+
*/
|
|
132
|
+
export function scanQbdLedger(content) {
|
|
133
|
+
const rows = [];
|
|
134
|
+
const anomalies = emptyAnomalies();
|
|
135
|
+
let linesScanned = 0;
|
|
136
|
+
/** Newest QBD timestamp seen so far, in FILE order — the monotonicity baseline. */
|
|
137
|
+
let maxSeenMs;
|
|
138
|
+
const lines = content.split('\n');
|
|
139
|
+
for (let i = 0; i < lines.length; i++) {
|
|
140
|
+
const line = lines[i].trim();
|
|
141
|
+
if (line.length === 0)
|
|
142
|
+
continue;
|
|
143
|
+
linesScanned++;
|
|
144
|
+
let parsed;
|
|
145
|
+
try {
|
|
146
|
+
parsed = JSON.parse(line);
|
|
147
|
+
// totem-context: a torn or hand-edited NDJSON line is counted (malformedJson) and surfaced in the DEGRADED envelope per ADR-115 § 2 — never silently dropped, and never a crash of the read-only sensor.
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
anomalies.malformedJson++;
|
|
151
|
+
pushDetail(anomalies, `line ${i + 1}: not valid JSON`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const rawObject = typeof parsed === 'object' && parsed !== null
|
|
155
|
+
? parsed
|
|
156
|
+
: undefined;
|
|
157
|
+
const rawType = rawObject?.type;
|
|
158
|
+
const result = LedgerEventSchema.safeParse(parsed);
|
|
159
|
+
if (!result.success) {
|
|
160
|
+
// ORDER IS LOAD-BEARING. The QBD-marker test must run BEFORE the
|
|
161
|
+
// "belongs to another subsystem" fast path. A row can carry a forged
|
|
162
|
+
// `qbd_correlation_id` while claiming a non-QBD `type` — and if the
|
|
163
|
+
// fast path ran first, that row would be dropped with zero anomalies
|
|
164
|
+
// and the ledger would render clean. That is exactly the tampering
|
|
165
|
+
// ADR-115 § 2 exists to make impossible to miss, so a qbd-field-bearing
|
|
166
|
+
// schema failure is a contract violation on ANY type.
|
|
167
|
+
const looksQbd = rawType === 'corpus_query' ||
|
|
168
|
+
rawType === 'derive_action' ||
|
|
169
|
+
(rawObject !== undefined && 'qbd_correlation_id' in rawObject);
|
|
170
|
+
const reason = result.error.issues.map((issue) => issue.message).join('; ');
|
|
171
|
+
if (looksQbd) {
|
|
172
|
+
anomalies.correlationContractViolations++;
|
|
173
|
+
pushDetail(anomalies, `line ${i + 1}: correlation contract violation — ${reason}`);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (typeof rawType === 'string' && NON_QBD_TYPES.has(rawType)) {
|
|
177
|
+
// Another subsystem's row failed its OWN schema and carries no QBD
|
|
178
|
+
// markers. Not this metric's integrity problem, not counted against it.
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (typeof rawType === 'string' && rawType.length > 0) {
|
|
182
|
+
// A type this build does not know. The benign cause is version skew —
|
|
183
|
+
// a newer writer in the same repo emitting an event type this binary
|
|
184
|
+
// predates — which is emphatically NOT evidence that the ledger was
|
|
185
|
+
// tampered with. Report it as a named advisory; do NOT flip DEGRADED,
|
|
186
|
+
// or routine skew would drown the signal that real tampering produces.
|
|
187
|
+
anomalies.unknownTypeRows++;
|
|
188
|
+
pushDetail(anomalies, `line ${i + 1}: unknown event type '${rawType}' (this build predates it — version skew, not tampering)`);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
// No usable type at all — this is structural corruption, not skew.
|
|
192
|
+
anomalies.unclassifiedInvalid++;
|
|
193
|
+
pushDetail(anomalies, `line ${i + 1}: unclassifiable invalid row — ${reason}`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const event = result.data;
|
|
197
|
+
const ms = Date.parse(event.timestamp);
|
|
198
|
+
if (event.type !== 'corpus_query' && event.type !== 'derive_action') {
|
|
199
|
+
// Not our row — but its timestamp still advances the monotonicity
|
|
200
|
+
// reference. This is load-bearing: on a ledger adopted mid-life, the
|
|
201
|
+
// EXISTING non-QBD history is the only baseline a backdated QBD append
|
|
202
|
+
// can be measured against. Referencing QBD rows alone left the check
|
|
203
|
+
// blind in exactly the fresh-adopter state the pre-registered first-20
|
|
204
|
+
// window is filled from — 20 backdated pairs read PASS, degraded=false.
|
|
205
|
+
if (Number.isFinite(ms) && (maxSeenMs === undefined || ms > maxSeenMs))
|
|
206
|
+
maxSeenMs = ms;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (!Number.isFinite(ms)) {
|
|
210
|
+
anomalies.unclassifiedInvalid++;
|
|
211
|
+
pushDetail(anomalies, `line ${i + 1}: QBD row with an unparseable timestamp`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
// Append-only monotonicity. The ledger only ever grows at the end, so a row
|
|
215
|
+
// stamped far behind the newest one already seen was APPENDED with a
|
|
216
|
+
// backdated timestamp. That is the cheap attack on a "first N sessions"
|
|
217
|
+
// window — no whole-file rewrite required, just `>> events.ndjson` with old
|
|
218
|
+
// stamps — so it must degrade the read. The row is still counted (dropping
|
|
219
|
+
// it would shrink the denominator, which is the other failure mode); the
|
|
220
|
+
// scan simply refuses to call the resulting number verified.
|
|
221
|
+
if (maxSeenMs !== undefined && ms < maxSeenMs - BACKDATE_TOLERANCE_MS) {
|
|
222
|
+
anomalies.backdatedRows++;
|
|
223
|
+
pushDetail(anomalies, `line ${i + 1}: timestamp ${new Date(ms).toISOString()} regresses more than BACKDATE_TOLERANCE_MS (${BACKDATE_TOLERANCE_MS}ms) behind ${new Date(maxSeenMs).toISOString()} in an append-only ledger`);
|
|
224
|
+
}
|
|
225
|
+
if (maxSeenMs === undefined || ms > maxSeenMs)
|
|
226
|
+
maxSeenMs = ms;
|
|
227
|
+
rows.push({
|
|
228
|
+
ms,
|
|
229
|
+
type: event.type,
|
|
230
|
+
...(event.activity_name !== undefined && { activityName: event.activity_name }),
|
|
231
|
+
...(event.session_id !== undefined && { sessionId: event.session_id }),
|
|
232
|
+
...(event.qbd_correlation_id !== undefined && { correlationId: event.qbd_correlation_id }),
|
|
233
|
+
...(event.agent_source !== undefined && { agentSource: event.agent_source }),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
rows.sort((a, b) => a.ms - b.ms);
|
|
237
|
+
// `unknownTypeRows` is deliberately absent: version skew is not tampering.
|
|
238
|
+
const degraded = anomalies.malformedJson > 0 ||
|
|
239
|
+
anomalies.correlationContractViolations > 0 ||
|
|
240
|
+
anomalies.unclassifiedInvalid > 0 ||
|
|
241
|
+
anomalies.backdatedRows > 0;
|
|
242
|
+
return { rows, linesScanned, anomalies, degraded };
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Group rows into sessions.
|
|
246
|
+
*
|
|
247
|
+
* Rows carrying a `session_id` group by it. Rows without one (hookless agents,
|
|
248
|
+
* pre-hook runs) fall back to a rolling-window roll-up, applied among
|
|
249
|
+
* themselves and PARTITIONED BY `agent_source`. Both are "instrumented
|
|
250
|
+
* sessions"; neither is privileged.
|
|
251
|
+
*
|
|
252
|
+
* The agent partition matters concretely: cohort seats share one working tree
|
|
253
|
+
* per repo, so two seats writing to the same ledger inside the same two-hour
|
|
254
|
+
* span would otherwise be rolled into a single "session", letting one seat's
|
|
255
|
+
* query sit in the same session as another seat's derive. Sessions are
|
|
256
|
+
* per-agent, so the fallback is too.
|
|
257
|
+
*
|
|
258
|
+
* Note on provenance: preferring an explicit session id over a time heuristic
|
|
259
|
+
* follows the `.session-id` primitive's own documented contract
|
|
260
|
+
* (`session-id.ts`), not ADR-029 § 2 — that section defines a session-GROUPING
|
|
261
|
+
* heuristic for the recall metric, which is a different question.
|
|
262
|
+
*/
|
|
263
|
+
export function groupQbdSessions(rows) {
|
|
264
|
+
const byId = new Map();
|
|
265
|
+
const idless = [];
|
|
266
|
+
for (const row of rows) {
|
|
267
|
+
if (row.sessionId === undefined) {
|
|
268
|
+
idless.push(row);
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
// Key on the agent too: a session id is only unique within the agent that
|
|
272
|
+
// minted it, and two seats must never share a session bucket.
|
|
273
|
+
const key = `sid:${row.agentSource ?? ''}:${row.sessionId}`;
|
|
274
|
+
const existing = byId.get(key);
|
|
275
|
+
if (existing === undefined) {
|
|
276
|
+
byId.set(key, { key, firstMs: row.ms, rows: [row] });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
existing.rows.push(row);
|
|
280
|
+
if (row.ms < existing.firstMs)
|
|
281
|
+
existing.firstMs = row.ms;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const sessions = [...byId.values()];
|
|
285
|
+
// Rolling-window fallback for id-less rows, PER AGENT (rows are time-sorted).
|
|
286
|
+
const openByAgent = new Map();
|
|
287
|
+
let windowIndex = 0;
|
|
288
|
+
for (const row of idless) {
|
|
289
|
+
const agent = row.agentSource ?? '';
|
|
290
|
+
const open = openByAgent.get(agent);
|
|
291
|
+
if (open === undefined || row.ms - open.lastMs > SESSION_ROLLUP_WINDOW_MS) {
|
|
292
|
+
const session = {
|
|
293
|
+
key: `win:${agent}:${windowIndex++}`,
|
|
294
|
+
firstMs: row.ms,
|
|
295
|
+
rows: [row],
|
|
296
|
+
};
|
|
297
|
+
sessions.push(session);
|
|
298
|
+
openByAgent.set(agent, { session, lastMs: row.ms });
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
open.session.rows.push(row);
|
|
302
|
+
open.lastMs = row.ms;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
sessions.sort((a, b) => a.firstMs - b.firstMs);
|
|
306
|
+
return sessions;
|
|
307
|
+
}
|
|
308
|
+
// ─── Compute ────────────────────────────────────────────
|
|
309
|
+
/**
|
|
310
|
+
* Decide which derive rows earn credit, across the WHOLE scan at once.
|
|
311
|
+
*
|
|
312
|
+
* Runs globally rather than per-session for two reasons: a correlation ID's
|
|
313
|
+
* query row may live outside the session being scored, and — the important one
|
|
314
|
+
* — **the 1:1 rule has to be enforced against every derive in the file**, not
|
|
315
|
+
* within one session's slice.
|
|
316
|
+
*
|
|
317
|
+
* ## Why the read side re-enforces a write-side rule
|
|
318
|
+
*
|
|
319
|
+
* `record.ts` consumes the pointer so one query grounds one derive. That is a
|
|
320
|
+
* write-time rule with no read-time check, which is the same shape as the
|
|
321
|
+
* tampering the scanner already exists to catch — and it is reachable without
|
|
322
|
+
* any adversary: the documented `clearPointer` failure ("may over-credit until
|
|
323
|
+
* removed"), the non-atomic read-then-clear between concurrent derives, or a
|
|
324
|
+
* duplicated line all produce several derives citing one ID. Before this, three
|
|
325
|
+
* derives on one query read as `compliance 1.00, degraded=false`.
|
|
326
|
+
*
|
|
327
|
+
* So: the FIRST derive (in time order) citing an ID takes the credit, and every
|
|
328
|
+
* later citation of that same ID is a named anomaly that degrades the read. The
|
|
329
|
+
* non-atomic read-then-clear race in `record.ts` is accepted *because* this
|
|
330
|
+
* check catches its result rather than silently inflating the number.
|
|
331
|
+
*
|
|
332
|
+
* Mutates `anomalies` with per-item counts. Returns the set of credited rows.
|
|
333
|
+
*/
|
|
334
|
+
function creditDerives(rows, queryIndex, anomalies) {
|
|
335
|
+
const credited = new Set();
|
|
336
|
+
/** Correlation IDs already spent. One query grounds one derive. */
|
|
337
|
+
const consumed = new Set();
|
|
338
|
+
// Query rows in time order, for the seat-mismatch diagnostic below.
|
|
339
|
+
const queries = rows.filter((r) => r.type === 'corpus_query');
|
|
340
|
+
// `rows` is time-sorted by the scanner, so "first" is unambiguous.
|
|
341
|
+
for (const row of rows) {
|
|
342
|
+
if (row.type !== 'derive_action')
|
|
343
|
+
continue;
|
|
344
|
+
if (row.correlationId === undefined) {
|
|
345
|
+
// Seat-plumbing diagnostic (NOT an integrity anomaly). An uncorrelated
|
|
346
|
+
// derive whose in-window candidate query carries a DIFFERENT seat is the
|
|
347
|
+
// signature of one-sided seating — e.g. a seated CLI and an unseated MCP
|
|
348
|
+
// server — which silently drives the number to 0.00 with no other tell.
|
|
349
|
+
// A config smell, not tampering, so it never degrades the read.
|
|
350
|
+
// The hint means "this derive had NO same-seat query to correlate to, but
|
|
351
|
+
// a different seat was querying in the same window" — the one-sided-seat
|
|
352
|
+
// signature. Seeing a different-seat query is therefore not sufficient:
|
|
353
|
+
// if a same-seat query is also in-window, the uncorrelated derive has an
|
|
354
|
+
// ordinary explanation (spent pointer, out-of-session) and seat plumbing
|
|
355
|
+
// is not implicated. Flagging on the first different-seat hit reported a
|
|
356
|
+
// config problem that was not there — and the `.some()` this walk replaced
|
|
357
|
+
// had the same false-positive semantics, so this corrects the semantic,
|
|
358
|
+
// not just the rewrite.
|
|
359
|
+
//
|
|
360
|
+
// Reverse walk: `queries` is time-sorted, so the walk stops at the window
|
|
361
|
+
// edge once it is below the derive's timestamp. Bounded for interleaved
|
|
362
|
+
// ledgers; when a run of derives precedes a run of queries, the `continue`
|
|
363
|
+
// over newer queries makes it O(derives × queries) worst-case again —
|
|
364
|
+
// measured 83ms at 5k×5k, accepted. Both arrays are time-sorted, so a
|
|
365
|
+
// two-pointer sweep can tighten this if ledgers outgrow that.
|
|
366
|
+
let sawSameSeat = false;
|
|
367
|
+
let sawDifferentSeat = false;
|
|
368
|
+
for (let q = queries.length - 1; q >= 0; q--) {
|
|
369
|
+
const query = queries[q];
|
|
370
|
+
if (query.ms > row.ms)
|
|
371
|
+
continue;
|
|
372
|
+
if (row.ms - query.ms > QBD_CORRELATION_WINDOW_MS)
|
|
373
|
+
break;
|
|
374
|
+
if (query.agentSource === row.agentSource) {
|
|
375
|
+
sawSameSeat = true;
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
sawDifferentSeat = true;
|
|
379
|
+
}
|
|
380
|
+
if (!sawSameSeat && sawDifferentSeat)
|
|
381
|
+
anomalies.seatMismatchHints++;
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const candidates = queryIndex.get(row.correlationId);
|
|
385
|
+
const grounding = candidates?.find((q) => q.ms <= row.ms);
|
|
386
|
+
if (grounding === undefined) {
|
|
387
|
+
anomalies.orphanCorrelations++;
|
|
388
|
+
pushDetail(anomalies, `derive at ${new Date(row.ms).toISOString()} cites correlation ID ${row.correlationId} with no preceding query row`);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (grounding.sessionId !== row.sessionId || grounding.agentSource !== row.agentSource) {
|
|
392
|
+
// Different session OR different seat. Both are the same defect from the
|
|
393
|
+
// metric's side: a query that cannot have grounded this derive.
|
|
394
|
+
anomalies.crossSessionCorrelations++;
|
|
395
|
+
pushDetail(anomalies, `derive at ${new Date(row.ms).toISOString()} correlates to a query from a different session or seat`);
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (consumed.has(row.correlationId)) {
|
|
399
|
+
anomalies.duplicateCorrelations++;
|
|
400
|
+
pushDetail(anomalies, `derive at ${new Date(row.ms).toISOString()} re-cites correlation ID ${row.correlationId}, already spent by an earlier derive (one query grounds one derive)`);
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
consumed.add(row.correlationId);
|
|
404
|
+
credited.add(row);
|
|
405
|
+
}
|
|
406
|
+
return credited;
|
|
407
|
+
}
|
|
408
|
+
/** Tally one session against the globally-decided credit set. */
|
|
409
|
+
function scoreSession(session, credited) {
|
|
410
|
+
const stat = { derives: 0, correlated: 0 };
|
|
411
|
+
for (const row of session.rows) {
|
|
412
|
+
if (row.type !== 'derive_action')
|
|
413
|
+
continue;
|
|
414
|
+
// Every derive counts, correlated or not (falsifier 1).
|
|
415
|
+
stat.derives++;
|
|
416
|
+
if (credited.has(row))
|
|
417
|
+
stat.correlated++;
|
|
418
|
+
}
|
|
419
|
+
return stat;
|
|
420
|
+
}
|
|
421
|
+
function sumStats(stats) {
|
|
422
|
+
return stats.reduce((acc, s) => ({ derives: acc.derives + s.derives, correlated: acc.correlated + s.correlated }), { derives: 0, correlated: 0 });
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Compute the compliance report from a scan.
|
|
426
|
+
*
|
|
427
|
+
* The verdict stays `PENDING` until the pre-registered window fills. That is
|
|
428
|
+
* deliberate: declaring PASS at n=3 would be as much a post-hoc reinterpretation
|
|
429
|
+
* of the registration as moving the threshold would be.
|
|
430
|
+
*/
|
|
431
|
+
export function computeQbdCompliance(scan) {
|
|
432
|
+
const anomalies = {
|
|
433
|
+
...scan.anomalies,
|
|
434
|
+
details: [...scan.anomalies.details],
|
|
435
|
+
};
|
|
436
|
+
const queryIndex = new Map();
|
|
437
|
+
for (const row of scan.rows) {
|
|
438
|
+
if (row.type !== 'corpus_query' || row.correlationId === undefined)
|
|
439
|
+
continue;
|
|
440
|
+
const bucket = queryIndex.get(row.correlationId);
|
|
441
|
+
if (bucket === undefined)
|
|
442
|
+
queryIndex.set(row.correlationId, [row]);
|
|
443
|
+
else
|
|
444
|
+
bucket.push(row);
|
|
445
|
+
}
|
|
446
|
+
const sessions = groupQbdSessions(scan.rows);
|
|
447
|
+
const instrumented = sessions.filter((s) => s.rows.some((r) => r.type === 'derive_action'));
|
|
448
|
+
// Credit is decided globally FIRST — the 1:1 rule spans sessions.
|
|
449
|
+
const credited = creditDerives(scan.rows, queryIndex, anomalies);
|
|
450
|
+
const perSession = instrumented.map((s) => scoreSession(s, credited));
|
|
451
|
+
const evaluated = perSession.slice(0, QBD_PRE_REGISTERED_WINDOW_SESSIONS);
|
|
452
|
+
const window = sumStats(evaluated);
|
|
453
|
+
const compliance = window.derives === 0 ? null : window.correlated / window.derives;
|
|
454
|
+
let verdict = 'PENDING';
|
|
455
|
+
if (instrumented.length >= QBD_PRE_REGISTERED_WINDOW_SESSIONS && compliance !== null) {
|
|
456
|
+
verdict = compliance >= QBD_PRE_REGISTERED_THRESHOLD ? 'PASS' : 'FAIL';
|
|
457
|
+
}
|
|
458
|
+
// Trend across ALL instrumented sessions, earlier half vs recent half.
|
|
459
|
+
let trend = null;
|
|
460
|
+
if (perSession.length >= MIN_SESSIONS_PER_TREND_SIDE * 2) {
|
|
461
|
+
const mid = Math.floor(perSession.length / 2);
|
|
462
|
+
trend = {
|
|
463
|
+
earlier: sumStats(perSession.slice(0, mid)),
|
|
464
|
+
recent: sumStats(perSession.slice(mid)),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
// `seatMismatchHints` is deliberately absent: one-sided seat plumbing is a
|
|
468
|
+
// config smell, not evidence the ledger cannot be trusted.
|
|
469
|
+
const degraded = scan.degraded ||
|
|
470
|
+
anomalies.orphanCorrelations > 0 ||
|
|
471
|
+
anomalies.crossSessionCorrelations > 0 ||
|
|
472
|
+
anomalies.duplicateCorrelations > 0;
|
|
473
|
+
return {
|
|
474
|
+
instrumentedSessions: instrumented.length,
|
|
475
|
+
evaluatedSessions: evaluated.length,
|
|
476
|
+
window,
|
|
477
|
+
compliance,
|
|
478
|
+
verdict,
|
|
479
|
+
trend,
|
|
480
|
+
anomalies,
|
|
481
|
+
degraded,
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
/** Format a rate as a fixed-2 fraction, or `n/a` when there is nothing to divide. */
|
|
485
|
+
export function formatQbdRate(stat) {
|
|
486
|
+
if (stat.derives === 0)
|
|
487
|
+
return 'n/a (0 derive-class events)';
|
|
488
|
+
return `${(stat.correlated / stat.derives).toFixed(2)} (${stat.correlated}/${stat.derives})`;
|
|
489
|
+
}
|
|
490
|
+
//# sourceMappingURL=compliance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.js","sourceRoot":"","sources":["../../src/qbd/compliance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance.test.d.ts","sourceRoot":"","sources":["../../src/qbd/compliance.test.ts"],"names":[],"mappings":""}
|