From f97ed0299afc5778651fb30b9455aca236655df9 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Wed, 17 Jun 2026 04:11:09 +0000 Subject: [PATCH] =?UTF-8?q?review(samever):=20Adversary=20orientation=20?= =?UTF-8?q?=E2=80=94=20samever=20phase=20started;=20awaiting=20M1=20claim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machine-docs/REVIEW-samever.md | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 machine-docs/REVIEW-samever.md diff --git a/machine-docs/REVIEW-samever.md b/machine-docs/REVIEW-samever.md new file mode 100644 index 0000000..a3dd93c --- /dev/null +++ b/machine-docs/REVIEW-samever.md @@ -0,0 +1,74 @@ +# REVIEW — phase `samever` (Adversary writes here) + +**Phase:** samever — step back to older base when canonical == head version (no same-version upgrade) +**SSOT:** `/srv/cc-ci/cc-ci-plan/plan-phase-samever-older-base-fallback.md` +**Adversary loop started:** 2026-06-17T04:09Z +**Adversary clone:** /srv/cc-ci/cc-ci-adv + +--- + +## Gate verdicts + +(none yet — waiting for Builder M1 claim) + +--- + +## Orientation @2026-06-17T04:09Z + +Phase `samever` plan created 2026-06-17T03:56Z. Builder has not yet started (no STATUS-samever.md). + +**Root cause confirmed (cold-read of resolver, lines 133–148 of run_recipe_ci.py):** +```python +rec = canonical.read_registry(recipe) +if rec and rec.get("version"): + return BasePlan( + "version", + rec["version"], + None, + f"last-green (warm canonical, status={rec.get('status')})", + ) +``` +The warm-canonical path returns `canonical["version"]` WITHOUT checking if it equals the head version. +The resolver is not passed the head's semantic version (only `head_ref`, a commit sha), so it cannot compare. + +**Current unit tests (8 tests in tests/unit/test_upgrade_base.py) — none cover canonical==head:** +- test_upgrade_not_in_stages_skip +- test_expected_na_upgrade_skip_even_with_canonical_and_override +- test_explicit_override_wins_over_canonical +- test_last_green_warm_canonical_is_primary ← uses canonical["version"]="0.6.0+3.1.1", HEAD="aaaa1111head" (different version — correct but doesn't test the same-version edge) +- test_main_tip_fallback_when_no_last_green +- test_head_equals_main_tip_skip +- test_no_canonical_no_main_skip +- test_expected_na_other_rung_does_not_suppress_upgrade + +**Key utilities available for the fix:** +- `warm_reconcile.recipe_tags(recipe)` — returns all git tags from recipe clone +- `warm_reconcile.sort_versions(tags)` — ascending sort of version tags (coop-cloud semver) +- `warm_reconcile.latest_version(tags)` — the newest tag +- Head version read from compose.yml: `coop-cloud.${STACK_NAME}.version` label at `abra.recipe_dir(recipe)/compose.yml` (head checkout already at that path when resolver runs) + +**M1 verification plan (what I'll cold-verify when claimed):** +1. Resolver reads head version from compose.yml (inspect the parsing — look for compose YAML read + `coop-cloud.*version` label extraction) +2. New chain: override → (canonical if canonical≠head_version) → (newest older published if canonical==head_version) → main-tip → skip +3. Unit tests added: at minimum canonical==head→step_back, canonical≠head→unchanged, no_older_published→skip, version ordering correct +4. Run `python -m pytest tests/unit/test_upgrade_base.py -v` cold from own clone +5. Confirm OVERRIDE, EXPECTED_NA, main-tip, skip paths are untouched (regression: existing 8 tests still pass) +6. Teeth check: a "broken base" scenario should still fail (unit test or from plan F1d-2 evidence) + +**M2 verification plan:** +1. Cold-on-latest run on an enrolled recipe whose canonical == latest (seed the canonical to latest, then trigger cold run) +2. Evidence in logs: `base_version < head_version` (not a no-op, not a skip) +3. Re-run discourse #4 or equivalent version-bump PR → UNAFFECTED (canonical→head path still uses canonical) +4. Spot-check ≥1 other recipe + +--- + +## Adversary findings + +(empty — phase not yet started) + +--- + +## Break-it probes log + +(none yet)