feat: D2 — канал коммита под ревью (агент коммитит под commit:<hash>)
Опечатанный ревью-план (GO наставника+судьи, judge_mode=live-block) + одно согласие владельца `FLOOR-ESCAPE: commit:<plan-hash>` → агент делает git add/commit/push без терминала владельца. Гейт ПРИСУТСТВИЯ (router-gate git-approval) отходит; гейты КАЧЕСТВА (criterion-gate/verify-gate) НЕ тронуты — код-коммит всё равно требует по-критерийный GREEN и свежую расписку. Согласия деплоя (ops-runbook:) и коммита (commit:) — раздельные кнопки. - escape-grant: обобщён plan-scoped загрузчик (loadPlanScopedGrants/ planScopedGrantOpen, окно = существование плана); D1 ops-runbook стал тонкой обёрткой; добавлены commit: COMMIT_GRANT_PREFIX/loadCommitGrants/commitGrantOpen. - commit-grant (новый мост план↔router-gate): commitGrantOpenForSession — открыт ли commit:<hash> на валидный sealed live-block план сессии. - shell-content-rules classifyGitCommand: conditional-git пускается при ctx.commitGrantOpen; GIT_HARD (force-push/--no-verify/-c) блокирует ПЕРВЫМ (качество/безопасность не ослаблены). - enforce-router-gate: main кладёт ctx.commitGrantOpen (gated через мост). План: docs/superpowers/plans/2026-06-18-agent-commit-channel-plan.md Спека: docs/superpowers/specs/2026-06-18-agent-commit-channel-design.md §3.1-3.2. ОТЛОЖЕНО (требует решения владельца, в хвосте плана): - §3.3 docs/ops без criterion/verify: .md уже пропускается; расширение на не-.md ops-артефакты конфликтует с CLAUDE.md §13 v2.40 — нужен явный список. - §3.4 десинк push-последним-шагом: рискованная правка снятия печати стены. +22 теста, свод 4319 passed / 2 skipped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -145,6 +145,26 @@ describe('isApproved (one-shot + 5-min window)', () => {
|
||||
});
|
||||
import { classifyGitCommand } from './shell-content-rules.mjs';
|
||||
|
||||
describe('classifyGitCommand commit-грант (D2)', () => {
|
||||
it('git commit при ctx.commitGrantOpen → allow (гейт присутствия отходит)', () => {
|
||||
const r = classifyGitCommand('git commit -m x', { commitGrantOpen: true });
|
||||
expect(r.result).toBe('allow');
|
||||
expect(r.reason).toMatch(/commit:|ревью-план|согласие/i);
|
||||
});
|
||||
it('git push при ctx.commitGrantOpen → allow', () => {
|
||||
expect(classifyGitCommand('git push gitea main', { commitGrantOpen: true }).result).toBe('allow');
|
||||
});
|
||||
it('без гранта и без approve → block (default-deny держит)', () => {
|
||||
expect(classifyGitCommand('git commit -m x', {}).result).toBe('block');
|
||||
});
|
||||
it('GIT_HARD (force-push) блокирует ДАЖЕ при commitGrantOpen (качество/безопасность)', () => {
|
||||
expect(classifyGitCommand('git push --force', { commitGrantOpen: true }).result).toBe('block');
|
||||
});
|
||||
it('--no-verify блокируется при commitGrantOpen', () => {
|
||||
expect(classifyGitCommand('git commit --no-verify -m x', { commitGrantOpen: true }).result).toBe('block');
|
||||
});
|
||||
});
|
||||
|
||||
describe('classifyGitCommand — readonly', () => {
|
||||
it.each(['git status', 'git log --oneline', 'git diff HEAD~1', 'git branch --show-current', 'git remote -v'])(
|
||||
'allows %s',
|
||||
|
||||
Reference in New Issue
Block a user