--- phase: 28-38 name: v1.8-p1-remediation-uptime-standards-encryption-decommission-docs milestone: v1.8 requirements: [REQ-76, REQ-77, REQ-78, REQ-79, REQ-80, REQ-81, REQ-82, REQ-83, REQ-84, REQ-85, REQ-86, REQ-87, REQ-88, REQ-89, REQ-90, REQ-91, REQ-92, REQ-93, REQ-94, REQ-95, REQ-96, REQ-97, REQ-98, REQ-99] type: fix/feat/docs --- # ACDL v1.8 — Phase Plans > Milestone: v1.8. Planner: ci-planner. Status: active. > 11 phases (28–38), 24 requirements (REQ-76..99). ## Phase 28 — adapter-waf-and-resolver-outputs **Requirements:** REQ-76 (WAF nested rules + default_action), REQ-77 (L2 outputs resolution) **Personas:** platform-engineer (lead), backend-engineer **Type:** fix ### Tasks (Wave 1 — sequential): 1. **platform-engineer:** Fix WAF `rules` emission in `adapters/terraform/adapter.py:346-348` — replace `rules = {_value_expr(...)}` with nested `rules { ... }` block emission per rule. Read `inputs.get("default_action")` (line 334) and emit `allow {}` / `block {}` based on input (default `allow` if absent). 2. **backend-engineer:** Implement L2 composition `outputs[]` processing in `core/contract_resolver.py` `resolve_l2()` — after building `resources` (line 232), parse `composition.get("outputs", [])`, resolve source via `child_outputs`, build `stack_instance["outputs"]` dict. 3. **platform-engineer:** Extend `adapter.py` `adapt()` to emit `output "" { value = }` blocks from `stack_instance.get("outputs", {})`. 4. **platform-engineer:** Add tests to `tests/test_adapter.py` (WAF custom rules, default_action block, output blocks) + `tests/test_contract_resolver.py` (L2 outputs for static-assets). ### Must-haves: - WAF with custom rules emits `rules {` blocks, not `rules = [` - WAF `default_action: block` emits `block {}` - L2 resolution yields `stack.outputs.*` - Adapter emits `output` blocks - `pytest` passes (275 → ~285) --- ## Phase 29 — ssm-kms-and-invoke-policy **Requirements:** REQ-78 (SSM fail-loud), REQ-79 (Terraform-rendered invoke policy) **Personas:** backend-engineer (lead), lambda-engineer, security-engineer **Type:** fix ### Tasks (Wave 1): 1. **backend-engineer:** Change `core/output_publisher.py:54-55` `_kms_key_id()` — raise `RuntimeError` when `ACDL_KMS_KEY_ID` unset; add `ACDL_ALLOW_DEFAULT_KMS=1` escape hatch. 2. **lambda-engineer:** Convert `terraform/platform/consumer_invoke_policy.json` to Terraform-rendered template — add `terraform/platform/variables.tf` with `data "aws_caller_identity" "current" {}` + `templatestring` or `replace()` for account ID injection. 3. **backend-engineer:** Add `tests/test_output_publisher.py` cases: `test_kms_unset_raises`, `test_kms_unset_allow_default_kms`. Add `tests/test_invoke_policy.py` asserting rendered policy has no `000000000000`. ### Must-haves: - SSM raises RuntimeError without CMK; escape hatch works - Rendered invoke policy has live account ID - `pytest` passes (~290) --- ## Phase 30 — run-platform-isolation-and-api-portability **Requirements:** REQ-80 (temp dir), REQ-81 (forge-agnostic URLs), REQ-82 (static-key override) **Personas:** backend-engineer (lead), lambda-engineer **Type:** fix ### Tasks (Wave 1 — parallel): 1. **backend-engineer:** Change `scripts/run_platform.sh:122` adapter target from `terraform/spike` to `$WORK/tf`. Update all downstream references. Remove committed `terraform/spike/*.tf`. Update `tests/test_pipeline.py`. Update deploy.yml artifact upload path. 2. **lambda-engineer:** Add `_github_api_base()` + `_forge_type()` to `core/lambda/contract_ingestor.py`. Replace hardcoded URLs at lines 109, 149, 163. Add `tests/test_contract_ingestor.py` Gitea base URL test. 3. **backend-engineer:** Restructure `configure-aws-credentials` step in both deploy workflows (byte-identical) — single conditional step with `access-key`/`secret-key` inputs when static key present. Update `tests/test_pipeline_contract.py`. ### Must-haves: - `run_platform.sh --check-only` writes to temp dir - `contract_ingestor.py` uses `GITHUB_API_BASE` - Deploy workflow static-key override wired - Both deploy workflows byte-identical - `pytest` passes (~295) --- ## Phase 31 — encryption-by-default-and-per-stack-cmk **Requirements:** REQ-83 (kms-key primitive), REQ-84 (encryption NFRs on all primitives), REQ-85 (L2 CMK wiring) **Personas:** platform-engineer (lead), security-engineer **Type:** feat ### Tasks (Wave 1 — kms-key primitive + adapter): 1. **platform-engineer:** Create `modules/l1/kms-key/` with `interface.json` (type `aws:kms:key`, inputs: description/region/deletion_window_days, outputs: kms_key_arn/kms_key_id, NFRs: enable_rotation default true, deletion_protection default true) + `instance.json` + `README.md` + `examples/`. 2. **platform-engineer:** Add `aws:kms:key → aws_kms_key` + `aws:kms:alias → aws_kms_alias` to adapter TYPE_MAP. Emit `enable_key_rotation = true` + alias. ### Tasks (Wave 2 — encryption NFRs on all primitives, after Wave 1): 3. **platform-engineer:** Add `encryption_enabled` NFR (default true) + `kms_key_arn` input to every L1 `interface.json` (s3, rds, ecr, ecs-service, ecs-cluster, alb, cloudfront, waf, vpc, iam-role). Update adapter to emit encryption blocks referencing the CMK when `kms_key_arn` is provided; managed KMS fallback with stderr warning when not. 4. **platform-engineer:** Update both L2 `composition.json` files — add `kms-key` child + wires connecting `kms_key_arn` output to each child's `kms_key_arn` input. 5. **platform-engineer:** Add `tests/test_encryption.py` — assert every primitive has encryption NFRs; assert adapter emits encryption blocks; assert L2 wires CMK; assert `enable_key_rotation = true`. ### Must-haves: - kms-key primitive exists + registered - All primitives have `encryption_enabled` NFR + `kms_key_arn` input - L2 modules wire per-stack CMK - Adapter emits encryption blocks - `pytest` passes (~310) --- ## Phase 32 — deletion-protection-by-default-and-l2-feature-flag **Requirements:** REQ-86 (deletion_protection NFR on all primitives), REQ-87 (L2 feature flag) **Personas:** platform-engineer (lead), backend-engineer **Type:** feat ### Tasks (Wave 1): 1. **platform-engineer:** Add `deletion_protection` NFR (boolean, default true) to every L1 `interface.json` (rds already has it). Update adapter to emit `lifecycle { prevent_destroy = true }` when NFR is true; omit when false. RDS gets BOTH `deletion_protection` arg + `prevent_destroy` lifecycle. 2. **backend-engineer:** Add `features` object support to `schemas/stack.schema.json` (optional `features.deletion_protection`). Update `core/contract_resolver.py` `resolve_l2()` to propagate `features.deletion_protection` to each child's `deletion_protection` NFR. Add `inputs.deletion_protection` to `schemas/contract.schema.json` (optional boolean). 3. **platform-engineer:** Add `tests/test_deletion_protection.py` — assert every primitive has the NFR; assert adapter emits `prevent_destroy`; assert L2 feature flag propagation. ### Must-haves: - Every primitive has `deletion_protection` NFR (default true) - Adapter emits `prevent_destroy = true` when true - L2 feature flag propagates - `pytest` passes (~320) --- ## Phase 33 — uptime-kuma-primitive **Requirements:** REQ-88 (uptime primitive), REQ-89 (deployed by default after L2), REQ-90 (feature flag), REQ-91 (pipeline stage) **Personas:** platform-engineer (lead), backend-engineer **Type:** feat ### Tasks (Wave 1 — primitive + adapter): 1. **platform-engineer:** Create `modules/l1/uptime/` with `interface.json` (type `aws:ecs:uptime-service`, inputs: container_image/region/monitored_endpoints/static_checks/alert_channels/feature_flag_enabled/cpu/memory, outputs: uptime_url/service_arn/task_definition_arn, NFRs: deletion_protection/encryption_enabled) + `instance.json` + `README.md` + `examples/simple.yaml` + `examples/complex.yaml`. 2. **platform-engineer:** Add `aws:ecs:uptime-service` to adapter TYPE_MAP. Emit ECS Fargate task + service + ALB + listener + EFS volume + CloudWatch log group. When `feature_flag_enabled=false`, emit NO resources. Register in `registry.json`. ### Tasks (Wave 2 — pipeline + script, after Wave 1): 3. **backend-engineer:** Add `deploy-uptime` stage to `pipelines/deploy.yaml` (after `publish-outputs`). Update both deploy workflows (byte-identical) with the stage. Add `scripts/seed_uptime_monitors.py` for post-deploy monitor seeding via uptime-kuma API. 4. **backend-engineer:** Update `scripts/run_platform.sh` — add `deploy-uptime` step: read L2 stack outputs, construct synthetic uptime contract with `monitored_endpoints` from outputs, run second terraform apply with separate state (`$WORK/uptime-tf/`), publish uptime URL via PR comment. Skip when `inputs.uptime_enabled=false`. 5. **backend-engineer:** Add `tests/test_uptime_primitive.py` — validate interface; assert adapter emits ECS service when flag=true; assert no resources when flag=false; assert `deploy-uptime` stage in pipeline contract. ### Must-haves: - Uptime primitive exists with feature flag + alert channels - Deployed by default after L2 (separate state) - Uptime URL published via PR comment - Feature flag disables deployment - `deploy-uptime` stage in deploy contract + byte-identical workflows - `pytest` passes (~335) --- ## Phase 34 — decommission-alias-and-cmdb-validation **Requirements:** REQ-92 (decommission mode), REQ-93 (CMDB validation), REQ-94 (consumer docs) **Personas:** backend-engineer (lead), lambda-engineer, security-engineer **Type:** feat ### Tasks (Wave 1 — CMDB + Lambda, parallel): 1. **lambda-engineer:** Add `acdl-change-requests` DynamoDB table to `terraform/platform/main.tf` (PK changeRequestId, SK submittedAt, SSE via CMK, PITR). Add `validate_change_request` action to `core/lambda/contract_ingestor.py` — query table, assert status=approved + consumerRepo match, return CR details or 403. 2. **backend-engineer:** Add `decommission_transform(stack_instance)` to `core/contract_resolver.py` — zero all counts (desired_count=0 for ECS, etc.). ### Tasks (Wave 2 — pipeline + docs, after Wave 1): 3. **backend-engineer:** Add `mode: decommission` to deploy workflow inputs. Add decommission stages to `pipelines/deploy.yaml`: validate-change-request → disable-deletion-protection (HITL SRE gate via GitHub environment) → zero-counts (second HITL SRE gate) → confirm-decommission. Update both deploy workflows (byte-identical). 4. **backend-engineer:** Update `docs/CONSUMER_GUIDE.md` with "Decommissioning a stack" section (request CR, trigger decommission, HITL gates, what happens). 5. **backend-engineer:** Add `tests/test_decommission.py` — assert `decommission_transform` zeroes counts; assert `validate_change_request` rejects invalid CRs; assert decommission stages in pipeline contract. ### Must-haves: - Decommission mode on existing deploy pipeline - 2-step with HITL SRE gates - CR ID validated against DynamoDB CMDB - Documented in consumer guide - `pytest` passes (~345) --- ## Phase 35 — module-engineering-standards **Requirements:** REQ-95 (STANDARDS.md), REQ-96 (catalog fix + template update) **Personas:** lead-developer (lead), platform-engineer, backend-engineer **Type:** docs + refactor ### Tasks (Wave 1): 1. **lead-developer:** Author `modules/STANDARDS.md` — comprehensive L1+L2 authoring + review standards (scanned from current modules per RESEARCH TARGET 6): required files, interface schema, input/output/NFR conventions, encryption + deletion protection as mandatory NFRs, naming, multi-resource pattern, adapter extension pattern, code review checklist. 2. **lead-developer:** Fix `modules/README.md` catalog index — add rds + uptime + kms-key to Primitives table. Update `modules/README-TEMPLATE.md` — add `## NFRs` section. 3. **backend-engineer:** Add `tests/test_module_standards.py` — automated enforcement: every L1 has `deletion_protection` + `encryption_enabled` NFRs; every L2 has valid structure; every module registered; every module has README + examples. ### Must-haves: - `modules/STANDARDS.md` exists with L1+L2 standards - Catalog index includes all primitives - Template has NFRs section - Automated standards test passes - `pytest` passes (~355) --- ## Phase 36 — schemas-adapters-pipelines-readmes **Requirements:** REQ-97 (schemas README), REQ-98 (pipelines README), REQ-99 (adapters README) **Personas:** lead-developer (lead), backend-engineer, platform-engineer **Type:** docs ### Tasks (Wave 1 — parallel): 1. **lead-developer:** Author `schemas/README.md` — how to write schemas, wire into platform, test in CI, dependencies, existing catalog. 2. **lead-developer:** Author `pipelines/README.md` — how to write pipeline contracts, wire into workflows, test, dependencies, catalog. 3. **lead-developer:** Author `adapters/README.md` — how to write adapters, wire into platform, test, dependencies, catalog. 4. **backend-engineer:** Add `tests/test_docs_coverage.py` — assert all 3 READMEs exist + contain required sections. ### Must-haves: - All 3 READMEs exist with comprehensive documentation - CI validates presence - `pytest` passes (~358) --- ## Phase 37 — verify **Personas:** lead-developer (lead), all personas **Type:** verify ### Tasks: 1. Structural: all new files present. 2. Behavioral: `pytest` passes (~358); `run_ci.sh` exits 0; `run_platform.sh --check-only` exits 0. 3. Security: no secrets; CMK enforced; no placeholder account IDs; deletion protection on by default. 4. Quality: each P1 fix + each new feature has a dedicated test. --- ## Phase 38 — review-audit-complete **Personas:** lead-developer (lead), all personas **Type:** review + audit + complete ### Tasks: 1. Review: 0 new P0/P1; all P1-3..P1-9 + S1 resolved; 3 new requirements delivered. 2. Audit: reconstruction, file discipline, branch hygiene, commit discipline. 3. Complete: update REQUIREMENTS.md (REQ-76..99), ROADMAP.md, PROJECT.md. Tag `v1.8.0`. Update floating `v1.8` + `v1` tags. Bump `uses:` to `@v1.8`.