# PLAN — v1.24 (Consumer Guide Accuracy & Env-Promotion Lifecycle Enforcement)

> Feature milestone (one `feat` phase: env-transition destroy enforcement;
> the rest are `fix`/`docs`/`test`). Tags on the **v1.23.x** line:
> v1.23.0 (P0) → v1.23.1 (P1) → v1.23.2 (P2) → v1.23.3 (P3) → v1.23.4 (P4
> final = milestone release). 15 requirements (REQ-276..290), 4 phases +
> P0 pre-execution.

## Phase breakdown

### Phase P1 — consumer-guide-fixes (Wave 1, lead-developer)

**Type:** `docs` + `fix` + `test` (consumer guide accuracy + guide test updates)

**Requirements:** REQ-276, REQ-277, REQ-278, REQ-279, REQ-280, REQ-281, REQ-290

**Must-haves:**
- `docs/consumer-guide.md` Step 3 contract fields table corrected (REQ-276)
- `docs/consumer-guide.md` Step 4 caller consistent with Step 2 (REQ-277)
- `docs/consumer-guide.md` Step 5 stage 8 "(dev only)" → "(autonomous in dev; higher environments apply after HITL attestation)" (REQ-278)
- `docs/consumer-guide.md` Step 8 rewritten with destroy-then-rebuild semantics + cross-ref to Shape B (REQ-279)
- `docs/consumer-guide.md` Per-env section gains Shape B lead sentence (REQ-280)
- `docs/consumer-guide.md` Reference table `@v1.19` wording corrected (REQ-281)
- `tests/test_consumer_guide_per_env_section.py` updated: rename `test_consumer_guide_states_no_field_editing` → `test_consumer_guide_documents_both_promotion_shapes`; add `test_consumer_guide_documents_destroy_on_env_change` (REQ-290)

**Vertical slice:** A reader of `docs/consumer-guide.md` can promote via
either shape (A: edit environment + platform destroys prior; B: per-env
caller workflow) without contradiction. The guide's field table, caller
examples, and stage descriptions match the actual schema and platform
behavior. All consumer-guide tests pass.

**Files touched:**
- `docs/consumer-guide.md`
- `tests/test_consumer_guide_per_env_section.py`

**Verification:** `pytest tests/test_consumer_guide_per_env_section.py -v`
(all 7 tests pass). Manual read of `docs/consumer-guide.md` end-to-end
for internal consistency.

---

### Phase P2 — env-transition-detect-and-destroy (Wave 2, backend-engineer)

**Type:** `feat` (new platform feature: env-transition detect-and-destroy)

**Requirements:** REQ-282, REQ-283, REQ-284, REQ-285, REQ-286, REQ-287

**Must-haves:**
- `core/env_transition.py` new module: `detect_prior_env()` + `record_applied_env()` with boto3 DynamoDB queries (REQ-282, REQ-283)
- `scripts/run_platform.sh` Step 0b: environment-transition check — detect prior env, re-resolve with `environment_override=prior_env` + `deletion_protection=false`, `terraform init -reconfigure` + `terraform destroy -auto-approve` against prior state key, emit `nova.env.destroyed` evidence event, fail closed on destroy failure (REQ-284)
- `scripts/run_platform.sh` records applied env after successful apply (REQ-285)
- `.github/workflows/deploy.yml` passes `NOVA_CONSUMER_REPO=${{ github.repository }}` to `run_platform.sh` (REQ-286)
- `adapters/terraform/adapter.py` state-key block gains doc comment (REQ-287)

**Vertical slice:** When a consumer changes `environment:` on a stable
`contract.id`, the pipeline detects the prior env from DynamoDB, destroys
the prior env's Terraform state (with `deletion_protection=false`), emits
an evidence event, and only then applies the new env. If the destroy
fails, the pipeline exits non-zero (no orphan path). If no prior env
exists (first deploy or Shape B), the pipeline proceeds normally.

**Files touched:**
- `core/env_transition.py` (NEW)
- `scripts/run_platform.sh`
- `.github/workflows/deploy.yml`
- `adapters/terraform/adapter.py` (doc comment only)

**Verification:** `python3 -m py_compile core/env_transition.py`.
`pytest tests/test_pipeline.py tests/test_deploy_workflow_env_input.py -v`
(existing tests still pass). The new tests in P3 validate the behavior.

**Key implementation notes (from RESEARCH §5 pitfalls):**
1. The destroy step must re-resolve with `environment_override=prior_env`
   so the emitted TF matches the prior env's resources.
2. `terraform init -reconfigure` is required when switching state backends.
3. `deletion_protection: false` must be injected (same as decommission
   Step 2 in `scripts/run_decommission.sh:34-37`) or `prevent_destroy`
   blocks the destroy.
4. DynamoDB unreachable in local/CI → log warning + return `None`
   (conservative, no prior env assumed).
