vdelta 0.1.0 → 0.2.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/store.d.ts CHANGED
@@ -1,22 +1,153 @@
1
- import { type RunRecord } from './schema.js';
1
+ /**
2
+ * Content-addressed run store (spec §4): immutable records, atomic writes,
3
+ * fail-open advisory lock, enforced gitignore. Recency is store insertion
4
+ * order (the append-only index), never timestamps (§7.8).
5
+ *
6
+ * The advisory lock (`.veridelta/lock`, mkdir-based for atomicity) is
7
+ * fail-open per INV-5: a lock that cannot be proven live degrades the
8
+ * caller to transparent passthrough rather than blocking indefinitely.
9
+ * On top of that, acquireLock() auto-reclaims *stale* locks so a crashed
10
+ * process doesn't wedge recording forever:
11
+ * - if the lock carries `meta.json` ({pid, acquired_at_ms}), staleness is
12
+ * decided purely by PID liveness (dead PID => stale, reclaim now;
13
+ * regardless of age otherwise a live holder is never stolen);
14
+ * - if `meta.json` is missing or unreadable/malformed (a legacy lock, or
15
+ * a write that failed), staleness falls back to an mtime threshold
16
+ * (`staleLockMs`, default 10 minutes) — this also preserves INV-5 for
17
+ * the existing fail-open-held-lock conformance fixture, whose fresh
18
+ * bare-mkdir lock must still degrade to passthrough.
19
+ * Reclaim moves the stale lock dir aside via renameSync (atomic: at most
20
+ * one concurrent reclaimer can walk off with that specific directory —
21
+ * a second racer's rename fails outright instead of silently trampling
22
+ * whatever now occupies the path) and deletes the moved-aside copy, then
23
+ * retries mkdir once; if that retry loses the race, we throw
24
+ * LockHeldError (fail-open), never loop. acquireLock() reports back
25
+ * whether it reclaimed a stale lock (and that lock's prior meta, if any)
26
+ * so callers can surface the event instead of reclaiming silently.
27
+ */
28
+ import { type CompletenessStatus, type RunRecord } from './schema.js';
2
29
  export declare class StoreCorruptError extends Error {
3
30
  constructor(message: string);
4
31
  }
5
32
  export declare class LockHeldError extends Error {
6
- constructor();
33
+ readonly lockPath: string;
34
+ constructor(lockPath: string);
7
35
  }
8
36
  /** run_id = content address of the record excluding the recording group (§3.5). */
9
37
  export declare function computeRunId(record: RunRecord): string;
