@sentropic/track 0.2.1 → 0.2.2

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.
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Cross-process write serialization for the single-stream event log.
3
+ *
4
+ * `EventStore.appendCommand` runs read → validate → compute (prevHash/seq) → append → writeHead as a
5
+ * critical section with NO mutual exclusion. Two writers on the same `events.jsonl` (a CLI run while an
6
+ * MCP server is live, two `track-mcp` instances, an h2a sidecar) both read the same N-event prefix,
7
+ * compute the SAME `prevHash`/`seq`, and append — producing a broken `prevHash` chain + duplicate `seq`
8
+ * + a stale `head.json`. The fail-closed guard then refuses EVERY future append (a permanent, human-only
9
+ * repair): an integrity-DoS triggerable by any concurrent writer. `withFileLock` serializes that section
10
+ * across processes so the single-writer contract holds in practice, not just in intent.
11
+ *
12
+ * DELIBERATELY NO automatic stale-lock stealing (review verdict, Lot v2.3b-0): pathname-based stealing
13
+ * is intrinsically racy — two waiters can both judge a lock abandoned, the slower `unlink` then deletes
14
+ * the WINNER's fresh lock and mutual exclusion is broken; and an age-based steal can preempt a merely
15
+ * SLOW live holder (large log, slow disk, SIGSTOP/suspend), putting two writers in the critical section.
16
+ * Both failure modes recreate the exact corruption this lock exists to prevent. Posture instead:
17
+ * fail-closed with a DIAGNOSED timeout — the error reports the holder PID and whether it is still
18
+ * running, so a human can safely remove an orphaned lock (the only way one arises is a writer dying
19
+ * mid-append, e.g. SIGKILL/power loss; appends take milliseconds). This matches the store's existing
20
+ * fail-closed stance (a torn trailing line is also detected, never silently repaired).
21
+ *
22
+ * Scope: same-host writers only (advisory `O_EXCL` lockfile + local PID diagnosis). Shared/networked
23
+ * filesystems (NFS) are out of scope, as is the store itself (single host, single writer — SPEC).
24
+ * Operational only — it does NOT touch the frozen event contract (stream/seq/prevHash/hash).
25
+ * Upgrade path: `flock(2)` on a held fd would auto-release on process death (no orphan, no manual rm),
26
+ * but Node's stdlib does not expose it — adopt only if a native dep ever becomes acceptable.
27
+ */
28
+ export interface LockOptions {
29
+ /** Max time to wait to acquire before throwing (never hang). */
30
+ timeoutMs?: number;
31
+ /** Poll interval while contended. */
32
+ retryMs?: number;
33
+ }
34
+ /**
35
+ * Run `fn` while holding an exclusive cross-process lock on `<targetPath>.lock`. Released in `finally`
36
+ * (only its own generation — a token mismatch means the lock is no longer ours and is left alone).
37
+ * Throws a diagnosed error after `timeoutMs` rather than hanging or stealing. NOT reentrant (the store
38
+ * never nests appends). NOTE: the store is synchronous, so a contended acquire blocks the whole event
39
+ * loop for up to `timeoutMs` — acceptable for the CLI and the (serial) stdio MCP server.
40
+ */
41
+ export declare function withFileLock<T>(targetPath: string, fn: () => T, options?: LockOptions): T;
42
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/events/lock.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAgDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,OAAO,GAAE,WAAgB,GAAG,CAAC,CAyC7F"}
@@ -0,0 +1,91 @@
1
+ import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync } from 'node:fs';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { hostname } from 'node:os';
4
+ import { dirname } from 'node:path';
5
+ const DEFAULTS = { timeoutMs: 10_000, retryMs: 20 };
6
+ /** Synchronous sleep — the store is fully synchronous. Blocks the thread without burning CPU. */
7
+ function sleepSync(ms) {
8
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, Math.max(1, ms));
9
+ }
10
+ /** Is `pid` a live process on THIS host? ESRCH ⇒ dead; EPERM ⇒ alive but not ours to signal. */
11
+ function isAlive(pid) {
12
+ if (!Number.isInteger(pid) || pid <= 0)
13
+ return false;
14
+ try {
15
+ process.kill(pid, 0);
16
+ return true;
17
+ }
18
+ catch (err) {
19
+ return err.code === 'EPERM';
20
+ }
21
+ }
22
+ function readHolder(lockPath) {
23
+ try {
24
+ return JSON.parse(readFileSync(lockPath, 'utf8'));
25
+ }
26
+ catch {
27
+ return undefined; // missing, torn, or empty — caller decides what that means
28
+ }
29
+ }
30
+ /** Human-actionable diagnosis for a timeout: who holds it, and is removing it safe? */
31
+ function diagnose(lockPath) {
32
+ const holder = readHolder(lockPath);
33
+ if (holder === undefined) {
34
+ return 'holder record unreadable (lock vanished or torn)';
35
+ }
36
+ const liveness = isAlive(holder.pid)
37
+ ? 'still RUNNING — another track writer is active, do not remove'
38
+ : 'NOT running — orphaned (writer died mid-append); safe to delete the lock file to recover';
39
+ return `held by pid ${holder.pid}@${holder.host} since ${new Date(holder.time).toISOString()}, ${liveness}`;
40
+ }
41
+ /**
42
+ * Run `fn` while holding an exclusive cross-process lock on `<targetPath>.lock`. Released in `finally`
43
+ * (only its own generation — a token mismatch means the lock is no longer ours and is left alone).
44
+ * Throws a diagnosed error after `timeoutMs` rather than hanging or stealing. NOT reentrant (the store
45
+ * never nests appends). NOTE: the store is synchronous, so a contended acquire blocks the whole event
46
+ * loop for up to `timeoutMs` — acceptable for the CLI and the (serial) stdio MCP server.
47
+ */
48
+ export function withFileLock(targetPath, fn, options = {}) {
49
+ const { timeoutMs, retryMs } = { ...DEFAULTS, ...options };
50
+ const lockPath = `${targetPath}.lock`;
51
+ mkdirSync(dirname(lockPath), { recursive: true });
52
+ const token = randomBytes(12).toString('hex');
53
+ const deadline = Date.now() + timeoutMs;
54
+ for (;;) {
55
+ try {
56
+ const fd = openSync(lockPath, 'wx'); // O_CREAT|O_EXCL|O_WRONLY — fails with EEXIST if held
57
+ try {
58
+ const holder = { pid: process.pid, host: hostname(), time: Date.now(), token };
59
+ writeSync(fd, JSON.stringify(holder));
60
+ }
61
+ finally {
62
+ closeSync(fd);
63
+ }
64
+ break; // acquired
65
+ }
66
+ catch (err) {
67
+ if (err.code !== 'EEXIST')
68
+ throw err;
69
+ if (Date.now() >= deadline) {
70
+ throw new Error(`withFileLock: timed out after ${timeoutMs}ms waiting for ${lockPath} — ${diagnose(lockPath)}.`);
71
+ }
72
+ sleepSync(retryMs);
73
+ }
74
+ }
75
+ try {
76
+ return fn();
77
+ }
78
+ finally {
79
+ // Release ONLY our own generation. If the file no longer carries our token (e.g. a human removed an
80
+ // orphan and another writer acquired), deleting it would break THEIR mutual exclusion — leave it.
81
+ if (readHolder(lockPath)?.token === token) {
82
+ try {
83
+ unlinkSync(lockPath);
84
+ }
85
+ catch {
86
+ // already gone — nothing to release
87
+ }
88
+ }
89
+ }
90
+ }
91
+ //# sourceMappingURL=lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.js","sourceRoot":"","sources":["../../src/events/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAoCnC,MAAM,QAAQ,GAA0B,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;AAU1E,iGAAiG;AACjG,SAAS,SAAS,CAAC,EAAU;IAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;AAC/E,CAAC;AAED,gGAAgG;AAChG,SAAS,OAAO,CAAC,GAAW;IAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IACpD,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAQ,GAA6B,CAAC,IAAI,KAAK,OAAO,CAAA;IACxD,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAW,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA,CAAC,2DAA2D;IAC9E,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,QAAQ,CAAC,QAAgB;IAChC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,kDAAkD,CAAA;IAC3D,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;QAClC,CAAC,CAAC,+DAA+D;QACjE,CAAC,CAAC,0FAA0F,CAAA;IAC9F,OAAO,eAAe,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ,EAAE,CAAA;AAC7G,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAI,UAAkB,EAAE,EAAW,EAAE,UAAuB,EAAE;IACxF,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAA;IAC1D,MAAM,QAAQ,GAAG,GAAG,UAAU,OAAO,CAAA;IACrC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;IAEvC,SAAS,CAAC;QACR,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA,CAAC,sDAAsD;YAC1F,IAAI,CAAC;gBACH,MAAM,MAAM,GAAW,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAA;gBACtF,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;YACvC,CAAC;oBAAS,CAAC;gBACT,SAAS,CAAC,EAAE,CAAC,CAAA;YACf,CAAC;YACD,MAAK,CAAC,WAAW;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAA;YAC/D,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,iCAAiC,SAAS,kBAAkB,QAAQ,MAAM,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAChG,CAAA;YACH,CAAC;YACD,SAAS,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAA;IACb,CAAC;YAAS,CAAC;QACT,oGAAoG;QACpG,kGAAkG;QAClG,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,KAAK,EAAE,CAAC;YAC1C,IAAI,CAAC;gBACH,UAAU,CAAC,QAAQ,CAAC,CAAA;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,oCAAoC;YACtC,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/events/store.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,YAAY,EAAqB,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAGnF;;;;;;;GAOG;AACH,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE7C,mFAAmF;IACnF,OAAO,IAAI,UAAU,EAAE;IAiBvB;;;;OAIG;IACH,aAAa,CACX,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EACnC,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,IAAI,CAAA;KAAO,GAC1B,UAAU,EAAE;IAgEf;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;CAcrB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/events/store.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAqB,UAAU,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAGnF;;;;;;;GAOG;AACH,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE7C,mFAAmF;IACnF,OAAO,IAAI,UAAU,EAAE;IAiBvB;;;;OAIG;IACH,aAAa,CACX,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,EACnC,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,IAAI,CAAA;KAAO,GAC1B,UAAU,EAAE;IAqEf;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;CAcrB"}
@@ -3,6 +3,7 @@ import { dirname } from 'node:path';
3
3
  import { canonicalize, materialize } from './canonical.js';
