status(1e): E1/HC3 CLAIMED — additive generic + op-once verified e2e (custom-html)

default run: every tier ran generic+overlay (op once, deploy-count=1); CCCI_SKIP_GENERIC=1 run:
generic skipped, overlays only. Clean teardown both. E0/HC2 recorded as Adversary PASS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 03:18:41 +01:00
parent b7e6cbd7be
commit 7fba6b0547
3 changed files with 56 additions and 4 deletions

View File

@ -6,7 +6,7 @@ Phase-namespaced backlog. Builder edits `## Build backlog`; Adversary edits `##
- [x] **E0 / HC2** — repo-local approval allowlist (`tests/repo-local-approved.txt`, default-deny);
gate `discovery.resolve_op`/`custom_tests`/`install_steps` behind `repo_local_approved(recipe)`;
update unit tests (`tests/unit/test_discovery.py`) for approved vs non-approved.
- [ ] **E1 / HC3** — generic-by-default (additive); op/assertion split. Orchestrator performs each
- [x] **E1 / HC3** — generic-by-default (additive); op/assertion split. Orchestrator performs each
mutating op once; runs generic test_<op>.py (unless opt-out) + overlay test_<op>.py. Opt-out:
`CCCI_SKIP_GENERIC` / `CCCI_SKIP_GENERIC_<OP>` / `recipe_meta.SKIP_GENERIC`. Pre-op seed via
optional `tests/<recipe>/ops.py`. Migrate generic + overlays to assertion-only. Keep count==1.

View File

@ -38,3 +38,41 @@ Next: E0 — implement the HC2 allowlist + discovery gate + unit tests.
- Committed d38a695, pushed. Gate E0/HC2 CLAIMED for Adversary.
Next: E1 (HC3) — orchestrator op/assertion split + additive generic + opt-out + overlay migration.
## 2026-05-28 — E1 / HC3 additive generic + op/assertion split (implemented + e2e verified)
- **Harness core:** `lifecycle.deployed_identity` now returns `{version,image,chaos}` (chaos label
captured, ready for HC1). `generic.py` split: op primitives `perform_upgrade/perform_backup/
perform_restore` (orchestrator-only, no asserts) + assertions `assert_upgraded` (serving + MOVED via
version/image/chaos), `assert_backup_artifact`, `assert_restore_healthy`, all reading the run-scoped
`op_state()` (`$CCCI_OP_STATE_FILE`).
- **Orchestrator** (`run_recipe_ci.py`): new `run_lifecycle_tier` = pre-op seed hook (`ops.py
pre_<op>`, imported in-process w/ recipe dir on sys.path) → perform the op ONCE → run generic
assertion (unless `_skip_generic`) + overlay assertion, both against the shared post-op deployment.
Opt-out: `CCCI_SKIP_GENERIC` / `CCCI_SKIP_GENERIC_<OP>` / `recipe_meta.SKIP_GENERIC`. `_scrub`
factored so op-failure messages are redacted too. Op primitives never call `deploy_app` ⇒
deploy-count stays 1.
- **Tiers/overlays migrated to assertion-only:** generic `_generic/test_{upgrade,backup,restore}.py`;
all 6 recipes' `test_{upgrade,backup,restore}.py`. Pre-op seeding (data-continuity markers + the
backup→restore mutation) moved to per-recipe `ops.py` (`pre_upgrade/pre_backup/pre_restore`).
install overlays unchanged (no op). No assertion weakened — every data-survival/return check kept.
- **Verified on cc-ci:**
- `cc-ci-run -m pytest tests/unit -q` → **8 passed**; `nix develop .#lint` → **lint: PASS** (ruff
format + check clean).
- Full e2e `RECIPE=custom-html STAGES=install,upgrade,backup,restore,custom` → every tier ran BOTH
generic AND overlay (additive): install(generic test_serving + overlay test_serving_and_content),
upgrade(pre_upgrade seed → generic test_upgrade_reconverges + overlay test_upgrade_preserves_data),
backup(pre_backup → generic test_backup_artifact + overlay test_backup_captures_state),
restore(pre_restore → generic test_restore_healthy + overlay test_restore_returns_state).
**RUN SUMMARY: deploy-count=1, install/upgrade/backup/restore=pass, custom=skip; no leftover
custom-html stack (clean teardown).** Log: /root/ccci-1e-customhtml.log on cc-ci.
- Opt-out run (`CCCI_SKIP_GENERIC=1`) in flight to show generic skipped + overlay still runs.
Next: confirm opt-out result, claim E1/HC3 gate, then E2 (HC1 chaos-to-PR-head).
## 2026-05-28 — E1 opt-out verified; gate CLAIMED
- Opt-out e2e `RECIPE=custom-html STAGES=install,upgrade,backup,restore CCCI_SKIP_GENERIC=1`:
every tier logged `generic=skip, overlay=cc-ci`; **0** `_generic/test_*` files ran; only the 4
cc-ci overlays ran; **deploy-count=1**; install/upgrade/backup/restore=pass; clean teardown (no
leftover custom-html stack). Log: /root/ccci-1e-optout.log.
- HC3 proven both ways: default = generic+overlay additive on one deployment (op once); opt-out =
generic floor skipped, overlay still runs. Gate E1/HC3 CLAIMED for Adversary.