38
+ /** Retention limits for {@link RunStore.gc}. `undefined` disables that limit. */
39
+ export interface GcPolicy {
40
+ maxCount?: number;
41
+ maxBytes?: number;
42
+ }
43
+ /** Outcome of a {@link RunStore.gc} pass. */
44
+ export interface GcResult {
45
+ removed: string[];
46
+ keptCount: number;
47
+ keptBytes: number;
48
+ }
49
+ /**
50
+ * Default retention policy (§4.1 SHOULD be bounded). Overridable via
51
+ * VDELTA_GC_MAX_COUNT / VDELTA_GC_MAX_BYTES (positive integers only; unset,
52
+ * empty, zero, or non-numeric values fall back to defaults or disable the
53
+ * limit respectively).
54
+ */
55
+ export declare function defaultGcPolicy(): GcPolicy;
56
+ /** Lightweight, non-strict view of a run record's addressing fields. */
57
+ export interface RunMeta {
58
+ repo: {
59
+ identity: string;
60
+ worktree: string;
61
+ branch: string;
62
+ cwd: string;
63
+ };
64
+ invocation: {
65
+ command: string[];
66
+ selector: string[];
67
+ };
68
+ instrument: {
69
+ adapter: string;
70
+ adapter_version: string;
71
+ composition_id: string;
72
+ config_digest: string;
73
+ };
74
+ provenance: {
75
+ head: string | null;
76
+ tree_digest: string;
77
+ };
78
+ completeness: {
79
+ status: CompletenessStatus;
80
+ child_exit_code: number;
81
+ };
82
+ }
83
+ /** Options for RunStore's advisory lock stale-detection (testability + tuning). */
84
+ export interface RunStoreOptions {
85
+ /** mtime threshold (ms) for reclaiming a meta-less legacy lock. Default 10 minutes. */
86
+ staleLockMs?: number;
87
+ /** PID liveness probe. Default: process.kill(pid, 0) (ESRCH => dead, else alive). */
88
+ isPidAlive?: (pid: number) => boolean;
89
+ }
90
+ /** Parsed contents of a lock's `meta.json`. */
91
+ export interface LockMeta {
92
+ pid: number;
93
+ acquired_at_ms: number;
94
+ }
95
+ /** Result of acquireLock(): whether a stale lock had to be reclaimed. */
96
+ export interface AcquireLockResult {
97
+ /** True if the lock we now hold was reclaimed from a stale prior holder. */
98
+ reclaimed: boolean;
99
+ /** The reclaimed lock's prior meta.json, if it had one and it was readable. */
100
+ staleMeta: LockMeta | null;
101
+ }
10
102
  export declare class RunStore {
11
103
  readonly dir: string;
12
- constructor(worktreeRoot: string);
104
+ private readonly staleLockMs;
105
+ private readonly isPidAlive;
106
+ constructor(worktreeRoot: string, options?: RunStoreOptions);
13
107
  private get runsDir();
14
108
  private get indexPath();
15
109
  private get lastPath();
16
110
  private get lockPath();
111
+ private get lockMetaPath();
17
112
  ensure(): void;
18
- /** Advisory lock via mkdir; throws LockHeldError when already held (fail-open at the caller, INV-5). */
19
- acquireLock(): void;
113
+ /** Best-effort: write lock metadata for future stale-detection. Never throws. */
114
+ private writeLockMeta;
115
+ /**
116
+ * Read and parse the currently-held lock's meta.json.
117
+ * Returns null if it's missing, unreadable, unparseable, or malformed
118
+ * (no finite numeric `pid`) — i.e. whenever the lock must be treated as
119
+ * a legacy, meta-less lock.
120
+ */
121
+ private readLockMeta;
122
+ /**
123
+ * Decide whether the currently-held lock is stale and may be reclaimed.
124
+ * - meta.json present and parseable with a finite numeric pid: stale iff
125
+ * that pid is not alive (PID liveness is authoritative, any age).
126
+ * - meta.json missing/unreadable/unparseable/malformed (legacy lock):
127
+ * stale iff the lock dir's mtime is older than staleLockMs (strict >).
128
+ */
129
+ private isLockStale;
130
+ private isLegacyLockStale;
131
+ /**
132
+ * Move the stale lock dir aside (renameSync, atomic) and delete the
133
+ * moved-aside copy. If the rename fails — another process already moved
134
+ * or recreated the lock — we do nothing further: the mkdir retry in
135
+ * acquireLock() is the sole arbiter of who actually ends up holding the
136
+ * lock, so a lost race here just falls through to that retry instead of
137
+ * blindly deleting whatever now occupies the path (which is what let two
138
+ * racers both end up "holding" the lock under a plain rmSync).
139
+ */
140
+ private reclaimStaleLock;
141
+ /**
142
+ * Advisory lock via mkdir (atomic). A stale lock (dead PID, or an aged
143
+ * legacy lock past staleLockMs) is auto-reclaimed: rename the stale dir
144
+ * aside and delete it, then retry mkdir once. If the lock is live, or
145
+ * the retry loses a race, throws LockHeldError — fail-open at the
146
+ * caller (INV-5). The return value reports whether a reclaim happened
147
+ * (and the reclaimed lock's prior meta, if any) so callers can surface
148
+ * the event rather than reclaiming silently.
149
+ */
150
+ acquireLock(): AcquireLockResult;
20
151
  releaseLock(): void;
21
152
  /**
22
153
  * Persist a record. Atomic (tmp+rename). Content-identical re-records are
@@ -33,6 +164,29 @@ export declare class RunStore {
33
164
  resolveRunId(idOrPrefix: string): string | null;
34
165
  /** Read and validate a record; parse/validation failures are store corruption. */
35
166
  readRun(runId: string): RunRecord;
167
+ /**
168
+ * Read a record's addressing/provenance fields without the full §9.4
169
+ * schema validation (used for cheap baseline pre-filtering). Same
170
+ * missing/unparseable error text as {@link readRun}; extracted-field
171
+ * absence or type mismatch is also a StoreCorruptError. Does not inspect
172
+ * observations/finding/recording.
173
+ */
174
+ readRunMeta(runId: string): RunMeta;
36
175
  /** INV-10: recompute the content address and compare with the stored id. */
37
176
  verifyIntegrity(runId: string): boolean;
177
+ /**
178
+ * Enforce a retention policy (§4.1 SHOULD be bounded). Evicts whole
179
+ * records (file + index entry), oldest first, until both limits are
180
+ * satisfied. The record pointed to by `last`, and any id passed in
181
+ * `protectedIds` (e.g. a baseline just selected for a comparison), are
182
+ * never evicted, even if one alone exceeds maxBytes (AC-3).
183
+ *
184
+ * PRECONDITION: the caller holds the advisory lock (see acquireLock()).
185
+ * gc() itself does not take the lock — callers that gc concurrently with a
186
+ * writer risk racing writeRun()'s index append.
187
+ *
188
+ * Index ids whose record file is already missing (dangling) are dropped
189
+ * from the index unconditionally, independent of the policy limits.
190
+ */
191
+ gc(policy: GcPolicy, protectedIds?: readonly string[]): GcResult;
38
192
  }
