Implemented
2026-03
Remediation (semantic fixes) requires clean YAML as input. If formatting and semantic fixes are interleaved, diffs become noisy and convergence is harder to guarantee.
| Option | Pros | Cons |
|---|---|---|
| Format + fix in one pass | Single pipeline | Noisy diffs, hard to verify formatter stability |
| Format as Phase 1, then fix | Clean separation, idempotency gate | Two passes over files |
| Route formatter through remediation engine | Unified pipeline | Requires artificial "formatting violations", scan-before-format |
YAML formatter runs as Phase 1, completely independent of the scan and remediation engine.
The pipeline is:
format → idempotency gate → scan → remediate → rescan → converge
- The formatter (
ruamel.yamlround-trip) normalizes:- Indentation
- Key ordering
- Jinja spacing
- Tab removal
- Idempotency is verified by running the formatter twice — if the second pass produces any diffs, the formatter has a bug and the pipeline aborts
- Subsequent semantic diffs are clean because formatting noise has been eliminated
- The formatter does not consume violations — it operates on raw YAML
- Clean semantic diffs
- Idempotency guarantee
- Formatter bugs caught early
- Separation of concerns
- Two passes over files
- Formatter must be idempotent
def verify_idempotency(path: Path) -> bool:
"""Format twice, verify no diff on second pass."""
format_yaml(path)
first_content = path.read_text()
format_yaml(path)
second_content = path.read_text()
if first_content != second_content:
raise FormatterNotIdempotentError(path)
return Trueformatter:
indent_sequences: 2
indent_mappings: 2
preserve_quotes: true
explicit_start: true
jinja_spacing: true- Format: Normalize all YAML files
- Idempotency Gate: Re-format, verify zero diff
- Scan: Run all validators
- Remediate: Apply Tier 1 transforms
- Rescan: Verify fixes
- Converge: Repeat 4-5 until stable
- ADR-009: Remediation engine (consumes formatted YAML)