I3110 — A blocking rule reads proven only when one of its cases shows its violation refused
Extend the rule proof so that a blocking rule is satisfied only when one of its named cases declares the rule whose violation it refuses with a '# majordomus-refutes: <rule-id>' header and has a passing recorded run. '# majordomus-negative:' keeps its command vocabulary and is never read as rule proof. majordomus-cli rules report prints the blocking rules that lack such a case, and scripts/ci/rule-proof-check ratchets that list.
PŘIPRAVENO vlna 0 · p1 · profil implementation · bezpečné souběžně
Připraveno. Všechny závislosti jsou hotové, takže majordomus plan start I3110 bude přijato.
Cíl
Extend the rule proof so that a blocking rule is satisfied only when one of its named cases declares the rule whose violation it refuses with a '# majordomus-refutes: <rule-id>' header and has a passing recorded run. '# majordomus-negative:' keeps its command vocabulary and is never read as rule proof. majordomus-cli rules report prints the blocking rules that lack such a case, and scripts/ci/rule-proof-check ratchets that list.
Proč
The owner asked eleven times between 2026-09-11 and 2026-10-14 for rules to be enforced \"positive, negative and wiring tested\" (c139#1, c259#6). On 2026-10-08 the independent audit showed Majordomus treating wired as enforced. Rule proof today accepts any named, present, passing case, so a rule backed only by a happy-path case reads proven. The refusal gets its own header because '# majordomus-negative:' already names a failure mode of a command, gate, script, workflow or capability (lib/commands.sh:216-229, scripts/ci/command-furnished:71), mj_covers_resolve refuses any other prefix (lib/commands.sh:186-188), and only the first such line of a file is read. It extends milestone architecture-is-enforced. Proposed in ADR 0188 (A rule's proof of effect is a recorded refusal of its violation, not the presence of its wiring) (proposed; it carries no authority until the owner accepts it). Sources: chatgpt-majordomus:c115#1, chatgpt-majordomus:c115#4, chatgpt-majordomus:c129#3, chatgpt-majordomus:c139#1, chatgpt-majordomus:c193#1, chatgpt-majordomus:c207#6, chatgpt-majordomus:c214#2, chatgpt-majordomus:c259#6.
Aktuální stav
apps/majordomus-cli/src/evidence/subject.rs reads the first '# majordomus-covers:' and the first '# majordomus-negative:' line of every case (module doc at :21, NEGATIVE const at :126). apps/majordomus-cli/src/rules/mod.rs builds rule proof from named, present, recorded cases, and RuleState has no notion of a refusal. No case carries a refutes header. .ai/repo/rule-proof-baseline.txt holds only its header. The number of blocking rules is read with majordomus-cli rules report --format json, not quoted here.
Cílový stav
RuleProof carries refusal_shown: bool for a blocking rule. The report and its MCP and HTTP projections name the rules without a refusal case. A new baseline, written by --write-baseline, freezes today's list and may only shrink.
Rozsah
- apps/majordomus-cli/src/rules
- scripts/ci/rule-proof-check
- test/cases/125_rule_proof.sh
- .ai/repo/rules/project/rule-is-a-doctrine.v1.md
- apps/majordomus-cli/src/evidence/subject.rs
- lib/commands.sh
- scripts/ci/command-furnished
- scripts/generate-site-data
- test/cases/31_command_coverage.sh
- .ai/repo/project/intents
- .ai/repo/rule-proof-baseline.txt
- .ai/repo/adrs/0188-a-rule-s-proof-of-effect-is-a-recorded-refusal-of-its-violation.md
- apps/majordomus-cli/src/capability/builtin/rules.rs
- apps/majordomus-cli/tests/rules.rs
Mimo rozsah
- Writing the missing negative cases themselves (follow-up issues per rule family)
- Advisory rules
- Adding a rule: vocabulary to '# majordomus-negative:' or to mj_covers_resolve
Závislosti
Žádné. Tento úkol je kořenem grafu.
Co na tom čeká
- I3111BLOCKED Every dispatched blocking validator is run against a declared violation, and one that accepts it fails the case
- I3112BLOCKED rule-proof-check prints the blocking rules no recorded run proves, and that count only falls
Kritéria přijetí
- A blocking rule none of whose named cases carries a '# majordomus-refutes:' header naming it is listed by majordomus-cli rules report as refusal_not_shown
- Adding a blocking rule with no refusal case fails rule-proof-check; removing one from the baseline after adding a case passes
- majordomus-cli rules report --format json carries refusal_shown per rule, and the MCP and HTTP projections carry the same field
- A case declares the rule whose violation it refuses with its own header line '# majordomus-refutes: <rule-id>' (one or more per file, every line read); '# majordomus-negative:' keeps its command vocabulary and is never read as rule proof
- refusal_shown is true for a blocking rule only when a named case carries a refutes header naming that rule id and has a passing recorded run; case 125 ('negative: rules') and case 99 ('negative: adr doctor') show no rule refused
- doctor, test/cases/31_command_coverage.sh and scripts/ci/command-furnished pass unchanged over a tree that carries refutes headers
- A new case carrying evidence case_rule_refusal_ratchet (its number from scripts/case-numbers next, announced on the board when the issue starts) fails on master 707a04c and passes with this issue; the same commit rebinds intent criterion blocking-rule-shows-refusal to it
Validace
- cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib rules
- cargo test --manifest-path apps/majordomus-cli/Cargo.toml --test rules
- MJ_TEST_JOBS=4 bash test/run.sh 125_rule_proof 31_command_coverage
- scripts/ci/rule-proof-check
Požadované důkazy
- case_rule_refusal_ratchet
Důkazy
Nic nezaznamenáno. Za každým tokenem výše musí stát příkaz nebo artefakt, než lze tento úkol dokončit; vyprávění se odmítá.
Časová osa
- zahájeno
- —
- ověřeno
- —
- dokončeno
- —
Tato tři pole, důkazy výše a stav závislostí jsou vše, z čeho se stav skládá. Neexistuje žádné pole stavu, které by s nimi mohlo být v rozporu.
Canonical record: .ai/repo/project/issues/I3110.yaml. Read it back with majordomus plan show I3110.