package/dist/store.js CHANGED
@@ -2,13 +2,35 @@
2
2
  * Content-addressed run store (spec §4): immutable records, atomic writes,
3
3
  * fail-open advisory lock, enforced gitignore. Recency is store insertion
4
4
  * order (the append-only index), never timestamps (§7.8).
5
+ *
6
+ * The advisory lock (`.veridelta/lock`, mkdir-based for atomicity) is
7
+ * fail-open per INV-5: a lock that cannot be proven live degrades the
8
+ * caller to transparent passthrough rather than blocking indefinitely.
9
+ * On top of that, acquireLock() auto-reclaims *stale* locks so a crashed
10
+ * process doesn't wedge recording forever:
11
+ * - if the lock carries `meta.json` ({pid, acquired_at_ms}), staleness is
12
+ * decided purely by PID liveness (dead PID => stale, reclaim now;
13
+ * regardless of age otherwise a live holder is never stolen);
14
+ * - if `meta.json` is missing or unreadable/malformed (a legacy lock, or
15
+ * a write that failed), staleness falls back to an mtime threshold
16
+ * (`staleLockMs`, default 10 minutes) — this also preserves INV-5 for
17
+ * the existing fail-open-held-lock conformance fixture, whose fresh
18
+ * bare-mkdir lock must still degrade to passthrough.
19
+ * Reclaim moves the stale lock dir aside via renameSync (atomic: at most
20
+ * one concurrent reclaimer can walk off with that specific directory —
21
+ * a second racer's rename fails outright instead of silently trampling
22
+ * whatever now occupies the path) and deletes the moved-aside copy, then
23
+ * retries mkdir once; if that retry loses the race, we throw
24
+ * LockHeldError (fail-open), never loop. acquireLock() reports back
25
+ * whether it reclaimed a stale lock (and that lock's prior meta, if any)
26
+ * so callers can surface the event instead of reclaiming silently.
5
27
  */
6
- import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmdirSync, writeFileSync, } from 'node:fs';
7
- import { join } from 'node:path';
8
28
  import { randomUUID } from 'node:crypto';
29
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, } from 'node:fs';
30
+ import { join } from 'node:path';
9
31
  import { canonicalJson } from './canonical.js';
10
32
  import { sha256Hex } from './digest.js';
