@mmnto/cli 1.114.0 → 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 (82) hide show
  1. package/dist/commands/doctor-seat-identity.d.ts +71 -0
  2. package/dist/commands/doctor-seat-identity.d.ts.map +1 -0
  3. package/dist/commands/doctor-seat-identity.js +352 -0
  4. package/dist/commands/doctor-seat-identity.js.map +1 -0
  5. package/dist/commands/doctor-seat-identity.test.d.ts +13 -0
  6. package/dist/commands/doctor-seat-identity.test.d.ts.map +1 -0
  7. package/dist/commands/doctor-seat-identity.test.js +230 -0
  8. package/dist/commands/doctor-seat-identity.test.js.map +1 -0
  9. package/dist/commands/doctor.d.ts.map +1 -1
  10. package/dist/commands/doctor.js +3 -0
  11. package/dist/commands/doctor.js.map +1 -1
  12. package/dist/commands/doctor.test.js +1 -0
  13. package/dist/commands/doctor.test.js.map +1 -1
  14. package/dist/commands/ecl-gc.d.ts.map +1 -1
  15. package/dist/commands/ecl-gc.js +18 -7
  16. package/dist/commands/ecl-gc.js.map +1 -1
  17. package/dist/commands/ecl-gc.test.js +63 -1
  18. package/dist/commands/ecl-gc.test.js.map +1 -1
  19. package/dist/commands/eject.d.ts +62 -3
  20. package/dist/commands/eject.d.ts.map +1 -1
  21. package/dist/commands/eject.js +382 -47
  22. package/dist/commands/eject.js.map +1 -1
  23. package/dist/commands/eject.test.js +557 -7
  24. package/dist/commands/eject.test.js.map +1 -1
  25. package/dist/commands/gemini-beforetool-contract.test.d.ts +2 -0
  26. package/dist/commands/gemini-beforetool-contract.test.d.ts.map +1 -0
  27. package/dist/commands/gemini-beforetool-contract.test.js +106 -0
  28. package/dist/commands/gemini-beforetool-contract.test.js.map +1 -0
  29. package/dist/commands/gemini-sessionstart-contract.test.d.ts +2 -0
  30. package/dist/commands/gemini-sessionstart-contract.test.d.ts.map +1 -0
  31. package/dist/commands/gemini-sessionstart-contract.test.js +184 -0
  32. package/dist/commands/gemini-sessionstart-contract.test.js.map +1 -0
  33. package/dist/commands/init-templates.d.ts +2 -2
  34. package/dist/commands/init-templates.d.ts.map +1 -1
  35. package/dist/commands/init-templates.js +267 -15
  36. package/dist/commands/init-templates.js.map +1 -1
  37. package/dist/commands/init.test.js +25 -7
  38. package/dist/commands/init.test.js.map +1 -1
  39. package/dist/commands/install-hooks-exit-contract.test.js +5 -0
  40. package/dist/commands/install-hooks-exit-contract.test.js.map +1 -1
  41. package/dist/commands/mail-degraded-e4.test.js +126 -0
  42. package/dist/commands/mail-degraded-e4.test.js.map +1 -1
  43. package/dist/commands/mail.d.ts +19 -1
  44. package/dist/commands/mail.d.ts.map +1 -1
  45. package/dist/commands/mail.js +195 -30
  46. package/dist/commands/mail.js.map +1 -1
  47. package/dist/commands/mail.test.js +291 -3
  48. package/dist/commands/mail.test.js.map +1 -1
  49. package/dist/commands/orient.d.ts.map +1 -1
  50. package/dist/commands/orient.js +82 -0
  51. package/dist/commands/orient.js.map +1 -1
  52. package/dist/commands/orient.test.js +144 -1
  53. package/dist/commands/orient.test.js.map +1 -1
  54. package/dist/commands/seat-cli-wiring.test.d.ts +20 -0
  55. package/dist/commands/seat-cli-wiring.test.d.ts.map +1 -0
  56. package/dist/commands/seat-cli-wiring.test.js +147 -0
  57. package/dist/commands/seat-cli-wiring.test.js.map +1 -0
  58. package/dist/commands/seat-poll-chain.test.d.ts +13 -0
  59. package/dist/commands/seat-poll-chain.test.d.ts.map +1 -0
  60. package/dist/commands/seat-poll-chain.test.js +103 -0
  61. package/dist/commands/seat-poll-chain.test.js.map +1 -0
  62. package/dist/commands/seat.d.ts +92 -0
  63. package/dist/commands/seat.d.ts.map +1 -0
  64. package/dist/commands/seat.js +649 -0
  65. package/dist/commands/seat.js.map +1 -0
  66. package/dist/commands/seat.test.d.ts +19 -0
  67. package/dist/commands/seat.test.d.ts.map +1 -0
  68. package/dist/commands/seat.test.js +532 -0
  69. package/dist/commands/seat.test.js.map +1 -0
  70. package/dist/commands/sessionstart-manifest-contract.test.d.ts +2 -0
  71. package/dist/commands/sessionstart-manifest-contract.test.d.ts.map +1 -0
  72. package/dist/commands/sessionstart-manifest-contract.test.js +176 -0
  73. package/dist/commands/sessionstart-manifest-contract.test.js.map +1 -0
  74. package/dist/hooks/__tests__/auto-context.test.js +20 -0
  75. package/dist/hooks/__tests__/auto-context.test.js.map +1 -1
  76. package/dist/hooks/auto-context.d.ts +19 -0
  77. package/dist/hooks/auto-context.d.ts.map +1 -1
  78. package/dist/hooks/auto-context.js +22 -4
  79. package/dist/hooks/auto-context.js.map +1 -1
  80. package/dist/index.js +71 -0
  81. package/dist/index.js.map +1 -1
  82. package/package.json +2 -2
