---ci--- project: acdl phase: 28-38 milestone: v1.8 status: plan ---/ci--- 11 phase plans created covering 24 requirements (REQ-76..99): P28: adapter WAF + resolver outputs (P1-4,5,7) P29: SSM KMS + invoke policy (P1-3,6) P30: run-platform isolation + API portability + S1 (P1-8,9,S1) P31: encryption-by-default + per-stack CMK P32: deletion-protection-by-default + L2 feature flag P33: uptime-kuma primitive + pipeline stage P34: decommission alias + CMDB validation P35: module engineering standards P36: schemas/adapters/pipelines READMEs P37: verify (4-layer) P38: review-audit-complete
14 KiB
phase, name, milestone, requirements, type
| phase | name | milestone | requirements | type | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 28-38 | v1.8-p1-remediation-uptime-standards-encryption-decommission-docs | v1.8 |
|
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):
- platform-engineer: Fix WAF
rulesemission inadapters/terraform/adapter.py:346-348— replacerules = {_value_expr(...)}with nestedrules { ... }block emission per rule. Readinputs.get("default_action")(line 334) and emitallow {}/block {}based on input (defaultallowif absent). - backend-engineer: Implement L2 composition
outputs[]processing incore/contract_resolver.pyresolve_l2()— after buildingresources(line 232), parsecomposition.get("outputs", []), resolve source viachild_outputs, buildstack_instance["outputs"]dict. - platform-engineer: Extend
adapter.pyadapt()to emitoutput "<outName>" { value = <ref> }blocks fromstack_instance.get("outputs", {}). - 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, notrules = [ - WAF
default_action: blockemitsblock {} - L2 resolution yields
stack.outputs.* - Adapter emits
outputblocks pytestpasses (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):
- backend-engineer: Change
core/output_publisher.py:54-55_kms_key_id()— raiseRuntimeErrorwhenACDL_KMS_KEY_IDunset; addACDL_ALLOW_DEFAULT_KMS=1escape hatch. - lambda-engineer: Convert
terraform/platform/consumer_invoke_policy.jsonto Terraform-rendered template — addterraform/platform/variables.tfwithdata "aws_caller_identity" "current" {}+templatestringorreplace()for account ID injection. - backend-engineer: Add
tests/test_output_publisher.pycases:test_kms_unset_raises,test_kms_unset_allow_default_kms. Addtests/test_invoke_policy.pyasserting rendered policy has no000000000000.
Must-haves:
- SSM raises RuntimeError without CMK; escape hatch works
- Rendered invoke policy has live account ID
pytestpasses (~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):
- backend-engineer: Change
scripts/run_platform.sh:122adapter target fromterraform/spiketo$WORK/tf. Update all downstream references. Remove committedterraform/spike/*.tf. Updatetests/test_pipeline.py. Update deploy.yml artifact upload path. - lambda-engineer: Add
_github_api_base()+_forge_type()tocore/lambda/contract_ingestor.py. Replace hardcoded URLs at lines 109, 149, 163. Addtests/test_contract_ingestor.pyGitea base URL test. - backend-engineer: Restructure
configure-aws-credentialsstep in both deploy workflows (byte-identical) — single conditional step withaccess-key/secret-keyinputs when static key present. Updatetests/test_pipeline_contract.py.
Must-haves:
run_platform.sh --check-onlywrites to temp dircontract_ingestor.pyusesGITHUB_API_BASE- Deploy workflow static-key override wired
- Both deploy workflows byte-identical
pytestpasses (~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):
- platform-engineer: Create
modules/l1/kms-key/withinterface.json(typeaws: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/. - platform-engineer: Add
aws:kms:key → aws_kms_key+aws:kms:alias → aws_kms_aliasto adapter TYPE_MAP. Emitenable_key_rotation = true+ alias.
Tasks (Wave 2 — encryption NFRs on all primitives, after Wave 1):
- platform-engineer: Add
encryption_enabledNFR (default true) +kms_key_arninput to every L1interface.json(s3, rds, ecr, ecs-service, ecs-cluster, alb, cloudfront, waf, vpc, iam-role). Update adapter to emit encryption blocks referencing the CMK whenkms_key_arnis provided; managed KMS fallback with stderr warning when not. - platform-engineer: Update both L2
composition.jsonfiles — addkms-keychild + wires connectingkms_key_arnoutput to each child'skms_key_arninput. - platform-engineer: Add
tests/test_encryption.py— assert every primitive has encryption NFRs; assert adapter emits encryption blocks; assert L2 wires CMK; assertenable_key_rotation = true.
Must-haves:
- kms-key primitive exists + registered
- All primitives have
encryption_enabledNFR +kms_key_arninput - L2 modules wire per-stack CMK
- Adapter emits encryption blocks
pytestpasses (~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):
- platform-engineer: Add
deletion_protectionNFR (boolean, default true) to every L1interface.json(rds already has it). Update adapter to emitlifecycle { prevent_destroy = true }when NFR is true; omit when false. RDS gets BOTHdeletion_protectionarg +prevent_destroylifecycle. - backend-engineer: Add
featuresobject support toschemas/stack.schema.json(optionalfeatures.deletion_protection). Updatecore/contract_resolver.pyresolve_l2()to propagatefeatures.deletion_protectionto each child'sdeletion_protectionNFR. Addinputs.deletion_protectiontoschemas/contract.schema.json(optional boolean). - platform-engineer: Add
tests/test_deletion_protection.py— assert every primitive has the NFR; assert adapter emitsprevent_destroy; assert L2 feature flag propagation.
Must-haves:
- Every primitive has
deletion_protectionNFR (default true) - Adapter emits
prevent_destroy = truewhen true - L2 feature flag propagates
pytestpasses (~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):
- platform-engineer: Create
modules/l1/uptime/withinterface.json(typeaws: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. - platform-engineer: Add
aws:ecs:uptime-serviceto adapter TYPE_MAP. Emit ECS Fargate task + service + ALB + listener + EFS volume + CloudWatch log group. Whenfeature_flag_enabled=false, emit NO resources. Register inregistry.json.
Tasks (Wave 2 — pipeline + script, after Wave 1):
- backend-engineer: Add
deploy-uptimestage topipelines/deploy.yaml(afterpublish-outputs). Update both deploy workflows (byte-identical) with the stage. Addscripts/seed_uptime_monitors.pyfor post-deploy monitor seeding via uptime-kuma API. - backend-engineer: Update
scripts/run_platform.sh— adddeploy-uptimestep: read L2 stack outputs, construct synthetic uptime contract withmonitored_endpointsfrom outputs, run second terraform apply with separate state ($WORK/uptime-tf/), publish uptime URL via PR comment. Skip wheninputs.uptime_enabled=false. - backend-engineer: Add
tests/test_uptime_primitive.py— validate interface; assert adapter emits ECS service when flag=true; assert no resources when flag=false; assertdeploy-uptimestage 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-uptimestage in deploy contract + byte-identical workflowspytestpasses (~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):
- lambda-engineer: Add
acdl-change-requestsDynamoDB table toterraform/platform/main.tf(PK changeRequestId, SK submittedAt, SSE via CMK, PITR). Addvalidate_change_requestaction tocore/lambda/contract_ingestor.py— query table, assert status=approved + consumerRepo match, return CR details or 403. - backend-engineer: Add
decommission_transform(stack_instance)tocore/contract_resolver.py— zero all counts (desired_count=0 for ECS, etc.).
Tasks (Wave 2 — pipeline + docs, after Wave 1):
- backend-engineer: Add
mode: decommissionto deploy workflow inputs. Add decommission stages topipelines/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). - backend-engineer: Update
docs/CONSUMER_GUIDE.mdwith "Decommissioning a stack" section (request CR, trigger decommission, HITL gates, what happens). - backend-engineer: Add
tests/test_decommission.py— assertdecommission_transformzeroes counts; assertvalidate_change_requestrejects 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
pytestpasses (~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):
- 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. - lead-developer: Fix
modules/README.mdcatalog index — add rds + uptime + kms-key to Primitives table. Updatemodules/README-TEMPLATE.md— add## NFRssection. - backend-engineer: Add
tests/test_module_standards.py— automated enforcement: every L1 hasdeletion_protection+encryption_enabledNFRs; every L2 has valid structure; every module registered; every module has README + examples.
Must-haves:
modules/STANDARDS.mdexists with L1+L2 standards- Catalog index includes all primitives
- Template has NFRs section
- Automated standards test passes
pytestpasses (~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):
- lead-developer: Author
schemas/README.md— how to write schemas, wire into platform, test in CI, dependencies, existing catalog. - lead-developer: Author
pipelines/README.md— how to write pipeline contracts, wire into workflows, test, dependencies, catalog. - lead-developer: Author
adapters/README.md— how to write adapters, wire into platform, test, dependencies, catalog. - 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
pytestpasses (~358)
Phase 37 — verify
Personas: lead-developer (lead), all personas Type: verify
Tasks:
- Structural: all new files present.
- Behavioral:
pytestpasses (~358);run_ci.shexits 0;run_platform.sh --check-onlyexits 0. - Security: no secrets; CMK enforced; no placeholder account IDs; deletion protection on by default.
- 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:
- Review: 0 new P0/P1; all P1-3..P1-9 + S1 resolved; 3 new requirements delivered.
- Audit: reconstruction, file discipline, branch hygiene, commit discipline.
- Complete: update REQUIREMENTS.md (REQ-76..99), ROADMAP.md, PROJECT.md. Tag
v1.8.0. Update floatingv1.8+v1tags. Bumpuses:to@v1.8.