# JOURNAL — Phase lvl5

## 2026-06-11 bootstrap
- Read plan-phase-lvl5-lint-rung.md in full + plan.md §6/§6.1/§7/§9. Phase files created.
- Orientation reads: level.py (RUNGS 4, compute_level gap-caps, backup_restore_status, tier_to_rung), results.py derive_rungs/build_results (cap fields at :215-229), card.py (LEVEL_COLOR 0-6!, cap line :246, level_badge_svg cap_skip third segment), dashboard.py (_LEVEL_COLOR :68, _level_pill :245, cap div :277, render_level_badge :363), run_recipe_ci.py build_results call :1248 + badge wiring :1296-1320, bridge.py :224 (badge embed — number-only already, no cap text → likely untouched), docs (results-ux.md has cap language; recipe-customization.md EXPECTED_NA row).
- Notable: card.py LEVEL_COLOR already has keys 0-6 (5=green, 6=bright green) — only 0-4 reachable today; dashboard._LEVEL_COLOR needs checking for the same.
- Lint context: abra.py:105-127 documents the R014/lightweight-tag + origin-repoint/go-git history. Per-run recipe tree = $ABRA_DIR/recipes/<recipe>, origin = private mirror (SRC) on PR runs, upstream tags fetched in by fetch_recipe. OPEN QUESTION for B2: what does `abra recipe lint` actually touch (origin fetch? auth? R014 against which tags?) — probe on cc-ci host next, in a scratch clone, both origin-shapes (mirror-origin vs canonical-origin).
- Next: probe abra lint behavior on cc-ci (scratch clones, no shared-checkout touch), then B1.

## 2026-06-11 P1+P2 built, M1 claimed (branch phase-lvl5)
- level.py rewritten (5 rungs, 4-status vocabulary, compute_level → int, cap concept deleted);
  harness/lint.py executor; results.py derive_rungs classification + schema 2 + lint stage/block;
  run_recipe_ci.py wiring (lint before tiers, double-wrapped; badge level-only; unver coverage log);
  card.py/dashboard.py de-capped (0-5 ramp, ladder line, unverified rows, lint.txt servable);
  docs results-ux.md/recipe-customization.md; DECISIONS.md phase entry.
- Verified: `cc-ci-run -m pytest tests/unit/ -q` → 246 passed (cold venv on cc-ci, tree rsynced);
  `ruff format --check` + `ruff check` clean. Real-abra smoke on cc-ci:
  run_lint("hedgedoc") → pass; with a lightweight tag → fail R014 (output in /tmp/lvl5-smoke/lint.txt).
- BUG found by the real-abra smoke (would have shipped unver-everywhere): abra renders the lint
  table with HEAVY box verticals (┃ U+2503), parser matched only │ (U+2502) → "no lint table in
  output". Fixed (regex accepts both), test fixtures switched to the real heavy chars + a
  light-variant tolerance test. Lesson: the unit fixtures were hand-typed, not pasted from the
  real capture — always paste.
- test_meta.py::test_generated_doc_table_in_sync caught my hand-edit of the GENERATED meta table
  in recipe-customization.md — moved the wording into the meta.py KEYS registry and regenerated.
- PROCESS DEVIATION + correction: I pushed P1+P2 straight to main (3 commits) before re-reading
  the M1 gate text ("pre-merge ... PASS required before merge to main") — and event=custom
  recipe builds run from main, so that made unreviewed code live. Corrected within the hour:
  branch `phase-lvl5` created at the tip, main reverted (589943f docs, cd62743 feat; DECISIONS
  entry + phase state files kept on main). After M1 PASS the merge is revert-of-the-reverts or a
  plain merge of the branch (the reverts make the branch content "new" again relative to main —
  verify the merge diff matches the branch before pushing).
- M1 claimed in STATUS-lvl5.md with full cold-verify recipe.

## 2026-06-11 P3 sweep (while parked at M1)
- Sweep command shape: per recipe `git clone <canonical origin> /tmp/lvl5-sweep/abra/recipes/<r>`
  + upstream tag fetch + `run_lint(r, None, /tmp/lvl5-sweep/art/<r>)` from /tmp/lvl5-wt (branch
  tree) with ABRA_DIR=/tmp/lvl5-sweep/abra. Output: 19/19 `{"status": "pass"}`; warn misses per
  recipe captured from the ❌ rows of each lint.txt. Matrix + §2.9 baseline table → BACKLOG-lvl5.
- lasuite-meet R014 pass is genuine: all 3 version tags are annotated now (cat-file -t = tag) —
  upstream re-tagged since abra.py:105 was written.
- Baseline artifact archaeology: builds ≤205 carry an ancient SIX-rung schema (integration/
  recipe_local rungs, stored levels up to 5 under that old rule); recent builds (370/371) the
  current 4-rung. Both are schema-1 + cap fields; baseline column re-scored on the four
  essential rungs. bluesky-pds and mumble have no retained results.json.
- NB the mirror origin URLs on cc-ci embed the bot token — kept out of all committed text.

## 2026-06-11 M1 PASS consumed → merged → dashboard rolled
- M1 PASS (review cfc87fd). Merge: revert-of-reverts conflicted with branch-side parser fix →
  resolved by `git merge --no-commit phase-lvl5` + `git checkout phase-lvl5 -- runner tests
  dashboard docs` (take the Adversary-verified tip verbatim); merge 08e6cc8; verified
  `git diff phase-lvl5 main --name-only` = the four main-only state files. NB during resume a
  reflexive `git pull --rebase` tried to flatten the un-pushed merge commit → aborted, plain push
  (local was strictly ahead). Lesson: never pull --rebase with an un-pushed merge commit.
