@mmnto/cli 1.116.0 → 1.118.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 (60) hide show
  1. package/dist/commands/bootstrap-wiring.test.js +28 -0
  2. package/dist/commands/bootstrap-wiring.test.js.map +1 -1
  3. package/dist/commands/init-templates.d.ts +6 -6
  4. package/dist/commands/init-templates.d.ts.map +1 -1
  5. package/dist/commands/init-templates.js +11 -8
  6. package/dist/commands/init-templates.js.map +1 -1
  7. package/dist/commands/init.test.js +54 -6
  8. package/dist/commands/init.test.js.map +1 -1
  9. package/dist/commands/install-hooks.d.ts.map +1 -1
  10. package/dist/commands/install-hooks.js +12 -1
  11. package/dist/commands/install-hooks.js.map +1 -1
  12. package/dist/commands/lint.js +1 -1
  13. package/dist/commands/lint.js.map +1 -1
  14. package/dist/commands/mail-cli-wiring.test.d.ts +8 -5
  15. package/dist/commands/mail-cli-wiring.test.d.ts.map +1 -1
  16. package/dist/commands/mail-cli-wiring.test.js +95 -42
  17. package/dist/commands/mail-cli-wiring.test.js.map +1 -1
  18. package/dist/commands/mail-degraded-e4.test.js +46 -13
  19. package/dist/commands/mail-degraded-e4.test.js.map +1 -1
  20. package/dist/commands/mail.d.ts +29 -0
  21. package/dist/commands/mail.d.ts.map +1 -1
  22. package/dist/commands/mail.js +182 -14
  23. package/dist/commands/mail.js.map +1 -1
  24. package/dist/commands/mail.test.js +425 -58
  25. package/dist/commands/mail.test.js.map +1 -1
  26. package/dist/commands/pre-push-gate-matrix.test.d.ts +17 -0
  27. package/dist/commands/pre-push-gate-matrix.test.d.ts.map +1 -0
  28. package/dist/commands/pre-push-gate-matrix.test.js +135 -0
  29. package/dist/commands/pre-push-gate-matrix.test.js.map +1 -0
  30. package/dist/commands/shield-admission.test.d.ts +14 -0
  31. package/dist/commands/shield-admission.test.d.ts.map +1 -0
  32. package/dist/commands/shield-admission.test.js +301 -0
  33. package/dist/commands/shield-admission.test.js.map +1 -0
  34. package/dist/commands/shield-classify.d.ts +10 -0
  35. package/dist/commands/shield-classify.d.ts.map +1 -1
  36. package/dist/commands/shield-classify.js +19 -1
  37. package/dist/commands/shield-classify.js.map +1 -1
  38. package/dist/commands/shield-covariate.test.js +3 -0
  39. package/dist/commands/shield-covariate.test.js.map +1 -1
  40. package/dist/commands/shield-estimate.js +5 -5
  41. package/dist/commands/shield-estimate.js.map +1 -1
  42. package/dist/commands/shield-estimate.test.js +7 -3
  43. package/dist/commands/shield-estimate.test.js.map +1 -1
  44. package/dist/commands/shield-nonreview.test.d.ts +12 -14
  45. package/dist/commands/shield-nonreview.test.d.ts.map +1 -1
  46. package/dist/commands/shield-nonreview.test.js +228 -42
  47. package/dist/commands/shield-nonreview.test.js.map +1 -1
  48. package/dist/commands/shield.d.ts +116 -1
  49. package/dist/commands/shield.d.ts.map +1 -1
  50. package/dist/commands/shield.js +439 -116
  51. package/dist/commands/shield.js.map +1 -1
  52. package/dist/git.d.ts +20 -2
  53. package/dist/git.d.ts.map +1 -1
  54. package/dist/git.js +11 -4
  55. package/dist/git.js.map +1 -1
  56. package/dist/git.test.js +58 -18
  57. package/dist/git.test.js.map +1 -1
  58. package/dist/index.js +17 -3
  59. package/dist/index.js.map +1 -1
  60. package/package.json +2 -2
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Pre-push hook gate-mapped review invocation tests (mmnto-ai/totem#2473).
3
+ *
4
+ * The managed pre-push hook's strict arm consumes the gate-mapped review form:
5
+ * probe `review --help` for `--gate` support, invoke `review --gate` when
6
+ * present, fall back to the bare sensor form with a VISIBLE compat line when
7
+ * absent (the `--scope-to-diff` defensive-degrade precedent). Structural
8
+ * assertions cover every platform; the behavioral matrix executes the real
9
+ * generated hook under `sh` with a stub CLI and is POSIX-only (the stub is a
10
+ * shell script on PATH, which Windows CreateProcess cannot resolve — the
11
+ * ubuntu/macos CI legs carry this coverage, the string assertions carry win32).
12
+ *
13
+ * Byte-parity between this template and `tools/pre-push` is enforced by
14
+ * `tools-hook-parity.test.ts` — not duplicated here.
15
+ */
16
+ import { spawnSync } from 'node:child_process';
17
+ import * as fs from 'node:fs';
18
+ import * as os from 'node:os';
19
+ import * as path from 'node:path';
20
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
21
+ import { cleanTmpDir } from '../test-utils.js';
22
+ import { buildPrePushHook } from './install-hooks.js';
23
+ describe('buildPrePushHook — gate-mapped strict arm (structural, all platforms)', () => {
24
+ const hook = buildPrePushHook('pnpm dlx @mmnto/cli', 'standard');
25
+ it('probes review --help for --gate before invoking it', () => {
26
+ expect(hook).toContain(`if $TOTEM_CMD review --help 2>/dev/null | grep -q -- '--gate'; then`);
27
+ });
28
+ it('carries the gate-mapped invocation, the visible compat fallback, and the bare form — in that order', () => {
29
+ const gateIdx = hook.indexOf('$TOTEM_CMD review --gate || exit 1');
30
+ const compatIdx = hook.indexOf('Hook running review in compat mode');
31
+ const bareIdx = hook.indexOf('$TOTEM_CMD review || exit 1');
32
+ expect(gateIdx).toBeGreaterThan(-1);
33
+ expect(compatIdx).toBeGreaterThan(gateIdx);
34
+ expect(bareIdx).toBeGreaterThan(compatIdx);
35
+ // The compat disclosure is stderr-routed (a hook's stdout can be swallowed).
36
+ expect(hook).toMatch(/Hook running review in compat mode[^\n]*" >&2/);
37
+ });
38
+ });
39
+ // Behavioral coverage of the probe/fallback/blocking branches (string
40
+ // assertions alone are satisfiable without the behavior). POSIX-only — see the
41
+ // file doc comment; win32 carries the structural suite above (#2473).
42
+ describe.skipIf(process.platform === 'win32')('pre-push gate matrix (POSIX behavior)', () => {
43
+ let tmpDir;
44
+ let repoDir;
45
+ let binDir;
46
+ let logPath;
47
+ beforeEach(() => {
48
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'prepush-gate-'));
49
+ repoDir = path.join(tmpDir, 'repo');
50
+ binDir = path.join(tmpDir, 'stub-bin');
51
+ fs.mkdirSync(repoDir, { recursive: true });
52
+ fs.mkdirSync(binDir);
53
+ logPath = path.join(tmpDir, 'totem-invocations.log');
54
+ fs.writeFileSync(path.join(repoDir, 'pre-push'), buildPrePushHook('pnpm dlx @mmnto/cli'), {
55
+ mode: 0o755,
56
+ });
57
+ });
58
+ afterEach(() => {
59
+ cleanTmpDir(tmpDir);
60
+ });
61
+ /**
62
+ * A stub `totem` on PATH: records every invocation, serves `review --help`
63
+ * from a canned help text, and exits per-branch with the configured codes.
64
+ * The bare repo dir skips every earlier hook gate (no manifest, no compiled
65
+ * rules, no lockfile, no package.json), so the strict arm under
66
+ * CLAUDE_CODE_AGENT=1 is the only live block.
67
+ */
68
+ function writeStub(params) {
69
+ const stub = `#!/bin/sh
70
+ printf '%s\\n' "$*" >> "${logPath}"
71
+ if [ "$1" = "doctor" ]; then exit 0; fi
72
+ if [ "$1" = "review" ] && [ "$2" = "--help" ]; then
73
+ cat <<'TOTEM_STUB_HELP'
74
+ ${params.helpText}
75
+ TOTEM_STUB_HELP
76
+ exit ${params.helpExit}
77
+ fi
78
+ if [ "$1" = "review" ]; then exit ${params.reviewExit}; fi
79
+ exit 0
80
+ `;
81
+ fs.writeFileSync(path.join(binDir, 'totem'), stub, { mode: 0o755 });
82
+ }
83
+ function runHook() {
84
+ const result = spawnSync('sh', ['./pre-push'], {
85
+ cwd: repoDir,
86
+ env: {
87
+ ...process.env,
88
+ PATH: `${binDir}:${process.env.PATH ?? ''}`,
89
+ CLAUDE_CODE_AGENT: '1',
90
+ },
91
+ encoding: 'utf-8',
92
+ });
93
+ return { status: result.status, stderr: result.stderr ?? '' };
94
+ }
95
+ const invocations = () => fs.existsSync(logPath) ? fs.readFileSync(logPath, 'utf-8').trim().split('\n') : [];
96
+ it('supported --gate: invokes the gate-mapped form and passes', () => {
97
+ writeStub({
98
+ helpText: 'Usage: totem review\n --gate declared mapping',
99
+ helpExit: 0,
100
+ reviewExit: 0,
101
+ });
102
+ const result = runHook();
103
+ expect(result.status).toBe(0);
104
+ expect(invocations()).toContain('review --gate');
105
+ expect(invocations()).toContain('doctor --strict');
106
+ expect(result.stderr).not.toContain('compat mode');
107
+ });
108
+ it('unsupported CLI: falls back to the bare form with a VISIBLE compat line', () => {
109
+ writeStub({
110
+ helpText: 'Usage: totem review\n --covariate transport',
111
+ helpExit: 0,
112
+ reviewExit: 0,
113
+ });
114
+ const result = runHook();
115
+ expect(result.status).toBe(0);
116
+ expect(invocations()).toContain('review');
117
+ expect(invocations()).not.toContain('review --gate');
118
+ expect(result.stderr).toContain('compat mode');
119
+ });
120
+ it('probe failure (help errors, no output): falls back to the bare form', () => {
121
+ writeStub({ helpText: '', helpExit: 1, reviewExit: 0 });
122
+ const result = runHook();
123
+ expect(result.status).toBe(0);
124
+ expect(invocations()).toContain('review');
125
+ expect(invocations()).not.toContain('review --gate');
126
+ expect(result.stderr).toContain('compat mode');
127
+ });
128
+ it('hard failure under --gate blocks the push (any nonzero — the unknown-disposition fail-closed exit rides this same arm)', () => {
129
+ writeStub({ helpText: ' --gate', helpExit: 0, reviewExit: 3 });
130
+ const result = runHook();
131
+ expect(result.status).toBe(1);
132
+ expect(invocations()).toContain('review --gate');
133
+ });
134
+ });
135
+ //# sourceMappingURL=pre-push-gate-matrix.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-push-gate-matrix.test.js","sourceRoot":"","sources":["../../src/commands/pre-push-gate-matrix.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Admission-evaluator unit tests (mmnto-ai/totem#2473).
3
+ *
4
+ * `evaluateAdmission` is the ONE closed evaluator behind the ruled admission
5
+ * phase: it receives the resolved full-scope diff and returns either the exact
6
+ * fan inputs (`admitted`) or the exact record inputs (`not-applicable` with a
7
+ * deterministic reason). These tests lock the identity semantics — two
8
+ * different diffs on one branch are two different observations, a policy
9
+ * change re-keys equal bytes, and the no-diff arm carries the REQUESTED
10
+ * selector (no global null identity) — plus the disposition→exit mapping's
11
+ * fail-closed unknown arm under `--gate`.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=shield-admission.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-admission.test.d.ts","sourceRoot":"","sources":["../../src/commands/shield-admission.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Admission-evaluator unit tests (mmnto-ai/totem#2473).
3
+ *
4
+ * `evaluateAdmission` is the ONE closed evaluator behind the ruled admission
5
+ * phase: it receives the resolved full-scope diff and returns either the exact
6
+ * fan inputs (`admitted`) or the exact record inputs (`not-applicable` with a
7
+ * deterministic reason). These tests lock the identity semantics — two
8
+ * different diffs on one branch are two different observations, a policy
9
+ * change re-keys equal bytes, and the no-diff arm carries the REQUESTED
10
+ * selector (no global null identity) — plus the disposition→exit mapping's
11
+ * fail-closed unknown arm under `--gate`.
12
+ */
13
+ import { createHash } from 'node:crypto';
14
+ import * as fs from 'node:fs';
15
+ import * as os from 'node:os';
16
+ import * as path from 'node:path';
17
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
18
+ import { NOT_APPLICABLE_REASONS } from '@mmnto/totem';
19
+ import { cleanTmpDir } from '../test-utils.js';
20
+ import { buildProjectionPolicy, evaluateAdmission, requestedSelectorForm, resolveNotApplicableExit, selectExecutionPayload, } from './shield.js';
21
+ import { CLASSIFIER_POLICY_TABLES } from './shield-classify.js';
22
+ const SHA_EMPTY = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
23
+ const TEST_CONFIG = {
24
+ totemDir: '.totem',
25
+ review: { sourceExtensions: ['.ts'] },
26
+ };
27
+ /** A minimal single-file diff section for `file`. */
28
+ function diffFor(file) {
29
+ return [
30
+ `diff --git a/${file} b/${file}`,
31
+ 'index 1111111..2222222 100644',
32
+ `--- a/${file}`,
33
+ `+++ b/${file}`,
34
+ '@@ -1 +1 @@',
35
+ '-old',
36
+ '+new',
37
+ ].join('\n');
38
+ }
39
+ function diffResultFor(files) {
40
+ return {
41
+ diff: files.map(diffFor).join('\n'),
42
+ changedFiles: files,
43
+ source: 'uncommitted',
44
+ };
45
+ }
46
+ describe('evaluateAdmission — the closed admission evaluator', () => {
47
+ let tmpDir;
48
+ beforeEach(() => {
49
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shield-admission-'));
50
+ });
51
+ afterEach(() => {
52
+ cleanTmpDir(tmpDir);
53
+ });
54
+ async function evaluate(files, config = TEST_CONFIG) {
55
+ return evaluateAdmission({
56
+ diffResult: files === null ? null : diffResultFor(files),
57
+ requestedSelector: '(default-chain)',
58
+ cwd: tmpDir,
59
+ config,
60
+ quiet: true,
61
+ });
62
+ }
63
+ it('no-diff (legacy scope-less arm): records source none + the REQUESTED selector', async () => {
64
+ const outcome = await evaluate(null);
65
+ expect(outcome.status).toBe('not-applicable');
66
+ if (outcome.status !== 'not-applicable')
67
+ return;
68
+ expect(outcome.reason).toBe('no-diff');
69
+ expect(outcome.scope).toEqual({
70
+ source: 'none',
71
+ base: null,
72
+ head: null,
73
+ selectorForm: '(default-chain)',
74
+ });
75
+ expect(outcome.inputHash).toBe(SHA_EMPTY);
76
+ expect(outcome.skippedFileCount).toBe(0);
77
+ });
78
+ it('no-diff binds the RESOLVED empty scope from the discriminated resolver result (conformance note 1)', async () => {
79
+ const resolved = await evaluateAdmission({
80
+ diffResult: { empty: true, source: 'branch-vs-base', base: 'main' },
81
+ requestedSelector: '(default-chain)',
82
+ cwd: tmpDir,
83
+ config: TEST_CONFIG,
84
+ quiet: true,
85
+ });
86
+ if (resolved.status !== 'not-applicable')
87
+ throw new Error('expected not-applicable');
88
+ expect(resolved.scope).toEqual({
89
+ source: 'branch-vs-base',
90
+ base: 'main',
91
+ head: null,
92
+ selectorForm: '(default-chain)',
93
+ });
94
+ // The resolver's OWN selectorForm wins where it supplies one (explicit range).
95
+ const explicit = await evaluateAdmission({
96
+ diffResult: {
97
+ empty: true,
98
+ source: 'explicit-range',
99
+ base: 'main',
100
+ head: 'HEAD',
101
+ selectorForm: 'main..HEAD',
102
+ },
103
+ requestedSelector: '--diff main..HEAD',
104
+ cwd: tmpDir,
105
+ config: TEST_CONFIG,
106
+ quiet: true,
107
+ });
108
+ if (explicit.status !== 'not-applicable')
109
+ throw new Error('expected not-applicable');
110
+ expect(explicit.scope.selectorForm).toBe('main..HEAD');
111
+ expect(explicit.scope.source).toBe('explicit-range');
112
+ // Empty runs under different scopes never collapse: forced-branch,
113
+ // explicit-range, and an empty --staged run (same terminal branch fallback,
114
+ // different requested selector) are three distinct observations.
115
+ const staged = await evaluateAdmission({
116
+ diffResult: { empty: true, source: 'branch-vs-base', base: 'main' },
117
+ requestedSelector: '--staged',
118
+ cwd: tmpDir,
119
+ config: TEST_CONFIG,
120
+ quiet: true,
121
+ });
122
+ if (staged.status !== 'not-applicable')
123
+ throw new Error('expected not-applicable');
124
+ expect(staged.scope.selectorForm).toBe('--staged');
125
+ const scopes = [resolved.scope, explicit.scope, staged.scope].map((s) => JSON.stringify(s));
126
+ expect(new Set(scopes).size).toBe(3);
127
+ });
128
+ it('classifies each deterministic reason from the full scope', async () => {
129
+ const nonCode = await evaluate(['docs/plan.md', 'README.md']);
130
+ expect(nonCode.status === 'not-applicable' && nonCode.reason).toBe('all-non-code');
131
+ const generated = await evaluate(['pnpm-lock.yaml']);
132
+ expect(generated.status === 'not-applicable' && generated.reason).toBe('all-generated');
133
+ // filtered-empty: a code file in the LIST whose hunks are absent from the
134
+ // diff body (a mode-only change has this shape).
135
+ const filteredEmpty = await evaluateAdmission({
136
+ diffResult: {
137
+ diff: diffFor('docs/plan.md'),
138
+ changedFiles: ['docs/plan.md', 'src/index.ts'],
139
+ source: 'uncommitted',
140
+ },
141
+ requestedSelector: '(default-chain)',
142
+ cwd: tmpDir,
143
+ config: TEST_CONFIG,
144
+ quiet: true,
145
+ });
146
+ expect(filteredEmpty.status === 'not-applicable' && filteredEmpty.reason).toBe('filtered-empty');
147
+ const admitted = await evaluate(['docs/plan.md', 'src/index.ts']);
148
+ expect(admitted.status).toBe('admitted');
149
+ if (admitted.status !== 'admitted')
150
+ return;
151
+ expect(admitted.filteredFiles).toEqual(['src/index.ts']);
152
+ });
153
+ it('two different diffs on one branch are two different observations (inputHash)', async () => {
154
+ const a = await evaluate(['docs/a.md']);
155
+ const b = await evaluate(['docs/b.md']);
156
+ if (a.status !== 'not-applicable' || b.status !== 'not-applicable') {
157
+ throw new Error('both fixtures must be not-applicable');
158
+ }
159
+ expect(a.reason).toBe(b.reason);
160
+ expect(a.scope).toEqual(b.scope);
161
+ expect(a.inputHash).not.toBe(b.inputHash);
162
+ });
163
+ it('a policy change re-keys equal bytes (projectionPolicyHash)', async () => {
164
+ const a = await evaluate(['docs/a.md']);
165
+ const b = await evaluate(['docs/a.md'], {
166
+ ...TEST_CONFIG,
167
+ review: { sourceExtensions: ['.ts', '.py'] },
168
+ });
169
+ if (a.status !== 'not-applicable' || b.status !== 'not-applicable') {
170
+ throw new Error('both fixtures must be not-applicable');
171
+ }
172
+ expect(a.inputHash).toBe(b.inputHash);
173
+ expect(a.projectionPolicyHash).not.toBe(b.projectionPolicyHash);
174
+ });
175
+ it('a .gitattributes change re-keys equal bytes (generated globs are policy)', async () => {
176
+ const before = await evaluate(['docs/a.md']);
177
+ fs.writeFileSync(path.join(tmpDir, '.gitattributes'), 'src/gen.ts linguist-generated\n');
178
+ const after = await evaluate(['docs/a.md']);
179
+ if (before.status !== 'not-applicable' || after.status !== 'not-applicable') {
180
+ throw new Error('both fixtures must be not-applicable');
181
+ }
182
+ expect(after.projectionPolicyHash).not.toBe(before.projectionPolicyHash);
183
+ });
184
+ });
185
+ /**
186
+ * PINNED classifier-table digest + entry count (CR on #2641): a live-vs-live
187
+ * recompute moves with any edit and can never observe the re-key property the
188
+ * mechanical binding exists for. Editing ANY classifier table fails here and
189
+ * states the new address key — update BOTH literals in the SAME commit as the
190
+ * table edit; that update IS the re-key signal made reviewable.
191
+ */
192
+ const EXPECTED_TABLES_DIGEST = '7641cc478a33';
193
+ const EXPECTED_TABLES_SIZE = 80;
194
+ describe('buildProjectionPolicy — classifier tables bound mechanically (leg MATERIAL 2)', () => {
195
+ it('classifierId embeds the PINNED digest of the exported classifier tables — a table edit fails here with the new key', async () => {
196
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shield-policy-'));
197
+ try {
198
+ const policy = await buildProjectionPolicy(TEST_CONFIG, tmpDir);
199
+ // The pin makes the re-key observable; the cross-check proves the pin is
200
+ // the digest of the LIVE constant (wiring), so the two cannot drift apart.
201
+ expect(policy.classifierId).toBe(`classifyChangedFiles@1:${EXPECTED_TABLES_DIGEST}`);
202
+ expect(createHash('sha256')
203
+ .update(JSON.stringify(CLASSIFIER_POLICY_TABLES), 'utf-8')
204
+ .digest('hex')
205
+ .slice(0, 12)).toBe(EXPECTED_TABLES_DIGEST);
206
+ // Exact size — a deleted table fails here, never a range check.
207
+ expect(CLASSIFIER_POLICY_TABLES.length).toBe(EXPECTED_TABLES_SIZE);
208
+ expect([...CLASSIFIER_POLICY_TABLES]).toEqual([...CLASSIFIER_POLICY_TABLES].sort());
209
+ }
210
+ finally {
211
+ cleanTmpDir(tmpDir);
212
+ }
213
+ });
214
+ });
215
+ describe('selectExecutionPayload — payload selection never changes admission (conformance note 3)', () => {
216
+ let tmpDir;
217
+ beforeEach(() => {
218
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shield-selection-'));
219
+ });
220
+ afterEach(() => {
221
+ cleanTmpDir(tmpDir);
222
+ });
223
+ async function admitted() {
224
+ const outcome = await evaluateAdmission({
225
+ diffResult: diffResultFor(['src/full-a.ts', 'src/full-b.ts']),
226
+ requestedSelector: '(default-chain)',
227
+ cwd: tmpDir,
228
+ config: TEST_CONFIG,
229
+ quiet: true,
230
+ });
231
+ if (outcome.status !== 'admitted')
232
+ throw new Error('fixture must admit');
233
+ return outcome;
234
+ }
235
+ it('ineligible incremental → the admitted full-scope payload, un-narrowed', async () => {
236
+ const selection = await selectExecutionPayload(await admitted(), { eligible: false, reason: 'multi-lane fan requires full diff scope' }, tmpDir, true);
237
+ expect(selection.narrowed).toBe(false);
238
+ expect(selection.deltaFallbackReason).toBeUndefined();
239
+ expect(selection.payload.filteredFiles).toEqual(['src/full-a.ts', 'src/full-b.ts']);
240
+ });
241
+ it('a reviewable delta narrows the execution payload', async () => {
242
+ const selection = await selectExecutionPayload(await admitted(), {
243
+ eligible: true,
244
+ deltaDiff: diffFor('src/full-a.ts'),
245
+ changedFiles: ['src/full-a.ts'],
246
+ linesChanged: 2,
247
+ }, tmpDir, true);
248
+ expect(selection.narrowed).toBe(true);
249
+ expect(selection.payload.filteredFiles).toEqual(['src/full-a.ts']);
250
+ });
251
+ it('a non-reviewable delta falls back to the full-scope payload — never a demotion to skip', async () => {
252
+ const selection = await selectExecutionPayload(await admitted(), {
253
+ eligible: true,
254
+ deltaDiff: diffFor('docs/notes.md'),
255
+ changedFiles: ['docs/notes.md'],
256
+ linesChanged: 2,
257
+ }, tmpDir, true);
258
+ expect(selection.narrowed).toBe(false);
259
+ expect(selection.deltaFallbackReason).toBe('all-non-code');
260
+ expect(selection.payload.filteredFiles).toEqual(['src/full-a.ts', 'src/full-b.ts']);
261
+ });
262
+ });
263
+ describe('requestedSelectorForm', () => {
264
+ const form = (options) => requestedSelectorForm(options);
265
+ it('records the requested selector expression per flag shape', () => {
266
+ expect(form({ diff: 'main..HEAD' })).toBe('--diff main..HEAD');
267
+ expect(form({ staged: true })).toBe('--staged');
268
+ expect(form({ base: 'develop' })).toBe('--branch --base develop');
269
+ expect(form({ branch: true })).toBe('--branch');
270
+ expect(form({})).toBe('(default-chain)');
271
+ });
272
+ });
273
+ describe('resolveNotApplicableExit — declared mapping, fail-closed unknown under --gate', () => {
274
+ class FakeGateError extends Error {
275
+ code;
276
+ hint;
277
+ constructor(code, message, hint) {
278
+ super(message);
279
+ this.code = code;
280
+ this.hint = hint;
281
+ }
282
+ }
283
+ it('every KNOWN reason maps to exit 0 under both bare and --gate (the ruled no-nonzero-by-default shape)', () => {
284
+ // Iterate the core's OWN closed reason set (CR on #2641, strengthened
285
+ // beyond the suggested typed literal — a subset would still typecheck):
286
+ // a NEW union member is exercised automatically and would fail CLOSED
287
+ // under --gate right here, forcing the mapping switch to grow with the
288
+ // union in the same change.
289
+ const known = NOT_APPLICABLE_REASONS;
290
+ expect(known).toHaveLength(4);
291
+ for (const reason of known) {
292
+ expect(resolveNotApplicableExit(reason, false, FakeGateError)).toBe(0);
293
+ expect(resolveNotApplicableExit(reason, true, FakeGateError)).toBe(0);
294
+ }
295
+ });
296
+ it('an UNKNOWN disposition fails CLOSED under --gate and stays sensor-0 bare', () => {
297
+ expect(() => resolveNotApplicableExit('mystery-disposition', true, FakeGateError)).toThrow(/unknown admission disposition/);
298
+ expect(resolveNotApplicableExit('mystery-disposition', false, FakeGateError)).toBe(0);
299
+ });
300
+ });
301
+ //# sourceMappingURL=shield-admission.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shield-admission.test.js","sourceRoot":"","sources":["../../src/commands/shield-admission.test.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,16 @@ export interface ClassificationResult {
5
5
  allNonCode: boolean;
6
6
  allCode: boolean;
7
7
  }
