I4223 — The pre-commit generation gate answers inside its bound, and a failed case's reason reaches an artifact
Make `generate --check`, which `scripts/pages current` runs in front of every commit, stop paying for the plan's scope-conflict scan: choose the runnable issues once, normalise every scope entry once, and compare normalised entries without allocating, with the same findings in the same order. And make the reason a failed case prints reach a file CI keeps: test/run.sh writes every failed or timed-out case's output to MJ_TEST_FAILURES, and validate.yml uploads it per suite shard.
READY wave 0 · p1 · implementation profile · runs alone
Part of M004 — Performance is executable evidence, and the hot path does no canonical work twice.
Ready. Every dependency is done, so majordomus plan start I4223 will be accepted.
Objective
Make `generate --check`, which `scripts/pages current` runs in front of every commit, stop paying for the plan's scope-conflict scan: choose the runnable issues once, normalise every scope entry once, and compare normalised entries without allocating, with the same findings in the same order. And make the reason a failed case prints reach a file CI keeps: test/run.sh writes every failed or timed-out case's output to MJ_TEST_FAILURES, and validate.yml uploads it per suite shard.
Why
Master's validate 40086406859 at 563fe99 failed 56_derived_current_gate on suite-shard 3: the gate took 31 s at best of two against a bound of 30. It was the only failure of case 56 among the last 60 failed validate runs (2026-10-16 to 2026-10-24), but it had no margin. Profiled on the development Mac, the scope-conflict scan in plan::derive (every pair of runnable issues of a wave, every pair of their scope entries, four new strings per comparison) was 3.9 of the 12.1 s the main thread spent in `generate --check`, through the benchmark cases that derive the plan as well as the plan's own artifacts. The case's reason was printed in the job's log, but suite.tsv, the shard's artifact, held only FAIL and 150 s.
Current state
On 563fe99 plan::overlap normalises both entries into new Strings and formats two more per question, and the conflict loop visits every pair of issues of the plan before asking their status. A debug `generate --check` took 18.4 s here (load 7.6). test/run.sh records name, word, seconds and phase per case; a case's output exists only in the job log.
Desired state
The same `generate --check` takes 11.3 s on the same machine under a heavier load (27), with plan::derive gone from the top of its profile and every plan finding unchanged. The bound of case 56 stays at 30 s. A failed case's output is in the suite-failures-<shard> artifact under its name.
Scope
- .ai/repo/project/issues/I4223.yaml
- apps/majordomus-cli/src/plan.rs
- test/run.sh
- .github/workflows/validate.yml
- test/cases/56_derived_current_gate.sh
- test/cases/4223_a_failed_cases_reason_reaches_the_artifact.sh
Out of scope
- Raising the 30 s bound of case 56
- The changelog's per-decision git walks (added_at_each), whose answers depend on git's per-path history simplification and are a change of their own
Dependencies
None. This issue is a root of the graph.
Acceptance criteria
- overlap answers every pair of the entries normalisation exists for as the allocating definition did, and a conflict is reported once per pair and only between runnable issues
- The plan unit tests pass unchanged
- A run with MJ_TEST_FAILURES set writes a failed case's output under its name and nothing of the cases that passed or declined, and a green run leaves the file empty
- Case 56 passes on CI with its bound unchanged
Validation
- cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib plan::
- bash test/run.sh 4223_a_failed_cases_reason_reaches_the_artifact 56_derived_current_gate
Evidence required
- scope_conflict_scan_allocates_nothing
- failed_case_reason_in_artifact
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I4223.yaml. Read it back with majordomus plan show I4223.