@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
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
- export const LedgerEventSchema = z.object({
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';
@@ -1 +1 @@
1
- {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../src/ledger.ts"],"names":[],"mappings":"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"}
@@ -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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"}