- Suite re-run from merged main rsynced to cc-ci: 246 passed.
- Dashboard rolled per the SETTLED migration-era mechanism (DECISIONS Phase 3/U2 — NO
  nixos-rebuild switch on the live host): rsync main → /root/lvl5-main, `nixos-rebuild build
  --flake path:/root/lvl5-main#cc-ci` (non-activating), ran produced
  cc-ci-reconcile-dashboard → ccci-dashboard_app now cc-ci-dashboard:15addbc7bf45, 1/1.
- Live checks: / 200; /runs/370/{results.json,summary.png} 200 (old artifacts unharmed);
  /badge/immich.svg 200 = number+colour only (#a0b93f, "level 4"); /recipe/immich 200.

## 2026-06-11 P4 wave 1 — first proofs green
- Triggered drone custom builds via bridge-token API (same shape as bridge.trigger_build).
- Build 398 hedgedoc cold: SUCCESS 100s — **genuine L5** (all five rungs pass, schema 2, no cap
  fields, lint.txt+badge 200). Build 399 custom-html-tiny cold: SUCCESS 45s — **N/A-skip climb:
  LEVEL 5 with backup_restore=skip** (declared reason in skips.intentional; was L2 at baseline
  #205). Durations nowhere near inflated (lint ≈0.7s inside).
- Lint-blocked-L4 demo: probed mechanism in scratch — extra committed compose.lintdemo.yml
  (version-matched, empty image) → R011 error ❌ table row, run_lint → fail/['R011']; deploy
  unaffected (COMPOSE_FILE="compose.yml"). Pushed branch lvl5-lintdemo to custom-html mirror
  (BRANCH only, never main), opened PR #4 (marked do-not-merge throwaway).
- !testme posted (comments 14326/14327/14328) on custom-html#4, immich#2, plausible#3 →
  bridge-triggered builds 400/401/402 (drone path ×3). Awaiting.

## 2026-06-11 P4 wave 2 — PR-path bug found by drone proof, fixed, all PR proofs green
- Builds 400-402 (first !testme wave): lint rung came back UNVER with FATA "unable to check out
  default branch" — abra lint SELECTS+CHECKS OUT the repo's default branch; a clone of the
  detached per-run PR tree has no local branch. Worse latent risk: with a stale default branch
  present abra would lint THAT, not the PR head. Fix 68c3486: `git checkout -f -B main <ref>` in
  the scratch + origin repointed to the scratch itself (offline tag fetch, zero drift) + detached
  two-commit regression test proving exact-ref content (247 tests green; real-abra detached
  smoke pass). Note the verdicts/other rungs of 400-402 were UNAFFECTED (level 4, run success) —
  the unver path degraded exactly as designed.
- Re-ran !testme ×3 (comments 14332-14334) → builds 405/406/407, all SUCCESS:
  - 405 custom-html PR4 (lintdemo): **lint fail R011 → LEVEL 4, verdict SUCCESS** — the
    lint-blocked-L4 + verdict-neutrality proof on the real drone path (61s).
  - 406 immich PR2: **LEVEL 5** (199s, = shot-phase baseline). 407 plausible PR3: **LEVEL 5** (164s).
- Visual verification (PNGs Read, badges inspected): 398 hedgedoc card "level 5 of 5" all-pass
  incl lint row, green 5 corner badge; 405 card "level 4 of 5" with red lint FAIL row; 399 card
  level 5 with "backup/restore INTENTIONAL SKIP" + declared reason inline; badge SVGs
  number+colour only (405 #a0b93f "level 4", 398 #3fb950 "level 5").
- Canaries 411 (bkp-bad) + 412 (rst-bad) + mumble cold 413 triggered.

## 2026-06-11 P4 complete — M2 claimed
- Canaries: first attempts 411/412 died in 1s (FATA no recipe — they are mirror-only, need
  SRC+REF like prior phases ran them); re-triggered as 415/416 with SRC+REF → both verdict RED,
  level 1 (re-derived designed level: no version tags on mirror → upgrade skip climbs-but-never-
  earns; backup_restore fail blocks; functional unver post-abort; lint pass).
- mumble cold 413: level 5, 80s — first retained mumble artifact, fills its table row.
- Synthesized unver-blocks: hand-run `RECIPE=custom-html STAGES=install,upgrade,custom
  CCCI_RUN_ID=lvl5-unver-demo cc-ci-run runner/run_recipe_ci.py` (log /tmp/lvl5-unver-run.log,
  rc=0) → results.json level=2, backup_restore=unver, functional+lint pass above it — mission
  worked example #3 on the real harness.
- OBSERVATION (pre-existing, not phase scope): the green STAGES-filtered hand-run triggered WC5
  promote (canonical custom-html advanced) — should_promote_canonical doesn't check stage
  completeness. Surfaced to Adversary in the M2 claim notes; not fixing inside this phase.
- M2 claimed in STATUS-lvl5 with the full evidence table (runs 398/399/405/406/407/413/415/416 +
  lvl5-unver-demo). B11 ticked.

## 2026-06-11 M2 PASS → DONE
- M2 PASS (review 13cad1f, @11:27Z) — all 13 evidence points cold-verified, §6 DoD satisfied,
  no VETO, cleared for ## DONE. Both gates passed today (M1 cfc87fd, M2 13cad1f); no standing VETO.
- Cleanup: PR custom-html#4 closed + branch lvl5-lintdemo deleted (204). WC5 stage-completeness
  observation filed to machine-docs/DEFERRED.md (operator decision; Adversary concurs not a finding).
- Phase complete: L5 lint rung + de-capped level semantics live end-to-end.