5. The state key `spike/{id}/{env}/terraform.tfstate` stays as-is — the
   env segment is what lets the destroy target the prior env.

---

### Phase P3 — env-transition-tests (Wave 3, backend-engineer + lead-developer)

**Type:** `test` (new test coverage for env-transition + pipeline integration)

**Requirements:** REQ-288, REQ-289

**Must-haves:**
- `tests/test_env_transition.py` (NEW): `detect_prior_env` returns `None` when no record; returns prior env when record differs; returns `None` when record matches; `record_applied_env` writes record. Uses moto for DynamoDB (REQ-288)
- `tests/test_run_platform_env_transition.py` (NEW): asserts `run_platform.sh` has Step 0b; calls `env_transition.py detect`; calls `terraform destroy` on prior env; fails closed on destroy failure; records applied env after success (REQ-289)

**Vertical slice:** The env-transition detect-and-destroy behavior is
fully covered by automated tests. The DynamoDB query logic is unit-tested
with moto. The pipeline orchestration is tested via shell-text assertions
(pattern from `tests/test_pipeline.py:79-95`).

**Files touched:**
- `tests/test_env_transition.py` (NEW)
- `tests/test_run_platform_env_transition.py` (NEW)

**Verification:** `pytest tests/test_env_transition.py tests/test_run_platform_env_transition.py -v` (all new tests pass). Full suite: `pytest tests/ -k "env_transition or consumer_guide or pipeline or adapter or deploy_workflow" -v`.

---

### Phase P4 — final-review-ship (Wave 4, lead-developer)

**Type:** `docs` (review + audit + milestone ship)

**Requirements:** (none new — milestone completion)

**Must-haves:**
- Multi-persona code review across P1-P3 changes (ci-code-reviewer)
- Project health audit (ci-doc-verifier + ci-audit)
- Milestone ship: tag v1.23.4 (final phase patch = milestone release), merge to main, Gitea release
- Update REQUIREMENTS.md traceability (all REQ-276..290 → complete)
- Update ROADMAP.md (v1.24 → complete)

---

## Wave ordering

```
Wave 1 (P1): consumer-guide-fixes          [lead-developer]
    ↓
Wave 2 (P2): env-transition-detect-and-destroy  [backend-engineer]
    ↓
Wave 3 (P3): env-transition-tests          [backend-engineer + lead-developer]
    ↓
Wave 4 (P4): final-review-ship             [lead-developer]
```

**Dependencies:**
- P2 depends on P1: the Step 8 rewrite in P1 documents the destroy
  semantics that P2 implements. Doing P1 first ensures the docs and code
  land in the right order (docs describe the intended behavior, then code
  implements it).
- P3 depends on P2: the tests validate the env-transition module and
  pipeline Step 0b that P2 creates.
- P4 depends on P1+P2+P3: the final review covers all changes.

**Parallelization:** P1 and P2 could run in parallel (different
territories: docs vs code), but the wave ordering is sequential for
safety — if P1's Step 8 rewrite reveals a design issue, P2's
implementation should follow the corrected design. With
`parallelization.enabled=true` and `min_plans_for_parallel=2`, the
orchestrator *could* run them concurrently; however, the dependency
(P2 follows P1's design) makes sequential the safer choice. P3 must
follow P2 (tests validate the code). P4 must follow all.

## Requirement → Phase mapping

| REQ | Phase | Type | Description |
|-----|-------|------|-------------|
| REQ-276 | P1 | docs | Contract fields table corrected |
| REQ-277 | P1 | docs | Step 4 caller consistent with Step 2 |
| REQ-278 | P1 | docs | Step 5 stage 8 "dev only" corrected |
| REQ-279 | P1 | docs | Step 8 rewritten with destroy semantics |
| REQ-280 | P1 | docs | Per-env section Shape B lead sentence |
| REQ-281 | P1 | docs | Reference table @v1.19 wording corrected |
| REQ-282 | P2 | feat | env_transition.py detect_prior_env() |
| REQ-283 | P2 | feat | env_transition.py record_applied_env() |
| REQ-284 | P2 | feat | run_platform.sh Step 0b detect-and-destroy |
| REQ-285 | P2 | feat | run_platform.sh records applied env |
| REQ-286 | P2 | feat | deploy.yml passes NOVA_CONSUMER_REPO |
| REQ-287 | P2 | docs | adapter.py state-key doc comment |
| REQ-288 | P3 | test | test_env_transition.py |
| REQ-289 | P3 | test | test_run_platform_env_transition.py |
| REQ-290 | P1 | test | consumer guide test updates |

## Tag plan

- P0 (this phase): `v1.23.0` — pre-execution patch
- P1: `v1.23.1` — consumer guide fixes
- P2: `v1.23.2` — env-transition detect-and-destroy
- P3: `v1.23.3` — env-transition tests
- P4: `v1.23.4` — final review + ship = **milestone release**