@mmnto/cli 1.40.2 → 1.42.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.
@@ -1,11 +1,27 @@
1
1
  // ─── Constants ──────────────────────────────────────────
2
2
  const TAG = 'Verify';
3
+ // Path of the compile-worker prompt template relative to the monorepo root.
4
+ // Used in the branch-diff check to determine whether a fingerprint change is
5
+ // "justified" (the user explicitly edited the prompts) or "unjustified" (the
6
+ // fingerprint moved without a corresponding source change).
7
+ const COMPILE_TEMPLATES_REL_PATH = 'packages/cli/src/commands/compile-templates.ts';
8
+ // Heading the PR body must contain when `--allow-compile-drift` is used in CI.
9
+ // The heading itself is the accountability surface; the body underneath is the
10
+ // reviewer-readable justification.
11
+ const DRIFT_JUSTIFICATION_HEADING_RE = /^## Compile Drift Justification\b/m;
12
+ // Best-effort timeouts for the auxiliary git/gh lookups. The drift check
13
+ // should never block verify-manifest indefinitely if origin/main or `gh` is
14
+ // unreachable.
15
+ const AUX_LOOKUP_TIMEOUT_MS = 10_000;
16
+ const AUX_LOOKUP_MAX_BUFFER = 5 * 1024 * 1024;
3
17
  // ─── Main command ───────────────────────────────────────