11
- import { parseRunRecord } from './schema.js';
33
+ import { COMPLETENESS_STATUSES, parseRunRecord, } from './schema.js';
12
34
  export class StoreCorruptError extends Error {
13
35
  constructor(message) {
14
36
  super(message);
@@ -16,8 +38,10 @@ export class StoreCorruptError extends Error {
16
38
  }
17
39
  }
18
40
  export class LockHeldError extends Error {
19
- constructor() {
20
- super('advisory lock is held');
41
+ lockPath;
42
+ constructor(lockPath) {
43
+ super(`advisory lock is held at ${lockPath} — if no other vdelta run is active, remove it: rm -rf ${lockPath}`);
44
+ this.lockPath = lockPath;
21
45
  this.name = 'LockHeldError';
22
46
  }
23
47
  }
@@ -27,10 +51,122 @@ export function computeRunId(record) {
27
51
  const { recording: _recording, ...addressed } = record;
28
52
  return `run_${sha256Hex(canonicalJson(addressed))}`;
29
53
  }
54
+ function parsePositiveIntEnv(name, fallback) {
55
+ const raw = process.env[name];
56
+ if (raw === undefined || raw === '')
57
+ return fallback;
58
+ if (!/^[0-9]+$/.test(raw))
59
+ return undefined;
60
+ const n = Number(raw);
61
+ if (!Number.isInteger(n) || n <= 0)
62
+ return undefined;
63
+ return n;
64
+ }
65
+ /**
66
+ * Default retention policy (§4.1 SHOULD be bounded). Overridable via
67
+ * VDELTA_GC_MAX_COUNT / VDELTA_GC_MAX_BYTES (positive integers only; unset,
68
+ * empty, zero, or non-numeric values fall back to defaults or disable the
69
+ * limit respectively).
70
+ */
71
+ export function defaultGcPolicy() {
72
+ const policy = {};
73
+ const maxCount = parsePositiveIntEnv('VDELTA_GC_MAX_COUNT', 100);
74
+ const maxBytes = parsePositiveIntEnv('VDELTA_GC_MAX_BYTES', 64 * 1024 * 1024);
75
+ if (maxCount !== undefined)
76
+ policy.maxCount = maxCount;
77
+ if (maxBytes !== undefined)
78
+ policy.maxBytes = maxBytes;
79
+ return policy;
80
+ }
81
+ function metaFail(runId, detail) {
82
+ throw new StoreCorruptError(`run record meta invalid (${runId}): ${detail}`);
83
+ }
84
+ function asMetaObject(v, runId, path) {
85
+ if (v === null || typeof v !== 'object' || Array.isArray(v))
86
+ metaFail(runId, `${path}: expected object`);
87
+ return v;
88
+ }
89
+ function asMetaString(v, runId, path) {
90
+ if (typeof v !== 'string')
91
+ metaFail(runId, `${path}: expected string`);
92
+ return v;
93
+ }
94
+ function asMetaStringArray(v, runId, path) {
95
+ if (!Array.isArray(v))
96
+ metaFail(runId, `${path}: expected array`);
97
+ return v.map((e, i) => asMetaString(e, runId, `${path}[${i}]`));
98
+ }
99
+ /**
100
+ * Extract {@link RunMeta} from an already-parsed record without running the
101
+ * full §9.4 schema validation (observations/finding/recording are not
102
+ * inspected). Field-level absence or type mismatch in the extracted fields
103
+ * is still a StoreCorruptError.
104
+ */
105
+ function extractRunMeta(value, runId) {
106
+ const o = asMetaObject(value, runId, 'record');
107
+ const repoRaw = asMetaObject(o.repo, runId, 'record.repo');
108
+ const repo = {
109
+ identity: asMetaString(repoRaw.identity, runId, 'record.repo.identity'),
110
+ worktree: asMetaString(repoRaw.worktree, runId, 'record.repo.worktree'),
111
+ branch: asMetaString(repoRaw.branch, runId, 'record.repo.branch'),
112
+ cwd: asMetaString(repoRaw.cwd, runId, 'record.repo.cwd'),
113
+ };
114
+ const invocationRaw = asMetaObject(o.invocation, runId, 'record.invocation');
115
+ const invocation = {
116
+ command: asMetaStringArray(invocationRaw.command, runId, 'record.invocation.command'),
117
+ selector: asMetaStringArray(invocationRaw.selector, runId, 'record.invocation.selector'),
118
+ };
119
+ const instrumentRaw = asMetaObject(o.instrument, runId, 'record.instrument');
120
+ const instrument = {
121
+ adapter: asMetaString(instrumentRaw.adapter, runId, 'record.instrument.adapter'),
122
+ adapter_version: asMetaString(instrumentRaw.adapter_version, runId, 'record.instrument.adapter_version'),
123
+ composition_id: asMetaString(instrumentRaw.composition_id, runId, 'record.instrument.composition_id'),
124
+ config_digest: asMetaString(instrumentRaw.config_digest, runId, 'record.instrument.config_digest'),
125
+ };
126
+ const provenanceRaw = asMetaObject(o.provenance, runId, 'record.provenance');
127
+ const head = provenanceRaw.head === null
128
+ ? null
129
+ : asMetaString(provenanceRaw.head, runId, 'record.provenance.head');
130
+ const provenance = {
131
+ head,
132
+ tree_digest: asMetaString(provenanceRaw.tree_digest, runId, 'record.provenance.tree_digest'),
133
+ };
134
+ const completenessRaw = asMetaObject(o.completeness, runId, 'record.completeness');
135
+ const status = completenessRaw.status;
136
+ if (typeof status !== 'string' ||
137
+ !COMPLETENESS_STATUSES.includes(status)) {
138
+ metaFail(runId, 'record.completeness.status: invalid');
139
+ }
140
+ const childExitCode = completenessRaw.child_exit_code;
141
+ if (typeof childExitCode !== 'number' || !Number.isInteger(childExitCode)) {
142
+ metaFail(runId, 'record.completeness.child_exit_code: expected integer');
143
+ }
144
+ const completeness = {
145
+ status: status,
146
+ child_exit_code: childExitCode,
147
+ };
148
+ return { repo, invocation, instrument, provenance, completeness };
149
+ }
150
+ function defaultIsPidAlive(pid) {
151
+ try {
152
+ process.kill(pid, 0);
153
+ return true;
154
+ }
155
+ catch (e) {
156
+ // ESRCH: no such process => dead. Anything else (EPERM, unknown) means
157
+ // we cannot prove it's dead, so treat as alive — never steal a lock we
158
+ // cannot prove is unheld.
159
+ return e.code !== 'ESRCH';
160
+ }
161
+ }
30
162
  export class RunStore {
31
163
  dir;
32
- constructor(worktreeRoot) {
164
+ staleLockMs;
165
+ isPidAlive;
166
+ constructor(worktreeRoot, options) {
33
167
  this.dir = join(worktreeRoot, '.veridelta');
168
+ this.staleLockMs = options?.staleLockMs ?? 10 * 60_000;
169
+ this.isPidAlive = options?.isPidAlive ?? defaultIsPidAlive;
34
170
  }
35
171
  get runsDir() {
36
172
  return join(this.dir, 'runs');
@@ -44,24 +180,135 @@ export class RunStore {
44
180
  get lockPath() {
45
181
  return join(this.dir, 'lock');
46
182
  }
183
+ get lockMetaPath() {
184
+ return join(this.lockPath, 'meta.json');
185
+ }
47
186
  ensure() {
48
187
  mkdirSync(this.runsDir, { recursive: true });
49
188
  const gi = join(this.dir, '.gitignore');
50
189
  if (!existsSync(gi))
51
190
  writeFileSync(gi, '*\n');
52
191
  }
53
- /** Advisory lock via mkdir; throws LockHeldError when already held (fail-open at the caller, INV-5). */
192
+ /** Best-effort: write lock metadata for future stale-detection. Never throws. */
193
+ writeLockMeta() {
194
+ try {
195
+ writeFileSync(this.lockMetaPath, JSON.stringify({ pid: process.pid, acquired_at_ms: Date.now() }));
196
+ }
197
+ catch {
198
+ // advisory only: an unwritten meta.json just makes this lock behave
199
+ // like a legacy lock (mtime-only staleness) for the next acquirer
200
+ }
201
+ }
202
+ /**
203
+ * Read and parse the currently-held lock's meta.json.
204
+ * Returns null if it's missing, unreadable, unparseable, or malformed
205
+ * (no finite numeric `pid`) — i.e. whenever the lock must be treated as
206
+ * a legacy, meta-less lock.
207
+ */
208
+ readLockMeta() {
209
+ let raw;
210
+ try {
211
+ raw = readFileSync(this.lockMetaPath, 'utf8');
212
+ }
213
+ catch {
214
+ return null;
215
+ }
216
+ let parsed;
217
+ try {
218
+ parsed = JSON.parse(raw);
219
+ }
220
+ catch {
221
+ return null;
222
+ }
223
+ const pid = parsed?.pid;
224
+ if (typeof pid !== 'number' || !Number.isFinite(pid)) {
225
+ return null;
226
+ }
227
+ const acquiredAtMs = parsed
228
+ ?.acquired_at_ms;
229
+ return {
230
+ pid,
231
+ acquired_at_ms: typeof acquiredAtMs === 'number' ? acquiredAtMs : Number.NaN,
232
+ };
233
+ }
234
+ /**
235
+ * Decide whether the currently-held lock is stale and may be reclaimed.
236
+ * - meta.json present and parseable with a finite numeric pid: stale iff
237
+ * that pid is not alive (PID liveness is authoritative, any age).
238
+ * - meta.json missing/unreadable/unparseable/malformed (legacy lock):
239
+ * stale iff the lock dir's mtime is older than staleLockMs (strict >).
240
+ */
241
+ isLockStale() {
242
+ const meta = this.readLockMeta();
243
+ if (meta === null)
244
+ return this.isLegacyLockStale();
245
+ return !this.isPidAlive(meta.pid);
246
+ }
247
+ isLegacyLockStale() {
248
+ let mtimeMs;
249
+ try {
250
+ mtimeMs = statSync(this.lockPath).mtimeMs;
251
+ }
252
+ catch {
253
+ // lock vanished concurrently: safe to treat as stale and retry
254
+ return true;
255
+ }
256
+ return Date.now() - mtimeMs > this.staleLockMs;
257
+ }
258
+ /**
259
+ * Move the stale lock dir aside (renameSync, atomic) and delete the
260
+ * moved-aside copy. If the rename fails — another process already moved
261
+ * or recreated the lock — we do nothing further: the mkdir retry in
262
+ * acquireLock() is the sole arbiter of who actually ends up holding the
263
+ * lock, so a lost race here just falls through to that retry instead of
264
+ * blindly deleting whatever now occupies the path (which is what let two
265
+ * racers both end up "holding" the lock under a plain rmSync).
266
+ */
267
+ reclaimStaleLock() {
268
+ const tombstone = `${this.lockPath}.stale-${randomUUID()}`;
269
+ try {
270
+ renameSync(this.lockPath, tombstone);
271
+ }
272
+ catch {
273
+ return;
274
+ }
275
+ rmSync(tombstone, { recursive: true, force: true });
276
+ }
277
+ /**
278
+ * Advisory lock via mkdir (atomic). A stale lock (dead PID, or an aged
279
+ * legacy lock past staleLockMs) is auto-reclaimed: rename the stale dir
280
+ * aside and delete it, then retry mkdir once. If the lock is live, or
281
+ * the retry loses a race, throws LockHeldError — fail-open at the
282
+ * caller (INV-5). The return value reports whether a reclaim happened
283
+ * (and the reclaimed lock's prior meta, if any) so callers can surface
284
+ * the event rather than reclaiming silently.
285
+ */
54
286
  acquireLock() {
55
287
  try {
56
288
  mkdirSync(this.lockPath);
289
+ this.writeLockMeta();
290
+ return { reclaimed: false, staleMeta: null };
57
291
  }
58
292
  catch {
59
- throw new LockHeldError();
293
+ // fall through to stale-reclaim below
60
294
  }
295
+ if (!this.isLockStale()) {
296
+ throw new LockHeldError(this.lockPath);
297
+ }
298
+ const staleMeta = this.readLockMeta();
299
+ this.reclaimStaleLock();
300
+ try {
301
+ mkdirSync(this.lockPath);
302
+ }
303
+ catch {
304
+ throw new LockHeldError(this.lockPath);
305
+ }
306
+ this.writeLockMeta();
307
+ return { reclaimed: true, staleMeta };
61
308
  }
62
309
  releaseLock() {
63
310
  try {
64
- rmdirSync(this.lockPath);
311
+ rmSync(this.lockPath, { recursive: true, force: true });
65
312
  }
66
313
  catch {
67
314
  // releasing a lock we no longer hold is not an error path worth failing on
@@ -123,7 +370,9 @@ export class RunStore {
123
370
  /** Resolve a possibly-prefixed run id to a stored full id (§3.5 MAY). */
124
371
  resolveRunId(idOrPrefix) {
125
372
  if (RUN_ID_RE.test(idOrPrefix)) {
126
- return existsSync(join(this.runsDir, `${idOrPrefix}.json`)) ? idOrPrefix : null;
373
+ return existsSync(join(this.runsDir, `${idOrPrefix}.json`))
374
+ ? idOrPrefix
375
+ : null;
127
376
  }
128
377
  if (!existsSync(this.runsDir))
129
378
  return null;
@@ -152,10 +401,104 @@ export class RunStore {
152
401
  }
153
402
  return parseRunRecord(parsed);
154
403
  }
404
+ /**
405
+ * Read a record's addressing/provenance fields without the full §9.4
406
+ * schema validation (used for cheap baseline pre-filtering). Same
407
+ * missing/unparseable error text as {@link readRun}; extracted-field
408
+ * absence or type mismatch is also a StoreCorruptError. Does not inspect
409
+ * observations/finding/recording.
410
+ */
411
+ readRunMeta(runId) {
412
+ const path = join(this.runsDir, `${runId}.json`);
413
+ let raw;
414
+ try {
415
+ raw = readFileSync(path, 'utf8');
416
+ }
417
+ catch {
418
+ throw new StoreCorruptError(`run record missing: ${runId}`);
419
+ }
420
+ let parsed;
421
+ try {
422
+ parsed = JSON.parse(raw);
423
+ }
424
+ catch {
425
+ throw new StoreCorruptError(`run record unparseable: ${runId}`);
426
+ }
427
+ return extractRunMeta(parsed, runId);
428
+ }
155
429
  /** INV-10: recompute the content address and compare with the stored id. */
156
430
  verifyIntegrity(runId) {
157
431
  const record = this.readRun(runId);
158
432
  return computeRunId(record) === runId;
159
433
  }
434
+ /**
435
+ * Enforce a retention policy (§4.1 SHOULD be bounded). Evicts whole
436
+ * records (file + index entry), oldest first, until both limits are
437
+ * satisfied. The record pointed to by `last`, and any id passed in
438
+ * `protectedIds` (e.g. a baseline just selected for a comparison), are
439
+ * never evicted, even if one alone exceeds maxBytes (AC-3).
440
+ *
441
+ * PRECONDITION: the caller holds the advisory lock (see acquireLock()).
442
+ * gc() itself does not take the lock — callers that gc concurrently with a
443
+ * writer risk racing writeRun()'s index append.
444
+ *
445
+ * Index ids whose record file is already missing (dangling) are dropped
446
+ * from the index unconditionally, independent of the policy limits.
447
+ */
448
+ gc(policy, protectedIds = []) {
449
+ const lastId = this.lastRunId();
450
+ const protectedSet = new Set(protectedIds);
451
+ if (lastId !== null)
452
+ protectedSet.add(lastId);
453
+ if (policy.maxCount === undefined && policy.maxBytes === undefined) {
454
+ const ids = this.listRunIds();
455
+ let keptBytes = 0;
456
+ for (const id of ids) {
457
+ try {
458
+ keptBytes += statSync(join(this.runsDir, `${id}.json`)).size;
459
+ }
460
+ catch {
461
+ // dangling id with no-op policy: leave it be, don't account for it
462
+ }
463
+ }
464
+ return { removed: [], keptCount: ids.length, keptBytes };
465
+ }
466
+ const ids = this.listRunIds();
467
+ const removed = [];
468
+ const kept = [];
469
+ for (const id of ids) {
470
+ let size;
471
+ try {
472
+ size = statSync(join(this.runsDir, `${id}.json`)).size;
473
+ }
474
+ catch {
475
+ removed.push(id);
476
+ continue;
477
+ }
478
+ kept.push({ id, size });
479
+ }
480
+ let totalBytes = kept.reduce((sum, e) => sum + e.size, 0);
481
+ const overCount = () => policy.maxCount !== undefined && kept.length > policy.maxCount;
482
+ const overBytes = () => policy.maxBytes !== undefined && totalBytes > policy.maxBytes;
483
+ while (overCount() || overBytes()) {
484
+ const idx = kept.findIndex((e) => !protectedSet.has(e.id));
485
+ if (idx === -1)
486
+ break;
487
+ const [evicted] = kept.splice(idx, 1);
488
+ if (!evicted)
489
+ break;
490
+ totalBytes -= evicted.size;
491
+ rmSync(join(this.runsDir, `${evicted.id}.json`), { force: true });
492
+ removed.push(evicted.id);
493
+ }
494
+ if (removed.length === 0) {
495
+ return { removed: [], keptCount: kept.length, keptBytes: totalBytes };
496
+ }
497
+ const tmp = join(this.dir, `.tmp-index-${randomUUID()}`);
498
+ const survivors = kept.map((e) => e.id);
499
+ writeFileSync(tmp, survivors.length > 0 ? `${survivors.join('\n')}\n` : '');
500
+ renameSync(tmp, this.indexPath);
501
+ return { removed, keptCount: kept.length, keptBytes: totalBytes };
502
+ }
160
503
  }
161
504
  //# sourceMappingURL=store.js.map
package/dist/store.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}