feat(1e): HC3 additive generic + op/assertion split (orchestrator owns the op)

- orchestrator: per mutating tier, run optional pre-op seed hook (ops.py pre_<op>) → perform the op
  ONCE (harness-owned) → run generic assertion (unless opted out) AND overlay assertion, both against
  the shared post-op deployment. Op results passed op→assertion via run-scoped CCCI_OP_STATE_FILE.
- opt-out: CCCI_SKIP_GENERIC / CCCI_SKIP_GENERIC_<OP> / recipe_meta.SKIP_GENERIC (declarative).
- generic.py: split do_* into op primitives (perform_upgrade/backup/restore) + assertions
  (assert_upgraded/backup_artifact/restore_healthy) reading op_state(); deployed_identity now returns
  {version,image,chaos} (chaos label ready for HC1).
- generic test_<op>.py + all 6 recipe overlays migrated to assertion-only; pre-op seeding moved to
  per-recipe ops.py (pre_upgrade/pre_backup/pre_restore). install overlays unchanged (no op).
- deploy-count stays 1 (op primitives never call deploy_app). lint PASS; 8 unit tests PASS on cc-ci.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 03:12:04 +01:00
parent 6a59343996
commit b7e6cbd7be
31 changed files with 623 additions and 412 deletions

View File

@ -1,8 +1,9 @@
"""Generic RESTORE tier (Phase 1d DG3) — recipe-agnostic, backup-capable recipes only.
"""Generic RESTORE tier (Phase 1d DG3 + Phase 1e HC3) — recipe-agnostic, assertion-only.
Restores the latest snapshot (produced by the backup tier on the same shared deployment) and asserts
the restore completes and the app is healthy + serving afterwards. App-specific data-integrity
(marker survives) is a recipe overlay (test_restore.py); the generic verifies the restore mechanism."""
The orchestrator restored the latest snapshot ONCE (produced by the backup op on the same shared
deployment). This tier ASSERTS the restore completed and the app is healthy + serving afterwards — it
does NOT perform the op. App-specific data-integrity (marker survives) is a recipe overlay
(test_restore.py); the generic verifies the restore mechanism. Runs by default ALONGSIDE any overlay."""
import os
import sys
@ -12,4 +13,4 @@ from harness import generic # noqa: E402
def test_restore_healthy(live_app, meta):
generic.do_restore(live_app, meta)
generic.assert_restore_healthy(live_app, meta)