claim(M1): samever resolver step-back implemented + unit-tested (13 pass)
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
WHAT/HOW/EXPECTED/WHERE in STATUS-samever.md. Adversary: cold pytest tests/unit/test_upgrade_base.py → 13 passed; canonical==head steps back to a strictly-older base, canonical!=head unchanged, no-older→declared skip.
This commit is contained in:
43
machine-docs/JOURNAL-samever.md
Normal file
43
machine-docs/JOURNAL-samever.md
Normal file
@ -0,0 +1,43 @@
|
||||
# JOURNAL — phase `samever` (Builder reasoning; Adversary does not read before verdict)
|
||||
|
||||
## 2026-06-17 — M1 design + implementation
|
||||
|
||||
**Root cause (confirmed against `runner/run_recipe_ci.py`):** the warm-canonical path of
|
||||
`resolve_upgrade_base` returned `BasePlan("version", rec["version"], …)` unconditionally — it was
|
||||
never given the head's *version*, only `head_ref` (a commit sha), so it could not detect the
|
||||
canonical==head collision. The ref (main-tip) path was already guarded (`main_tip == head_ref →
|
||||
skip`); the version path was not. In the nightly steady state a green cold-on-latest run promotes
|
||||
`canonical → latest`, so the *next* night finds `canonical == latest == version-under-test` and the
|
||||
upgrade tier deploys base==head: a vacuous same-version "upgrade."
|
||||
|
||||
**Why pass `head_version` as a param rather than read compose inside the resolver:** keeps the
|
||||
resolver pure/unit-testable (the existing 8 tests inject `canonical.read_registry` /
|
||||
`lifecycle.recipe_branch_commit` via monkeypatch and never touch the filesystem). The call site
|
||||
(`main()`) reads it once via `abra.head_compose_version(recipe)` from the head checkout that already
|
||||
exists on disk. Tests pass `head_version=` directly.
|
||||
|
||||
**Why `version_key`-based equality instead of raw string `==`:** the canonical record version and the
|
||||
compose label *should* be byte-identical when equal, but routing both through the existing coop-cloud
|
||||
ordering key (`warm_reconcile.version_key`) means a re-published or incidentally-reformatted equal
|
||||
version still compares equal, and the step-back's "strictly older" uses the *same* single ordering
|
||||
source — no hand-rolled semver (plan §2 constraint). `version_key` is the inner key of the existing
|
||||
`sort_versions`, lifted out so `sort_versions`/`newest_older_version` share it (no behavior change to
|
||||
`sort_versions` — verified by the unchanged existing warm_reconcile tests).
|
||||
|
||||
**Why the step-back inherits F1d-2 automatically:** it returns `kind="version"` exactly like the
|
||||
normal canonical base, so it flows through the same deploy path (`abra.recipe_checkout` pins the tag
|
||||
on disk, non-chaos deploy) — the chosen older base genuinely deploys that pinned version, never
|
||||
LATEST. No new deploy code; the protection is structural.
|
||||
|
||||
**Skip only when genuinely no older predecessor:** `newest_older_version` returns None only when the
|
||||
head version is the oldest (or only) published tag — then, and only then, a declared skip
|
||||
(`"base == head … and no older published predecessor"`), never a same-version no-op.
|
||||
|
||||
**`head_version is None` (compose unreadable / no label):** cannot compare → `same=False` →
|
||||
preserves prevb behavior exactly (canonical is primary). No regression for any caller that omits
|
||||
`head_version`; the existing `test_last_green_warm_canonical_is_primary` still passes unchanged.
|
||||
|
||||
**Pre-existing unrelated failures** (confirmed failing on clean `279d84d` with my changes stashed,
|
||||
so NOT introduced here): `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` (KeyError
|
||||
'health_domain'). Out of scope for samever.
|
||||
Reference in New Issue
Block a user