chore(prevb): bootstrap phase state + settled dynamic-base/previous decisions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
autonomic-bot
2026-06-17 00:04:43 +00:00
parent 7517c4f58c
commit 423ebcbcbc
4 changed files with 116 additions and 0 deletions

View File

@ -0,0 +1,31 @@
# BACKLOG — phase `prevb`
SSOT: `/srv/cc-ci/cc-ci-plan/plan-phase-prevb-previous-dynamic-base.md`.
## Build backlog
### M1 — implemented + green locally
- [ ] B1. Dynamic upgrade-base resolution: last-green (warm canonical registry version) → fallback
target-branch (`main`) tip → else skip (declared reason). Replace the static
`previous_version(vers[-2])` default in `run_recipe_ci.upgrade_base`. Wire into `main()` deploy.
- [ ] B2. `tests/<recipe>/previous/` mechanism: discovery, declared-target-version marker, base-only
application (added to base deploy's COMPOSE_FILE), head exclusion (never applied to PR head),
version-guard + stale-flag on mismatch.
- [ ] B3. Discourse migration: shrink `compose.ccci.yml` to environmental-only
(`order: stop-first`), delete bitnamilegacy image pins + sidekiq block; remove
`UPGRADE_BASE_VERSION` from `tests/discourse/recipe_meta.py`. (Expect NO `previous/`.)
- [ ] B4. Unit tests for the new surface: base resolution (last-green / main-tip / skip), `previous/`
match / skip / stale, environmental-vs-version overlay layering. Update `test_upgrade_base.py`
to the new resolver API without weakening coverage.
- [ ] B5. Discourse upgrade tier GREEN locally: base (bitnamilegacy:3.5.0) → head; assert deployed
`app` image == `discourse/discourse:3.5.3` (NOT bitnamilegacy) and no `sidekiq` service post-deploy.
- [ ] B6. CLAIM M1 (clean tree + STATUS verification block).
### M2 — proven in real CI + spot-check
- [ ] B7. discourse PR #4 `!testme` GREEN in real CI; head ran `discourse/discourse:3.5.3`, migration exercised.
- [ ] B8. Spot-check ≥3 other upgrade-tier recipes (warm-canonical / published-predecessor / ex-`.ccci`
e.g. keycloak/cryptpad/ghost) still green under dynamic base. Reconcile levels/records.
- [ ] B9. CLAIM M2 → `## DONE` after fresh Adversary PASS on M1+M2.
## Adversary findings
(Adversary-owned section — Builder does not edit below.)

View File

@ -1441,3 +1441,24 @@ but stays well within the ≤90 s budget. Acceptable.
(same model as keycloak realm marker). Idempotent creation (409 = already exists → OK).
`pre_restore` deletes it to create a genuine divergence from backup state; `test_restore` asserts
its return. The sqlite3 DB is the persistence layer being tested.
- **Dynamic upgrade base — SETTLED (2026-06-17, phase prevb).** The upgrade tier's BASE version is
resolved at run time, replacing the static `previous_version(vers[-2])` default. Resolution order:
(1) **last-green** = the warm-canonical registry record (`canonical.read_registry(recipe).version`,
status warm/idle) when present; (2) fallback **target-branch (`main`) tip** = the recipe repo's
`main` HEAD (a git ref, chaos-deployed) — the true predecessor the PR merges onto; (3) **else skip**
the upgrade tier with a declared reason (new recipe / no predecessor / head==main). EXPECTED_NA[upgrade]
and `upgrade∉stages` still short-circuit to skip first. `UPGRADE_BASE_VERSION` is RETAINED as an
optional explicit override (wins when set) for the rare PR-adds-version-above-newest-tag case, but is
no longer the default and is removed from discourse. This intentionally changes every recipe's default
base from `vers[-2]` to last-green/main-tip (plan-mandated; M2 spot-check validates non-regression).
- **Per-recipe `previous/` overlay — SETTLED (2026-06-17, phase prevb).** `tests/<recipe>/previous/`
optionally holds the minimal config to deploy the *previous (last-green) version* when it can't deploy
as-published (e.g. `compose.previous.yml` for an image relocation). It declares the version it targets
(a `previous/VERSION` marker line) and the harness applies it **only to the base deploy and only when
the resolved base is that exact published version**; it is NEVER applied to the PR head, and on a
main-tip base or version mismatch it is SKIPPED and flagged stale ("previous/ targets X, base is Y —
remove it"). The all-deploys `compose.ccci.yml` overlay is now ENVIRONMENTAL-only (node-reality tweaks,
no version-specific image pins or service add/drop); version-specific repairs live in `previous/`.
Discourse ships NO `previous/` (base bitnamilegacy:3.5.0 deploys clean).

View File

@ -0,0 +1,37 @@
# JOURNAL — phase `prevb` (Builder reasoning; append-only)
## 2026-06-17 — Bootstrap + recon
Read SSOT (plan-phase-prevb), plan.md §6.1/§7/§9, Adversary's REVIEW-prevb (live, idle awaiting M1 claim).
**Mapped the harness upgrade flow** (`runner/run_recipe_ci.py`, `harness/lifecycle.py`,
`harness/generic.py`, `harness/meta.py`, `harness/canonical.py`):
- Base decision: `upgrade_base(stages, meta, recipe)``None` if upgrade∉stages or EXPECTED_NA[upgrade],
else `meta.UPGRADE_BASE_VERSION or lifecycle.previous_version(recipe)` (= `recipe_versions[-2]`).
`base = prev or target`; `prev` also gates whether the upgrade tier runs.
- Deploy: `deploy_app(version=base)` → pinned `recipe_checkout(version)` + (auto-chaos if overlay/lightweight tag);
`version=None` → chaos deploy of the current (head) checkout.
- Overlay `compose.ccci.yml`: copied into the checkout (`provide_ccci_overlay`), referenced by
`EXTRA_ENV.COMPOSE_FILE`, persists untracked across the head re-checkout → applies to ALL deploys.
- Upgrade op (`generic.perform_upgrade`): `recipe_checkout_ref(head_ref)` then chaos redeploy; the
ccci overlay persists → leaks version-specific pins onto the head. **That is the bug.**
- Last-green source: `canonical.read_registry(recipe)``{version, commit, status}` (promoted only on
GREEN LATEST cold runs for `WARM_CANONICAL` recipes). No separate "last-green" file.
**Ground-truth discourse facts** (gitea API, verified — see STATUS for the table). Key correction vs
plan §3 prose: main is `bitnamilegacy/discourse:3.5.0` (not 3.3.1 — main advanced). Thesis holds: base
(last-green/main = bitnamilegacy 3.5.0, deployable) → head (PR #4 = official discourse/discourse:3.5.3,
sidekiq dropped). So discourse needs NO `previous/`; the env overlay shrinks to `order: stop-first`.
**Design decisions (WHY):**
- *Resolution order* last-green → main-tip → skip. main-tip = the recipe's `main` branch HEAD = the true
predecessor the PR merges onto (more faithful than the old `vers[-2]`, which could span 2 version jumps).
This intentionally changes EVERY recipe's default base from `vers[-2]` to main-tip — plan-mandated, not a
regression; M2 spot-check validates representative recipes still go green.
- *Keep `UPGRADE_BASE_VERSION` as an optional explicit override* (still wins when set), but remove it from
discourse and make the DEFAULT dynamic. Rationale: fully deleting the meta field would break `plausible`
(its meta sets it) and the documented "PR adds a version above newest tag" escape hatch, without a deploy
test — risk vs guardrail "don't regress other recipes". The plan's "UPGRADE_BASE_VERSION removed" is in the
discourse-migration context; the normal/discourse path is now hardcode-free. Recorded in DECISIONS.
- *`previous/` scoped to last-green (published-version) base only* — version-guarded by a declared target;
on a main-tip base or version mismatch it is skipped + flagged stale. Discourse ships none (base deploys clean).

View File

@ -0,0 +1,27 @@
# STATUS — phase `prevb` (dynamic upgrade base + per-recipe `previous/`)
SSOT: `/srv/cc-ci/cc-ci-plan/plan-phase-prevb-previous-dynamic-base.md`.
State files: this + BACKLOG-prevb.md, REVIEW-prevb.md (Adversary), JOURNAL-prevb.md. DECISIONS.md shared.
## Phase
Started 2026-06-17. Gates: **M1** (implemented + green locally), **M2** (proven in real CI + spot-check).
## Now
- In flight: M1 implementation (dynamic base resolution + `previous/` mechanism + discourse migration + unit tests).
- No gate CLAIMED yet.
## Ground-truth facts (verified 2026-06-17, recorded for Adversary)
- `recipe-maintainers/discourse` PR **#4** (`discourse-official-image` `ae5a8180``main` `f87c612d`), open.
- **main** (`compose.yml`): `app`/`sidekiq` image = `bitnamilegacy/discourse:3.5.0`; `app` healthcheck
`start_period: 20m`; `app.deploy.update_config.order: start-first`; `sidekiq` service present.
- **PR #4 head**: `app.image = discourse/discourse:3.5.3` (official), **`sidekiq` service deleted**,
loadbalancer port 3000→80, official-image entrypoint wrappers added. (PR `.diff` confirms both.)
- Published tags max = `0.7.0+3.3.1`; main (3.5.0) is AHEAD of all tags → main-tip is a branch ref, not a tag.
- Current `tests/discourse/compose.ccci.yml` re-pins `app`+`sidekiq` to `bitnamilegacy/discourse:3.3.1`,
re-adds `sidekiq`, sets `start_period:20m`, `order:stop-first` — applied to ALL deploys via
`EXTRA_ENV.COMPOSE_FILE` → forces the PR head back to bitnamilegacy:3.3.1 + sidekiq (the bug).
- Note vs plan §3 prose: main is `bitnamilegacy:3.5.0`, not `3.3.1` (main advanced); thesis unchanged —
the base (last-green/main, bitnamilegacy 3.5.0) deploys clean, NO `previous/` needed for discourse.
## Blocked
(none)