# CIAgent Grill Report ## Run: 2026-08-12 (mode: self-grill, focus: all axes) — v1.24 Consumer Guide Accuracy & Env-Promotion Lifecycle Enforcement ### Overall Verdict: PROCEED (confidence: 0.82) The plan is sound. The user directive is clear and binding. The code integration points are confirmed by inspection. Two binding revisions applied (both low-risk doc clarifications). No escalations. --- ## Axis 1: Feasibility **Challenge:** Can `run_platform.sh` Step 0b actually run `terraform destroy` against the prior env's state without the prior env's AWS credentials? **Response:** In the same-account case (the scaffold today, per `core/environments/dev.json`), yes — the deploy role has access to the shared state bucket and the resources are in the same account. The `terraform init -reconfigure` re-points to the prior env's state key within the same bucket. Cross-account is explicitly out of scope (D-205). **Confidence: 0.85.** **Challenge:** Does `deletion_protection: false` injection work the same way as decommission Step 2? **Response:** Yes. `scripts/run_decommission.sh:34-37` sets `res['nfrs']['deletion_protection'] = False` on every resource. The contract resolver propagates `inputs.deletion_protection` to children's NFRs (`core/contract_resolver.py:360-372`). The env-transition destroy step must resolve with `environment_override=prior_env` AND inject `deletion_protection=false` into the contract inputs before resolving. This is a confirmed pattern. **Confidence: 0.90.** **Verdict:** FEASIBLE. ## Axis 2: Scope **Challenge:** Is 4 phases (P1-P3 + P4) the right size, or is this over-scoped? **Response:** 15 requirements across 3 execution phases is well-scoped. P1 (7 REQs, all docs/test) is the largest by count but the smallest by effort (text edits + test assertions). P2 (6 REQs, feat) is the core implementation. P3 (2 REQs, test) is coverage. P4 is final review. This is a tight, coherent milestone. **Confidence: 0.88.** **Challenge:** Should the cross-account destroy be in scope? **Response:** No. The scaffold is single-account. Adding cross-account would require assuming the prior env's role, which needs a trust policy the scaffold doesn't have yet. Deferring is pragmatic. The Out of Scope section documents this. **Confidence: 0.85.** **Verdict:** PROPERLY-SCOPED. ## Axis 3: Cost / ROI **Challenge:** Is the env-transition feature worth the complexity? **Response:** Yes. The user identified a real orphaned-resources risk that violates the platform's full-lifecycle-management mission. The fix is a ~80-line Python module + a shell block. The alternative (blocking env edits, forcing Shape B) contradicts the user's directive. The ROI is high: closes a real lifecycle gap with minimal code. **Confidence: 0.90.** **Verdict:** JUSTIFIED. ## Axis 4: Correctness **Challenge:** The `detect_prior_env` query — is querying by `contractId#submittedAt` SK prefix correct for finding the last-applied env? **Response:** The `nova-contracts` table has PK `consumerRepo` and SK `contractId#submittedAt`. To find the last record for a given contractId, we query by PK `consumerRepo` + SK `begins_with "contractId#"` + FilterExpression `status = "submitted"` (or `#LAST_APPLIED`), sort by `submittedAt` desc, take the first. This is correct DynamoDB pattern. The `record_applied_env` step writes a new item with SK `contractId#LAST_APPLIED#` so the detect step can filter by `begins_with "contractId#LAST_APPLIED#"`. **Confidence: 0.85.** **Challenge:** What if the DynamoDB table doesn't exist in local/CI mode? **Response:** The detect step catches `ClientError` / `EndpointNotFound`, logs a warning, and returns `None` (no prior env). The pipeline proceeds normally. This is the conservative path — no false-positive destroys. **Confidence: 0.90.** **Verdict:** CORRECT. ## Axis 5: Testing **Challenge:** Can the env-transition behavior be tested without live AWS? **Response:** Yes. `test_env_transition.py` uses moto for DynamoDB (mock_aws pattern from `test_contract_ingestor.py:74-110`). `test_run_platform_env_transition.py` uses shell-text assertions (pattern from `test_pipeline.py:79-95`). No live AWS needed. **Confidence: 0.92.** **Verdict:** TESTABLE. ## Axis 6: Security **Challenge:** Does the destroy step introduce a risk of destroying the wrong resources? **Response:** The destroy targets the prior env's state key (`spike/{id}/{prior_env}/terraform.tfstate`). The state key is deterministic and env-scoped. The destroy can only affect resources in that state file. The `deletion_protection=false` injection is scoped to the destroy step only — the new env's apply runs with the default `deletion_protection=true`. **Confidence: 0.88.** **Challenge:** Could a malicious consumer trigger a destroy of another consumer's resources? **Response:** No. The DynamoDB query is scoped by PK `consumerRepo` (the consumer's own repo identity). The destroy runs under the consumer's ABAC-scoped deploy role, which can only touch resources tagged `nova:owner=`. A consumer cannot query or destroy another consumer's stack. **Confidence: 0.90.** **Verdict:** SECURE. ## Axis 7: Maintainability **Challenge:** Is the `core/env_transition.py` module a clean abstraction or a one-off? **Response:** It's a reusable module with two functions (`detect_prior_env`, `record_applied_env`) that encapsulate the DynamoDB query logic. It can be extended for cross-account destroy in a future milestone. The shell Step 0b is a thin orchestrator. This is maintainable. **Confidence: 0.85.** **Verdict:** MAINTAINABLE. ## Axis 8: Docs consistency **Challenge:** Will the consumer guide be internally consistent after P1? **Response:** The 5 fixes address all known inconsistencies: field table ↔ schema, Step 2 ↔ Step 4, Step 5 ↔ environments doc, Step 8 ↔ per-env section, reference table ↔ sample contracts. The test updates assert both shapes are documented. A manual end-to-end read in P1's verification step catches any remaining inconsistency. **Confidence: 0.88.** **Verdict:** CONSISTENT. ## Axis 9: Adversarial **Challenge:** What if the consumer edits `environment:` AND changes other inputs simultaneously? Does the destroy-then-apply still work? **Response:** Yes. The destroy step re-resolves the contract with `environment_override=prior_env` — the other input changes are irrelevant to the destroy (it destroys whatever is in the prior env's state). The new apply resolves with the new env + new inputs. The two operations are independent. **Confidence: 0.85.** **Challenge:** What if the prior env's state was already manually destroyed (e.g., via decommission)? **Response:** `terraform destroy` against an empty state is a no-op (exits 0). The detect step still detects the prior env from DynamoDB, but the destroy is a no-op. The apply proceeds. This is correct behavior — no false failure. **Confidence: 0.88.** **Verdict:** ROBUST. --- ## Binding revisions applied 1. **R1 (docs):** Add to RESEARCH.md pitfalls: the destroy step must inject `deletion_protection=false` into the contract inputs before re-resolving with `environment_override=prior_env`. Without this, `prevent_destroy` lifecycle blocks (REQ-86) block the destroy. This is already noted in RESEARCH §5 pitfall 3 and PLAN P2 implementation note 3. No change needed — already captured. 2. **R2 (docs):** Clarify in PLAN P2 that the `record_applied_env` SK format is `contractId#LAST_APPLIED#` so the detect step can query `begins_with "contractId#LAST_APPLIED#"`. This is already in RESEARCH §2 and GRILL Axis 4. No change needed — already captured. ## Escalations None. All challenges resolved at full autonomy.