@mmnto/totem 1.113.1 → 1.115.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 (50) hide show
  1. package/dist/config-schema.d.ts +1 -1
  2. package/dist/config-schema.d.ts.map +1 -1
  3. package/dist/config-schema.js +1 -1
  4. package/dist/config-schema.js.map +1 -1
  5. package/dist/errors.d.ts +5 -1
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/errors.js.map +1 -1
  8. package/dist/fs-atomic.d.ts +63 -0
  9. package/dist/fs-atomic.d.ts.map +1 -0
  10. package/dist/fs-atomic.js +114 -0
  11. package/dist/fs-atomic.js.map +1 -0
  12. package/dist/fs-atomic.test.d.ts +2 -0
  13. package/dist/fs-atomic.test.d.ts.map +1 -0
  14. package/dist/fs-atomic.test.js +162 -0
  15. package/dist/fs-atomic.test.js.map +1 -0
  16. package/dist/index.d.ts +6 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +7 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/ingest/pipeline.d.ts.map +1 -1
  21. package/dist/ingest/pipeline.js +5 -5
  22. package/dist/ingest/pipeline.js.map +1 -1
  23. package/dist/orchestration-resolver.d.ts +19 -0
  24. package/dist/orchestration-resolver.d.ts.map +1 -1
  25. package/dist/orchestration-resolver.js +5 -1
  26. package/dist/orchestration-resolver.js.map +1 -1
  27. package/dist/seat-lifecycle.d.ts +118 -0
  28. package/dist/seat-lifecycle.d.ts.map +1 -0
  29. package/dist/seat-lifecycle.js +197 -0
  30. package/dist/seat-lifecycle.js.map +1 -0
  31. package/dist/seat-lifecycle.test.d.ts +11 -0
  32. package/dist/seat-lifecycle.test.d.ts.map +1 -0
  33. package/dist/seat-lifecycle.test.js +210 -0
  34. package/dist/seat-lifecycle.test.js.map +1 -0
  35. package/dist/selection-manifest.d.ts +416 -0
  36. package/dist/selection-manifest.d.ts.map +1 -0
  37. package/dist/selection-manifest.js +444 -0
  38. package/dist/selection-manifest.js.map +1 -0
  39. package/dist/selection-manifest.test.d.ts +26 -0
  40. package/dist/selection-manifest.test.d.ts.map +1 -0
  41. package/dist/selection-manifest.test.js +331 -0
  42. package/dist/selection-manifest.test.js.map +1 -0
  43. package/dist/spine/ledgers.d.ts +12 -12
  44. package/dist/verification-outcomes.d.ts.map +1 -1
  45. package/dist/verification-outcomes.js +6 -12
  46. package/dist/verification-outcomes.js.map +1 -1
  47. package/dist/worktree-registry.d.ts.map +1 -1
  48. package/dist/worktree-registry.js +4 -4
  49. package/dist/worktree-registry.js.map +1 -1
  50. package/package.json +15 -11
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Declared seat lifecycle — the per-seat `lifecycle.json` marker behind
3
+ * `totem seat add | suspend | remove | list` (mmnto-ai/totem#2511).
4
+ *
5
+ * Seat EXISTENCE stays dir-derived (`readSeatDirs`, the mmnto-ai/totem#2141
6
+ * dirs-union invariant): a seat's first write registers it, and this file adds
7
+ * no second registration surface. An ABSENT marker means `active`, so a
8
+ * markerless tree behaves bit-identically to a pre-#2511 one. Lifecycle
9
+ * filters downstream consumers (broadcast denominators, annotations); it never
10
+ * decides who exists — `resolveSelfAgents` stays lifecycle-blind.
11
+ *
12
+ * Reads FAIL OPEN and LOUD: an unreadable or invalid marker degrades to
13
+ * `active` with a warning that names the marker file, because a corrupt marker
14
+ * must never shrink a broadcast denominator (wrongly closing an obligation)
15
+ * nor hide held mail. Writes fail HARD: the atomic helper leaves the old
16
+ * marker or the new one, never a torn transition.
17
+ *
18
+ * The whole tree is gitignored, so markers are machine-local by design —
19
+ * the same scope ECL coordination already has.
20
+ */
21
+ import * as fs from 'node:fs';
22
+ import * as path from 'node:path';
23
+ import { z } from 'zod';
24
+ import { getErrorMessage, TotemError } from './errors.js';
25
+ import { writeFileAtomicSync } from './fs-atomic.js';
26
+ import { isPathSafeAgentId, readSeatDirs } from './orchestration-resolver.js';
27
+ /** Marker filename inside `<repoRoot>/.totem/orchestration/<seat>/`. */
28
+ export const SEAT_LIFECYCLE_FILENAME = 'lifecycle.json';
29
+ /** The on-disk compatibility contract for a lifecycle marker. */
30
+ export const SEAT_LIFECYCLE_SCHEMA_VERSION = 1;
31
+ const TOTEM_DIR = '.totem';
32
+ const ORCHESTRATION_DIR = 'orchestration';
33
+ /**
34
+ * Errno values that PROVE a marker is absent rather than unreadable. Every
35
+ * other errno is a real read failure and earns a warning: "I could not tell"
36
+ * must never render as "there is no marker" (`worktreePathExists`'s posture).
37
+ */
38
+ const MARKER_ABSENT_ERRNOS = new Set(['ENOENT', 'ENOTDIR']);
39
+ /**
40
+ * `errors.ts` is out of this slice's scope, so the two refusal classes reuse
41
+ * existing codes and are named here — one edit site if a `SEAT_*` code is
42
+ * later minted.
43
+ */
44
+ const SEAT_LIFECYCLE_INVALID_CODE = 'CONFIG_INVALID';
45
+ const SEAT_LIFECYCLE_WRITE_FAILED_CODE = 'CHECK_FAILED';
46
+ /**
47
+ * The closed lifecycle set. DECLARED state only — operator-driven and durable.
48
+ * Session state (`LIVE`/`IDLE`/`FAULTED`) is a different axis entirely: it is
49
+ * DERIVED by the totem-status#127 projection, which CONSUMES lifecycle.
50
+ */
51
+ export const SeatLifecycleStateSchema = z.enum(['active', 'suspended', 'retired']);
52
+ /**
53
+ * The `lifecycle.json` payload.
54
+ *
55
+ * `.strict()` plus the closed enum is what makes the totem-status#127 axis
56
+ * ruling STRUCTURAL rather than advisory: session-state vocabulary
57
+ * (`LIVE`/`IDLE`/`FAULTED`) is unrepresentable here — not as a `state` value
58
+ * (the enum rejects it) and not as a smuggled sibling key (strict rejects it).
59
+ * A marker can only ever say what was declared.
60
+ *
61
+ * `by` is resolved from the environment BY CALLERS (the `TOTEM_SELF_AGENT`
62
+ * seat) or honestly absent — a stamped absence, never a fabricated attribution
63
+ * (the mmnto-ai/totem#2625 MB-2 rule).
64
+ */
65
+ export const SeatLifecycleMarkerSchema = z
66
+ .object({
67
+ schemaVersion: z.literal(SEAT_LIFECYCLE_SCHEMA_VERSION),
68
+ state: SeatLifecycleStateSchema,
69
+ /** ISO-8601 instant of the transition, stamped at the write site. */
70
+ since: z.string().datetime({ offset: true }),
71
+ by: z.string().trim().min(1).optional(),
72
+ /** Operator's recorded ruling — the §6.6 audit trail when present. */
73
+ reason: z.string().optional(),
74
+ })
75
+ .strict();
76
+ /** Absolute path to a seat's marker file. Caller guarantees a safe `agentId`. */
77
+ function markerPathFor(repoRoot, agentId) {
78
+ return path.join(path.resolve(repoRoot), TOTEM_DIR, ORCHESTRATION_DIR, agentId, SEAT_LIFECYCLE_FILENAME);
79
+ }
80
+ /** The fail-open answer: a seat with no usable marker is `active`. */
81
+ function defaultActive(warning) {
82
+ return warning === undefined
83
+ ? { state: 'active', source: 'default-active' }
84
+ : { state: 'active', source: 'default-active', warning };
85
+ }
86
+ /**
87
+ * The degraded-read warning. It names the marker file because the recovery
88
+ * route is "fix or delete the marker" — the message hands over the one-step
89
+ * target rather than making the reader hunt for it.
90
+ */
91
+ function unusableMarkerWarning(markerPath, agentId, detail) {
92
+ return `seat "${agentId}": unusable lifecycle marker at ${markerPath} (${detail}) — treating the seat as active; fix or delete the marker`;
93
+ }
94
+ /** Flatten zod issues into one line for a warning or error detail. */
95
+ function describeIssues(err) {
96
+ return err.issues
97
+ .map((issue) => `${issue.path.join('.') || '<root>'}: ${issue.message}`)
98
+ .join('; ');
99
+ }
100
+ /**
101
+ * Read one seat's declared lifecycle. NEVER throws — every failure direction
102
+ * lands on `active` with a warning, because refusing to answer would take a
103
+ * poll, a `seat list`, or a doctor check down with one bad file.
104
+ *
105
+ * An unsafe `agentId` degrades the same way rather than throwing: this is a
106
+ * read path, and the caller may be enumerating ids it did not choose.
107
+ */
108
+ export function readSeatLifecycle(repoRoot, agentId) {
109
+ if (!isPathSafeAgentId(agentId)) {
110
+ // JSON.stringify escapes control characters: echoing a raw unsafe id into
111
+ // a CLI log is the terminal-injection class the guard exists to stop.
112
+ return defaultActive(`unsafe seat id ${JSON.stringify(agentId)} — refusing to resolve a lifecycle marker path; treating the seat as active`);
113
+ }
114
+ const markerPath = markerPathFor(repoRoot, agentId);
115
+ let raw;
116
+ // totem-context: intentional degradation — the catch IS the answer: ENOENT/ENOTDIR PROVE the marker is absent (the expected state of every seat that predates #2511, silent by contract), and every other errno degrades LOUDLY to active so a corrupt marker can never shrink a broadcast denominator.
117
+ try {
118
+ raw = fs.readFileSync(markerPath, 'utf-8');
119
+ // totem-context: intentional degradation — see directive above the try; dual placement so the rule fires on either the catch-keyword line or the catch-body line.
120
+ }
121
+ catch (err) {
122
+ const code = err !== null && typeof err === 'object' && 'code' in err
123
+ ? err.code
124
+ : undefined;
125
+ if (code !== undefined && MARKER_ABSENT_ERRNOS.has(code)) {
126
+ return defaultActive();
127
+ }
128
+ return defaultActive(unusableMarkerWarning(markerPath, agentId, getErrorMessage(err)));
129
+ }
130
+ let payload;
131
+ // totem-context: intentional degradation — malformed JSON is the corrupt-marker failure mode (#2511 failure table): warn naming the file and fail open to active, never throw out of a read path.
132
+ try {
133
+ payload = JSON.parse(raw);
134
+ // totem-context: intentional degradation — see directive above the try; dual placement so the rule fires on either the catch-keyword line or the catch-body line.
135
+ }
136
+ catch (err) {
137
+ return defaultActive(unusableMarkerWarning(markerPath, agentId, getErrorMessage(err)));
138
+ }
139
+ const parsed = SeatLifecycleMarkerSchema.safeParse(payload);
140
+ if (!parsed.success) {
141
+ return defaultActive(unusableMarkerWarning(markerPath, agentId, describeIssues(parsed.error)));
142
+ }
143
+ return { state: parsed.data.state, source: 'marker', marker: parsed.data };
144
+ }
145
+ /**
146
+ * Write (or replace) one seat's marker atomically and return the marker path.
147
+ *
148
+ * Overwriting an existing marker — including a corrupt one — is deliberate:
149
+ * the verbs ARE the recovery path for the degraded read above. Callers surface
150
+ * the pre-write warning from `readSeatLifecycle`; they do not refuse the write.
151
+ *
152
+ * Throws on an unsafe seat id or a schema-invalid marker (both are caller
153
+ * errors that must not reach disk) and on any I/O failure — the atomic helper
154
+ * guarantees the old marker survives a failed write.
155
+ */
156
+ export function writeSeatLifecycle(repoRoot, agentId, marker) {
157
+ if (!isPathSafeAgentId(agentId)) {
158
+ throw new TotemError(SEAT_LIFECYCLE_INVALID_CODE, `Refusing to write a lifecycle marker for unsafe seat id ${JSON.stringify(agentId)}.`, 'Seat ids are single path segments: no separators, `..`, null byte, control/whitespace, or win32-reserved characters.');
159
+ }
160
+ const parsed = SeatLifecycleMarkerSchema.safeParse(marker);
161
+ if (!parsed.success) {
162
+ throw new TotemError(SEAT_LIFECYCLE_INVALID_CODE, `Refusing to write a lifecycle marker that violates the schema: ${describeIssues(parsed.error)}`, 'The marker schema is strict by contract (session state is not lifecycle state) — fix the caller rather than widening the schema.');
163
+ }
164
+ const markerPath = markerPathFor(repoRoot, agentId);
165
+ try {
166
+ fs.mkdirSync(path.dirname(markerPath), { recursive: true });
167
+ writeFileAtomicSync(markerPath, JSON.stringify(parsed.data, null, 2) + '\n');
168
+ }
169
+ catch (err) {
170
+ throw new TotemError(SEAT_LIFECYCLE_WRITE_FAILED_CODE, `Could not write the lifecycle marker at ${markerPath}: ${getErrorMessage(err)}`, 'Check write permissions on the seat directory and free disk space, then re-run — the write is atomic, so the seat is still in its previous state.', err);
171
+ }
172
+ return markerPath;
173
+ }
174
+ /**
175
+ * Every registered seat in a repo with its declared lifecycle, sorted by seat
176
+ * (`readSeatDirs` order).
177
+ *
178
+ * DERIVED at read time and never cached or persisted (Tenet 20): the dirs are
179
+ * the roster and the markers are the state, so a transition is visible to the
180
+ * very next read with no invalidation step — which is what lets `pollMail`
181
+ * consume per-invocation markers without a staleness seam.
182
+ */
183
+ export function deriveSeatStatuses(repoRoot) {
184
+ return readSeatDirs(repoRoot).map((seat) => {
185
+ const read = readSeatLifecycle(repoRoot, seat);
186
+ const status = { seat, state: read.state, source: read.source };
187
+ if (read.marker !== undefined) {
188
+ status.since = read.marker.since;
189
+ status.marker = read.marker;
190
+ }
191
+ if (read.warning !== undefined) {
192
+ status.warning = read.warning;
193
+ }
194
+ return status;
195
+ });
196
+ }
197
+ //# sourceMappingURL=seat-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-lifecycle.js","sourceRoot":"","sources":["../src/seat-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Tests for the declared seat-lifecycle markers (mmnto-ai/totem#2511).
3
+ *
4
+ * Filesystem-driven against real temp trees, mirroring
5
+ * `orchestration-resolver.test.ts` so the two seat-surface suites stay
6
+ * symmetric. The load-bearing invariants here are the fail-open read (a
7
+ * corrupt marker degrades to `active` and says so, naming the file) and the
8
+ * structural exclusion of session-state vocabulary from the marker schema.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=seat-lifecycle.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-lifecycle.test.d.ts","sourceRoot":"","sources":["../src/seat-lifecycle.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Tests for the declared seat-lifecycle markers (mmnto-ai/totem#2511).
3
+ *
4
+ * Filesystem-driven against real temp trees, mirroring
5
+ * `orchestration-resolver.test.ts` so the two seat-surface suites stay
6
+ * symmetric. The load-bearing invariants here are the fail-open read (a
7
+ * corrupt marker degrades to `active` and says so, naming the file) and the
8
+ * structural exclusion of session-state vocabulary from the marker schema.
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
14
+ import { TotemError } from './errors.js';
15
+ import { deriveSeatStatuses, readSeatLifecycle, SEAT_LIFECYCLE_FILENAME, SEAT_LIFECYCLE_SCHEMA_VERSION, SeatLifecycleMarkerSchema, writeSeatLifecycle, } from './seat-lifecycle.js';
16
+ import { cleanTmpDir } from './test-utils.js';
17
+ let tmpRoot;
18
+ let repoRoot;
19
+ const SINCE = '2026-08-11T04:00:00Z';
20
+ function markerPath(seat) {
21
+ return path.join(repoRoot, '.totem', 'orchestration', seat, SEAT_LIFECYCLE_FILENAME);
22
+ }
23
+ /** Create the seat dir (the registration) without writing any marker. */
24
+ function mkSeat(seat) {
25
+ fs.mkdirSync(path.join(repoRoot, '.totem', 'orchestration', seat), { recursive: true });
26
+ }
27
+ /** Plant raw bytes as a seat's marker — the corrupt-file fixture. */
28
+ function plantRawMarker(seat, contents) {
29
+ mkSeat(seat);
30
+ fs.writeFileSync(markerPath(seat), contents, 'utf-8');
31
+ }
32
+ function marker(overrides = {}) {
33
+ return {
34
+ schemaVersion: SEAT_LIFECYCLE_SCHEMA_VERSION,
35
+ state: 'active',
36
+ since: SINCE,
37
+ ...overrides,
38
+ };
39
+ }
40
+ beforeEach(() => {
41
+ // totem-context: test fixture only; agents do not consume this temp dir.
42
+ tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-seat-'));
43
+ repoRoot = path.join(tmpRoot, 'r');
44
+ fs.mkdirSync(repoRoot, { recursive: true });
45
+ });
46
+ afterEach(() => {
47
+ cleanTmpDir(tmpRoot);
48
+ });
49
+ // ─── Absent marker ─────────────────────────────────────────────────────────
50
+ describe('readSeatLifecycle — absent marker', () => {
51
+ it('reports active/default-active with NO warning when the seat has no marker', () => {
52
+ mkSeat('a-seat');
53
+ const result = readSeatLifecycle(repoRoot, 'a-seat');
54
+ expect(result.state).toBe('active');
55
+ expect(result.source).toBe('default-active');
56
+ expect(result.warning).toBeUndefined();
57
+ expect(result.marker).toBeUndefined();
58
+ });
59
+ it('reports active/default-active with no warning when the whole tree is absent', () => {
60
+ const result = readSeatLifecycle(repoRoot, 'never-written');
61
+ expect(result.state).toBe('active');
62
+ expect(result.source).toBe('default-active');
63
+ expect(result.warning).toBeUndefined();
64
+ });
65
+ });
66
+ // ─── Corrupt marker: fail open, name the file ──────────────────────────────
67
+ describe('readSeatLifecycle — unusable marker', () => {
68
+ it('degrades malformed JSON to active with a warning naming the marker path', () => {
69
+ plantRawMarker('a-seat', '{ this is not json');
70
+ const result = readSeatLifecycle(repoRoot, 'a-seat');
71
+ expect(result.state).toBe('active');
72
+ expect(result.source).toBe('default-active');
73
+ expect(result.warning).toContain(markerPath('a-seat'));
74
+ expect(result.warning).toContain('fix or delete the marker');
75
+ });
76
+ it('degrades a schema-invalid marker to active with a warning naming the marker path', () => {
77
+ plantRawMarker('a-seat', JSON.stringify({ schemaVersion: 1, state: 'LIVE', since: SINCE }));
78
+ const result = readSeatLifecycle(repoRoot, 'a-seat');
79
+ expect(result.state).toBe('active');
80
+ expect(result.source).toBe('default-active');
81
+ expect(result.warning).toContain(markerPath('a-seat'));
82
+ });
83
+ it('degrades a corrupt RETIRED marker to active — fails toward obligation-held', () => {
84
+ plantRawMarker('a-seat', '{"schemaVersion":1,"state":"retired"');
85
+ const result = readSeatLifecycle(repoRoot, 'a-seat');
86
+ expect(result.state).toBe('active');
87
+ expect(result.warning).toContain(markerPath('a-seat'));
88
+ });
89
+ });
90
+ // ─── Schema: the axis ruling, made structural ──────────────────────────────
91
+ describe('SeatLifecycleMarkerSchema', () => {
92
+ it.each(['LIVE', 'IDLE', 'FAULTED'])('rejects session-state vocabulary as state: %s', (state) => {
93
+ expect(SeatLifecycleMarkerSchema.safeParse({ schemaVersion: 1, state, since: SINCE }).success).toBe(false);
94
+ });
95
+ it('accepts each declared lifecycle state', () => {
96
+ for (const state of ['active', 'suspended', 'retired']) {
97
+ expect(SeatLifecycleMarkerSchema.safeParse(marker({ state })).success).toBe(true);
98
+ }
99
+ });
100
+ it('rejects unknown keys — no session state smuggled in as a sibling field', () => {
101
+ expect(SeatLifecycleMarkerSchema.safeParse({ ...marker(), sessionState: 'LIVE' }).success).toBe(false);
102
+ });
103
+ it('rejects a schemaVersion other than 1', () => {
104
+ expect(SeatLifecycleMarkerSchema.safeParse({ ...marker(), schemaVersion: 2 }).success).toBe(false);
105
+ });
106
+ it('rejects an empty or whitespace-only `by`', () => {
107
+ expect(SeatLifecycleMarkerSchema.safeParse({ ...marker(), by: '' }).success).toBe(false);
108
+ expect(SeatLifecycleMarkerSchema.safeParse({ ...marker(), by: ' ' }).success).toBe(false);
109
+ });
110
+ it('rejects a non-ISO-8601 `since`', () => {
111
+ expect(SeatLifecycleMarkerSchema.safeParse({ ...marker(), since: '2026-08-11' }).success).toBe(false);
112
+ });
113
+ });
114
+ // ─── Write → read round-trip ───────────────────────────────────────────────
115
+ describe('writeSeatLifecycle', () => {
116
+ it.each(['active', 'suspended', 'retired'])('round-trips state %s', (state) => {
117
+ writeSeatLifecycle(repoRoot, 'a-seat', marker({ state, by: 'totem-claude', reason: 'ruled' }));
118
+ const result = readSeatLifecycle(repoRoot, 'a-seat');
119
+ expect(result.state).toBe(state);
120
+ expect(result.source).toBe('marker');
121
+ expect(result.marker).toEqual({
122
+ schemaVersion: SEAT_LIFECYCLE_SCHEMA_VERSION,
123
+ state,
124
+ since: SINCE,
125
+ by: 'totem-claude',
126
+ reason: 'ruled',
127
+ });
128
+ });
129
+ it('omits `by` entirely when the caller did not resolve one — never fabricated', () => {
130
+ writeSeatLifecycle(repoRoot, 'a-seat', marker({ state: 'suspended' }));
131
+ const raw = JSON.parse(fs.readFileSync(markerPath('a-seat'), 'utf-8'));
132
+ expect(Object.keys(raw).sort()).toEqual([
133
+ 'schemaVersion',
134
+ 'since',
135
+ 'state',
136
+ ]);
137
+ // The written bytes round-trip the STRICT schema — no field the reader rejects.
138
+ expect(SeatLifecycleMarkerSchema.safeParse(raw).success).toBe(true);
139
+ expect(readSeatLifecycle(repoRoot, 'a-seat').marker?.by).toBeUndefined();
140
+ });
141
+ it('creates the seat directory when the seat has never written', () => {
142
+ const written = writeSeatLifecycle(repoRoot, 'fresh-seat', marker());
143
+ expect(written).toBe(markerPath('fresh-seat'));
144
+ expect(fs.existsSync(markerPath('fresh-seat'))).toBe(true);
145
+ });
146
+ it('overwrites a corrupt marker — the verbs ARE the recovery path', () => {
147
+ plantRawMarker('a-seat', 'not json at all');
148
+ expect(readSeatLifecycle(repoRoot, 'a-seat').warning).toBeDefined();
149
+ writeSeatLifecycle(repoRoot, 'a-seat', marker({ state: 'suspended' }));
150
+ const healed = readSeatLifecycle(repoRoot, 'a-seat');
151
+ expect(healed.state).toBe('suspended');
152
+ expect(healed.source).toBe('marker');
153
+ expect(healed.warning).toBeUndefined();
154
+ });
155
+ it('throws a TotemError on a schema-invalid marker rather than writing it', () => {
156
+ expect(() => writeSeatLifecycle(repoRoot, 'a-seat', { ...marker(), state: 'LIVE' })).toThrow(TotemError);
157
+ expect(fs.existsSync(markerPath('a-seat'))).toBe(false);
158
+ });
159
+ });
160
+ // ─── Unsafe seat ids ───────────────────────────────────────────────────────
161
+ describe('unsafe seat ids', () => {
162
+ it.each(['../escape', 'a/b', ''])('read degrades to default-active with a warning: %j', (id) => {
163
+ const result = readSeatLifecycle(repoRoot, id);
164
+ expect(result.state).toBe('active');
165
+ expect(result.source).toBe('default-active');
166
+ expect(result.warning).toContain('unsafe seat id');
167
+ });
168
+ it.each(['../escape', 'a/b', ''])('write throws a TotemError: %j', (id) => {
169
+ expect(() => writeSeatLifecycle(repoRoot, id, marker())).toThrow(TotemError);
170
+ });
171
+ it('does not write outside the orchestration tree for a traversal id', () => {
172
+ expect(() => writeSeatLifecycle(repoRoot, '../..', marker())).toThrow(TotemError);
173
+ expect(fs.existsSync(path.join(tmpRoot, SEAT_LIFECYCLE_FILENAME))).toBe(false);
174
+ });
175
+ });
176
+ // ─── deriveSeatStatuses ────────────────────────────────────────────────────
177
+ describe('deriveSeatStatuses', () => {
178
+ it('returns one sorted row per seat dir with read-time state', () => {
179
+ mkSeat('a-seat');
180
+ writeSeatLifecycle(repoRoot, 'b-seat', marker({ state: 'suspended', reason: 'paused' }));
181
+ plantRawMarker('c-seat', '{ corrupt');
182
+ writeSeatLifecycle(repoRoot, 'd-seat', marker({ state: 'retired' }));
183
+ // Routing surfaces are not seats.
184
+ fs.mkdirSync(path.join(repoRoot, '.totem', 'orchestration', '_broadcast'), { recursive: true });
185
+ const statuses = deriveSeatStatuses(repoRoot);
186
+ expect(statuses.map((s) => s.seat)).toEqual(['a-seat', 'b-seat', 'c-seat', 'd-seat']);
187
+ expect(statuses.map((s) => s.state)).toEqual(['active', 'suspended', 'active', 'retired']);
188
+ expect(statuses.map((s) => s.source)).toEqual([
189
+ 'default-active',
190
+ 'marker',
191
+ 'default-active',
192
+ 'marker',
193
+ ]);
194
+ expect(statuses[0]?.warning).toBeUndefined();
195
+ expect(statuses[0]?.since).toBeUndefined();
196
+ expect(statuses[1]?.since).toBe(SINCE);
197
+ expect(statuses[1]?.marker?.reason).toBe('paused');
198
+ expect(statuses[2]?.warning).toContain(markerPath('c-seat'));
199
+ });
200
+ it('returns an empty list when no orchestration tree exists', () => {
201
+ expect(deriveSeatStatuses(repoRoot)).toEqual([]);
202
+ });
203
+ it('reflects a transition on the very next read — nothing is cached', () => {
204
+ writeSeatLifecycle(repoRoot, 'a-seat', marker({ state: 'active' }));
205
+ expect(deriveSeatStatuses(repoRoot)[0]?.state).toBe('active');
206
+ writeSeatLifecycle(repoRoot, 'a-seat', marker({ state: 'suspended' }));
207
+ expect(deriveSeatStatuses(repoRoot)[0]?.state).toBe('suspended');
208
+ });
209
+ });
210
+ //# sourceMappingURL=seat-lifecycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seat-lifecycle.test.js","sourceRoot":"","sources":["../src/seat-lifecycle.test.ts"],"names":[],"mappings":"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"}