fix(enforce): hole 7 — ремонт инфраструктуры requires justification line
Brain-retro #5 candidate C, hole 7: the 'ремонт инфраструктуры' phrase suppressed ALL rule keys with no constraint. Now requires a 'ремонт: <what>' line in the same prompt documenting the target. enforce-override-vocab.json: added 'requires_justification: "ремонт:"' to the entry. enforce-hook-helpers.mjs findOverride(): honors requires_justification — when set, the user prompt must contain '<prefix> <non-empty-text>' or the override is rejected.
This commit is contained in:
@@ -200,7 +200,16 @@ export function findOverride(userPrompt, ruleKey, vocab) {
|
||||
for (const p of v.phrases || []) {
|
||||
if (!p.phrase || !Array.isArray(p.suppresses)) continue;
|
||||
if (!lo.includes(p.phrase.toLowerCase())) continue;
|
||||
if (p.suppresses.includes(ruleKey)) return p;
|
||||
if (!p.suppresses.includes(ruleKey)) continue;
|
||||
if (p.requires_justification) {
|
||||
// Hole 7 fix: master overrides require a line "<prefix> <non-empty>"
|
||||
// in the same prompt documenting what is being repaired.
|
||||
const prefix = p.requires_justification.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const re = new RegExp(prefix + '\\s+(\\S[^\\n]*)', 'i');
|
||||
const m = userPrompt.match(re);
|
||||
if (!m || !m[1] || !m[1].trim()) continue;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -151,6 +151,35 @@ describe('loadOverrideVocab / findOverride', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('findOverride — requires_justification (hole 7)', () => {
|
||||
const testVocab = {
|
||||
phrases: [
|
||||
{
|
||||
phrase: 'ремонт инфраструктуры',
|
||||
suppresses: ['classifier-mismatch'],
|
||||
requires_justification: 'ремонт:',
|
||||
description: 'master kill — requires justification',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('rejects when phrase present but justification line missing (hole 7)', () => {
|
||||
const r = findOverride('ремонт инфраструктуры', 'classifier-mismatch', testVocab);
|
||||
expect(r).toBeNull();
|
||||
});
|
||||
|
||||
it('accepts when justification line provides target', () => {
|
||||
const r = findOverride('ремонт инфраструктуры\nремонт: enforce-hook-helpers.mjs', 'classifier-mismatch', testVocab);
|
||||
expect(r).not.toBeNull();
|
||||
expect(r.phrase).toBe('ремонт инфраструктуры');
|
||||
});
|
||||
|
||||
it('rejects when justification line empty after the prefix', () => {
|
||||
const r = findOverride('ремонт инфраструктуры\nремонт: ', 'classifier-mismatch', testVocab);
|
||||
expect(r).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isProductionCodePath', () => {
|
||||
it('classifies tools/*.mjs as production', () => {
|
||||
expect(isProductionCodePath('tools/router-classifier.mjs')).toBe(true);
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
{
|
||||
"phrase": "ремонт инфраструктуры",
|
||||
"suppresses": ["tdd-gate", "verify-before-commit", "verify-before-push", "writing-plans-required", "skill-required", "memory-sync-coverage", "classifier-mismatch", "coverage-skill-match"],
|
||||
"description": "Bypass all rules (full opt-out). Use only when literally fixing the enforce-infrastructure itself."
|
||||
"requires_justification": "ремонт:",
|
||||
"description": "Bypass all rules (full opt-out). Requires 'ремонт: <what>' line in same prompt."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user