@mmnto/totem 1.122.0 → 1.124.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/artifacts/legs.d.ts +430 -0
- package/dist/artifacts/legs.d.ts.map +1 -0
- package/dist/artifacts/legs.js +577 -0
- package/dist/artifacts/legs.js.map +1 -0
- package/dist/artifacts/legs.test.d.ts +19 -0
- package/dist/artifacts/legs.test.d.ts.map +1 -0
- package/dist/artifacts/legs.test.js +628 -0
- package/dist/artifacts/legs.test.js.map +1 -0
- package/dist/config-schema.d.ts +35 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config-schema.js +28 -0
- package/dist/config-schema.js.map +1 -1
- package/dist/config-schema.test.js +73 -0
- package/dist/config-schema.test.js.map +1 -1
- 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 +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/routing/legs-owed.d.ts +65 -0
- package/dist/routing/legs-owed.d.ts.map +1 -0
- package/dist/routing/legs-owed.js +72 -0
- package/dist/routing/legs-owed.js.map +1 -0
- package/dist/routing/legs-owed.test.d.ts +10 -0
- package/dist/routing/legs-owed.test.d.ts.map +1 -0
- package/dist/routing/legs-owed.test.js +119 -0
- package/dist/routing/legs-owed.test.js.map +1 -0
- package/dist/semantic-dedup.d.ts.map +1 -1
- package/dist/semantic-dedup.js +2 -5
- package/dist/semantic-dedup.js.map +1 -1
- package/dist/semantic-dedup.test.js +32 -1
- package/dist/semantic-dedup.test.js.map +1 -1
- package/dist/store/lance-store.test.js +23 -0
- package/dist/store/lance-store.test.js.map +1 -1
- package/dist/store/search-lessons.d.ts +18 -0
- package/dist/store/search-lessons.d.ts.map +1 -0
- package/dist/store/search-lessons.js +18 -0
- package/dist/store/search-lessons.js.map +1 -0
- package/dist/store/search-lessons.test.d.ts +2 -0
- package/dist/store/search-lessons.test.d.ts.map +1 -0
- package/dist/store/search-lessons.test.js +48 -0
- package/dist/store/search-lessons.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leg-deposit contract — the machine-readable record a falsification leg
|
|
3
|
+
* leaves behind after it READ a diff (mmnto-ai/totem#2698, ruled 2026-09-03).
|
|
4
|
+
*
|
|
5
|
+
* The gate's question is deliberately narrow: *was THIS head read by a leg?*
|
|
6
|
+
* So the store is keyed by the READ sha — `<totemDir>/artifacts/legs/<diffSha>.json`
|
|
7
|
+
* — and NOT content-addressed like the verdict/admission/run families. Two
|
|
8
|
+
* legs that read the same head are the same answer to that question; a rerun
|
|
9
|
+
* on the same head supersedes by INTENT, which is why the writer is
|
|
10
|
+
* create-exclusive and a `replace` discloses the `readAt` it overwrote rather
|
|
11
|
+
* than silently deduping (the content-addressed stores' EEXIST-is-dedup rule
|
|
12
|
+
* would be a lie here — the second read is a different observation).
|
|
13
|
+
*
|
|
14
|
+
* Store mechanics still mirror the sibling families where the semantics agree:
|
|
15
|
+
* validate-on-write so a writer bug never poisons the store, a
|
|
16
|
+
* tolerant-within-major reader whose newer-major refusal is NAMED (an older
|
|
17
|
+
* CLI meeting a newer deposit reports "upgrade", never "corrupt"), unknown
|
|
18
|
+
* keys tolerated (forward-minor additive fields), and `0o600` bytes.
|
|
19
|
+
*
|
|
20
|
+
* Two properties are specific to this family:
|
|
21
|
+
*
|
|
22
|
+
* 1. **The loader never throws.** A deposit is a hand-editable JSON file that
|
|
23
|
+
* a pre-push hook reads on every push; one bad file must never take the
|
|
24
|
+
* gate down or hide a valid sibling. Every per-file failure — unreadable,
|
|
25
|
+
* non-JSON, schema-invalid, wrong major, or a filename that disagrees with
|
|
26
|
+
* the stored `diffSha` — becomes a one-line `corrupt` row the caller
|
|
27
|
+
* prints (Tenet 4: loud, never silent).
|
|
28
|
+
* 2. **Every stored string that reaches stdout is control-byte free at the
|
|
29
|
+
* SCHEMA boundary**, at write and at read alike. `verdict`, `claim`,
|
|
30
|
+
* `counterexample` and `file` land inside a hook's `[Totem] …` line; a
|
|
31
|
+
* newline in any of them would forge a second line, so the schema refuses
|
|
32
|
+
* C0 (0-31) and DEL/C1 (127-159) outright. "Single-line" needs no separate
|
|
33
|
+
* rule: LF and CR are inside that band.
|
|
34
|
+
*
|
|
35
|
+
* Core never shells out. Ancestry is supplied by the CLI through the injected
|
|
36
|
+
* {@link LegGitAdapter}, so every resolution rule here is unit-testable
|
|
37
|
+
* without a git fixture.
|
|
38
|
+
*/
|
|
39
|
+
import * as crypto from 'node:crypto';
|
|
40
|
+
import * as fs from 'node:fs';
|
|
41
|
+
import * as path from 'node:path';
|
|
42
|
+
import { z } from 'zod';
|
|
43
|
+
import { TotemError } from '../errors.js';
|
|
44
|
+
import { writeFileAtomicSync } from '../fs-atomic.js';
|
|
45
|
+
// ─── Schema version (mirrors the RunArtifact / panel F1 policy) ─────────────
|
|
46
|
+
/** The leg-deposit schemaVersion WRITTEN by this code. Readers accept any 1.x. */
|
|
47
|
+
export const LEG_DEPOSIT_SCHEMA_VERSION = '1.0.0';
|
|
48
|
+
/** The major this reader understands; another major needs a migration entry. */
|
|
49
|
+
export const LEG_DEPOSIT_KNOWN_MAJOR = 1;
|
|
50
|
+
/** Major-1 semver literal — keep in sync with {@link LEG_DEPOSIT_KNOWN_MAJOR}. */
|
|
51
|
+
const LEG_SCHEMA_VERSION_RE = /^1\.\d+\.\d+$/;
|
|
52
|
+
/**
|
|
53
|
+
* Accept any 1.x version; refuse another major with a NAMED reason (the panel
|
|
54
|
+
* precedent). Zod `.regex()` is the validation boundary — not a bare
|
|
55
|
+
* `RegExp.test` — so the ZodError carries the offending value, and the
|
|
56
|
+
* refusal reads the same at write and at read.
|
|
57
|
+
*/
|
|
58
|
+
const legSchemaVersionField = z.string().regex(LEG_SCHEMA_VERSION_RE, {
|
|
59
|
+
message: `unsupported leg-deposit schemaVersion — this reader understands major ${LEG_DEPOSIT_KNOWN_MAJOR}.x; a newer major needs a newer @mmnto/cli`,
|
|
60
|
+
});
|
|
61
|
+
/** The read sha: a full 40-char lowercase git object name, never abbreviated. */
|
|
62
|
+
const DIFF_SHA_RE = /^[0-9a-f]{40}$/;
|
|
63
|
+
/** Finding ids are filename-safe and short — they are echoed and cross-referenced. */
|
|
64
|
+
const LEG_FINDING_ID_RE = /^[A-Za-z0-9_-]{1,32}$/;
|
|
65
|
+
// ─── Control-byte discipline ────────────────────────────────────────────────
|
|
66
|
+
/**
|
|
67
|
+
* True when `text` carries any C0 (0-31) or DEL/C1 (127-159) code point.
|
|
68
|
+
*
|
|
69
|
+
* Written as a `charCodeAt` loop on purpose, mirroring the pre-commit hook's
|
|
70
|
+
* `safe()` (`install-hooks.ts`): the equivalent regex character class would
|
|
71
|
+
* have to be authored with `\u`/`\x` escapes, and this repo has a banked
|
|
72
|
+
* incident where an editing tool decoded such an escape into a RAW control
|
|
73
|
+
* byte in the source. The loop states the same rule with no escape to decode.
|
|
74
|
+
* U+0085 (NEL) is inside the band because it breaks a line on some terminals.
|
|
75
|
+
*/
|
|
76
|
+
function hasControlByte(text) {
|
|
77
|
+
for (let i = 0; i < text.length; i++) {
|
|
78
|
+
const code = text.charCodeAt(i);
|
|
79
|
+
if (code < 32 || (code >= 127 && code <= 159))
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
/** Replace every control byte with `?` — used for the one-line `corrupt` reasons. */
|
|
85
|
+
function toSingleLine(text) {
|
|
86
|
+
let out = '';
|
|
87
|
+
for (let i = 0; i < text.length; i++) {
|
|
88
|
+
const code = text.charCodeAt(i);
|
|
89
|
+
const control = code < 32 || (code >= 127 && code <= 159);
|
|
90
|
+
out = out + (control ? '?' : text.charAt(i));
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/** A string field that reaches a hook's stdout: no C0/C1 bytes, hence single-line. */
|
|
95
|
+
function controlFreeText(label) {
|
|
96
|
+
return z.string().refine((value) => !hasControlByte(value), {
|
|
97
|
+
message: `${label} must be a single line free of control characters (C0 0-31, DEL/C1 127-159) — the value is echoed on the gate's stdout`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Same, but also non-empty. */
|
|
101
|
+
function requiredControlFreeText(label) {
|
|
102
|
+
return z
|
|
103
|
+
.string()
|
|
104
|
+
.min(1, `${label} must not be empty`)
|
|
105
|
+
.refine((value) => !hasControlByte(value), {
|
|
106
|
+
message: `${label} must be a single line free of control characters (C0 0-31, DEL/C1 127-159) — the value is echoed on the gate's stdout`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// ─── Findings ───────────────────────────────────────────────────────────────
|
|
110
|
+
/**
|
|
111
|
+
* The leg's severity vocabulary. Deliberately NOT the verdict family's
|
|
112
|
+
* CRITICAL/WARN/INFO: a leg deposit answers "what did the leg find", and the
|
|
113
|
+
* doctrine spelling for that is BLOCKING (the fold must land) / MATERIAL (the
|
|
114
|
+
* seat rules) / MINOR (disclosed). Order here is documentation order; the
|
|
115
|
+
* value is data. One spelling — {@link LegFindingSeveritySchema} is built
|
|
116
|
+
* from this array, never a second literal list.
|
|
117
|
+
*/
|
|
118
|
+
export const LEG_FINDING_SEVERITIES = ['BLOCKING', 'MATERIAL', 'MINOR'];
|
|
119
|
+
export const LegFindingSeveritySchema = z.enum(LEG_FINDING_SEVERITIES);
|
|
120
|
+
/** The finding id — required, so `folded` can NAME a finding rather than index it. */
|
|
121
|
+
export const LegFindingIdSchema = z
|
|
122
|
+
.string()
|
|
123
|
+
.regex(LEG_FINDING_ID_RE, 'a finding id must be 1-32 characters of [A-Za-z0-9_-]');
|
|
124
|
+
/**
|
|
125
|
+
* One typed finding. `id` is required (mmnto-ai/totem#2698 OQ1, ruled): the
|
|
126
|
+
* contract JSON had none, and without one `folded` cannot reference a finding
|
|
127
|
+
* — positional indexes are fragile under reordering, and a bare count cannot
|
|
128
|
+
* be checked against anything.
|
|
129
|
+
*/
|
|
130
|
+
export const LegFindingSchema = z.object({
|
|
131
|
+
/** Unique within the deposit; the referent of every `folded` entry. */
|
|
132
|
+
id: LegFindingIdSchema,
|
|
133
|
+
severity: LegFindingSeveritySchema,
|
|
134
|
+
/** Repo-relative path the finding is about (free-form: core never resolves it). */
|
|
135
|
+
file: requiredControlFreeText('finding.file'),
|
|
136
|
+
/** 0 means "the file, no particular line" — never a sentinel like -1. */
|
|
137
|
+
line: z.number().int().nonnegative(),
|
|
138
|
+
/** The falsifiable claim, one line. */
|
|
139
|
+
claim: requiredControlFreeText('finding.claim'),
|
|
140
|
+
/** The evidence. MAY be empty — a claim with no counterexample is still disclosed. */
|
|
141
|
+
counterexample: controlFreeText('finding.counterexample'),
|
|
142
|
+
});
|
|
143
|
+
// ─── Deposit ────────────────────────────────────────────────────────────────
|
|
144
|
+
/**
|
|
145
|
+
* The deposit itself. Every field is required; the arrays may be empty (a leg
|
|
146
|
+
* that found nothing still deposits — that IS the evidence the gate wants).
|
|
147
|
+
*
|
|
148
|
+
* Unknown keys are TOLERATED, not refused (the run-artifact precedent): a
|
|
149
|
+
* forward-minor writer may add a field this reader strips, and a deposit is
|
|
150
|
+
* evidence a newer leg wrote, not a contract this reader gets to narrow.
|
|
151
|
+
*/
|
|
152
|
+
export const LegDepositSchema = z
|
|
153
|
+
.object({
|
|
154
|
+
/** Writer version; readers tolerate any 1.x, refuse another major by name. */
|
|
155
|
+
schemaVersion: legSchemaVersionField,
|
|
156
|
+
/** The head the leg READ — a full 40-hex commit, and the file's own name. */
|
|
157
|
+
diffSha: z.string().regex(DIFF_SHA_RE, 'diffSha must be a 40-character lowercase hex sha'),
|
|
158
|
+
/** The leg's own instant, ISO-8601. Ties are broken on it, so it is contract. */
|
|
159
|
+
readAt: z.string().datetime(),
|
|
160
|
+
findings: z.array(LegFindingSchema),
|
|
161
|
+
/** Ids of findings the seat FOLDED — a subset of `findings[].id` (superRefine). */
|
|
162
|
+
folded: z.array(LegFindingIdSchema),
|
|
163
|
+
/** The leg's one-line disposition; echoed verbatim on the gate's evidence line. */
|
|
164
|
+
verdict: requiredControlFreeText('verdict'),
|
|
165
|
+
})
|
|
166
|
+
.superRefine((deposit, ctx) => {
|
|
167
|
+
const seen = new Set();
|
|
168
|
+
for (const [index, finding] of deposit.findings.entries()) {
|
|
169
|
+
if (seen.has(finding.id)) {
|
|
170
|
+
ctx.addIssue({
|
|
171
|
+
code: z.ZodIssueCode.custom,
|
|
172
|
+
path: ['findings', index, 'id'],
|
|
173
|
+
message: `duplicate finding id "${finding.id}" — ids must be unique within a deposit (folded names them)`,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
seen.add(finding.id);
|
|
177
|
+
}
|
|
178
|
+
for (const [index, id] of deposit.folded.entries()) {
|
|
179
|
+
if (!seen.has(id)) {
|
|
180
|
+
ctx.addIssue({
|
|
181
|
+
code: z.ZodIssueCode.custom,
|
|
182
|
+
path: ['folded', index],
|
|
183
|
+
message: `folded names "${id}", which is not a finding id in this deposit`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
// ─── Paths ──────────────────────────────────────────────────────────────────
|
|
189
|
+
/** Storage layout segments under the totem dir (mirrors `runsDir`'s idiom). */
|
|
190
|
+
const LEGS_DIR_SEGMENTS = ['artifacts', 'legs'];
|
|
191
|
+
/** Absolute legs directory for a given absolute totem dir. */
|
|
192
|
+
export function legsDir(totemDirAbs) {
|
|
193
|
+
return path.join(totemDirAbs, ...LEGS_DIR_SEGMENTS);
|
|
194
|
+
}
|
|
195
|
+
/** Absolute path of the deposit for `diffSha` — the sha IS the filename stem. */
|
|
196
|
+
export function legDepositPath(totemDirAbs, diffSha) {
|
|
197
|
+
return path.join(legsDir(totemDirAbs), `${diffSha}.json`);
|
|
198
|
+
}
|
|
199
|
+
// ─── Save ───────────────────────────────────────────────────────────────────
|
|
200
|
+
/**
|
|
201
|
+
* Refusal to overwrite an existing deposit without `replace`. Typed so the
|
|
202
|
+
* CLI can print the incumbent's `readAt` and the one-flag cure rather than
|
|
203
|
+
* re-deriving either. `existingReadAt` is `undefined` when the incumbent
|
|
204
|
+
* itself is unreadable/corrupt — the refusal still stands (the seat decides
|
|
205
|
+
* whether to replace it), and the honest report is that its instant could not
|
|
206
|
+
* be read.
|
|
207
|
+
*/
|
|
208
|
+
export class LegDepositExistsError extends TotemError {
|
|
209
|
+
diffSha;
|
|
210
|
+
existingReadAt;
|
|
211
|
+
depositPath;
|
|
212
|
+
constructor(diffSha, existingReadAt, depositPath) {
|
|
213
|
+
super('LEG_DEPOSIT_EXISTS', `A leg deposit already exists for ${diffSha} (read ${existingReadAt ?? 'at an unreadable instant'}) at ${depositPath}.`, 'Pass --replace to overwrite it (the replaced readAt is reported), or deposit against the current head.');
|
|
214
|
+
this.name = 'LegDepositExistsError';
|
|
215
|
+
this.diffSha = diffSha;
|
|
216
|
+
this.existingReadAt = existingReadAt;
|
|
217
|
+
this.depositPath = depositPath;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/** Best-effort read of an incumbent's `readAt` — for disclosure only, never a gate. */
|
|
221
|
+
function peekReadAt(filePath) {
|
|
222
|
+
try {
|
|
223
|
+
const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
224
|
+
if (typeof raw !== 'object' || raw === null)
|
|
225
|
+
return undefined;
|
|
226
|
+
const readAt = raw['readAt'];
|
|
227
|
+
return typeof readAt === 'string' ? toSingleLine(readAt) : undefined;
|
|
228
|
+
// totem-context: intentional best-effort — the incumbent's instant is DISCLOSURE beside a refusal that happens either way; a corrupt incumbent must not turn "already deposited" into a read error
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Persist a deposit at `<legsDir>/<diffSha>.json`, create-exclusive by default.
|
|
236
|
+
*
|
|
237
|
+
* Ordering is contract: the deposit is VALIDATED before the filesystem is
|
|
238
|
+
* touched at all, and the occupancy check precedes the write — so a refused
|
|
239
|
+
* write (schema-invalid, or occupied without `replace`) leaves no file and no
|
|
240
|
+
* temp behind. The bytes go through the shared atomic helper (temp in the same
|
|
241
|
+
* directory, fsync), so a reader never observes a torn deposit.
|
|
242
|
+
*
|
|
243
|
+
* The PUBLISH is exclusive, not merely checked (Greptile P1 on PR
|
|
244
|
+
* mmnto-ai/totem#2745). `existsSync` then rename is check-then-act: two
|
|
245
|
+
* no-replace writers for one sha both see "absent" and the later rename wins
|
|
246
|
+
* silently, overwriting one leg's read with another's. Without `replace` the
|
|
247
|
+
* final name is therefore created by `fs.linkSync`, which is atomic and fails
|
|
248
|
+
* `EEXIST` if the name is taken — the loser refuses exactly as the pre-check
|
|
249
|
+
* does, and the incumbent's bytes are never touched. `replace: true` keeps the
|
|
250
|
+
* rename path, because overwriting is what it asks for.
|
|
251
|
+
*
|
|
252
|
+
* The file's name is DERIVED from `deposit.diffSha`, which is how the store's
|
|
253
|
+
* "the name is the read sha" invariant holds by construction; the loader
|
|
254
|
+
* re-checks it on the way back in, since the name comes off a filesystem a
|
|
255
|
+
* human can rename.
|
|
256
|
+
*/
|
|
257
|
+
export function saveLegDeposit(totemDirAbs, deposit, options = {}) {
|
|
258
|
+
// Validate on the way OUT (the run/admission/verdict precedent): a writer bug
|
|
259
|
+
// must never poison a store whose reader would then report it as corrupt.
|
|
260
|
+
const validated = LegDepositSchema.parse(deposit);
|
|
261
|
+
const filePath = legDepositPath(totemDirAbs, validated.diffSha);
|
|
262
|
+
let replaced;
|
|
263
|
+
// The cheap early refusal — it answers the common case without writing a
|
|
264
|
+
// byte. It is NOT the guarantee: two writers can both pass it (the exclusive
|
|
265
|
+
// publish below is what actually decides). Greptile P1 on PR
|
|
266
|
+
// mmnto-ai/totem#2745.
|
|
267
|
+
if (fs.existsSync(filePath)) {
|
|
268
|
+
const existingReadAt = peekReadAt(filePath);
|
|
269
|
+
if (options.replace !== true) {
|
|
270
|
+
throw new LegDepositExistsError(validated.diffSha, existingReadAt, filePath);
|
|
271
|
+
}
|
|
272
|
+
replaced = { readAt: existingReadAt };
|
|
273
|
+
}
|
|
274
|
+
fs.mkdirSync(legsDir(totemDirAbs), { recursive: true });
|
|
275
|
+
const body = JSON.stringify(validated, null, 2);
|
|
276
|
+
if (options.replace === true) {
|
|
277
|
+
// `replace` is ALLOWED to overwrite, so the rename path is correct here:
|
|
278
|
+
// the incumbent's `readAt` is already captured above and reported.
|
|
279
|
+
writeFileAtomicSync(filePath, body, { mode: 0o600 });
|
|
280
|
+
// `replaced` stays absent when `--replace` was passed with nothing to
|
|
281
|
+
// replace: reporting a replacement that did not happen would be a lie the
|
|
282
|
+
// writer's own success line then prints.
|
|
283
|
+
return replaced === undefined ? { path: filePath } : { path: filePath, replaced };
|
|
284
|
+
}
|
|
285
|
+
// Create-exclusive for real. `existsSync` then rename is check-then-act: two
|
|
286
|
+
// no-replace writers for one sha both see "absent", both rename, and the
|
|
287
|
+
// later one silently wins — one leg's read overwritten by another's with no
|
|
288
|
+
// refusal and no disclosure, in a store whose whole contract is that a
|
|
289
|
+
// second read at a head is a different observation.
|
|
290
|
+
//
|
|
291
|
+
// `link` is the exclusive primitive: it creates the final name atomically
|
|
292
|
+
// and fails EEXIST if anything already holds it. Measured on NTFS as well as
|
|
293
|
+
// POSIX for this fix — the loser gets EEXIST, the incumbent's bytes are
|
|
294
|
+
// untouched, and the loser's temp survives to be cleaned up here.
|
|
295
|
+
const tempPath = `${filePath}.${process.pid}-${randomSuffix()}.tmp`;
|
|
296
|
+
try {
|
|
297
|
+
writeFileAtomicSync(tempPath, body, { mode: 0o600 });
|
|
298
|
+
fs.linkSync(tempPath, filePath);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (err.code === 'EEXIST') {
|
|
302
|
+
// Someone published between the pre-check and here. Same refusal the
|
|
303
|
+
// pre-check raises, carrying the incumbent's instant — read AFTER the
|
|
304
|
+
// loss, so it names the deposit that actually won.
|
|
305
|
+
const existingReadAt = peekReadAt(filePath);
|
|
306
|
+
removeQuietly(tempPath);
|
|
307
|
+
throw new LegDepositExistsError(validated.diffSha, existingReadAt, filePath);
|
|
308
|
+
}
|
|
309
|
+
removeQuietly(tempPath);
|
|
310
|
+
throw err;
|
|
311
|
+
}
|
|
312
|
+
// The link succeeded, so `filePath` and `tempPath` name the same inode; the
|
|
313
|
+
// temp is just the second name and goes away.
|
|
314
|
+
removeQuietly(tempPath);
|
|
315
|
+
return { path: filePath };
|
|
316
|
+
}
|
|
317
|
+
/** Entropy for the publish temp's name — the `writeFileAtomicSync` idiom. */
|
|
318
|
+
function randomSuffix() {
|
|
319
|
+
return crypto.randomUUID().slice(0, 8);
|
|
320
|
+
}
|
|
321
|
+
/** Best-effort unlink of a publish temp. */
|
|
322
|
+
function removeQuietly(target) {
|
|
323
|
+
try {
|
|
324
|
+
fs.rmSync(target, { force: true });
|
|
325
|
+
// totem-context: intentional cleanup — a failed temp unlink must not mask the publish's own outcome, and the file it leaves behind is a `.tmp` sibling the loader already ignores (it is not `.json`)
|
|
326
|
+
}
|
|
327
|
+
catch {
|
|
328
|
+
/* best-effort: the temp is a `.tmp` sibling the loader never reads */
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/** Best-effort major extraction from a raw parsed payload; undefined when absent/garbled. */
|
|
332
|
+
function readMajor(raw) {
|
|
333
|
+
if (typeof raw !== 'object' || raw === null)
|
|
334
|
+
return undefined;
|
|
335
|
+
const version = raw['schemaVersion'];
|
|
336
|
+
if (typeof version !== 'string')
|
|
337
|
+
return undefined;
|
|
338
|
+
const major = Number.parseInt(version.split('.')[0] ?? '', 10);
|
|
339
|
+
return Number.isNaN(major) ? undefined : major;
|
|
340
|
+
}
|
|
341
|
+
/** Flatten a ZodError into one echo-safe line. */
|
|
342
|
+
function oneLineZodReason(zodError) {
|
|
343
|
+
return toSingleLine(zodError.issues
|
|
344
|
+
.map((issue) => {
|
|
345
|
+
const at = issue.path.length > 0 ? issue.path.join('.') : '<root>';
|
|
346
|
+
return `${at}: ${issue.message}`;
|
|
347
|
+
})
|
|
348
|
+
.join('; '));
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Read every deposit in the store, TOLERANTLY.
|
|
352
|
+
*
|
|
353
|
+
* Never throws: a missing directory is an empty store, a non-`.json` entry is
|
|
354
|
+
* not a deposit at all (ignored silently — the directory is not the store's
|
|
355
|
+
* inventory), and every other per-file failure is a `corrupt` row carrying a
|
|
356
|
+
* one-line reason. The reading is JSON-AWARE through the schema, so a file
|
|
357
|
+
* that merely *mentions* `diffSha` or `findings` in some other shape — a
|
|
358
|
+
* review artifact copied in, say — is corrupt, never a deposit.
|
|
359
|
+
*
|
|
360
|
+
* The filename is re-checked against the stored `diffSha`: the name is the
|
|
361
|
+
* store's address, a human can rename a file, and a deposit resolved under
|
|
362
|
+
* someone else's sha would answer the gate's question about the wrong head.
|
|
363
|
+
*/
|
|
364
|
+
export function loadLegDeposits(totemDirAbs) {
|
|
365
|
+
const dir = legsDir(totemDirAbs);
|
|
366
|
+
const deposits = [];
|
|
367
|
+
const corrupt = [];
|
|
368
|
+
let entries;
|
|
369
|
+
try {
|
|
370
|
+
entries = fs.readdirSync(dir);
|
|
371
|
+
// totem-context: intentional — a missing/unreadable store dir IS the "no deposit" state the gate already has a loud arm for; the loader's contract is that it never throws
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return { deposits, corrupt };
|
|
375
|
+
}
|
|
376
|
+
for (const entry of [...entries].sort()) {
|
|
377
|
+
if (!entry.endsWith('.json'))
|
|
378
|
+
continue;
|
|
379
|
+
const filePath = path.join(dir, entry);
|
|
380
|
+
const stem = entry.slice(0, -'.json'.length);
|
|
381
|
+
let raw;
|
|
382
|
+
try {
|
|
383
|
+
raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
384
|
+
// totem-context: intentional — an unreadable or non-JSON file becomes a NAMED corrupt row (reason carried, control bytes collapsed) and never a throw; the loader's contract is tolerant-per-file so one bad deposit can never mask a valid sibling
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
corrupt.push({
|
|
388
|
+
file: entry,
|
|
389
|
+
reason: toSingleLine(`unreadable or not JSON: ${err instanceof Error ? err.message : String(err)}`),
|
|
390
|
+
});
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
const major = readMajor(raw);
|
|
394
|
+
if (major !== undefined && major > LEG_DEPOSIT_KNOWN_MAJOR) {
|
|
395
|
+
corrupt.push({
|
|
396
|
+
file: entry,
|
|
397
|
+
reason: `written by a newer totem (schemaVersion major ${major}; this reader understands ${LEG_DEPOSIT_KNOWN_MAJOR}.x) — upgrade @mmnto/cli to read it, the deposit is valid`,
|
|
398
|
+
});
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
const parsed = LegDepositSchema.safeParse(raw);
|
|
402
|
+
if (!parsed.success) {
|
|
403
|
+
corrupt.push({ file: entry, reason: `schema-invalid: ${oneLineZodReason(parsed.error)}` });
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (parsed.data.diffSha !== stem) {
|
|
407
|
+
corrupt.push({
|
|
408
|
+
file: entry,
|
|
409
|
+
reason: `filename does not match its stored diffSha ${parsed.data.diffSha} — the name is this store's address`,
|
|
410
|
+
});
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
deposits.push({ deposit: parsed.data, path: filePath, diffSha: parsed.data.diffSha });
|
|
414
|
+
}
|
|
415
|
+
return { deposits, corrupt };
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Resolve which deposit (if any) answers for `headSha`.
|
|
419
|
+
*
|
|
420
|
+
* A deposit read at X answers for every DESCENDANT of X — the contract's
|
|
421
|
+
* ancestor-or-equal rule — so the ranking is: `exact` first, then the NEAREST
|
|
422
|
+
* ancestor (fewest commits since the read), ties to the LATEST `readAt`. The
|
|
423
|
+
* winner carries its `distance` so the caller can print "+N commits since the
|
|
424
|
+
* leg read" rather than pass a stale read off as a fresh one.
|
|
425
|
+
*
|
|
426
|
+
* Since mmnto-ai/totem#2698 fold 3 ancestry is only HALF the question. When a
|
|
427
|
+
* `coverage` query is supplied, each ancestor candidate is also measured on
|
|
428
|
+
* what it could have READ — the branch diff up to its own head, intersected
|
|
429
|
+
* with the owed paths — and a candidate covering NONE of them is stale, not a
|
|
430
|
+
* winner: it satisfies ancestor-or-equal while its leg saw nothing this push
|
|
431
|
+
* proposes (the merge-base deposit that produced the ruling). An EXACT match
|
|
432
|
+
* covers everything by construction and costs no git call.
|
|
433
|
+
*
|
|
434
|
+
* Ranking is unchanged: along one lineage a nearer ancestor's diff is a
|
|
435
|
+
* superset of a farther one's, so nearest-first already orders by coverage.
|
|
436
|
+
*
|
|
437
|
+
* Nothing here decides POLICY beyond that floor: partial coverage still
|
|
438
|
+
* resolves, and a distance of 200 still resolves. Whether either is evidence
|
|
439
|
+
* enough is the gate's disclosure to make and doctrine's re-arm to rule.
|
|
440
|
+
*/
|
|
441
|
+
export function findLegDepositForHead(totemDirAbs, headSha, git, coverage) {
|
|
442
|
+
const { deposits, corrupt } = loadLegDeposits(totemDirAbs);
|
|
443
|
+
const stale = [];
|
|
444
|
+
const candidates = [];
|
|
445
|
+
// Deduplicated here as well as by the caller: `owed` is PRINTED as the
|
|
446
|
+
// denominator of `covers K/N`, and one file matching three globs must not
|
|
447
|
+
// inflate N into a number no reader can reconcile with the basis.
|
|
448
|
+
const owedFiles = coverage === undefined ? [] : [...new Set(coverage.owedFiles)];
|
|
449
|
+
const fullCoverage = () => ({
|
|
450
|
+
covered: owedFiles.length,
|
|
451
|
+
owed: owedFiles.length,
|
|
452
|
+
missing: [],
|
|
453
|
+
});
|
|
454
|
+
for (const found of deposits) {
|
|
455
|
+
if (found.diffSha === headSha) {
|
|
456
|
+
// An exact match read THIS head: every owed path is inside the diff it
|
|
457
|
+
// saw, by construction. No git call — and an adapter that would throw on
|
|
458
|
+
// one is never reached, which is the property the test pins.
|
|
459
|
+
candidates.push({
|
|
460
|
+
...found,
|
|
461
|
+
rank: 'exact',
|
|
462
|
+
distance: 0,
|
|
463
|
+
...(coverage === undefined ? {} : { coverage: fullCoverage() }),
|
|
464
|
+
});
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
if (!git.isCommit(found.diffSha)) {
|
|
468
|
+
stale.push({
|
|
469
|
+
diffSha: found.diffSha,
|
|
470
|
+
readAt: found.deposit.readAt,
|
|
471
|
+
reason: 'unknown-commit',
|
|
472
|
+
});
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (!git.isAncestor(found.diffSha, headSha)) {
|
|
476
|
+
stale.push({ diffSha: found.diffSha, readAt: found.deposit.readAt, reason: 'not-ancestor' });
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
let measured;
|
|
480
|
+
if (coverage !== undefined && owedFiles.length === 0) {
|
|
481
|
+
// Nothing owed: the intersection is empty whatever the candidate reached,
|
|
482
|
+
// so the probe would be a git call whose result cannot change the answer
|
|
483
|
+
// (mmnto-ai/totem#2698 fold 5, Q3). `0/0` is vacuously covered.
|
|
484
|
+
measured = fullCoverage();
|
|
485
|
+
}
|
|
486
|
+
else if (coverage !== undefined) {
|
|
487
|
+
const reachable = new Set(git.changedFiles(coverage.base, found.diffSha));
|
|
488
|
+
const missing = owedFiles.filter((file) => !reachable.has(file));
|
|
489
|
+
measured = { covered: owedFiles.length - missing.length, owed: owedFiles.length, missing };
|
|
490
|
+
// Reached only with a non-empty owed set (the empty case returned above),
|
|
491
|
+
// so covering none of it is a real coverage failure.
|
|
492
|
+
if (measured.covered === 0) {
|
|
493
|
+
stale.push({
|
|
494
|
+
diffSha: found.diffSha,
|
|
495
|
+
readAt: found.deposit.readAt,
|
|
496
|
+
reason: 'no-coverage',
|
|
497
|
+
});
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
candidates.push({
|
|
502
|
+
...found,
|
|
503
|
+
rank: 'ancestor',
|
|
504
|
+
// Measured AFTER coverage, so a candidate that is already stale costs no
|
|
505
|
+
// second git call.
|
|
506
|
+
distance: git.distance(found.diffSha, headSha),
|
|
507
|
+
...(measured === undefined ? {} : { coverage: measured }),
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
candidates.sort((a, b) => {
|
|
511
|
+
if (a.rank !== b.rank)
|
|
512
|
+
return a.rank === 'exact' ? -1 : 1;
|
|
513
|
+
if (a.distance !== b.distance)
|
|
514
|
+
return a.distance - b.distance;
|
|
515
|
+
// Equal reach: the LATEST read wins — the later leg saw everything the
|
|
516
|
+
// earlier one did, at the same head.
|
|
517
|
+
return Date.parse(b.deposit.readAt) - Date.parse(a.deposit.readAt);
|
|
518
|
+
});
|
|
519
|
+
const [winner, ...rest] = candidates;
|
|
520
|
+
return {
|
|
521
|
+
...(winner === undefined ? {} : { winner }),
|
|
522
|
+
superseded: rest.map((candidate) => ({
|
|
523
|
+
diffSha: candidate.diffSha,
|
|
524
|
+
readAt: candidate.deposit.readAt,
|
|
525
|
+
rank: candidate.rank,
|
|
526
|
+
distance: candidate.distance,
|
|
527
|
+
...(candidate.coverage === undefined ? {} : { coverage: candidate.coverage }),
|
|
528
|
+
})),
|
|
529
|
+
stale,
|
|
530
|
+
corrupt,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Count a deposit's findings by severity, plus how many were folded.
|
|
535
|
+
*
|
|
536
|
+
* A folded finding is still a finding: it is counted in its severity bucket
|
|
537
|
+
* AND in `folded`. The covariate prints both, so a reader can see "3 blocking,
|
|
538
|
+
* 3 folded" (all addressed) apart from "3 blocking, 0 folded" (none were).
|
|
539
|
+
*/
|
|
540
|
+
export function countLegFindings(deposit) {
|
|
541
|
+
let blocking = 0;
|
|
542
|
+
let material = 0;
|
|
543
|
+
let minor = 0;
|
|
544
|
+
for (const finding of deposit.findings) {
|
|
545
|
+
if (finding.severity === 'BLOCKING')
|
|
546
|
+
blocking++;
|
|
547
|
+
else if (finding.severity === 'MATERIAL')
|
|
548
|
+
material++;
|
|
549
|
+
else
|
|
550
|
+
minor++;
|
|
551
|
+
}
|
|
552
|
+
return { blocking, material, minor, folded: deposit.folded.length };
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Render the covariate line's format-v1.2 `leg:` field — the ONE spelling of
|
|
556
|
+
* this text, exactly:
|
|
557
|
+
*
|
|
558
|
+
* `leg: <sha8> blocking=N material=N folded=N` (a deposit resolved)
|
|
559
|
+
* `leg: none` (none did)
|
|
560
|
+
*
|
|
561
|
+
* The field is COMPOSED BESIDE {@link renderCovariateLine} / `renderAdmissionLine`,
|
|
562
|
+
* never inside them: the v1 shapes stay byte-identical, and a consumer keeps
|
|
563
|
+
* discriminating on the second token. The text is contract — the pilot ledger
|
|
564
|
+
* greps this line — so it is spelled here and nowhere else.
|
|
565
|
+
*
|
|
566
|
+
* `minor` is deliberately absent from the field: the round rules on blocking
|
|
567
|
+
* and material, and `folded` is what says whether they were addressed. The
|
|
568
|
+
* full counts stay available via {@link countLegFindings}.
|
|
569
|
+
*/
|
|
570
|
+
export function renderLegField(deposit) {
|
|
571
|
+
if (deposit === undefined)
|
|
572
|
+
return 'leg: none';
|
|
573
|
+
const counts = countLegFindings(deposit);
|
|
574
|
+
const sha8 = deposit.diffSha.slice(0, 8);
|
|
575
|
+
return `leg: ${sha8} blocking=${counts.blocking} material=${counts.material} folded=${counts.folded}`;
|
|
576
|
+
}
|
|
577
|
+
//# sourceMappingURL=legs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legs.js","sourceRoot":"","sources":["../../src/artifacts/legs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Leg-deposit store tests (mmnto-ai/totem#2698).
|
|
3
|
+
*
|
|
4
|
+
* These lock the core-owned half of the design's "invariants to lock in via
|
|
5
|
+
* tests": the store is read JSON-AWARE through the schema (a file that merely
|
|
6
|
+
* quotes `diffSha`/`findings` in some other shape is not a deposit), ancestry
|
|
7
|
+
* ranking is exact > nearest ancestor > latest read, a corrupt file is
|
|
8
|
+
* disclosed by name and reason and never hides a valid sibling,
|
|
9
|
+
* `unknown-commit` and `not-ancestor` are DISTINCT stale reasons, the schema
|
|
10
|
+
* refuses control bytes and a non-subset `folded` at write and at read alike,
|
|
11
|
+
* and the writer is create-exclusive with a disclosed replacement.
|
|
12
|
+
*
|
|
13
|
+
* Every hostile string is built with `String.fromCharCode` on purpose: a
|
|
14
|
+
* literal `\u`/`\x` escape authored through an editing tool has landed as a
|
|
15
|
+
* RAW control byte in this repo before, which would make the test assert
|
|
16
|
+
* something other than what it reads as.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=legs.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legs.test.d.ts","sourceRoot":"","sources":["../../src/artifacts/legs.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|