feat(rule13): 执行前分歧重评估闸——main 撞声明范围→needs_attention 重评估
通用规则13的(B)半边:sync main 之前先跑 reevalScopeGate, 以 git diff HEAD...origin/main 取 main 自分支点以来改动的文件, 与任务 scopeFiles 求交集;非空即 emit needs-reeval → daemon markReeval 直接转 needs_attention(不重试/不计失败/run收尾cancelled)。 - checks.ts: + reevalScopeGate / ReevalGateFn / ReevalGateResult - pipeline.ts: createWorktree 后、syncMain 前插入重评估闸 + reevalGate 依赖注入 - protocol.ts: + needs-reeval OutboxRecord/Payload 事件 - ingest.ts: + case 'needs-reeval' → store.markReeval - store.ts: + markReeval(executing→needs_attention,不进重试链) - status.ts: executing 合法转移 + needs_attention - 测试 +5:reevalScopeGate(命中/未命中/空/无前移/git错) · pipeline(命中emit/未命中续跑) · store.markReeval;全套 242 绿 - docs: optimization-plan.html 规则13 标 ✅ 已实现 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+53
-1
@@ -4,7 +4,7 @@ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { parseChecks, runChecks, diffSizeGate, globToRegExp, matchesAnyGlob, scopeFileGate } from '../src/executor/checks.js';
|
||||
import { parseChecks, runChecks, diffSizeGate, globToRegExp, matchesAnyGlob, scopeFileGate, reevalScopeGate } from '../src/executor/checks.js';
|
||||
import type { Project } from '../src/model/types.js';
|
||||
|
||||
function withTmpData(cb: (dir: string) => Promise<void> | void): Promise<void> | void {
|
||||
@@ -145,3 +145,55 @@ test('scopeFileGate:git 出错 → 不拦截', async () => {
|
||||
const r = await scopeFileGate('/nonexistent-repo-xyz', 'a', 'b', ['src/**']);
|
||||
assert.equal(r.ok, true);
|
||||
});
|
||||
|
||||
test('reevalScopeGate(规则13):main 动了声明范围内文件 → overlap 非空;范围外 → 空;空声明 → 空', async () => {
|
||||
const repo = mkdtempSync(join(tmpdir(), 'maestro-reeval-'));
|
||||
const g = (args: string[]) => execFileSync('git', args, { cwd: repo }).toString();
|
||||
g(['init', '-q', '-b', 'main']);
|
||||
g(['config', 'user.email', 't@t']); g(['config', 'user.name', 't']);
|
||||
execFileSync('mkdir', ['-p', join(repo, 'src')]);
|
||||
writeFileSync(join(repo, 'src', 'a.ts'), 'a\n');
|
||||
writeFileSync(join(repo, 'docs.md'), 'd\n');
|
||||
g(['add', '-A']); g(['commit', '-qm', 'base']);
|
||||
// 任务分支从此刻 main 切出(尚无任务提交,模拟 sync 前的 worktree HEAD)
|
||||
g(['checkout', '-q', '-b', 'feature']);
|
||||
// main 在任务排队期间前移:改了 src/a.ts(声明范围内)
|
||||
g(['checkout', '-q', 'main']);
|
||||
writeFileSync(join(repo, 'src', 'a.ts'), 'a changed by main\n');
|
||||
g(['add', '-A']); g(['commit', '-qm', 'main moved']);
|
||||
g(['checkout', '-q', 'feature']); // worktree HEAD 回到分支点
|
||||
|
||||
try {
|
||||
// 声明 src/**,main 动了 src/a.ts → 撞上,触发重评估
|
||||
const hit = await reevalScopeGate(repo, 'main', ['src/**']);
|
||||
assert.deepEqual(hit.overlap, ['src/a.ts']);
|
||||
|
||||
// 声明 docs.md,main 只动了 src/a.ts → 不撞,不触发
|
||||
const miss = await reevalScopeGate(repo, 'main', ['docs.md']);
|
||||
assert.deepEqual(miss.overlap, []);
|
||||
|
||||
// 空声明 → 不评估
|
||||
const skip = await reevalScopeGate(repo, 'main', []);
|
||||
assert.deepEqual(skip.overlap, []);
|
||||
} finally {
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('reevalScopeGate(规则13):main 无前移 → 空 overlap;git 出错 → 空', async () => {
|
||||
const repo = mkdtempSync(join(tmpdir(), 'maestro-reeval2-'));
|
||||
const g = (args: string[]) => execFileSync('git', args, { cwd: repo }).toString();
|
||||
g(['init', '-q', '-b', 'main']);
|
||||
g(['config', 'user.email', 't@t']); g(['config', 'user.name', 't']);
|
||||
writeFileSync(join(repo, 'src.ts'), 'x\n');
|
||||
g(['add', '-A']); g(['commit', '-qm', 'base']);
|
||||
g(['checkout', '-q', '-b', 'feature']); // 分支点 = main tip,main 未前移
|
||||
try {
|
||||
const r = await reevalScopeGate(repo, 'main', ['**']);
|
||||
assert.deepEqual(r.overlap, []);
|
||||
} finally {
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
}
|
||||
const err = await reevalScopeGate('/nonexistent-repo-xyz', 'main', ['src/**']);
|
||||
assert.deepEqual(err.overlap, []);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user