The milestone capstone. Implement l2-static-asset (thin-composition
referencing l1-s3 only, depth 1), the contract→IR resolution, and one
end-to-end contract submission flowing through: contract schema
validation → IR resolution → terraform plan (real AWS) → Checkov
PolicyCheckResult → confidence signal → evidence event to the DynamoDB
outbox. Verify the IR commitments hold (REQ-28: the adapter is the only
substrate-specific code; no polyglot mess).
After Phase 10 ships + verifies: the COMPLETE gate (review → ship v1.2.0
→ audit).
T-10.6 — Extend adapters/terraform/adapter.py for kind=l2
Owner: platform-engineer
Content: D-P10-1: the adapter consumes the resolved IR instance (which has kind=l2 + the L1 resources as its resources array). For a depth-1 thin-composition, the L2 root module IS the L1's resource — no separate module block. The existing adapt() + TYPE_MAP + resource emission handle both l1 and l2 instances (the resources array is the same shape). The only L2-specific bit: the relationships array is ignored at TF level for the spike. Update the backend key to spike/l2-static-asset/terraform.tfstate for the L2 spike.
Content:resolve(contract_path) -> ir_instance dict. Steps: (1) load YAML; (2) validate against contract.schema.json; (3) look up the L2 in registry.json; (4) load composition.json; (5) map contract inputs through wires to child L1 inputs; (6) emit IR instance; (7) validate IR against ir.schema.json. CLI: contract_resolver.py <contract.yaml> <out_ir.json>. stdlib + jsonschema + yaml only.
T-10.7 — Author acdl_platform/outbox_writer.py
Owner: backend-engineer
Content:write_event(event, outbox_table="acdl-outbox") — compute SHA-256 over canonical JSON, set prev_event_hash="GENESIS" for the first event, build DynamoDB item, boto3 put_item. CLI: outbox_writer.py <event.json>. stdlib + boto3.
Content: the 10-step orchestrator: (1) load .env.secrets; (2) resolve contract→IR (contract_resolver.py validates as step 1); (3) adapter compiles IR→terraform/spike/*.tf; (4) terraform init -lock=false + validate + plan -lock=false -out=tfplan; (5) run Checkov on terraform/spike/main.tf → /tmp/checkov.json; (6) checkov_adapter.py → /tmp/pcr.json (PolicyCheckResult list); (7) build confidence inputs (policy = PCR list, validation all true, freshness/source/history/nfrs cold-start) + confidence_signal.py → /tmp/signal.json; (8) assert band=="pass" for dev; (9) write evidence event to outbox (outbox_writer.py); (10) print summary + Signal + outbox item. Exit 0 only if all steps succeed + band==pass.
Wave 4 — lead-developer: verify script
T-10.9 — Author scripts/verify_phase10.sh
Owner: lead-developer
Content: 8 checks: (a) composition.json exists + shape; (b) spike.yaml validates against contract schema; (c) resolver py_compiles + emits IR validating against ir.schema.json; (d) adapter py_compiles + emits main.tf with aws_s3_bucket; (e) run_spike_e2e.sh exits 0; (f) confidence band is "pass" for dev; (g) outbox item exists (query DynamoDB); (h) REQ-28: grep for aws_s3_bucket + aws_ — only adapters/ match; modules-ir/ schemas/ contracts/ acdl_platform/ do NOT match (substrate-agnostic).
Wave 5 — EXECUTE-only
Run scripts/run_spike_e2e.sh against real AWS + scripts/verify_phase10.sh + traceability + ship.
Decisions made during planning
ID
Decision
Rationale
D-P10-1
The adapter handles kind=l2 by consuming the resolved IR instance (L1 resources as the resources array); for depth-1, the L2 root module IS the L1's resource — no separate module block. Relationships ignored at TF level for the spike.
The adapter is a thin layer; the composition is shallow. v1.2 may emit module "l1_s3" { source = "..." } when L1s become real TF modules.
D-P10-2
The contract is authored as YAML + the resolver parses YAML→dict→validates against the JSON contract schema.
YAML is the consumer surface; JSON Schema validates the parsed dict. PyYAML required.
D-P10-3
The evidence event is a single CONFIDENCE_COMPUTED event (spike writes ONE event; chain = GENESIS→this event).
The spike proves the outbox write path; v1.2 writes the full event stream.
Spike scope vs v1.2 boundary
Concern
Spike (Phase 10)
v1.2
L2 composition
depth-1, one child, wires passthrough
multi-child, complex wires, module blocks
Evidence events
ONE CONFIDENCE_COMPUTED event
full stream (submission, validation, plan, policy, confidence, promotion)
Audit chain
GENESIS → one event
full chain + JWS + Object Lock
HITL
dev-only (not exercised)
qa/prod/dr gates wired
Checkov
terraform framework + ACDL_TAG_NAMING SKIPPED
custom Checkov YAML rule + Kyverno + OPA
REQ-28 verification (the binding spike claim)
verify_phase10.sh's Check (h) greps the repo for aws_s3_bucket +
aws_ (Terraform-specific terms). ONLY adapters/terraform/adapter.py
adapters/terraform/policy/checkov_adapter.py should match.
modules-ir/, schemas/, contracts/, acdl_platform/confidence_signal.py,
acdl_platform/contract_resolver.py, acdl_platform/outbox_writer.py
should NOT match (substrate-agnostic). This proves the IR commitments
hold: the adapter is the only substrate-specific code; the L1 content,
contract YML, resolver, confidence signal, and outbox writer are all
substrate-neutral.