5.6 KiB
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
- Gate: M1 CLAIMED, awaiting Adversary. (claim commit below.)
Gate: M1 — CLAIMED @2026-06-17T00:40Z (HEAD e1b32ea)
WHAT (DoD §4 M1): dynamic upgrade-base resolution (last-green → main-tip → skip); previous/
discovery + base-only application + version-guard/stale-flag; environmental overlay separated from
version-specific config; UPGRADE_BASE_VERSION removed from discourse; discourse migrated; unit tests
for the new surface; discourse upgrade tier GREEN locally with proof the head ran the real official
image (discourse/discourse:3.5.3, NOT bitnamilegacy) and no sidekiq service post-deploy.
WHERE (commit e1b32ea on origin/main):
runner/run_recipe_ci.py:BasePlan+resolve_upgrade_base(stages, meta, recipe, head_ref)(override → last-green viacanonical.read_registry→ main-tip vialifecycle.recipe_branch_commit→ skip); wired inmain()(deploybase_ref/apply_previous, gate upgrade tier onbase_plan.runs).runner/harness/lifecycle.py:previous_*surface (has_previous,previous_target_version,previous_status,provide/remove_previous_overlay,compose_file_add/remove),recipe_branch_commit,stack_service_names,compose_services,prune_orphan_services;deploy_appbase_ref/apply_previouspaths.runner/harness/generic.pyperform_upgrade: stripprevious/overlay + COMPOSE_FILE entry before head redeploy;prune_orphan_servicesafter convergence (reconcile stack to head compose).tests/discourse/compose.ccci.yml: ENVIRONMENTAL-only (app.deploy.update_config.order: stop-first; bitnamilegacy pins +sidekiqremoved).tests/discourse/recipe_meta.py:UPGRADE_BASE_VERSIONremoved.tests/discourse/test_upgrade.py: asserts head image == official 3.5.3 (not bitnamilegacy) + no sidekiq.- Unit:
tests/unit/test_upgrade_base.py(resolver matrix),tests/unit/test_previous.py(previous/ + COMPOSE_FILE layering).
HOW to verify (cold, from a fresh clone at e1b32ea):
- Unit (prevb surface):
cc-ci-run -m pytest tests/unit/test_upgrade_base.py tests/unit/test_previous.py tests/unit/test_meta.py -q. - e2e:
RECIPE=discourse SRC=recipe-maintainers/discourse REF=ae5a81802b4d1d6cd1b449ac46cfa16d80730aaa PR=4 STAGES=install,upgrade cc-ci-run runner/run_recipe_ci.py(HOME=/root). - Inspect:
grep -vE '^\s*#' tests/discourse/compose.ccci.yml(env-only);grep UPGRADE_BASE_VERSION tests/discourse/recipe_meta.py(none).
EXPECTED:
- Unit: all pass (38 across the 2 prevb files; test_meta clean). NOTE scope: the prevb surface is green;
the FULL
tests/unit/suite has 1 PRE-EXISTING unrelated fail —test_warm_reconcile.py::test_traefik_spec_is_stateless_with_setup(KeyError 'health_domain') — which fails identically at gtea-DONE (778720c) and was not touched by prevb (pxgate0e9fd38refactored the spec without updating the test). Out of scope for prevb; flagged to the operator/next phase. - e2e log shows:
upgrade base: kind=ref ref=f87c612d71b4 (target-branch (main) tip); base = main-tip chaos deploy;prune-orphans: removed 'sidekiq';upgrade→PR-head: head_ref=ae5a8180 chaos-version=ae5a8180+U version=0.8.1+3.5.0→1.0.0+3.5.3; RUN SUMMARYdeploy-count = 1 (expect 1),install : pass,upgrade : pass; bothtests/discourse/test_upgrade.pyasserts PASS (app image official 3.5.3 not bitnamilegacy; no sidekiq); teardown leaves no stacks/volumes/secrets. (Level caps at 2/5 because only install,upgrade ran — not a fail.)
TEETH (where a broken head still goes RED — for the Adversary's break-it probe): the upgrade tier
gates on the REAL head deploy — assert_upgrade_converged (rejects silent swarm rollback/pause) +
wait_healthy on HEALTH_PATH + HC1 chaos-version==head commit + the discourse image/sidekiq asserts.
Base resolution/prune/previous never deploy the head's code, so a deliberately-broken head cannot be
papered over: it won't converge/serve → RED. previous/ is base-only (stripped before the head redeploy,
proven by remove_previous_overlay + COMPOSE_FILE strip in perform_upgrade); discourse ships no previous/.
Ground-truth facts (verified 2026-06-17, recorded for Adversary)
recipe-maintainers/discoursePR #4 (discourse-official-imageae5a8180→mainf87c612d), open.- main (
compose.yml):app/sidekiqimage =bitnamilegacy/discourse:3.5.0;apphealthcheckstart_period: 20m;app.deploy.update_config.order: start-first;sidekiqservice present. - PR #4 head:
app.image = discourse/discourse:3.5.3(official),sidekiqservice deleted, loadbalancer port 3000→80, official-image entrypoint wrappers added. (PR.diffconfirms 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.
- main (
- Current
tests/discourse/compose.ccci.ymlre-pinsapp+sidekiqtobitnamilegacy/discourse:3.3.1, re-addssidekiq, setsstart_period:20m,order:stop-first— applied to ALL deploys viaEXTRA_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, not3.3.1(main advanced); thesis unchanged — the base (last-green/main, bitnamilegacy 3.5.0) deploys clean, NOprevious/needed for discourse.
Blocked
(none)