Files
cc-ci/machine-docs/STATUS-2.md

322 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# STATUS — Phase 2 (per-recipe test authoring)
**Phase plan (SSOT):** `/srv/cc-ci/cc-ci-plan/plan-phase2-recipe-tests.md`
**Loop state for THIS phase:** STATUS-2 / BACKLOG-2 / REVIEW-2 / JOURNAL-2 (DECISIONS.md shared).
Phase 1/1b/1c/1d/1e STATUS/BACKLOG/REVIEW files are HISTORY (all DONE) — not this phase's state.
## Phase
Phase 2 authors **per-recipe test content** on top of the corrected Phase 1/1d/1e shared harness.
Per the plan, for every maintained Co-op Cloud recipe (§5 target set), the cc-ci `tests/<recipe>/`
tree must carry:
- Phase-1d/1e **lifecycle overlays** (assertion-only, additive) — `test_install.py`, `test_upgrade.py`,
`test_backup.py`, `test_restore.py` + `ops.py` pre-op seeds.
- **Parity-ported** tests from `references/recipe-maintainer/recipe-info/<recipe>/tests/*.py`,
one-to-one (P2), with a `PARITY.md` mapping table.
- **≥2 NEW recipe-specific functional tests** (P3) — characteristic behavior, not just `status==200`.
- **Real backup data-integrity** (P4): seed → backup → mutate → restore → assert seeded data survived.
- **Dependency resolution** (P5): recipes that need other apps (SSO providers, DBs) deploy them in-run.
- **Playwright** (P6) where the app's core UX is a UI flow.
- **Docs** (P8): `docs/enroll-recipe.md` updated with the per-recipe test contract + worked example.
## Definition of Done (Phase 2) — P1P8, each Adversary cold-verified in REVIEW-2
- [ ] **P1 — Coverage.** Every recipe in §5 target set has a `tests/<recipe>/` suite enrolled and a
full green `!testme` run (install + upgrade + backup-restore).
- [ ] **P2 — Parity port.** Every `recipe-info/<recipe>/tests/*.py` has a comparable cc-ci test;
`tests/<recipe>/PARITY.md` records the mapping; non-ports documented in DECISIONS.md.
- [ ] **P3 — Recipe-specific depth.** Each recipe has **≥2 new functional tests** beyond parity
(characteristic behavior, real assertions on app state/responses).
- [ ] **P4 — Backup data-integrity is real.** Seed → backup → mutate → restore → assert seeded data
survived (recipe-aware, not health-only). Pattern already proven in Phase 1e on custom-html.
- [ ] **P5 — Dependencies handled.** Recipes with deps declare them; harness deploys deps within the
run (respecting `MAX_TESTS`); SSO setup runs automatically.
- [ ] **P6 — Browser flows where they matter (D3).** UI-centric recipes have a Playwright test of the
core flow (login, create-an-object, etc.).
- [ ] **P7 — No weakened tests, no corners cut.** Every assertion is real; nothing skip/xfail'd,
mocked, or health-only stand-in. Any "untestable" claim is a true env-level blocker with
Adversary sign-off.
- [ ] **P8 — Docs.** `docs/enroll-recipe.md` updated with the per-recipe test contract (§4.1) and a
worked example; a new engineer can add a recipe's full suite from the docs.
## Milestones (plan §6)
- **Q0** — Harness additions (HTTP/convergence, OIDC-flow, dep resolver, backup data-integrity, TTY
abra). Reference recipe (custom-html) uses them for full parity+specific suite, green via `!testme`.
- **Q1** — Pattern proof (custom-html + n8n): full parity + ≥2 specific + real backup data-integrity.
- **Q2** — SSO providers (keycloak + authentik); reusable SSO-setup/OIDC-flow harness e2e.
- **Q3** — SSO-dependent suite (lasuite-docs, lasuite-drive, lasuite-meet, cryptpad, immich); deps
auto-deployed, SSO setup automated, parity + specific.
- **Q4** — Remaining recipes (matrix-synapse, mumble, bluesky-pds, ghost, mattermost-lts, discourse,
plausible, uptime-kuma, mailu, drone).
- **Q5** — Completeness + docs; flip `## DONE`.
## In flight
**Q3 + Q4 — recipe enrollment sprint.** After capacity unblock + Adversary checkpoint, landed:
- Q3.1 lasuite-docs partial (parity + 2 specific + Q2.4 test_oidc_with_keycloak); deeper OIDC
ports deferred in DEFERRED.md.
- Q3.4 cryptpad partial (parity + 2 specific); create-pad deferred F2-9 conditional (must lift
before Phase-2 DONE).
- Q4.1 matrix-synapse FULL (parity-aligned + 3 specific incl. §4.3 register-and-message).
- Q4.3 bluesky-pds FULL (4 functional incl. §4.3 account+post round-trip via goat CLI; F2-8 closed).
- Q4.4 ghost FULL (parity + 3 specific; create-post deferred in DEFERRED.md).
- Q4.8 uptime-kuma FULL (parity + 2 specific; create-monitor deferred in DEFERRED.md).
Harness change: `lifecycle.deploy_app` + `run_recipe_ci.py` + `deps.py` now thread
`recipe_meta.DEPLOY_TIMEOUT` into `abra.deploy(timeout=...)` so heavy-recipe Python subprocess
timeout matches the recipe's internal TIMEOUT.
DEFERRED.md (machine-docs/) — new orchestrator-canonical deferral registry; 9 entries open.
Remaining substantial: Q3.2 lasuite-drive (needs mirror), Q3.3 lasuite-meet (mirrored), Q3.5
immich (needs mirror), Q4.2/Q4.5-7/Q4.9-10 (mostly need mirror). The mirror-and-enroll path is
established (recipe-create-pr skill); pausing this sprint for Adversary cold-verify.
## Adversary findings — Builder response
**F2-11 — FIXED, awaiting Adversary re-verify** (commit: `git log --oneline | grep 'F2-11'`).
SSO-dep "deps-not-ready"
SKIP no longer yields a GREEN `!testme`.
- **WHAT:** when a recipe declares `DEPS` and `setup_custom_tests` fails (deps not ready) so its
`@requires_deps` (SSO/OIDC) tests SKIP, the run now reports **FAIL** (`overall=1`), not green —
while generic-tier failure-isolation is preserved (install/upgrade/backup/restore results stand).
- **WHERE (code):**
- `tests/conftest.py::pytest_collection_modifyitems` — now counts the requires_deps tests it skips
and appends the count to `$CCCI_DEPS_SKIP_REPORT`.
- `runner/run_recipe_ci.py` — sets `CCCI_DEPS_SKIP_REPORT` (run-scoped temp, near `depsfile`);
after teardown sums the count into `requires_deps_skipped`; RUN SUMMARY annotates the custom tier
(`custom: pass (N requires_deps SKIPPED ... SSO UNVERIFIED)`); new pure predicate
`sso_dep_unverified(declared, deps_ready, requires_deps_skipped)` flips `overall=1`.
- `tests/unit/test_f211_sso_skip.py` — 7 new unit tests.
- **HOW to verify (both deploy-free, rate-limit-independent):**
1. `ssh cc-ci 'cd /root/cc-ci && cc-ci-run -m pytest tests/unit -q'`**EXPECTED: 35 passed**
(28 prior + 7 F2-11).
2. Cold real-test signal proof:
`ssh cc-ci 'cd /root/cc-ci && rm -f /tmp/f211-skip.txt && CCCI_DEPS_READY=0 \
CCCI_DEPS_NOT_READY_REASON=boom CCCI_DEPS_SKIP_REPORT=/tmp/f211-skip.txt \
cc-ci-run -m pytest tests/lasuite-docs/functional/test_oidc_with_keycloak.py -rs; \
cat /tmp/f211-skip.txt'`
**EXPECTED:** `1 skipped`, pytest exit 0 (the hazard), and `/tmp/f211-skip.txt` == `1`. Since
lasuite-docs declares `DEPS=["keycloak"]`, the orchestrator computes
`sso_dep_unverified(["keycloak"], False, 1)=True``overall=1`.
- **NOT verified by a live run yet:** full e2e (real deploy with forced setup_custom_tests failure →
observe `overall=1`) is deferred until the Docker Hub rate limit (## Blocked) lifts. The two proofs
above cover the predicate, the conftest signal on real files, and the count flow; only the
straight-line read→sum→predicate→overall wiring is unexercised by a live deploy.
## Gate
**Gate: Q2 — Adversary PASS @2026-05-28** (REVIEW-2 `## Q2 — PASS @2026-05-28 (re-verify after
F2-5 fix + F2-6 collateral resolution)`; cold e2e on `/root/adv-verify` HEAD `874bfbb`:
deploy-count=2, all 5 assertions PASS, DEPS teardown clean, post-run docker stack/volume/secret
with 'keyc|lasuite' filter all empty; NO VETO). F2-5 + F2-6 CLOSED; F2-7 stands as open scope
(authentik backend in harness.sso when Q2.2 enrolls). Builder may advance to Q3 — already in
flight (Q3.1 partial @ `874bfbb`, Q5.1 docs @ `b2151af`).
Acceptance per plan §6 Q2: "a dependent recipe deploys its provider + runs an OIDC login test
in one run." Proven cold:
**Objective evidence pointers (Q2):**
- **Q2.1 keycloak parity + 2 NEW specific tests** — commit `d5f5e86`:
- `tests/keycloak/functional/test_health_check.py` — parity port.
- `tests/keycloak/functional/test_password_grant_token.py` — password grant, JWT decoded, claims
(iss/azp/typ/exp/iat) validated.
- `tests/keycloak/functional/test_create_client_and_use.py` — admin-API client CRUD +
client_credentials grant + JWT azp/iss validation + idempotent cleanup.
- `oidc_integration.py` parity deferred to Q3 (cross-recipe; see PARITY.md note).
- Bumped DEPLOY_TIMEOUT + HTTP_TIMEOUT to 900s.
- Cold e2e (log `/root/ccci-q2-keycloak-r3.log`): all 5 stages PASS, deploy-count=1,
`head_ref=666649a6 == chaos-version=666649a6`, version `10.7.0+26.6.1 → 10.7.1+26.6.2`.
- **Q2.3 dep resolver + SSO-setup harness primitives** — commit `4d6b040`:
- `runner/harness/deps.py` — declared_deps + dep_domain + deploy_deps + teardown_deps + JSON
run state. Subsumes Q0.4 (dep resolver).
- `runner/harness/sso.py` — setup_keycloak_realm + oidc_password_grant +
assert_discovery_endpoint. Reusable by every SSO-dependent recipe (Q3 will exercise).
- `runner/run_recipe_ci.py` — wired in dep deploy BEFORE recipe-under-test, dep teardown
AFTER in finally (reverse order). DG4.1 expected count = 1 + len(deps).
- `tests/conftest.py``deps_apps` fixture exposes dep domains to dependent tests.
- 7 new unit tests in `tests/unit/test_deps.py`; **28/28 unit tests PASS** cold.
- **F2-5 fix — dep teardown verify=True** — commit `c6e94af`, log `/root/ccci-f25-verify.log`:
- `runner/harness/deps.py::teardown_deps` now uses `lifecycle.teardown_app(..., verify=True)`
so residuals raise `TeardownError`. Errors are logged per-dep but we continue to other deps;
a combined `TeardownError` is raised after all attempts.
- `runner/run_recipe_ci.py` catches the dep `TeardownError` in finally, surfaces via
`dep_teardown_error` in the run summary + non-zero exit code.
- Cold-verified: lasuite-docs+keycloak dep e2e PASSED clean (3 custom + 2 lifecycle install =
5 PASS); post-run cc-ci state has NO leftover keycloak (`docker stack ls | grep keyc`
empty; `docker volume ls | grep keyc` → empty; `docker secret ls | grep keyc` → empty).
- deploy-count=2, expected 2.
- **Q2.4 acceptance (the gate)** — commit `9e88741`, log `/root/ccci-q24-lasuite-keycloak.log`:
- `tests/lasuite-docs/recipe_meta.py` declares `DEPS = ["keycloak"]`.
- `tests/lasuite-docs/functional/test_oidc_with_keycloak.py`:
- Asserts `deps_apps["keycloak"]` is the per-run dep domain.
- Calls `harness.sso.setup_keycloak_realm` → realm/client/user.
- GETs OIDC discovery; asserts `issuer == https://<kc>/realms/lasuite-docs`.
- Performs password grant → JWT; asserts iss/azp/typ/exp claims.
- Cold-run output:
```
===== DEPS: ['keycloak'] =====
dep: deploying keycloak -> keyc-c12afe.ci.commoninternet.net
dep: keycloak ready @ keyc-c12afe.ci.commoninternet.net
===== TIER: install ===== 2 PASS (generic + cc-ci overlay)
===== TIER: custom ===== 1 PASS (test_oidc_password_grant_against_dep_keycloak)
===== DEPS teardown =====
===== RUN SUMMARY =====
deploy-count = 2 (expect 2)
```
- **F2-3 systemic fix** — commit `47f7cb4`: `runner/harness/browser.py::goto_with_retry`
centralizes the F2-3 try/except PlaywrightError pattern; applied to **all** install overlays
using page.goto (custom-html, n8n, keycloak, cryptpad, lasuite-docs) + the custom-html
playwright/test_browser_smoke. Cold e2e (custom-html, log `/root/ccci-q2-customhtml-r2.log`):
all 5 stages PASS, deploy-count=1, HC1 non-vacuous.
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/<your-clone> && \
cc-ci-run -m pytest tests/unit -v && \
RECIPE=keycloak cc-ci-run runner/run_recipe_ci.py && \
RECIPE=lasuite-docs STAGES=install,custom cc-ci-run runner/run_recipe_ci.py'
```
---
**Gate: Q1 — Adversary PASS @2026-05-28** (REVIEW-2 `## Q1 — PASS @2026-05-28 (re-verify after
F2-3 + F2-4 fixes)`; cold e2e on `/root/adv-verify` HEAD `fc89552` → all 5 stages PASS,
deploy-count=1, HC1 non-vacuous; F2-3 + F2-4 CLOSED; NO VETO). Builder may advance to Q2.
**Objective evidence pointers (Q1):**
- **custom-html (Q1.1)** — already cold-verified in Q0 PASS. Same evidence stands: full e2e green,
HC1 non-vacuous, deploy-count=1; PARITY.md + functional/ + playwright/ in place.
- **n8n (Q1.2)** — full e2e on cc-ci (log `/root/ccci-q1-n8n-r3.log`):
- **HC1 PR-head proof:** `head_ref=63dd3e0f == chaos-version=63dd3e0f`, version
`3.1.0+2.9.4 → 3.2.0+2.20.6`.
- **Deploy-count = 1** (DG4.1 holds).
- **Lifecycle tier results (generic + cc-ci overlay both PASS at each stage):**
- install: generic `test_serving` PASS + cc-ci `test_serving_and_editor` PASS (the robust
Playwright poll handles n8n's /healthz-200-before-/-route-registered window).
- upgrade: generic `test_upgrade_reconverges` PASS + cc-ci `test_upgrade_preserves_data`
PASS (marker `upgrade-survives` written into /home/node/.n8n by `ops.pre_upgrade` survived
the chaos redeploy of PR-head).
- backup: generic `test_backup_artifact` PASS + cc-ci `test_backup_captures_state` PASS
(marker `original` from `ops.pre_backup` captured by `abra app backup create`).
- restore: generic `test_restore_healthy` PASS + cc-ci `test_restore_returns_state` PASS
(marker mutated to `mutated` by `ops.pre_restore`, restored to `original` — real backup
data-integrity).
- **Custom tier results (4 PASS — log `/root/ccci-q1-n8n-r4.log` post-F2-4/F2-3 fix):**
- `tests/n8n/functional/test_health_check.py::test_n8n_returns_200` — parity port (HTTP 200
from `/`), with `SOURCE: recipe-info/n8n/tests/health_check.py` comment.
- `tests/n8n/functional/test_workflow_roundtrip.py::test_workflow_create_and_read_back` —
**plan §4.3 prescribed create+read-back**: owner setup → POST /rest/workflows → GET
/rest/workflows/<id>; assert id/name/nodes round-trip. (F2-4 fix.)
- `tests/n8n/functional/test_rest_settings.py::test_rest_settings_returns_json_with_known_keys`
— polls `/rest/settings` until content-type is `application/json` (rejecting the
"n8n is starting up" placeholder HTML), then asserts known public-settings keys
(`userManagement` / `defaultLocale` / `authCookie`) in the `data` envelope.
- `tests/n8n/functional/test_login_state.py::test_login_endpoint_returns_json` — polls
`/rest/login` until content-type is `application/json`, proves auth subsystem initialized.
- **PARITY.md complete:** `tests/n8n/PARITY.md` — parity row for `health_check.py`, rationale
for the 2 recipe-specific tests, data-integrity + playwright sections.
- **Q1 has no Adversary findings yet.** No tests skipped/weakened; rejecting-the-placeholder
pattern in the new functional tests is non-vacuous (a stuck-booting n8n that only serves the
placeholder fails the test).
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/<your-clone> && RECIPE=n8n cc-ci-run runner/run_recipe_ci.py'
```
---
**Gate: Q0 — Adversary PASS @2026-05-28** (REVIEW-2 `## Q0 — PASS @2026-05-28`; cold re-verify on
`/root/adv-verify` HEAD `0b834e9` → 21 unit PASS + e2e PASS; NO VETO). F2-1 closed; F2-2 (scope
observation) acknowledged.
**Prior Q0 claim detail (commit `5741e88` — F2-1 fix landed on top of the original Q0 changeset).** Acceptance evidence (per plan §6 Q0): a reference recipe
(custom-html) uses the new harness additions for a full parity + specific suite, green via the
existing run path. F2-1 (test_custom_tests_repo_local_gated stale assertion) closed by Builder; cold
re-run on cc-ci → **21/21 PASS** including the previously-failing test. F2-2 (scope observation:
OIDC-flow + dep resolver not in Q0) acknowledged — those primitives implement when Q2/Q3 consume
them; BACKLOG-2 Q0.4 remains open and explicitly deferred.
**Objective evidence pointers (Q0):**
- **Harness additions landed**
- `runner/harness/http.py` — canonical Phase-2 recipe-test HTTP API (vendored from
`references/recipe-maintainer/utils/tests/helpers.py`): `http_get`, `http_post`, `http_request`,
`retry_http_get`, `retry_http_post`, `wait_for_http`, `assert_converges`. JSON + form bodies,
transport-failure → status=0.
- `runner/harness/discovery.custom_tests` recurses into `tests/<recipe>/functional/` and
`tests/<recipe>/playwright/` (Phase 2 §4.1 layout) while excluding lifecycle `test_<op>.py`
names; HC2 repo-local gate continues to apply.
- TTY abra wrapper already present in `runner/harness/abra.py::_run_pty` (Phase 1d) — reused.
- **Unit-test proof (deterministic, cc-ci; post-F2-1 fix commit `5741e88`)**
- `cc-ci-run -m pytest tests/unit -v` → **21 passed in 5.38s** (the previously-failing
`test_custom_tests_repo_local_gated` now passes; synthetic-recipe + monkeypatch fixture):
- 8× pre-existing `tests/unit/test_discovery.py` (overlay + HC2 gate, regressed).
- 2× new `tests/unit/test_discovery_phase2.py` (functional/+playwright/ recursion + HC2
gate still applies to subdirs).
- 11× new `tests/unit/test_http.py` (in-process http.server fixture — JSON parsing,
4xx-with-body, non-JSON body, transport-failure=0, headers, JSON+form POST, retry
convergence, retry timeout, wait_for_http, assert_converges return value).
- **End-to-end proof (custom-html on cc-ci, the reference recipe)**
- `RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py` (log `/root/ccci-q0-customhtml-full.log`):
- install/upgrade/backup/restore/custom **all PASS**, deploy-count=1.
- HC1 PR-head proof: `head_ref=8a026066 == chaos-version=8a026066`, version `1.10.0→1.11.0`.
- 5 lifecycle assertions (generic + cc-ci overlay across 4 ops) + 4 custom-stage assertions
(3 functional + 1 playwright). Reference command for Adversary cold re-run:
`RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py`.
- **Per-recipe contract artifact landed**
- `tests/custom-html/PARITY.md` — parity row for `health_check.py`, rationale for the 2
recipe-specific tests + the data-integrity + playwright sections.
- `tests/custom-html/functional/{test_health_check.py,test_content_roundtrip.py,test_content_type_header.py}` — parity port + 2 NEW recipe-specific tests; each parity file carries the
`SOURCE: recipe-info/custom-html/tests/<file>` comment for audit.
- `tests/custom-html/playwright/test_browser_smoke.py` — Phase-2 P6 home.
**Reference command for Adversary (cold, on cc-ci):**
```
ssh cc-ci 'cd /root/cc-ci && cc-ci-run -m pytest tests/unit -v && RECIPE=custom-html cc-ci-run runner/run_recipe_ci.py'
```
## Blocked
**(none) — the Docker Hub rate-limit block is RESOLVED @2026-05-28 ~22:10Z. Awaiting Adversary
re-verify of the 3 conditions (immediate relief already confirmed by Adversary in REVIEW-2).**
**Docker Hub rate-limit fix — DONE (registry-creds finding, plan §1.5), all 3 conditions met.**
Operator provided a read-only PAT (`DOCKERHUB_USERNAME=nptest2` + `DOCKERHUB_TOKEN` in `.testenv`).
Wired declaratively; verify commands + expected outcomes for the Adversary:
1. **Authenticated 200-limit from account source** (Adversary already CONFIRMED in REVIEW-2). Re-check:
`ssh cc-ci` → `docker info | grep Username` = `nptest2`; an authenticated manifest HEAD shows
`ratelimit-limit: 200;w=21600` and `docker-ratelimit-source: b662dd8b-…` (account hash, NOT IP
`68.14.43.142`).
2. **Swarm SERVICE-task pulls authenticate** — PROVEN with an **uncached** image:
`ssh cc-ci 'cd /root/cc-ci && RECIPE=n8n STAGES=install cc-ci-run runner/run_recipe_ci.py'`
→ EXPECTED: `install: pass`, deploy-count=1, NO `toomanyrequests`; the swarm task pulls
`n8nio/n8n:2.20.6` to 1/1. During the run the **account** counter decrements (197→196 resolution
→195 agent layer pull, source = account hash) — the agent pull is billed to the account, not the
anon IP. (n8n images were uncached, so this is a real fresh-pull test, not a cached false-pass.)
Conclusion: abra `docker stack deploy` propagates the cred on this single-node swarm; no
`--with-registry-auth` flag or pre-pull needed.
3. **Declarative persistence across a 1c rebuild** — PAT sops-encrypted (`secrets/secrets.yaml` key
`dockerhub_auth` = base64("nptest2:PAT"), submodule `cdd5e0a`); `nix/modules/secrets.nix` adds
`sops.secrets.dockerhub_auth` + `sops.templates."docker-config.json"` → renders
`/root/.docker/config.json` (0600 root) at activation. Verify: after `nixos-rebuild switch`,
`ls -l /root/.docker/config.json` → symlink to `/run/secrets/rendered/docker-config.json`; the
activation log shows `adding rendered secret: docker-config.json`. Recorded in DECISIONS.md
("Docker Hub auth: declarative config.json via sops").
**Bonus unblocked:** Q3.2 lasuite-drive base deploy now CONVERGES (all 12 services incl.
onlyoffice+collabora) — `RECIPE=lasuite-drive STAGES=install` → `install: pass`, deploy-count=1
(commit before this; the rate limit was the only blocker). Q3.2 specifics (OIDC/WOPI/upload) are next.
**Earlier Gitea outage (RESOLVED @~21:08Z).** git.autonomic.zone returned blanket `404` for ~1.5h
(backend down; same from my sandbox AND cc-ci). Reconciled: pulled + pushed queued commits. The 3
watchdog pings during the outage were phantoms (Adversary's failed push retries); nothing lost.
**Prior bootstrap state:** access re-verified @2026-05-28: `ssh cc-ci` ok (root, NixOS 24.11), Gitea
API HTTP 200, wildcard DNS resolves to gateway 143.244.213.108.
## Carryover from Phase 1e (not blockers for Phase 2)
- **F1e-2** [adversary] — concurrent same-recipe `abra recipe fetch` race in
`runner/run_recipe_ci.py::fetch_recipe`. Pre-existing in Phase 1d; not a 1e regression. Drone
caps `MAX_TESTS=1` today, so practical impact bounded. Tracked for Phase-2 breadth-ramp if
concurrent recipe runs become routine.