4
- export async function verifyManifestCommand() {
18
+ export async function verifyManifestCommand(opts) {
19
+ const fs = await import('node:fs');
5
20
  const path = await import('node:path');
6
- const { generateInputHash, generateOutputHash, readCompileManifest, TotemError } = await import('@mmnto/totem');
21
+ const { CompileManifestSchema, findRepoRootSync, generateInputHash, generateOutputHash, getDefaultBranch, readCompileManifest, safeExec, TotemConfigError, TotemError, } = await import('@mmnto/totem');
7
22
  const { bold, errorColor, log, success: successColor } = await import('../ui.js');
8
23
  const { loadConfig, resolveConfigPath } = await import('../utils.js');
24
+ const allowCompileDrift = opts?.allowCompileDrift ?? false;
9
25
  const cwd = process.cwd();
10
26
  const configPath = resolveConfigPath(cwd);
11
27
  const config = await loadConfig(configPath);
@@ -36,7 +52,217 @@ export async function verifyManifestCommand() {
36
52
  log.error('Totem Error', `${label} — Manifest verification failed.`);
37
53
  throw new TotemError('COMPILE_FAILED', 'Compile manifest verification failed.', 'Run "totem compile" to regenerate the manifest.');
38
54
  }
55
+ // ─── Fingerprint drift check (Proposal 278 § Action 3) ───
56
+ //
57
+ // The fingerprint is a producer attestation (model + sampling params +
58
+ // prompt-template content hash). When the local fingerprint differs from
59
+ // origin/main's AND the prompt-template source did not change in this
60
+ // branch, that's a signal something else moved — model alias rebrand,
61
+ // local-only template edit, or an unintended worker config swap.
62
+ //
63
+ // Scope-limited to the mmnto-ai/totem monorepo: external @mmnto/cli
64
+ // consumers don't own packages/cli/src/commands/compile-templates.ts, so
65
+ // a CLI version bump would always trip an unjustified-drift fail for them.
66
+ // Phase 1 scope per Proposal 278 is internal compile-worker surveillance —
67
+ // the fingerprint is still recorded in their manifest for observability,
68
+ // but the fail-loud gate only fires inside the monorepo. Detected via
69
+ // existence of the template source at its monorepo-relative path. Walk up
70
+ // from cwd so the check survives running from a sub-directory of the
71
+ // monorepo (e.g., `cd packages/cli && pnpm totem verify-manifest`).
72
+ const inMonorepo = findMonorepoTemplate(cwd, path, fs) !== undefined;
73
+ if (manifest.compile_worker_fingerprint !== undefined && inMonorepo) {
74
+ // Resolve the base branch dynamically — repos can use main, master, or
75
+ // something custom (e.g., `develop`). `getDefaultBranch` reads
76
+ // origin/HEAD with fallback to main/master. The base-ref/diff lookups
77
+ // below are themselves best-effort, so a wrong guess just no-ops the
78
+ // drift check rather than throwing.
79
+ let baseBranch = 'main';
80
+ try {
81
+ baseBranch = getDefaultBranch(cwd);
82
+ // totem-context: getDefaultBranch fall-through is best-effort; baseBranch keeps the 'main' initializer when git is unavailable or no remote is configured
83
+ }
84
+ catch (err) {
85
+ void err;
86
+ }
87
+ const baseFingerprint = tryReadBaseFingerprint({
88
+ cwd,
89
+ manifestPath,
90
+ safeExec,
91
+ CompileManifestSchema,
92
+ pathMod: path,
93
+ findRepoRootSync,
94
+ baseBranch,
95
+ });
96
+ if (baseFingerprint !== undefined && baseFingerprint !== manifest.compile_worker_fingerprint) {
97
+ const compileTemplatesChanged = branchDiffTouches({
98
+ cwd,
99
+ relPath: COMPILE_TEMPLATES_REL_PATH,
100
+ safeExec,
101
+ baseBranch,
102
+ });
103
+ if (compileTemplatesChanged) {
104
+ log.info(TAG, `Fingerprint changed (${baseFingerprint.slice(0, 8)}… → ${manifest.compile_worker_fingerprint.slice(0, 8)}…) — accompanied by compile-templates.ts edit; accepted.`);
105
+ }
106
+ else if (!allowCompileDrift) {
107
+ throw new TotemError('COMPILE_FAILED', `Compile-worker fingerprint drift detected without a packages/cli/src/commands/compile-templates.ts change.\n` +
108
+ ` Base (origin/${baseBranch}): ${baseFingerprint}\n` +
109
+ ` Current: ${manifest.compile_worker_fingerprint}`, 'Update packages/cli/src/commands/compile-templates.ts to make the worker change explicit, or pass --allow-compile-drift with a "## Compile Drift Justification" PR-body heading (or TOTEM_DRIFT_JUSTIFICATION env var when no PR exists yet).');
110
+ }
111
+ else {
112
+ verifyDriftJustification({ cwd, safeExec, TotemConfigError });
113
+ log.warn(TAG, `--allow-compile-drift accepted (${baseFingerprint.slice(0, 8)}… → ${manifest.compile_worker_fingerprint.slice(0, 8)}…). Justification recorded.`);
114
+ }
115
+ }
116
+ }
39
117
  const label = successColor(bold('PASS'));
40
118
  log.success(TAG, `${label} — Manifest verified: ${manifest.rule_count} rules, hashes match.`);
41
119
  }
120
+ /**
121
+ * Walk upward from `start` looking for `COMPILE_TEMPLATES_REL_PATH`. Returns
122
+ * the absolute path when found, undefined when the search reaches the
123
+ * filesystem root without a match. Allows `verify-manifest` to detect that
124
+ * it's running inside the totem monorepo regardless of which sub-directory
125
+ * the caller invoked it from.
126
+ */
127
+ function findMonorepoTemplate(start, pathMod, fsMod) {
128
+ let current = pathMod.resolve(start);
129
+ while (true) {
130
+ const candidate = pathMod.join(current, COMPILE_TEMPLATES_REL_PATH);
131
+ if (fsMod.existsSync(candidate))
132
+ return candidate;
133
+ const parent = pathMod.dirname(current);
134
+ if (parent === current)
135
+ return undefined; // hit filesystem root
136
+ current = parent;
137
+ }
138
+ }
139
+ /**
140
+ * Read the `compile_worker_fingerprint` field from origin/main's compile
141
+ * manifest. Best-effort: returns undefined when origin/main is unreachable,
142
+ * the manifest doesn't exist on origin/main, or parsing fails. Callers must
143
+ * treat undefined as "no comparison available" rather than "no drift".
144
+ */
145
+ function tryReadBaseFingerprint(args) {
146
+ const { cwd, manifestPath, safeExec, CompileManifestSchema, pathMod, findRepoRootSync, baseBranch, } = args;
147
+ // `git show <ref>:<path>` expects `<path>` relative to the repo root, not
148
+ // the current working directory. When verify-manifest runs from a sub-dir
149
+ // of the repo, `path.relative(cwd, manifestPath)` would produce a path
150
+ // that git rejects. `findRepoRootSync` walks up looking for `.git/` — the
151
+ // JS-side variant of `resolveGitRoot` that's portable on Windows where
152
+ // `git rev-parse --show-toplevel` may emit a path differing from cwd in
153
+ // case / 8.3 short-name resolution. See packages/core/src/sys/git.ts.
154
+ const pathBase = findRepoRootSync(cwd) ?? cwd;
155
+ const relPath = pathMod.relative(pathBase, manifestPath).replace(/\\/g, '/');
156
+ // Prefer origin/<base> as the canonical source — the local copy may be
157
+ // stale when the user hasn't pulled in a while. CI environments may only
158
+ // have origin/<branch> at all; local dev usually has both, and an
159
+ // out-of-date local copy would produce false-positive or false-negative
160
+ // drift signals.
161
+ for (const ref of [`origin/${baseBranch}`, baseBranch]) {
162
+ try {
163
+ const raw = safeExec('git', ['show', `${ref}:${relPath}`], {
164
+ cwd,
165
+ timeout: AUX_LOOKUP_TIMEOUT_MS,
166
+ maxBuffer: AUX_LOOKUP_MAX_BUFFER,
167
+ });
168
+ const parsed = CompileManifestSchema.parse(JSON.parse(raw));
169
+ return parsed.compile_worker_fingerprint;
170
+ // totem-context: best-effort base-ref lookup; missing/unparseable ref → fall through to undefined and skip the drift comparison
171
+ }
172
+ catch {
173
+ continue;
174
+ }
175
+ }
176
+ return undefined;
177
+ }
178
+ /**
179
+ * True when `relPath` appears in the file list of the branch-vs-main diff.
180
+ * Best-effort: returns false when the branch diff cannot be computed
181
+ * (uncommitted local-only branch, detached HEAD, etc.). Conservative default
182
+ * — a missing diff treats the drift as unjustified, forcing the user to
183
+ * either commit the template change or use the override flag.
184
+ */
185
+ function branchDiffTouches(args) {
186
+ const { cwd, relPath, safeExec, baseBranch } = args;
187
+ // Prefer origin/<base> to match `tryReadBaseFingerprint`'s ref order;
188
+ // stale local refs would produce inconsistent drift signals between the
189
+ // base-fingerprint read and the template-change detection.
190
+ for (const ref of [`origin/${baseBranch}`, baseBranch]) {
191
+ try {
192
+ const raw = safeExec('git', ['diff', '--name-only', `${ref}...HEAD`], {
193
+ cwd,
194
+ timeout: AUX_LOOKUP_TIMEOUT_MS,
195
+ maxBuffer: AUX_LOOKUP_MAX_BUFFER,
196
+ });
197
+ const files = raw
198
+ .split('\n')
199
+ .map((l) => l.trim())
200
+ .filter((l) => l.length > 0);
201
+ return files.includes(relPath);
202
+ // totem-context: best-effort branch-diff lookup; missing diff → conservative false (forces explicit template commit or override)
203
+ }
204
+ catch {
205
+ continue;
206
+ }
207
+ }
208
+ return false;
209
+ }
210
+ /**
211
+ * Resolve a justification for the `--allow-compile-drift` override.
212
+ *
213
+ * 1. If an open PR for the current branch is discoverable via `gh pr view`,
214
+ * require a `## Compile Drift Justification` heading in the PR body.
215
+ * 2. Otherwise (no PR open, `gh` unavailable, etc.), require the
216
+ * `TOTEM_DRIFT_JUSTIFICATION` env var to be set non-empty. The contents
217
+ * are not validated — the act of typing the justification is the
218
+ * forcing function. Per Proposal 278 § Q3 (env-var fortification).
219
+ *
220
+ * CI re-runs `verify-manifest` against the PR-body context at merge time, so
221
+ * the heading is the binding accountability surface even when the local
222
+ * override path took the env-var route.
223
+ */
224
+ function verifyDriftJustification(args) {
225
+ const { cwd, safeExec, TotemConfigError } = args;
226
+ const prBody = tryFetchCurrentBranchPrBody({ cwd, safeExec });
227
+ if (prBody !== undefined) {
228
+ if (!DRIFT_JUSTIFICATION_HEADING_RE.test(prBody)) {
229
+ // Flag misuse — TotemConfigError is the canonical CLI-layer
230
+ // flag-validation class per .gemini/styleguide.md § 76. CONFIG_INVALID
231
+ // because the flag was passed but the conditions for using it weren't
232
+ // met (heading missing).
233
+ throw new TotemConfigError('--allow-compile-drift requires a `## Compile Drift Justification` heading in the PR body.', 'Edit the PR body and add a `## Compile Drift Justification` section explaining the compile-worker change.', 'CONFIG_INVALID');
234
+ }
235
+ return;
236
+ }
237
+ // No PR body context — pre-push fortification.
238
+ const justification = process.env['TOTEM_DRIFT_JUSTIFICATION'];
239
+ if (justification === undefined || justification.trim().length === 0) {
240
+ throw new TotemConfigError('--allow-compile-drift requires either an open PR (with a `## Compile Drift Justification` heading) or the TOTEM_DRIFT_JUSTIFICATION env var set non-empty.', 'Open a PR with the heading, or set TOTEM_DRIFT_JUSTIFICATION="reason for the drift" in your shell and retry.', 'CONFIG_INVALID');
241
+ }
242
+ }
243
+ /**
244
+ * Fetch the body of the open PR associated with the current branch via
245
+ * `gh pr view --json body`. Returns undefined when no PR exists, `gh` is
246
+ * unavailable, or the call fails for any other reason. Callers treat
247
+ * undefined as "no PR context" rather than "empty PR body".
248
+ */
249
+ function tryFetchCurrentBranchPrBody(args) {
250
+ const { cwd, safeExec } = args;
251
+ try {
252
+ const raw = safeExec('gh', ['pr', 'view', '--json', 'body'], {
253
+ cwd,
254
+ timeout: AUX_LOOKUP_TIMEOUT_MS,
255
+ maxBuffer: AUX_LOOKUP_MAX_BUFFER,
256
+ env: { ...process.env, GH_PROMPT_DISABLED: '1' },
257
+ });
258
+ const parsed = JSON.parse(raw);
259
+ if (typeof parsed.body !== 'string')
260
+ return undefined;
261
+ return parsed.body;
262
+ // totem-context: best-effort PR body lookup; gh unavailable / no open PR → fall through to TOTEM_DRIFT_JUSTIFICATION env var gate
263
+ }
264
+ catch {
265
+ return undefined;
266
+ }
267
+ }
42
268
  //# sourceMappingURL=verify-manifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify-manifest.js","sourceRoot":"","sources":["../../src/commands/verify-manifest.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAE3D,MAAM,GAAG,GAAG,QAAQ,CAAC;AAErB,2DAA2D;AAE3D,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,UAAU,EAAE,GAC9E,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAC/B,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAClF,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAEtE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAE5C,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;IAC9E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAE9D,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,yCAAyC,CAAC,CAAC;IAEzD,mEAAmE;IACnE,MAAM,QAAQ,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAEnD,MAAM,eAAe,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAEvD,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,IAAI,eAAe,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5C,UAAU,CAAC,IAAI,CACb,6DAA6D;YAC3D,eAAe,QAAQ,CAAC,UAAU,IAAI;YACtC,eAAe,eAAe,EAAE,CACnC,CAAC;IACJ,CAAC;IAED,IAAI,gBAAgB,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC9C,UAAU,CAAC,IAAI,CACb,kFAAkF;YAChF,eAAe,QAAQ,CAAC,WAAW,IAAI;YACvC,eAAe,gBAAgB,EAAE,CACpC,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,KAAK,kCAAkC,CAAC,CAAC;QACrE,MAAM,IAAI,UAAU,CAClB,gBAAgB,EAChB,uCAAuC,EACvC,iDAAiD,CAClD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACzC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,KAAK,yBAAyB,QAAQ,CAAC,UAAU,uBAAuB,CAAC,CAAC;AAChG,CAAC"}
1
+ {"version":3,"file":"verify-manifest.js","sourceRoot":"","sources":["../../src/commands/verify-manifest.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { execFileSync } from 'node:child_process';
1
2
  import * as fs from 'node:fs';
2
3
  import * as os from 'node:os';
3
4
  import * as path from 'node:path';
@@ -99,4 +100,212 @@ describe('verify-manifest', () => {
99
100
  await verifyManifestCommand();
100
101
  });
101
102
  });
103
+ // ─── Fingerprint drift tests ────────────────────────────
104
+ /**
105
+ * Run a git command in `cwd`. Tests use a real local git repo so the
106
+ * verify-manifest base-ref + branch-diff lookups hit a genuine commit graph
107
+ * rather than a mock. Cheap to set up; vastly more honest than faking
108
+ * child_process.
109
+ */
110
+ function git(cwd, ...args) {
111
+ execFileSync('git', args, { cwd, stdio: 'pipe', encoding: 'utf-8' });
112
+ }
113
+ /**
114
+ * Initialize a git repo in `cwd` with `main` as the default branch. Sets a
115
+ * deterministic user identity so commits succeed in CI environments that
116
+ * don't have global git config.
117
+ */
118
+ function initGitRepo(cwd) {
119
+ git(cwd, 'init', '-q', '-b', 'main');
120
+ git(cwd, 'config', 'user.email', 'test@example.com');
121
+ git(cwd, 'config', 'user.name', 'Test');
122
+ git(cwd, 'config', 'commit.gpgsign', 'false');
123
+ }
124
+ describe('verify-manifest fingerprint drift', () => {
125
+ let tmpDir;
126
+ let originalCwd;
127
+ // Cache the original env so per-test mutations don't leak.
128
+ const originalDriftJustification = process.env['TOTEM_DRIFT_JUSTIFICATION'];
129
+ beforeEach(() => {
130
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'totem-verify-manifest-drift-'));
131
+ originalCwd = process.cwd();
132
+ process.chdir(tmpDir);
133
+ fs.writeFileSync(path.join(tmpDir, 'totem.config.ts'), 'export default {};', 'utf-8');
134
+ // Ensure each test sees a clean env unless it sets the var itself.
135
+ delete process.env['TOTEM_DRIFT_JUSTIFICATION'];
136
+ });
137
+ afterEach(() => {
138
+ process.chdir(originalCwd);
139
+ fs.rmSync(tmpDir, { recursive: true, force: true });
140
+ vi.restoreAllMocks();
141
+ if (originalDriftJustification !== undefined) {
142
+ process.env['TOTEM_DRIFT_JUSTIFICATION'] = originalDriftJustification;
143
+ }
144
+ else {
145
+ delete process.env['TOTEM_DRIFT_JUSTIFICATION'];
146
+ }
147
+ });
148
+ /**
149
+ * Build a manifest fixture pinned to current disk state plus the supplied
150
+ * fingerprint. The `scaffold()` helper above writes lessons + rules; we
151
+ * compute the matching hashes here so input_hash / output_hash always pass.
152
+ */
153
+ function writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, fingerprint) {
154
+ writeCompileManifest(manifestPath, {
155
+ compiled_at: new Date().toISOString(),
156
+ model: 'claude-sonnet-4-6',
157
+ input_hash: generateInputHash(lessonsDir),
158
+ output_hash: generateOutputHash(rulesPath),
159
+ rule_count: 1,
160
+ ...(fingerprint !== undefined ? { compile_worker_fingerprint: fingerprint } : {}),
161
+ });
162
+ }
163
+ /**
164
+ * Seed the compile-worker prompt template file at its monorepo-relative
165
+ * path so `verify-manifest`'s `inMonorepo` detection (existence check on
166
+ * `packages/cli/src/commands/compile-templates.ts`) returns true.
167
+ * Required for all drift-gate tests except the "external user / skip
168
+ * gate" case.
169
+ */
170
+ function seedMonorepoTemplate(cwd, content = 'export const COMPILER_SYSTEM_PROMPT = "base";\n') {
171
+ const templatesDir = path.join(cwd, 'packages/cli/src/commands');
172
+ fs.mkdirSync(templatesDir, { recursive: true });
173
+ const templatesPath = path.join(templatesDir, 'compile-templates.ts');
174
+ fs.writeFileSync(templatesPath, content);
175
+ return templatesPath;
176
+ }
177
+ it('passes when local and base fingerprints match', async () => {
178
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
179
+ seedMonorepoTemplate(tmpDir);
180
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'f'.repeat(64));
181
+ initGitRepo(tmpDir);
182
+ git(tmpDir, 'add', '.');
183
+ git(tmpDir, 'commit', '-q', '-m', 'initial');
184
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
185
+ await verifyManifestCommand();
186
+ });
187
+ it('passes when manifest has no fingerprint (Phase 1 anthropic-only — non-anthropic providers leave it undefined)', async () => {
188
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
189
+ seedMonorepoTemplate(tmpDir);
190
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, undefined);
191
+ initGitRepo(tmpDir);
192
+ git(tmpDir, 'add', '.');
193
+ git(tmpDir, 'commit', '-q', '-m', 'initial');
194
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
195
+ await verifyManifestCommand();
196
+ });
197
+ // External @mmnto/cli consumers don't own packages/cli/src/commands/
198
+ // compile-templates.ts; firing the drift gate on every CLI upgrade would
199
+ // force them to use --allow-compile-drift for every routine version bump.
200
+ // Scope-detect via template-source existence: when the file isn't present
201
+ // at the monorepo-relative path, skip the gate. The fingerprint is still
202
+ // recorded in their manifest for observability.
203
+ it('skips the drift gate when not running inside the totem monorepo (external user)', async () => {
204
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
205
+ // Intentionally DO NOT seed packages/cli/src/commands/compile-templates.ts
206
+ // → simulates an external user whose repo doesn't contain the totem
207
+ // monorepo source.
208
+ initGitRepo(tmpDir);
209
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
210
+ git(tmpDir, 'add', '.');
211
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
212
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/external-cli-upgrade');
213
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'b'.repeat(64));
214
+ git(tmpDir, 'add', path.relative(tmpDir, manifestPath).replace(/\\/g, '/'));
215
+ git(tmpDir, 'commit', '-q', '-m', 'fingerprint changed via CLI upgrade');
216
+ // Drift would normally fire — but gate is skipped because the monorepo
217
+ // template source is absent. Should pass without override.
218
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
219
+ await verifyManifestCommand();
220
+ });
221
+ it('fails when fingerprints differ and compile-templates.ts is not in the diff', async () => {
222
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
223
+ seedMonorepoTemplate(tmpDir);
224
+ initGitRepo(tmpDir);
225
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
226
+ git(tmpDir, 'add', '.');
227
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
228
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/no-template-edit');
229
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'b'.repeat(64));
230
+ // Commit only the manifest, no template file change.
231
+ git(tmpDir, 'add', path.relative(tmpDir, manifestPath).replace(/\\/g, '/'));
232
+ git(tmpDir, 'commit', '-q', '-m', 'unjustified drift');
233
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
234
+ await expect(verifyManifestCommand()).rejects.toThrow(/fingerprint drift/);
235
+ });
236
+ it('passes when fingerprints differ but compile-templates.ts is in the diff', async () => {
237
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
238
+ const templatesPath = seedMonorepoTemplate(tmpDir);
239
+ initGitRepo(tmpDir);
240
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
241
+ git(tmpDir, 'add', '.');
242
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
243
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/with-template-edit');
244
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'c'.repeat(64));
245
+ fs.writeFileSync(templatesPath, 'export const COMPILER_SYSTEM_PROMPT = "evolved";\n');
246
+ git(tmpDir, 'add', '.');
247
+ git(tmpDir, 'commit', '-q', '-m', 'justified drift');
248
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
249
+ await verifyManifestCommand();
250
+ });
251
+ it('--allow-compile-drift requires TOTEM_DRIFT_JUSTIFICATION when no PR body context is available', async () => {
252
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
253
+ seedMonorepoTemplate(tmpDir);
254
+ initGitRepo(tmpDir);
255
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
256
+ git(tmpDir, 'add', '.');
257
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
258
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/override-no-justification');
259
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'b'.repeat(64));
260
+ git(tmpDir, 'add', path.relative(tmpDir, manifestPath).replace(/\\/g, '/'));
261
+ git(tmpDir, 'commit', '-q', '-m', 'drift no justification');
262
+ // No remote → gh pr view will fail → falls through to env-var gate.
263
+ // No env var set → override should reject.
264
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
265
+ await expect(verifyManifestCommand({ allowCompileDrift: true })).rejects.toThrow(/TOTEM_DRIFT_JUSTIFICATION/);
266
+ });
267
+ // R2 fix verification: the repo-root anchor (via `rev-parse --show-toplevel`)
268
+ // ensures the base-fingerprint lookup constructs paths the way git expects
269
+ // when verify-manifest runs from a sub-directory of the repo. Without the
270
+ // fix, the lookup builds a cwd-relative path that git rejects (the path
271
+ // would walk above the repo root). The afterEach restores `process.cwd()`
272
+ // — no leak across tests.
273
+ it('resolves the base-ref path against the repo root when run from a sub-directory', async () => {
274
+ const subDir = path.join(tmpDir, 'packages/cli');
275
+ fs.mkdirSync(subDir, { recursive: true });
276
+ fs.writeFileSync(path.join(subDir, 'totem.config.ts'), 'export default {};', 'utf-8');
277
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(subDir);
278
+ seedMonorepoTemplate(tmpDir); // root-level monorepo marker
279
+ initGitRepo(tmpDir);
280
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
281
+ git(tmpDir, 'add', '.');
282
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
283
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/from-subdir');
284
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'b'.repeat(64));
285
+ git(tmpDir, 'add', path.relative(tmpDir, manifestPath).replace(/\\/g, '/'));
286
+ git(tmpDir, 'commit', '-q', '-m', 'drift from subdir');
287
+ process.chdir(subDir);
288
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
289
+ // Repo-root anchored lookup should locate the base manifest, the drift
290
+ // gate should fire, and the override-less path should reject. Without
291
+ // the fix, the lookup would silently return undefined and the gate
292
+ // would no-op, letting unjustified drift slip through.
293
+ await expect(verifyManifestCommand()).rejects.toThrow(/fingerprint drift/);
294
+ });
295
+ it('--allow-compile-drift accepts when TOTEM_DRIFT_JUSTIFICATION is set and no PR body context is available', async () => {
296
+ const { lessonsDir, rulesPath, manifestPath } = scaffold(tmpDir);
297
+ seedMonorepoTemplate(tmpDir);
298
+ initGitRepo(tmpDir);
299
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'a'.repeat(64));
300
+ git(tmpDir, 'add', '.');
301
+ git(tmpDir, 'commit', '-q', '-m', 'base on main');
302
+ git(tmpDir, 'checkout', '-q', '-b', 'feature/override-with-justification');
303
+ writeManifestWithFingerprint(manifestPath, lessonsDir, rulesPath, 'b'.repeat(64));
304
+ git(tmpDir, 'add', path.relative(tmpDir, manifestPath).replace(/\\/g, '/'));
305
+ git(tmpDir, 'commit', '-q', '-m', 'drift with justification');
306
+ process.env['TOTEM_DRIFT_JUSTIFICATION'] = 'Worker prompt-cache TTL bump per ADR-NNN';
307
+ const { verifyManifestCommand } = await import('./verify-manifest.js');
308
+ await verifyManifestCommand({ allowCompileDrift: true });
309
+ });
310
+ });
102
311
  //# sourceMappingURL=verify-manifest.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify-manifest.test.js","sourceRoot":"","sources":["../../src/commands/verify-manifest.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify-manifest.test.js","sourceRoot":"","sources":["../../src/commands/verify-manifest.test.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -482,15 +482,30 @@ program
