From f442176bd8d38d57e6e70fe1835bca226651951b Mon Sep 17 00:00:00 2001 From: jeffyxu Date: Tue, 6 Oct 2026 22:23:57 +0800 Subject: [PATCH] fix(dry-run): allow stats and recall previews after #970 The squash of #970 onto the #969 refusal list left both commands refused, so fork-safe e2e exits 1. The previews already write nothing. Co-authored-by: Cursor --- src/__tests__/dry-run-guard.test.ts | 6 +++++- src/__tests__/e2e/dry-run-refusal.test.ts | 2 +- src/__tests__/e2e/stats-recall-dry-run.test.ts | 8 ++++++-- src/dry-run-guard.ts | 4 ++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/__tests__/dry-run-guard.test.ts b/src/__tests__/dry-run-guard.test.ts index da9c5db7b..f9f2e2d4f 100644 --- a/src/__tests__/dry-run-guard.test.ts +++ b/src/__tests__/dry-run-guard.test.ts @@ -51,11 +51,15 @@ describe('--dry-run guard decisions', () => { } it.each([ - 'stats', 'digest', 'recall', + 'digest', ])('refuses %s until its writes have a preview', (path) => { expect(dryRunRefusal(command(path))).toBe(`teamai ${path} has no --dry-run preview, nothing was run`); }); + it.each(['stats', 'recall'])('allows the merged %s preview', (path) => { + expect(dryRunRefusal(command(path))).toBeUndefined(); + }); + it.each([ 'remove', 'roles init', 'roles add', 'roles remove', 'roles update', 'projects add', 'projects update', 'projects remove', diff --git a/src/__tests__/e2e/dry-run-refusal.test.ts b/src/__tests__/e2e/dry-run-refusal.test.ts index ed6aebc4a..9f1cc27b5 100644 --- a/src/__tests__/e2e/dry-run-refusal.test.ts +++ b/src/__tests__/e2e/dry-run-refusal.test.ts @@ -178,7 +178,7 @@ describe('--dry-run on a command with no preview', () => { }); it.each([ - ['stats'], ['digest'], ['recall', 'query'], + ['digest'], ['import', '--from-iwiki', 'page', '--from-mr', 'url'], ['import', '--from-claude'], ])('refuses unsafe preview %j before writing', (...args) => { const before = snapshot(home); diff --git a/src/__tests__/e2e/stats-recall-dry-run.test.ts b/src/__tests__/e2e/stats-recall-dry-run.test.ts index 8dc0ec10d..4e5d20820 100644 --- a/src/__tests__/e2e/stats-recall-dry-run.test.ts +++ b/src/__tests__/e2e/stats-recall-dry-run.test.ts @@ -39,14 +39,18 @@ function git(args: string[], cwd: string): void { const fwd = (value: string): string => value.split(path.sep).join('/'); -/** Every file under `dir` mapped to a content hash; git's transient lock files left out. */ +/** + * Every file under `dir` mapped to a content hash. Git's transient lock files + * and the CLI diagnostic log are left out: every log line appends to it, + * preview or not, the same way the other dry-run e2e suites ignore it. + */ function snapshotTree(dir: string): Record { const out: Record = {}; const walk = (current: string): void => { for (const entry of fs.readdirSync(current, { withFileTypes: true })) { const full = path.join(current, entry.name); if (entry.isDirectory()) walk(full); - else if (entry.isFile() && !entry.name.endsWith('.lock') && entry.name !== 'gc.pid') { + else if (entry.isFile() && !entry.name.endsWith('.lock') && entry.name !== 'gc.pid' && entry.name !== 'debug.log') { out[path.relative(dir, full)] = createHash('sha256').update(fs.readFileSync(full)).digest('hex'); } } diff --git a/src/dry-run-guard.ts b/src/dry-run-guard.ts index de7d67419..d90f1a6ed 100644 --- a/src/dry-run-guard.ts +++ b/src/dry-run-guard.ts @@ -75,6 +75,8 @@ export const DRY_RUN_PREVIEW: ReadonlySet = new Set([ 'models restore', 'session save', 'contribute', + 'stats', + 'recall', 'recall feedback', 'recall disable', 'recall enable', @@ -93,8 +95,6 @@ export const DRY_RUN_PREVIEW: ReadonlySet = new Set([ * on a command that is in neither. */ export const NO_DRY_RUN_PREVIEW: Readonly> = { - stats: 'creates or refreshes the reports worktree until #970 lands', - recall: 'writes recall quality and the search index until #970 lands', digest: 'creates or refreshes the reports worktree; #900 C11', init: 'no preview; clones, saves config and injects hooks (single-repo: bootstraps the clone)', 'models add': 'writes the personal profile and its key',