4
4
  import { contentHashOf } from './frame.js';
5
5
  import { readHead, writeHead } from './head.js';
6
+ import { withFileLock } from './lock.js';
6
7
  import { validate } from './validate.js';
7
8
  /**
8
9
  * Append-only single-writer event store over `.track/events.jsonl` (SPEC §3, §4).
@@ -51,48 +52,53 @@ export class EventStore {
51
52
  if (isBatch && opts.cmdId === undefined) {
52
53
  throw new Error('EventStore.appendCommand: a multi-event command requires a cmdId');
53
54
  }
54
- const existing = this.readAll();
55
- const integrity = validate(existing, readHead(this.filePath));
56
- if (!integrity.ok) {
57
- const kinds = integrity.findings.map((f) => f.kind).join(', ');
58
- throw new Error(`EventStore.appendCommand: refusing to extend an invalid log ` +
59
- `(${integrity.findings.length} finding(s): ${kinds})`);
60
- }
61
- let prevHash = existing.length > 0 ? existing[existing.length - 1].contentHash : null;
62
- // Next per-aggregate seq = max(seq) + 1, aligned with validate's authority.
63
- const lastSeqByAggregate = new Map();
64
- for (const e of existing) {
65
- lastSeqByAggregate.set(e.aggregateId, e.seq);
66
- }
67
- const events = [];
68
- inputs.forEach((input, i) => {
69
- const seq = (lastSeqByAggregate.get(input.aggregateId) ?? 0) + 1;
70
- lastSeqByAggregate.set(input.aggregateId, seq);
71
- const core = isBatch
72
- ? { ...input, cmdId: opts.cmdId, cmd: { i, n } }
73
- : { ...input };
74
- // Materialize ONCE to an inert plain-data snapshot, then hash AND persist that same
75
- // snapshot so a live payload (Proxy / getter / toJSON) cannot diverge between the two.
76
- const materialized = materialize(core);
77
- const contentHash = contentHashOf(materialized);
78
- const event = { ...materialized, seq, prevHash, contentHash };
79
- events.push(event);
80
- prevHash = contentHash;
81
- });
82
- // Validate the FULL candidate stream (not just the existing prefix): the command itself
83
- // could introduce a cross-event violation (e.g. an aggregate-mismatch, a malformed batch).
84
- const candidate = validate([...existing, ...events]);
85
- if (!candidate.ok) {
86
- const kinds = candidate.findings.map((f) => f.kind).join(', ');
87
- throw new Error(`EventStore.appendCommand: command would produce an invalid log ` +
88
- `(${candidate.findings.length} finding(s): ${kinds})`);
89
- }
90
- this.appendAtomic(events);
91
- writeHead(this.filePath, {
92
- streamLength: existing.length + events.length,
93
- lastContentHash: events[events.length - 1].contentHash,
55
+ // Serialize the read→validate→compute→append→writeHead critical section ACROSS processes. Without
56
+ // it, two concurrent writers compute the same prevHash/seq and corrupt the single stream, which the
57
+ // fail-closed guard below then turns into a permanent write-DoS for every future writer (see lock.ts).
58
+ return withFileLock(this.filePath, () => {
59
+ const existing = this.readAll();
60
+ const integrity = validate(existing, readHead(this.filePath));
61
+ if (!integrity.ok) {
62
+ const kinds = integrity.findings.map((f) => f.kind).join(', ');
63
+ throw new Error(`EventStore.appendCommand: refusing to extend an invalid log ` +
64
+ `(${integrity.findings.length} finding(s): ${kinds})`);
65
+ }
66
+ let prevHash = existing.length > 0 ? existing[existing.length - 1].contentHash : null;
67
+ // Next per-aggregate seq = max(seq) + 1, aligned with validate's authority.
68
+ const lastSeqByAggregate = new Map();
69
+ for (const e of existing) {
70
+ lastSeqByAggregate.set(e.aggregateId, e.seq);
71
+ }
72
+ const events = [];
73
+ inputs.forEach((input, i) => {
74
+ const seq = (lastSeqByAggregate.get(input.aggregateId) ?? 0) + 1;
75
+ lastSeqByAggregate.set(input.aggregateId, seq);
76
+ const core = isBatch
77
+ ? { ...input, cmdId: opts.cmdId, cmd: { i, n } }
78
+ : { ...input };
79
+ // Materialize ONCE to an inert plain-data snapshot, then hash AND persist that same
80
+ // snapshot — so a live payload (Proxy / getter / toJSON) cannot diverge between the two.
81
+ const materialized = materialize(core);
82
+ const contentHash = contentHashOf(materialized);
83
+ const event = { ...materialized, seq, prevHash, contentHash };
84
+ events.push(event);
85
+ prevHash = contentHash;
86
+ });
87
+ // Validate the FULL candidate stream (not just the existing prefix): the command itself
88
+ // could introduce a cross-event violation (e.g. an aggregate-mismatch, a malformed batch).
89
+ const candidate = validate([...existing, ...events]);
90
+ if (!candidate.ok) {
91
+ const kinds = candidate.findings.map((f) => f.kind).join(', ');
92
+ throw new Error(`EventStore.appendCommand: command would produce an invalid log ` +
93
+ `(${candidate.findings.length} finding(s): ${kinds})`);
94
+ }
95
+ this.appendAtomic(events);
96
+ writeHead(this.filePath, {
97
+ streamLength: existing.length + events.length,
98
+ lastContentHash: events[events.length - 1].contentHash,
99
+ });
100
+ return events;
94
101
  });
95
- return events;
96
102
  }
97
103
  /**
98
104
  * Append all of a command's lines in one fsync'd write. Each line is the event's `canonicalize`
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/events/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/events/store.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentropic/track",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Typed product-backlog and spec/plan/UAT system of record for the sentropic ecosystem (record-only MVP).",
5
5
  "license": "MIT",
6
6
  "author": "Fabien Antoine",