# STATUS — Phase 2b (confirm the test sequence minimizes deploys) **Phase plan (SSOT):** `/srv/cc-ci/cc-ci-plan/plan-phase2b-test-performance.md` **Loop state for THIS phase:** STATUS-2b / BACKLOG-2b / REVIEW-2b / JOURNAL-2b (DECISIONS.md shared). Phase 1/1*/2/2* STATUS/BACKLOG/REVIEW files are HISTORY — not this phase's state. ## Phase NARROWED scope (operator 2026-05-30): the only task is to **confirm the per-recipe test sequence already uses the minimum number of deploys** (and fix it if not) **without weakening any test**. The broad empirical-perf program is parked in IDEAS. Likely outcome (operator's expectation): already minimal via the deploy-once / deploy-sharing design. ## Definition of Done (Phase 2b) — B1–B4, each Adversary cold-verified in REVIEW-2b - [x] **B1 — Deploy budget documented and minimal.** PASS (REVIEW-2b @2026-05-31T05:38Z, `edf34e3`). - [x] **B2 — Enforced, not just claimed** (deploy-count guard + RUN SUMMARY, expected reflects budget). PASS (REVIEW-2b @2026-05-31T05:38Z). - [x] **B3 — No test weakened to save a deploy** (coverage/isolation/teardown unchanged). PASS (REVIEW-2b @2026-05-31T05:38Z; claim is doc-only, harness byte-identical). - [x] **B4 — Recorded** (`docs/perf/deploys.md`). PASS (REVIEW-2b @2026-05-31T05:38Z). ## DONE All four DoD items (B1–B4) Adversary cold-verified **PASS** in REVIEW-2b @2026-05-31T05:38Z (commit `edf34e3`); no Phase-2b VETO. Outcome: the per-recipe test-sequence deploy budget was **already minimal** (`1 base + N_cold_deps`, upgrade shares the base in place) and **enforced** (DG4.1); no redundant deploy existed, so none was removed. Recorded in `docs/perf/deploys.md` + DECISIONS.md. **Sequencing note (operator):** Phase 2b ran as a manually-kicked-off parallel loop; Phase 2 is not yet `## DONE` (plausible Q4.7b / drone Q4.10 / Q5 remain — standing Phase-2 DONE VETO in REVIEW-2.md). Phase-2b's DoD is independent of Phase-2 completion and is fully verified. Whether Phase-2b DONE is acknowledged before Phase-2 DONE is an operator sequencing call, not a verification gap. --- ## Gate: 2b CLAIMED, awaiting Adversary (@2026-05-31, commit on origin/main) **Outcome: the per-recipe deploy budget is ALREADY MINIMAL and ENFORCED. No redundant deploy found; none removed because none existed.** This is a confirm-and-document result (no harness behavior change). Deliverable: `docs/perf/deploys.md`. ### WHAT is claimed (the budget) Per cold `run_recipe_ci.py` run of a recipe: ``` deploys == 1 (base) + N_cold_deps # enforced as a hard failure ``` - **1 base deploy** shared by ALL five tiers: install → upgrade → backup → restore → custom. - **+1 per COLD declared dep**, deployed once and reused; a **live-warm** dep contributes **0**. - The **upgrade tier adds NO deploy**: the base is deployed at the **previous published version** when upgrade runs (`base = prev or target`), and the upgrade is an **in-place chaos redeploy** of PR-head onto that same app — NOT counted, and the real HC1 upgrade under test. - **backup/restore add NO deploy** (operate on the same running app). - This is **tighter** than plan B1's nominal `1 + 1(upgrade) + N` because the base deploy *is* the prior-version deploy — the prior-version and base deploy are the same deploy. ### HOW the Adversary can verify (from a fresh clone) **(a) Static — only `deploy_app` increments the count, and it's called in exactly 3 sites:** ``` grep -n "_record_deploy" runner/harness/lifecycle.py # called ONLY inside deploy_app (:107, :211) grep -rn "deploy_app(" runner/ | grep -v "def deploy_app" # 3 callers: :699 :819 (+ deps.py:100) ``` - `lifecycle.py:211` — `deploy_app` is the sole caller of `_record_deploy`. - `run_recipe_ci.py:819` — the single base deploy (cold main path). - `runner/harness/deps.py:100` — one per declared dep. - `run_recipe_ci.py:699` — `promote_canonical` (WC5), which **pops** `CCCI_DEPLOY_COUNT_FILE` first (`:697`) so it is OUTSIDE the per-run budget (post-green warm-cache maintenance, not a test deploy). - `lifecycle.chaos_redeploy` (the upgrade, `lifecycle.py:418-435`) does **NOT** call `deploy_app` → not counted (docstring states this explicitly). - `generic.perform_backup`/`perform_restore` → `backup_app`/`restore_app`: no `deploy_app` → not counted. - Base-version selection that makes upgrade share the base deploy: `run_recipe_ci.py:746-754` (`want_upgrade`; `prev = UPGRADE_BASE_VERSION or previous_version`; `base = prev or target`). **(b) Enforcement — DG4.1 guard hard-fails on mismatch:** ``` sed -n '958,1010p' runner/run_recipe_ci.py ``` - `expected_deploy_count = 1 + deps_deployed_count` (`:984`); warm deps excluded (`:982-983`). - RUN SUMMARY prints `deploy-count = N (expect M)` (`:986`). - `if deploy_count != expected_deploy_count: … overall = 1` → non-zero exit (`:1005-1010`). ⇒ every GREEN run proves the recipe stayed within budget; a redundant redeploy turns it RED. **(c) Dynamic (optional, cold) — re-run a no-dep and a cold-dep recipe:** ``` RECIPE=ghost STAGES=install,upgrade,backup,restore,custom cc-ci-run runner/run_recipe_ci.py RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py ``` **(d) B3 — coverage unchanged:** confirm all five tiers still run their real generic+overlay assertions against the shared app (`run_lifecycle_tier`, `ALL_STAGES` `run_recipe_ci.py:56`), the upgrade is a real prev→PR-head crossover (`assert_upgraded`), and P4 backup→restore is real data-integrity (seed→backup→mutate→restore→assert). Nothing is skipped/softened to share the deploy. **(e) B4 — the record:** `docs/perf/deploys.md` (this deliverable). ### EXPECTED outcomes - (a) `_record_deploy` appears only inside `deploy_app`; exactly the 3 `deploy_app` callers above. - (b) guard present and hard-failing as quoted; `expected = 1 + cold_deps`. - (c) ghost: `deploy-count = 1 (expect 1)`, all tiers `pass`. lasuite-docs + cold keycloak: `deploy-count = 2 (expect 2)`, `deps deployed: ['keycloak']`, all tiers `pass`, `DEPS teardown` clean. - Historical corroboration (Phase 2 runs, recorded in STATUS-2/REVIEW-2): every recipe ran at `deploy-count = 1` (no/warm dep) or `deploy-count = 2 (expect 2)` (one cold dep, lasuite-docs Q2.4 — REVIEW-2 `:114`). No run ever exceeded `1 + N_cold_deps`. ### WHERE the inputs live - Deliverable doc: `docs/perf/deploys.md`. - Code: `runner/run_recipe_ci.py` (`:56`, `:746-754`, `:819`, `:958-1010`), `runner/harness/lifecycle.py` (`:107-211`, `:418-435`), `runner/harness/deps.py` (`:81-120`), `runner/harness/generic.py` (`perform_upgrade`/`perform_backup`/`perform_restore`). - Commit: see `git log origin/main` for the `claim(2b)` commit. ## Gates - Gate 2b — CLAIMED, awaiting Adversary PASS in REVIEW-2b.