8
+ /**
9
+ * Canonical, namespaced flattening of EVERY classification table above — the
10
+ * classifier's entire behavioral policy surface. Exported so the #2473
11
+ * admission `projectionPolicyHash` binds the actual tables MECHANICALLY
12
+ * (falsification-leg MATERIAL 2 on the #2473 round): editing any set re-keys
13
+ * every admission address without anyone remembering to bump a version
14
+ * string. Namespace prefixes keep the flattening collision-free; the sort
15
+ * makes the digest deterministic.
16
+ */
17
+ export declare const CLASSIFIER_POLICY_TABLES: readonly string[];
8
18
  export declare function classifyFile(filePath: string): FileClass;
9
19
  export declare function classifyChangedFiles(changedFiles: string[]): ClassificationResult;
10
20
  //# sourceMappingURL=shield-classify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shield-classify.d.ts","sourceRoot":"","sources":["../../src/commands/shield-classify.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AA8GD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAsBxD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAgBjF"}
1
+ {"version":3,"file":"shield-classify.d.ts","sourceRoot":"","sources":["../../src/commands/shield-classify.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AA+GD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAM9C,CAAC;AAIT,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAsBxD;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAgBjF"}
@@ -89,14 +89,32 @@ const NON_CODE_FILENAMES = new Set([
89
89
  '.eslintignore',
90
90
  ]);
91
91
  // ─── Compound extension check ───────────────────────
92
+ /** Compound suffixes `path.extname` cannot see (it returns only the last segment). */
93
+ const COMPOUND_NON_CODE_SUFFIXES = ['.d.ts.map'];
92
94
  /**
93
95
  * Check for compound extensions like `.d.ts.map` that path.extname
94
96
  * won't catch (it only returns `.map`).
95
97
  */
96
98
  function hasCompoundNonCodeExtension(filePath) {
97
99
  const base = path.basename(filePath);
98
- return base.endsWith('.d.ts.map');
100
+ return COMPOUND_NON_CODE_SUFFIXES.some((suffix) => base.endsWith(suffix));
99
101
  }
102
+ /**
103
+ * Canonical, namespaced flattening of EVERY classification table above — the
104
+ * classifier's entire behavioral policy surface. Exported so the #2473
105
+ * admission `projectionPolicyHash` binds the actual tables MECHANICALLY
106
+ * (falsification-leg MATERIAL 2 on the #2473 round): editing any set re-keys
107
+ * every admission address without anyone remembering to bump a version
108
+ * string. Namespace prefixes keep the flattening collision-free; the sort
109
+ * makes the digest deterministic.
110
+ */
111
+ export const CLASSIFIER_POLICY_TABLES = [
112
+ ...[...CODE_EXTENSIONS].map((ext) => `code-ext:${ext}`),
113
+ ...[...NON_CODE_EXTENSIONS].map((ext) => `non-code-ext:${ext}`),
114
+ ...[...CODE_FILENAMES].map((name) => `code-name:${name}`),
115
+ ...[...NON_CODE_FILENAMES].map((name) => `non-code-name:${name}`),
116
+ ...COMPOUND_NON_CODE_SUFFIXES.map((suffix) => `compound-non-code:${suffix}`),
117
+ ].sort();
100
118
  // ─── Public API ─────────────────────────────────────
101
119
  export function classifyFile(filePath) {
102
120
  const basename = path.basename(filePath);
@@ -1 +1 @@
1
- {"version":3,"file":"shield-classify.js","sourceRoot":"","sources":["../../src/commands/shield-classify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shield-classify.js","sourceRoot":"","sources":["../../src/commands/shield-classify.ts"],"names":[],"mappings":"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"}
@@ -77,6 +77,9 @@ describe('shieldCommand --covariate short-circuit (rev-6 item 7)', () => {
77
77
  expect(fs.existsSync(path.join(tmpDir, '.totem', 'cache', '.reviewed-content-hash'))).toBe(false);
78
78
  // No verdict artifacts were written (no fan ran).
79
79
  expect(fs.existsSync(path.join(tmpDir, '.totem', 'artifacts', 'verdicts'))).toBe(false);
80
+ // No admission records either (mmnto-ai/totem#2473): the admission-aware
81
+ // resolution is read-only — exact-identity lookup, never a write.
82
+ expect(fs.existsSync(path.join(tmpDir, '.totem', 'artifacts', 'admissions'))).toBe(false);
80
83
  // No pre-push hook file was created.
81
84
  expect(fs.existsSync(path.join(tmpDir, '.git', 'hooks', 'pre-push'))).toBe(false);
82
85
  });
@@ -1 +1 @@
1
- {"version":3,"file":"shield-covariate.test.js","sourceRoot":"","sources":["../../src/commands/shield-covariate.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shield-covariate.test.js","sourceRoot":"","sources":["../../src/commands/shield-covariate.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAIzE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,kFAAkF;AAClF,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAgB,EAAiB,EAAE,GAAE,CAAC,CAAC,CAAC;AACnF,MAAM,qBAAqB,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,KAAgB,EAAW,EAAE,CAAC,KAAK,CAAC,CAAC;AAC7E,MAAM,mBAAmB,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAgB,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAEvE,MAAM,WAAW,GAAG;IAClB,QAAQ,EAAE,QAAQ;IAClB,MAAM,EAAE,EAAE,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE;CACZ,CAAC;AAE5B,kFAAkF;AAClF,EAAE,CAAC,IAAI,CAAC,8BAA8B,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IAC/D,MAAM,MAAM,GAAG,MAAM,cAAc,EAAiD,CAAC;IACrF,OAAO,EAAE,GAAG,MAAM,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC;AAC5D,CAAC,CAAC,CAAC;AAEH,qFAAqF;AACrF,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IACrD,MAAM,MAAM,GAAG,MAAM,cAAc,EAAuC,CAAC;IAC3E,OAAO,EAAE,GAAG,MAAM,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,CAAC;AAC1E,CAAC,CAAC,CAAC;AAEH,0FAA0F;AAC1F,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IAC9C,MAAM,MAAM,GAAG,MAAM,cAAc,EAAgC,CAAC;IACpE,OAAO;QACL,GAAG,MAAM;QACT,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE;QAChB,iBAAiB,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC;QACrE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,WAAW,CAAC;KAC3C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,uFAAuF;AACvF,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IAC5C,MAAM,MAAM,GAAG,MAAM,cAAc,EAA8B,CAAC;IAClE,OAAO,EAAE,GAAG,MAAM,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;AAC9D,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wDAAwD,EAAE,GAAG,EAAE;IACtE,IAAI,MAAc,CAAC;IAEnB,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;QACrE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACjD,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACxD,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtD,kBAAkB,CAAC,SAAS,EAAE,CAAC;QAC/B,qBAAqB,CAAC,SAAS,EAAE,CAAC;QAClC,mBAAmB,CAAC,SAAS,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,eAAe,EAAE,CAAC;QACrB,WAAW,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kFAAkF,EAAE,KAAK,IAAI,EAAE;QAChG,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACtD,sFAAsF;QACtF,MAAM,MAAM,CACV,aAAa,CAAC,EAAE,SAAS,EAAE,IAAI,EAAyC,CAAC,CAC1E,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;QAE3B,oFAAoF;QACpF,MAAM,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QACrD,4EAA4E;QAC5E,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAClD,+EAA+E;QAC/E,MAAM,CAAC,mBAAmB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAErD,sDAAsD;QACtD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,IAAI,CACxF,KAAK,CACN,CAAC;QACF,kDAAkD;QAClD,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxF,yEAAyE;QACzE,kEAAkE;QAClE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1F,qCAAqC;QACrC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -51,11 +51,11 @@ export async function runEstimate(options, config, cwd, configRoot) {
51
51
  const { runCompiledRules } = await import('./run-compiled-rules.js');
52
52
  log.info(ESTIMATE_DISPLAY_TAG, 'Pre-flight prediction (deterministic, zero-LLM):');
53
53
  const diffResult = await getDiffForReview(options, config, cwd, ESTIMATE_DISPLAY_TAG);
54
- if (!diffResult) {
55
- // Distinct from the `totem review` no-diff branch: the LLM path
56
- // stamps the push-gate content hash because an empty diff is a
57
- // trivial pass; an estimate is a forecast and explicitly does NOT
58
- // stamp the cache. (Q2 in `.totem/specs/1714.md`.)
54
+ if ('empty' in diffResult) {
55
+ // An estimate is a forecast and does not stamp the cache. (Since
56
+ // mmnto-ai/totem#2473 the LLM path's no-diff branch does not stamp
57
+ // either it records a not-applicable admission; the estimator stays
58
+ // record-free, matching Q2 in `.totem/specs/1714.md`.)
59
59
  log.info(ESTIMATE_DISPLAY_TAG, 'No changes detected. Nothing to estimate.');
60
60
  return;
61
61
  }