482
482
  program
483
483
  .command('verify-manifest')
484
484
  .description('Verify compiled-rules.json matches the compile manifest (CI gate)')
485
- .action(async () => {
485
+ .option('--allow-compile-drift', 'Override compile-worker fingerprint drift. CI requires a `## Compile Drift Justification` heading in the PR body; pre-push without an open PR requires TOTEM_DRIFT_JUSTIFICATION env var to be set.')
486
+ .action(async (options) => {
486
487
  try {
487
488
  const { verifyManifestCommand } = await import('./commands/verify-manifest.js');
488
- await verifyManifestCommand();
489
+ await verifyManifestCommand({ allowCompileDrift: options.allowCompileDrift });
489
490
  }
490
491
  catch (err) {
491
492
  handleError(err);
492
493
  }
493
494
  });
495
+ program
496
+ .command('verify-badges')
497
+ .description('Verify shields.io badges in README.md (deterministic claim-discipline gate)')
498
+ .action(async () => {
499
+ try {
500
+ const { verifyBadgesCliCommand } = await import('./commands/verify-badges.js');
501
+ await verifyBadgesCliCommand();
502
+ }
503
+ catch (err) {
504
+ handleError(err);
505
+ // totem-context: handleError returns `never` (process.exit), so the throw is unreachable but required to satisfy the Tenet 4 fail-loud rule that bans bare-catch silent-degrade. Mirrors the stats command pattern.
506
+ throw err;
507
+ }
508
+ });
494
509
  program
495
510
  .command('import')
496
511
  .description('Import rules from external linter configs (ESLint, Semgrep)')