Problem
ara check --fix (added in #41) applies a fix only when the whole artifact re-parses fully clean. On the messy real corpus — where, per docs/ara-format-feedback.md item 13, "none parse cleanly; about half emit errors" — this means --fix usually applies nothing, even when the fixable drift is itself the cause of the errors.
The guard's Ok-gate is here:
// crates/ara-core/src/fix.rs — guard_ara004
let Ok((mc, _)) = cand else {
return false; // any remaining error in the edited artifact → reject the fix
};
The guard_alias path (ARA002/ARA003) is similarly conservative: it requires a clean base parse to compute its targeted one-field diff, so an unrelated pre-existing error (duplicate id, cycle, etc.) discards those fixes too.
Evidence (from an ara check sweep over the 14 vendored fixtures)
Detection is correct (0 panics; 2 artifacts flagged with real ARA004 dash-header drift), but --fix applied 0 fixes to both fixable artifacts:
corpus/speedrun/nanogpt-speedrun — all 10 claims C01–C10 use em-dash headers (## C01 — …), so none parse, producing 29 evidence references unknown claim errors. The dash headers ARE the cause of those errors. Fixing them would recover the claims and clear the errors — but the fixpoint loop applies one fix at a time, and each single fix still leaves the artifact erroring, so every candidate is rejected and nothing moves.
corpus/rebench/rebench-restricted_mlm — the schema_version: "ara-2.0" shape (no tree:/root:); the base parse errors fatally, so all fixes are blocked. (This one is out of scope — a genuinely different format — and is fine to leave blocked.)
Proposed change
Relax the value-recovering guards (ARA004, and ARA002/003) from "must re-parse fully clean" to "must not introduce new errors" — i.e. accept the edit when errors_subset(cand, base) holds (the edited artifact's error set is a subset of the pre-fix error set) plus the existing targeted-recovery + idempotence checks. This keeps the safety guarantees (never adds an error, never corrupts a file, still idempotent) while letting a fix proceed on an already-imperfect artifact.
Note: errors_subset(cand, base) is already computed in guard_ara004 but is currently dead code behind the Ok early-return. The main implementation wrinkle is that parse_sources discards the manifest on any error, so recovery verification must use the tree-isolated claims_only(...) parse the guard already uses for the base claim set — extend that to the candidate side so the post-fix claim set is readable even when the tree still errors.
Acceptance
ara check --fix corpus/speedrun/nanogpt-speedrun (on a copy) recovers the C01–C10 headers and clears the resulting unknown claim errors.
- No fix is ever applied that introduces a new error diagnostic.
--fix remains idempotent; a discarded fix still leaves the file byte-identical.
- Add a corpus-style test with a pre-existing unrelated error to lock in the relaxed-but-safe behavior.
Follow-up from #41. See also the "conservative on an already-broken artifact" concern noted during that implementation.
Problem
ara check --fix(added in #41) applies a fix only when the whole artifact re-parses fully clean. On the messy real corpus — where, perdocs/ara-format-feedback.mditem 13, "none parse cleanly; about half emit errors" — this means--fixusually applies nothing, even when the fixable drift is itself the cause of the errors.The guard's
Ok-gate is here:The
guard_aliaspath (ARA002/ARA003) is similarly conservative: it requires a clean base parse to compute its targeted one-field diff, so an unrelated pre-existing error (duplicate id, cycle, etc.) discards those fixes too.Evidence (from an
ara checksweep over the 14 vendored fixtures)Detection is correct (0 panics; 2 artifacts flagged with real
ARA004dash-header drift), but--fixapplied 0 fixes to both fixable artifacts:corpus/speedrun/nanogpt-speedrun— all 10 claimsC01–C10use em-dash headers (## C01 — …), so none parse, producing 29evidence references unknown claimerrors. The dash headers ARE the cause of those errors. Fixing them would recover the claims and clear the errors — but the fixpoint loop applies one fix at a time, and each single fix still leaves the artifact erroring, so every candidate is rejected and nothing moves.corpus/rebench/rebench-restricted_mlm— theschema_version: "ara-2.0"shape (notree:/root:); the base parse errors fatally, so all fixes are blocked. (This one is out of scope — a genuinely different format — and is fine to leave blocked.)Proposed change
Relax the value-recovering guards (ARA004, and ARA002/003) from "must re-parse fully clean" to "must not introduce new errors" — i.e. accept the edit when
errors_subset(cand, base)holds (the edited artifact's error set is a subset of the pre-fix error set) plus the existing targeted-recovery + idempotence checks. This keeps the safety guarantees (never adds an error, never corrupts a file, still idempotent) while letting a fix proceed on an already-imperfect artifact.Note:
errors_subset(cand, base)is already computed inguard_ara004but is currently dead code behind theOkearly-return. The main implementation wrinkle is thatparse_sourcesdiscards the manifest on any error, so recovery verification must use the tree-isolatedclaims_only(...)parse the guard already uses for the base claim set — extend that to the candidate side so the post-fix claim set is readable even when the tree still errors.Acceptance
ara check --fix corpus/speedrun/nanogpt-speedrun(on a copy) recovers theC01–C10headers and clears the resultingunknown claimerrors.--fixremains idempotent; a discarded fix still leaves the file byte-identical.Follow-up from #41. See also the "conservative on an already-broken artifact" concern noted during that implementation.