Files
acdl/.ciagent/GRILL.md
T
Jon Chery 0920550ae5
acdl-ci / Lint (push) Successful in 9s
acdl-ci / Test (push) Failing after 22s
acdl-ci / Platform check-only (offline) (push) Successful in 24s
Nova Slides Render / render (push) Failing after 22s
docs(P00): grill — PROCEED (0.82), 0 escalations, 2 revisions (already captured)
---ci---
project: acdl
phase: 0
milestone: v1.24
status: grill
---/ci---
2026-08-12 14:23:55 +00:00

7.6 KiB

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#<timestamp> 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=<consumer-repo>. 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#<timestamp> 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.