# STATUS — phase `samever` (step-back to older base when canonical == head version) SSOT: `/srv/cc-ci/cc-ci-plan/plan-phase-samever-older-base-fallback.md`. State files: this + BACKLOG-samever.md, REVIEW-samever.md (Adversary), JOURNAL-samever.md. DECISIONS.md shared. ## Phase Started 2026-06-17. Gates: **M1** (implemented + unit-tested), **M2** (proven in real CI). ## Current status **M1: PASS** (REVIEW-samever.md @2026-06-17T04:27Z — cold-verified, teeth hold, no regression). **M2: IN PROGRESS** — real-CI demonstration on cc-ci. Plan: custom-html cold-on-latest twice (run A promotes canonical→latest 1.13.0+1.31.1; run B = nightly steady state → step-back to 1.11.0+1.29.0, base) and no older published predecessor"`. 5. no canonical → main-tip ref / skip paths unchanged. `head_version is None` (compose unreadable) → comparison is False → canonical stays primary (prevb behavior). ## M1 — WHERE (commit + paths) - Implementation commit: **b29bb3f** (feat(samever): …), on `main`. - `runner/run_recipe_ci.py` — `resolve_upgrade_base(..., head_version=None)` new chain (canonical block ~lines 147–180); call site `main()` reads `head_version = abra.head_compose_version(recipe)` (~line 1023) and passes it. - `runner/harness/abra.py` — `head_compose_version(recipe)` (regex `coop-cloud\.[^.\s]*\.version=([^\s"']+)` over the head checkout's `compose.yml`; matches quoted + unquoted labels; does NOT match `.chaos-version`). - `runner/warm_reconcile.py` — `version_key(tag)` (lifted from sort_versions; single ordering source) + `newest_older_version(tags, version)` (newest tag with `version_key < target`; None if none / version None). - `tests/unit/test_upgrade_base.py` — 5 new tests (13 total). ## M1 — HOW to verify (cold, from a clean clone) 1. Unit suite (the gate): ``` nix shell nixpkgs#python311Packages.pytest -c pytest tests/unit/test_upgrade_base.py -v ``` **EXPECTED: 13 passed.** New tests: - `test_canonical_equals_head_steps_back_to_newest_older` — canonical==head==`10.8.0+26.6.3`, tags `[10.6.0+26.5.0, 10.8.0+26.6.3, 10.7.1+26.6.2, 10.7.0+26.6.0, not-a-version]` → `plan.version == "10.7.1+26.6.2"` (strictly older; asserts `version_key(plan.version) < version_key(head)`), `kind=="version"`, reason contains `"step-back"`. main never consulted. - `test_canonical_differs_from_head_uses_canonical_unchanged` — canonical `10.7.1+26.6.2` ≠ head `10.8.0+26.6.3` → `version==10.7.1+26.6.2`, reason `"last-green"`; recipe_tags NOT consulted. - `test_canonical_equals_head_no_older_published_skips` — canonical==head==`1.0.0+3.5.3`, tags `[1.0.0+3.5.3]` only → `kind=="skip"`, reason contains `"no older published predecessor"`. - `test_no_head_version_preserves_canonical_primary` — head_version omitted → canonical primary, no step-back. - `test_newest_older_version_ordering` — ordering helper picks correct strictly-older tag, excludes equal, None-safe. The 8 prior tests (override / EXPECTED_NA / main-tip / head==main-tip skip / no-predecessor skip / other-rung) are UNCHANGED and still pass — proving override/ref/skip paths untouched. 2. Teeth (canonical==head MUST NOT yield a same-version base): in `test_canonical_equals_head_steps_back_to_newest_older`, `plan.version != head_version` and the `version_key(plan.version) < version_key(head)` assertion fails loudly if the resolver ever returns the same version or a newer one. 3. Compose-label parse (the head-version reader): the regex extracts `10.8.0+26.6.3` from a quoted label and `3.5.3+1.24.2-rootless` from an unquoted one, and returns no match for a `.chaos-version` label (verified — see JOURNAL). Real labels confirmed on cc-ci: keycloak `10.8.0+26.6.3`, gitea `3.5.3+1.24.2-rootless`, discourse `1.0.0+3.5.3`. 4. F1d-2: the step-back returns `kind="version"`, so it flows through the SAME pinned-tag deploy path as a normal canonical base (`abra.recipe_checkout` pins the tag on disk) — no new deploy code. Note (pre-existing, NOT introduced by this gate): `tests/unit/test_meta.py::test_generated_doc_table_in_sync` and `tests/unit/test_warm_reconcile.py::test_traefik_spec_is_stateless_with_setup` fail on clean `279d84d` too (verified by stashing my changes). Out of scope for samever. ## Blocked (none)