@@ -0,0 +1,71 @@
1
+ /**
2
+ * `totem doctor` — the seat-identity-binding SENSE (mmnto-ai/totem#2511).
3
+ *
4
+ * Tenet 9/13: this row senses, it never enforces. It carries `gateExempt: true`
5
+ * and never emits `fail`, so no `--strict` tier can give it teeth — the
6
+ * exemption is a property of the row (`doctor.ts` DiagnosticResult), not of the
7
+ * tier a later change might widen.
8
+ *
9
+ * Three post-hoc contradictions are sensed per registered seat dir:
10
+ *
11
+ * (a) `from-mismatch` — an outbox dispatch whose frontmatter `from:` names a
12
+ * DIFFERENT seat than the directory it sits in. The dir is the
13
+ * registration (the mmnto-ai/totem#2141 dirs-union invariant), so the two
14
+ * disagreeing is an identity contradiction on its face.
15
+ * (b) `writing-while-excluded` — a seat whose PARSED lifecycle marker says
16
+ * `suspended`/`retired` yet whose outbox carries filename-stamped writes
17
+ * newer than the marker's `since`: declared lifecycle contradicted by
18
+ * observed behaviour.
19
+ * (c) `env-names-excluded-seat` / `env-names-unknown-seat` — `TOTEM_SELF_AGENT`
20
+ * naming a non-active seat, or naming no seat directory in this repo.
21
+ *
22
+ * A corrupt marker degrades to `active` by core's contract
23
+ * (`seat-lifecycle.ts` — fail open on visibility), so (b) is NEVER evaluated
24
+ * against it: this sense refuses to build a finding on an unparsed marker.
25
+ * The core warning (which names the marker file) is relayed instead, as its own
26
+ * `unreadable-marker` row — a scan hole disclosed rather than a clean line that
27
+ * hides it.
28
+ *
29
+ * THE HONEST LIMIT is stated in every verdict, pass included: a CONSISTENT fake
30
+ * defeats all three arms, and that is precisely why write-time binding was
31
+ * judged infeasible for v1 and this doctor tier is the chartered fallback.
32
+ *
33
+ * Core is dynamic-imported so `@mmnto/totem` stays off the CLI cold-start
34
+ * graph, matching every other doctor check.
35
+ */
36
+ import type { DiagnosticResult } from './doctor.js';
37
+ /** Row label, `padEnd(18)`-safe in the doctor render. */
38
+ export declare const SEAT_IDENTITY_CHECK_NAME = "Seat Identity";
39
+ /**
40
+ * Newest-N outbox files scanned per seat, by filename sort. Dispatch basenames
41
+ * are stamp-prefixed (`YYYY-MM-DDTHHMMZ-`), so the lexical tail IS the newest
42
+ * tail. A bound is required — cohort outboxes grow without limit and this row
43
+ * runs on every `totem doctor` — and whenever it bites, the verdict SAYS so
44
+ * (never a silently partial scan).
45
+ */
46
+ export declare const OUTBOX_SCAN_LIMIT = 200;
47
+ /**
48
+ * The verbatim limit clause. Exported so the test pins it against drift: the
49
+ * whole justification for shipping a doctor-tier sense instead of write-time
50
+ * binding rides on this sentence staying true and staying said.
51
+ */
52
+ export declare const SEAT_IDENTITY_HONEST_LIMIT = "honest limit: a CONSISTENT fake \u2014 writing from the wrong seat dir with a matching forged `from:`, the agy shape \u2014 is NOT detectable post-hoc, which is why full write-time binding was judged infeasible for v1 and this doctor tier is the chartered fallback; this check does not discharge the 2026-06-18 seat-identity precondition.";
53
+ /** The contradiction classes this row can report. */
54
+ export type SeatIdentityFindingClass = 'from-mismatch' | 'writing-while-excluded' | 'env-names-excluded-seat' | 'env-names-unknown-seat' | 'unreadable-marker' | 'outbox-unreadable';
55
+ export interface SeatIdentitySeams {
56
+ /**
57
+ * Test seam — production reads `process.env`. Injected so the env arm is
58
+ * exercisable without mutating real env state (the `resolveSelfAgents`
59
+ * convention).
60
+ */
61
+ env?: Record<string, string | undefined>;
62
+ /** Test seam — overrides {@link OUTBOX_SCAN_LIMIT} so truncation is testable. */
63
+ outboxScanLimit?: number;
64
+ }
65
+ /**
66
+ * Sense seat-identity binding across every registered seat dir. Report-only:
67
+ * `gateExempt: true` on every arm, `fail` on none, and an unexpected throw
68
+ * lands as a warn row rather than taking `totem doctor` down (Tenet 13).
69
+ */
70
+ export declare function checkSeatIdentity(cwd: string, seams?: SeatIdentitySeams): Promise<DiagnosticResult>;
71
+ //# sourceMappingURL=doctor-seat-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-seat-identity.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-seat-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,yDAAyD;AACzD,eAAO,MAAM,wBAAwB,kBAAkB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,uVACqS,CAAC;AAwC7U,qDAAqD;AACrD,MAAM,MAAM,wBAAwB,GAChC,eAAe,GACf,wBAAwB,GACxB,yBAAyB,GACzB,wBAAwB,GACxB,mBAAmB,GACnB,mBAAmB,CAAC;AAQxB,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAqHD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,iBAAsB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CAwL3B"}
@@ -0,0 +1,352 @@
1
+ /**
2
+ * `totem doctor` — the seat-identity-binding SENSE (mmnto-ai/totem#2511).
3
+ *
4
+ * Tenet 9/13: this row senses, it never enforces. It carries `gateExempt: true`
5
+ * and never emits `fail`, so no `--strict` tier can give it teeth — the
6
+ * exemption is a property of the row (`doctor.ts` DiagnosticResult), not of the
7
+ * tier a later change might widen.
8
+ *
9
+ * Three post-hoc contradictions are sensed per registered seat dir:
10
+ *
11
+ * (a) `from-mismatch` — an outbox dispatch whose frontmatter `from:` names a
12
+ * DIFFERENT seat than the directory it sits in. The dir is the
13
+ * registration (the mmnto-ai/totem#2141 dirs-union invariant), so the two
14
+ * disagreeing is an identity contradiction on its face.
15
+ * (b) `writing-while-excluded` — a seat whose PARSED lifecycle marker says
16
+ * `suspended`/`retired` yet whose outbox carries filename-stamped writes
17
+ * newer than the marker's `since`: declared lifecycle contradicted by
18
+ * observed behaviour.
19
+ * (c) `env-names-excluded-seat` / `env-names-unknown-seat` — `TOTEM_SELF_AGENT`
20
+ * naming a non-active seat, or naming no seat directory in this repo.
21
+ *
22
+ * A corrupt marker degrades to `active` by core's contract
23
+ * (`seat-lifecycle.ts` — fail open on visibility), so (b) is NEVER evaluated
24
+ * against it: this sense refuses to build a finding on an unparsed marker.
25
+ * The core warning (which names the marker file) is relayed instead, as its own
26
+ * `unreadable-marker` row — a scan hole disclosed rather than a clean line that
27
+ * hides it.
28
+ *
29
+ * THE HONEST LIMIT is stated in every verdict, pass included: a CONSISTENT fake
30
+ * defeats all three arms, and that is precisely why write-time binding was
31
+ * judged infeasible for v1 and this doctor tier is the chartered fallback.
32
+ *
33
+ * Core is dynamic-imported so `@mmnto/totem` stays off the CLI cold-start
34
+ * graph, matching every other doctor check.
35
+ */
36
+ import * as fs from 'node:fs';
37
+ import * as path from 'node:path';
38
+ /** Row label, `padEnd(18)`-safe in the doctor render. */
39
+ export const SEAT_IDENTITY_CHECK_NAME = 'Seat Identity';
40
+ /**
41
+ * Newest-N outbox files scanned per seat, by filename sort. Dispatch basenames
42
+ * are stamp-prefixed (`YYYY-MM-DDTHHMMZ-`), so the lexical tail IS the newest
43
+ * tail. A bound is required — cohort outboxes grow without limit and this row
44
+ * runs on every `totem doctor` — and whenever it bites, the verdict SAYS so
45
+ * (never a silently partial scan).
46
+ */
47
+ export const OUTBOX_SCAN_LIMIT = 200;
48
+ /**
49
+ * The verbatim limit clause. Exported so the test pins it against drift: the
50
+ * whole justification for shipping a doctor-tier sense instead of write-time
51
+ * binding rides on this sentence staying true and staying said.
52
+ */
53
+ export const SEAT_IDENTITY_HONEST_LIMIT = 'honest limit: a CONSISTENT fake — writing from the wrong seat dir with a matching forged `from:`, the agy shape — is NOT detectable post-hoc, which is why full write-time binding was judged infeasible for v1 and this doctor tier is the chartered fallback; this check does not discharge the 2026-06-18 seat-identity precondition.';
54
+ /**
55
+ * Bytes read from the head of each dispatch. Sized to the mail reader's own
56
+ * frontmatter search window (`mail.ts` MAX_HEADER_SEARCH_BYTES, 16 KiB, sized
57
+ * ~4x the largest observed live header) so this sensor sees exactly the header
58
+ * the mail reader sees — one wire, one reading.
59
+ */
60
+ const HEAD_READ_BYTES = 16_384;
61
+ /** Example filenames carried per finding before the remainder is summarized. */
62
+ const MAX_EVIDENCE_FILES = 3;
63
+ /** Rendered cap for a token that came off the wire (a `from:` value, an env id). */
64
+ const MAX_TOKEN_CHARS = 120;
65
+ /** Errnos that PROVE an outbox is absent rather than unreadable. */
66
+ const OUTBOX_ABSENT_ERRNOS = new Set(['ENOENT', 'ENOTDIR']);
67
+ const TOTEM_DIR = '.totem';
68
+ const ORCHESTRATION_DIR = 'orchestration';
69
+ const OUTBOX_DIR = 'outbox';
70
+ /** The frontmatter opener every ADR-098 dispatch starts with. */
71
+ const FRONTMATTER_OPENER = '---';
72
+ /**
73
+ * Closing frontmatter delimiter — a `---` line after the opener (LF/CRLF/EOF),
74
+ * tolerating trailing whitespace. Copied in shape from `mail.ts` deliberately:
75
+ * a file the mail reader rejects as unparseable is not a dispatch whose `from:`
76
+ * binds anything, so both readers must agree on where the header ends.
77
+ */
78
+ const CLOSING_DELIMITER = /\r?\n---[ \t]*(?:\r?\n|$)/;
79
+ /** `from:` inside the delimited header only — a body line can never fabricate one. */
80
+ const FROM_FIELD = /^from:\s*(.+)$/im;
81
+ /** The stamped-dispatch basename prefix: `YYYY-MM-DDTHHMMZ-`. */
82
+ const STAMPED_BASENAME = /^(\d{4})-(\d{2})-(\d{2})T(\d{2})(\d{2})Z-/;
83
+ /** One-line, ANSI-stripped, length-capped rendering of an off-the-wire token. */
84
+ function capToken(value) {
85
+ return value.length > MAX_TOKEN_CHARS ? `${value.slice(0, MAX_TOKEN_CHARS)}…` : value;
86
+ }
87
+ /** Message text for an unknown throwable (checkEstate's shape). */
88
+ function messageOf(err) {
89
+ return err instanceof Error ? err.message : String(err);
90
+ }
91
+ /** Errno of a throwable, when it carries one. */
92
+ function errnoOf(err) {
93
+ return err !== null && typeof err === 'object' && 'code' in err
94
+ ? err.code
95
+ : undefined;
96
+ }
97
+ /**
98
+ * Strip a single pair of matching surrounding quotes. `composeDispatch` leaves
99
+ * a valid kebab agent-id unquoted (`yamlScalar` quotes only when the raw value
100
+ * would mis-parse), but hand-authored dispatches quote freely, and an
101
+ * unquote-blind compare would read every quoted `from:` as a mismatch.
102
+ */
103
+ function unquoteScalar(value) {
104
+ const trimmed = value.trim();
105
+ if (trimmed.length >= 2) {
106
+ const first = trimmed[0];
107
+ const last = trimmed[trimmed.length - 1];
108
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
109
+ return trimmed.slice(1, -1).trim();
110
+ }
111
+ }
112
+ return trimmed;
113
+ }
114
+ /**
115
+ * The `from:` value declared in a dispatch's frontmatter, or `null` when the
116
+ * file is not header-shaped or declares none. A missing `from:` is NOT a
117
+ * finding: the mail reader falls back to the outbox dir name, which is the
118
+ * binding this row is checking — absence agrees with the dir by construction.
119
+ */
120
+ function frontmatterFrom(content) {
121
+ if (!content.startsWith(FRONTMATTER_OPENER))
122
+ return null;
123
+ const window = content.slice(FRONTMATTER_OPENER.length);
124
+ const close = CLOSING_DELIMITER.exec(window);
125
+ if (close === null)
126
+ return null;
127
+ const match = FROM_FIELD.exec(window.slice(0, close.index));
128
+ return match === null ? null : unquoteScalar(match[1]);
129
+ }
130
+ /**
131
+ * The UTC instant encoded in a stamped basename, or `null` when the name
132
+ * carries no stamp. Minute granularity is the wire's own resolution
133
+ * (`compactStamp`), so a write in the SAME minute as a transition compares as
134
+ * not-newer — the conservative direction for a sensor that must not invent
135
+ * contradictions.
136
+ */
137
+ function stampedInstantMs(basename) {
138
+ const m = STAMPED_BASENAME.exec(basename);
139
+ if (m === null)
140
+ return null;
141
+ const ms = Date.parse(`${m[1]}-${m[2]}-${m[3]}T${m[4]}:${m[5]}:00.000Z`);
142
+ return Number.isNaN(ms) ? null : ms;
143
+ }
144
+ function listOutbox(outboxDir, limit) {
145
+ let entries;
146
+ // totem-context: intentional degradation — the catch IS the answer: ENOENT/ENOTDIR PROVE a seat has never written (the steady state of a fresh seat dir, silent by contract), and every other errno is a scan hole this row DISCLOSES as an outbox-unreadable finding rather than reporting a clean seat it never looked inside.
147
+ try {
148
+ entries = fs.readdirSync(outboxDir, { withFileTypes: true });
149
+ // 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.
150
+ }
151
+ catch (err) {
152
+ const code = errnoOf(err);
153
+ if (code !== undefined && OUTBOX_ABSENT_ERRNOS.has(code)) {
154
+ return { files: [], total: 0 };
155
+ }
156
+ return { files: [], total: 0, readFailure: messageOf(err) };
157
+ }
158
+ const all = entries
159
+ .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
160
+ .map((entry) => entry.name)
161
+ .sort();
162
+ return { files: all.length > limit ? all.slice(all.length - limit) : all, total: all.length };
163
+ }
164
+ /** Read at most `HEAD_READ_BYTES` from the head of a file. */
165
+ function readHead(filePath) {
166
+ const fd = fs.openSync(filePath, 'r');
167
+ try {
168
+ const buf = Buffer.alloc(HEAD_READ_BYTES);
169
+ const bytesRead = fs.readSync(fd, buf, 0, HEAD_READ_BYTES, 0);
170
+ return buf.toString('utf-8', 0, bytesRead);
171
+ }
172
+ finally {
173
+ fs.closeSync(fd);
174
+ }
175
+ }
176
+ /** `N file(s): a, b, c (+M more)` — every count stated, nothing silently dropped. */
177
+ function evidenceList(items) {
178
+ const shown = items.slice(0, MAX_EVIDENCE_FILES);
179
+ const more = items.length - shown.length;
180
+ const listed = more > 0 ? `${shown.join(', ')} (+${more} more)` : shown.join(', ');
181
+ return `${items.length} file(s): ${listed}`;
182
+ }
183
+ /**
184
+ * Sense seat-identity binding across every registered seat dir. Report-only:
185
+ * `gateExempt: true` on every arm, `fail` on none, and an unexpected throw
186
+ * lands as a warn row rather than taking `totem doctor` down (Tenet 13).
187
+ */
188
+ export async function checkSeatIdentity(cwd, seams = {}) {
189
+ const name = SEAT_IDENTITY_CHECK_NAME;
190
+ const limit = seams.outboxScanLimit ?? OUTBOX_SCAN_LIMIT;
191
+ const env = seams.env ?? process.env;
192
+ // Sanitize-at-interpolation: `from:` values, env values, and errno text are
193
+ // all off-process bytes, and this row's message reaches the terminal
194
+ // unsanitized downstream. `sanitizeForTerminal` is core-owned and must not be
195
+ // imported statically here, so it is captured after the dynamic import; until
196
+ // then the fallback still FLATTENS (the line-forging vector) and only lacks
197
+ // the ANSI strip — a pre-import failure carries loader text, not wire bytes.
198
+ let sanitize = (text) => text;
199
+ const render = (text) => sanitize(text)
200
+ .replace(/[\t\n\r]+/g, ' ')
201
+ .replace(/ {2,}/g, ' ')
202
+ .trim();
203
+ // totem-context: a scan failure is reported as a warn row — the seat-identity sensor must never take `totem doctor` down with it (report-only, Tenet 13; the checkEstate precedent).
204
+ try {
205
+ const { deriveSeatStatuses, resolveTotemRepoRootSync, sanitizeForTerminal } = await import('@mmnto/totem');
206
+ sanitize = sanitizeForTerminal;
207
+ // The shared walk-start-is-not-the-root contract (`pollMail` / `eclGc` /
208
+ // `eclCompact`, mmnto-ai/totem#2312): a doctor run from a subdirectory must
209
+ // still resolve the real orchestration tree, or this row renders a
210
+ // false-clean "seats sensed: 0".
211
+ const repoRoot = resolveTotemRepoRootSync(undefined, cwd);
212
+ const statuses = deriveSeatStatuses(repoRoot);
213
+ const bySeat = new Map(statuses.map((status) => [status.seat, status]));
214
+ const findings = [];
215
+ const truncations = [];
216
+ for (const status of statuses) {
217
+ // A degraded marker read is a HOLE in this sense, not a clean seat: core
218
+ // fails open to `active`, so arm (b) cannot be evaluated here at all. Say
219
+ // so, with core's own warning (it names the marker file — the one-step
220
+ // recovery target).
221
+ if (status.warning !== undefined) {
222
+ findings.push({
223
+ seat: status.seat,
224
+ cls: 'unreadable-marker',
225
+ evidence: render(status.warning),
226
+ });
227
+ }
228
+ const outboxDir = path.join(repoRoot, TOTEM_DIR, ORCHESTRATION_DIR, status.seat, OUTBOX_DIR);
229
+ const listing = listOutbox(outboxDir, limit);
230
+ if (listing.readFailure !== undefined) {
231
+ findings.push({
232
+ seat: status.seat,
233
+ cls: 'outbox-unreadable',
234
+ evidence: render(listing.readFailure),
235
+ });
236
+ continue;
237
+ }
238
+ if (listing.total > listing.files.length) {
239
+ truncations.push(`${status.seat}: newest ${listing.files.length} of ${listing.total} outbox file(s) scanned`);
240
+ }
241
+ // Arm (b) arms ONLY on a successfully PARSED exclusion marker. A corrupt
242
+ // marker reads as `default-active` and is deliberately skipped here: this
243
+ // sense never builds a finding on an unparsed marker.
244
+ const excluded = status.source === 'marker' && (status.state === 'suspended' || status.state === 'retired');
245
+ const sinceMs = excluded && status.since !== undefined ? Date.parse(status.since) : Number.NaN;
246
+ const mismatched = [];
247
+ const postSince = [];
248
+ const unreadable = [];
249
+ for (const file of listing.files) {
250
+ if (!Number.isNaN(sinceMs)) {
251
+ const stamped = stampedInstantMs(file);
252
+ if (stamped !== null && stamped > sinceMs) {
253
+ postSince.push(render(file));
254
+ }
255
+ }
256
+ let head;
257
+ // totem-context: intentional degradation — a per-file read failure (mid-rename race, EACCES) is collected into an outbox-unreadable finding for this seat and the scan continues; dropping the file silently would let an unreadable dispatch read as a checked one.
258
+ try {
259
+ head = readHead(path.join(outboxDir, file));
260
+ // 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.
261
+ }
262
+ catch (err) {
263
+ unreadable.push(`${render(file)} (${render(messageOf(err))})`);
264
+ continue;
265
+ }
266
+ const declared = frontmatterFrom(head);
267
+ if (declared !== null && declared !== status.seat) {
268
+ mismatched.push(`${render(file)} declares from: ${capToken(render(declared))}`);
269
+ }
270
+ }
271
+ if (mismatched.length > 0) {
272
+ findings.push({
273
+ seat: status.seat,
274
+ cls: 'from-mismatch',
275
+ evidence: evidenceList(mismatched),
276
+ });
277
+ }
278
+ if (postSince.length > 0) {
279
+ findings.push({
280
+ seat: status.seat,
281
+ cls: 'writing-while-excluded',
282
+ evidence: `${status.state} since ${render(status.since ?? 'unknown')} — ${evidenceList(postSince)} stamped after it`,
283
+ });
284
+ }
285
+ if (unreadable.length > 0) {
286
+ findings.push({
287
+ seat: status.seat,
288
+ cls: 'outbox-unreadable',
289
+ evidence: evidenceList(unreadable),
290
+ });
291
+ }
292
+ }
293
+ // Arm (c). Same comma-split as `resolveSelfAgents`' env layer, and the same
294
+ // parsed-marker-only rule as arm (b): a corrupt marker reads active and
295
+ // earns no env finding.
296
+ const envRaw = env['TOTEM_SELF_AGENT'];
297
+ if (typeof envRaw === 'string' && envRaw.trim().length > 0) {
298
+ for (const named of envRaw
299
+ .split(',')
300
+ .map((entry) => entry.trim())
301
+ .filter((entry) => entry.length > 0)) {
302
+ const status = bySeat.get(named);
303
+ if (status === undefined) {
304
+ findings.push({
305
+ seat: capToken(render(named)),
306
+ cls: 'env-names-unknown-seat',
307
+ evidence: `TOTEM_SELF_AGENT names a seat with no directory under ${TOTEM_DIR}/${ORCHESTRATION_DIR}/ in this repo`,
308
+ });
309
+ }
310
+ else if (status.source === 'marker' && status.state !== 'active') {
311
+ findings.push({
312
+ seat: status.seat,
313
+ cls: 'env-names-excluded-seat',
314
+ evidence: `TOTEM_SELF_AGENT names a ${status.state} seat (since ${render(status.since ?? 'unknown')})`,
315
+ });
316
+ }
317
+ }
318
+ }
319
+ const parts = [`seats sensed: ${statuses.length}`];
320
+ parts.push(findings.length === 0
321
+ ? 'no identity contradictions sensed'
322
+ : `${findings.length} finding(s): ${findings
323
+ .map((f) => `${f.seat} [${f.cls}] ${f.evidence}`)
324
+ .join(' | ')}`);
325
+ if (truncations.length > 0) {
326
+ parts.push(`scan bounded at ${limit}/outbox — ${truncations.join('; ')}`);
327
+ }
328
+ parts.push(SEAT_IDENTITY_HONEST_LIMIT);
329
+ return {
330
+ name,
331
+ status: findings.length === 0 ? 'pass' : 'warn',
332
+ message: parts.join(' · '),
333
+ ...(findings.length > 0
334
+ ? {
335
+ remediation: 'Inspect the named files and `totem seat list` — this row senses only and never gates.',
336
+ }
337
+ : {}),
338
+ gateExempt: true,
339
+ };
340
+ // 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.
341
+ }
342
+ catch (err) {
343
+ return {
344
+ name,
345
+ status: 'warn',
346
+ message: `Seat-identity scan failed: ${render(messageOf(err))} · ${SEAT_IDENTITY_HONEST_LIMIT}`,
347
+ remediation: 'Check .totem/orchestration/ readability, then re-run `totem doctor`.',
348
+ gateExempt: true,
349
+ };
350
+ }
351
+ }
352
+ //# sourceMappingURL=doctor-seat-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-seat-identity.js","sourceRoot":"","sources":["../../src/commands/doctor-seat-identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Sense-tier contract for the seat-identity doctor row (mmnto-ai/totem#2511).
3
+ *
4
+ * Real temp trees, because every arm this row senses is literally a filesystem
5
+ * shape (a dir, a marker, a stamped basename). Fixture roots stay SHORT — the
6
+ * orchestration paths nest four levels deep before the dispatch basename, and
7
+ * MAX_PATH bites on win32.
8
+ *
9
+ * The two invariants asserted on EVERY arm: `gateExempt: true` and never
10
+ * `fail`. A sense that could gate is not a sense.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=doctor-seat-identity.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-seat-identity.test.d.ts","sourceRoot":"","sources":["../../src/commands/doctor-seat-identity.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}