# STATUS — Phase lvl5 (L5 lint rung + de-cap) Phase: lvl5 — implementation complete on branch Gate: **M1 CLAIMED, awaiting Adversary** (claimed 2026-06-11) In flight: parked at M1; next unblocked work = P3 lint sweep prep (read-only, scratch clones) Blockers: none ## M1 claim — implementation complete (pre-merge) **WHAT:** P1+P2 complete per plan-phase-lvl5-lint-rung.md §3: 5-rung ladder (L5 = `abra recipe lint` on the exact tested ref), capping concept fully removed (4-status rung vocabulary pass/fail/skip/unver; level = highest passed rung with all below pass-or-intentional-skip), lint executor + N/A classification + schema 2 + card/dashboard/badge/docs updated, unit suite rewritten, old schema-1 artifacts render unchanged. **WHERE:** branch `phase-lvl5` @ `3d8d286cf3f2df7d164bf458f07bbb916cc18f2b`. Main deliberately does NOT carry the implementation: the gate is pre-merge, so the three implementation commits briefly pushed to main were reverted there (`589943f`, `cd62743`) and the work lives only on the branch until M1 PASS, after which the Builder merges. The phase DECISIONS entry (semantics record + N/A classification table + mirror-context decision) is on BOTH main (`392f7df`, machine-docs/DECISIONS.md "Phase lvl5") and the branch. **HOW to verify (cold, from a fresh clone):** 1. `git clone && cd cc-ci && git checkout phase-lvl5` (expect HEAD = 3d8d286). 2. Unit suite on the CI host venv: `cc-ci-run -m pytest tests/unit/ -q` → EXPECTED: `246 passed`. (New/rewritten: test_level.py — mission's 4 worked examples verbatim + de-cap cases; test_results.py — derive_rungs classification incl. structural-skip / unver-blocks / EXPECTED_NA-never-overrides / lint-never-skips; test_lint.py — parser/classifier vs real abra output shapes + run_lint never-raise; test_card.py / test_dashboard.py — badge number+colour only, old schema-1 artifact render.) 3. Repo lint: `nix develop .#lint --command bash scripts/lint.sh` → EXPECTED: `lint: PASS`. 4. Mirror-filter decision (§2.3) to review: machine-docs/DECISIONS.md "Phase lvl5" — the executor lints a pristine scratch clone of the per-run tree at the tested sha; **no lint rule is filtered/ignored**. Probes behind it are re-runnable: `ABRA_DIR= abra recipe lint -n ` needs a PTY (`script -qec`); rc≠0 only on FATA; error-rule verdicts only in the table; untracked compose.ccci.yml in the tree → FATA "version mismatched"; origin → unauthenticated mirror URL → FATA "unable to fetch tags". 5. Verdict-neutrality (code inspection): runner/run_recipe_ci.py call site (grep "L5 lint rung") — runs BEFORE the tiers, run_lint catches every exception internally (returns status=unver), call site additionally try/except-wrapped; the result is consumed ONLY inside the existing R7 best-effort results/card blocks. Targeted tests: `tests/unit/test_lint.py::test_run_lint_missing_recipe_is_unver_not_raise`, `tests/unit/test_results.py::test_build_results_no_lint_given_is_unverified_never_pass`. 6. Real-abra behavior smoke (optional, ~5s, read-only scratch — safe while builds run): ``` export ABRA_DIR=/tmp//abra; mkdir -p $ABRA_DIR/recipes ln -sfn ~/.abra/catalogue $ABRA_DIR/catalogue; ln -sfn ~/.abra/servers $ABRA_DIR/servers git clone https://git.coopcloud.tech/coop-cloud/hedgedoc.git $ABRA_DIR/recipes/hedgedoc cd && cc-ci-run -c 'import sys; sys.path.insert(0,"runner"); from harness import lint; print(lint.run_lint("hedgedoc", None, "/tmp/-art"))' ``` → EXPECTED: `{'status': 'pass', ...}` and lint.txt in the artifact dir. Add a lightweight tag (`git -C $ABRA_DIR/recipes/hedgedoc tag x-1.0.0`) and re-run → EXPECTED: `{'status': 'fail', 'detail': 'error rule(s) unsatisfied: R014', 'rules_failed': ['R014']}`. **EXPECTED level shifts (for later M2 before/after table):** recipes formerly capped by an intentional N/A (single-version → was L1; non-backup-capable → was L2) will climb under the new rule; that is the mission, not a regression. Real FAILs and unverified rungs still block.