View File

@ -29,11 +29,25 @@ Three corrections, each Adversary cold-verified, no test weakened:
- **E3** — HC4 cold re-verification + docs → DONE.
## In flight
E1 (HC3) — additive generic + op/assertion split (orchestrator owns the op; generic+overlay both
assert post-op state; opt-out via env/recipe_meta; migrate generic + overlays to assertion-only).
E2 (HC1) — upgrade tier upgrades to the PR-head code under test via `abra app deploy --chaos`
(re-checkout PR head after the prev-tag base deploy; chaos label proves PR-head deployed); reconcile
the DG4.1 deploy-count guard with the in-place chaos redeploy.
## Gate
**Gate: E0/HC2 — CLAIMED, awaiting Adversary @2026-05-28.** Repo-local (PR-authored)
**Gate: E1/HC3 — CLAIMED, awaiting Adversary @2026-05-28.** Generic runs by default ADDITIVELY
alongside any overlay; the orchestrator OWNS each mutating op (runs it ONCE), then runs the generic
assertion (unless opted out) + the overlay assertion against the shared post-op state. Opt-out:
`CCCI_SKIP_GENERIC` / `CCCI_SKIP_GENERIC_<OP>` / `recipe_meta.SKIP_GENERIC`. Pre-op seeds via per-recipe
`ops.py` (`pre_<op>`); op results pass op→assert via `$CCCI_OP_STATE_FILE`. All generic + 6 recipe
overlays migrated to assertion-only (no assertion weakened). Evidence (commit b7e6cbd; on cc-ci):
- `pytest tests/unit`**8 passed**; `nix develop .#lint`**PASS**.
- e2e `custom-html install,upgrade,backup,restore,custom` (default): EVERY tier ran BOTH generic AND
overlay; pre_upgrade/pre_backup/pre_restore seeds fired; **deploy-count=1**; all pass; clean teardown.
- e2e same stages `CCCI_SKIP_GENERIC=1`: every tier `generic=skip, overlay=cc-ci`; **0** generic files
ran; only overlays ran; deploy-count=1; clean. Logs: /root/ccci-1e-{customhtml,optout}.log.
**Gate: E0/HC2 — Adversary PASS @2026-05-28** (REVIEW-1e; hostile-code probe, no finding).
Prior CLAIM detail: Repo-local (PR-authored)
`test_*.py`/`install_steps.sh`/`ops.py` is default-deny: consulted only for recipes on the cc-ci
approval allowlist `tests/repo-local-approved.txt` (empty ⇒ deny). Centralized gate in
`discovery.py` (`repo_local_approved`/`_gated`); `resolve_overlay_op`/`custom_tests`/`install_steps`/