# ACDL — Roadmap ## Overview - **v1.0 (demo):** complete — tag `v1.1.0`, 2026-07-21. All 5 phases shipped + audited PASS. - **v1.1 (complete):** architecture finalization + v1 spike. 5 phases (06–10). Tag `v1.2.0`, 2026-07-21. All 5 phases shipped + verified; review READY TO SHIP (0 P0); audit CLEAN. Gitea release id 202. - **v1.2 (complete):** platform hardening + first real consumer deployment. 6 phases (11–16). Tag `v1.3.0`, 2026-07-21. All 6 phases shipped + verified; review READY TO SHIP (1 P0 operator action, 1 P1 deferred); audit CLEAN. - **v1.3 (complete):** module documentation + thin-composition removal. The L2 composition layer is removed; module READMEs are built out. Tag `v1.3.2`. - **v1.4 (complete):** central pipeline contract + shell reproducibility + output streaming. A declarative pipeline contract (`schemas/pipeline.schema.json` + `pipelines/ci.yaml`) binds the Gitea and GitHub workflows to a single source of truth. `scripts/run_ci.sh` mirrors the CI pipeline locally. `scripts/run_platform.sh` streams terraform/checkov output by default. - **v1.5 (complete, tag `v1.5.0`):** consumer happy path + zero-trust docs + reusable deploy workflow. README rewritten so the consumer model is unambiguous (consumer owns only contract + app code; the rest is the platform source). Platform-flow + consumer-guide diagrams converted to mermaid. Legacy surface + implementation nomenclature removed from docs. Credentials section rewritten for zero-trust OIDC + ABAC (with a static-key override + daily rotation). A generic `docs/CONSUMER_GUIDE.md` (all L2 modules, versioned `uses:`, consumer-scoped prereqs, run-time platform fetch) replaces the module-specific guide. A byte-identical reusable `deploy.yml` workflow (Gitea + GitHub) implements `pipelines/deploy.yaml` and is invoked by consumer repos via a versioned tag. - **v1.6 (complete, tag `v1.6.0`):** consumer-facing docs restructure + terminology normalization + environments concept. `docs/` becomes a Jekyll-style GitHub Pages site. `acdl_platform/` is renamed to `core/`. L2 → "modules", L1 → "primitives", "composition" → "pattern" in prose. README restructured: Features + Roadmap (no internal status), repository roles restated (consumer = app code + contracts + CI definitions), mermaid fixed (visible text, security-checks + infrastructure-apply stages, no tool names), credentials section minus go-gitea/waivers. Platform-managed environments concept + a minimal onboarding scaffold. `.ciagent/` + `.gitea/` references removed from all consumer-facing docs. - **v1.7 (complete, tag `v1.7.0`):** production platform + contract ingestion + pipeline maturation. Rename `static-assets` → `static-assets` (D-048 — incl. `.ciagent/` historical narrative). Author `cloudfront` + `waf` primitives; augment `static-assets` to a production-ready S3 + CloudFront (OAC) + WAF stack (D-049). Tagging-standard enforcement (Checkov custom rule, D-043 closure, D-054). Wiz adapter stub (D-052) + Kyverno K8s-native adapter (D-053). Platform Lambda + DynamoDB `acdl-contracts` table for contract ingestion (D-051) + cross-account IAM. Deploy outputs via SSM SecureString + GitHub PR comment (D-050). Uniform error reporting via the Lambda `report_error` action → GitHub issue on the platform repo (D-055); Gitea excluded. Stage comments after every successful pipeline stage. Three platform pipelines (platform-test unit+integration, primitives-plan, patterns-plan). Release job with semver + MAJOR.MINOR/MAJOR tag maintenance (D-057). `uses:`/`ref:` bumped to `@v1.6`; floating `v1.6` + `v1` tags created in Phase 22. Remove the legacy consumer-repos directory (a v1.2 artifact, removed in v1.7); add validated per-module examples (`modules//examples/`, D-058) including a new RDS primitive demonstrating multi-engine variation (D-059). - **v1.8 (complete, tag `v1.8.0`):** P1 remediation + uptime monitoring + engineering standards + encryption/deletion-protection by default + decommission alias + path documentation. Clears 8 pending P1 issues (P1-3..P1-9 + S1). Adds per-stack CMK + encryption-by-default for all primitives. Adds deletion-protection-by-default + L2 feature flag. Adds uptime-kuma primitive (ECS Fargate, deployed by default after L2, separate state, feature flag, alert channels). Adds decommission mode (2-step pipeline with HITL SRE gates + CMDB-validated change request). Adds `modules/STANDARDS.md` (L1+L2 authoring + review standards). Adds `schemas/README.md`, `pipelines/README.md`, `adapters/README.md`. - **v1.9.1 (complete, tag `v1.9.1`):** leadership presentation decks. Two leadership-facing presentation decks (How the Platform Works + The Developer Experience) for senior leadership (CTO, Head of Cloud, Head of Infrastructure, Head of DevOps). Each deck has a full markdown source of truth (with speaker notes + mermaid diagrams) and a lean Marp deck (no speaker notes, embedded PNG diagrams). A README documents the 3-step slide creation process (full markdown → Marp synthesis → PPTX export). Docs-only NFR patch. - **v1.9.2 (complete, tag `v1.9.2`):** S&P Global Energy theme for presentation decks. Applies the S&P Global Energy brand visual identity (red-core #D6002A, grey-90 #1B1B1B, Akkurat Pro font) to both Marp decks. Title headers changed to full platform name. Footer 'Confidential' → 'Internal'. Title slide subtitle removed. Last DX slide renamed to 'The Desired Outcomes'. Docs-only NFR patch. - **v1.9.3 (complete, tag `v1.9.3`):** rendered presentation decks. HTML renderings of both Marp decks committed to docs/presentations/ (self-contained, base64-embedded images, S&P Global Energy theme). PPTX files uploaded to the Gitea release as downloadable attachments. README updated to document HTML as committed artifacts and PPTX as release attachments. Docs-only NFR patch. - **v1.9.4 (complete, tag `v1.9.4`):** presentation slide updates + complete removal of a specific compliance framework from all docs. Title slide redesigned (deck title as H1, 'Agentic Cloud Delivery Platform' as subtitle). DX deck: removed Local Reproducibility slide, redesigned Safe Promotion Path with side-by-side layout, 'an agent' → 'an AI agent', What a Developer Does diagram floated right. All references to that framework removed from 25 files (presentations, module READMEs, docs). Compliance lists now: GDPR, SOX, SOC2, DORA. HTML re-rendered. PPTX uploaded to release. Docs-only NFR patch. - **v1.9.5 (complete, tag `v1.9.5`):** vision gaps + Testing badge + engine terminology + agentic tags + CR format. 9 requirements: (1) DX closing slide strengthened with 'infrastructure as a utility' vision bullet; (2) 'moving' → 'promoting'; (3) added red tape + scalability bullets to Problem slide; (4) Roadmap slide redesigned side-by-side; (5) new 'What This Platform Is — and Isn't' slide (PW deck 16 slides); (6) 'shipped'/'Available today' → 'Testing' (0 consumer adoption); (7) global 'substrate' → 'engine' (88 matches, 30+ files); (8) 'forge' → 'VCS' in presentation files only; (9) new Agentic badge (purple) on agentic features. CR format changed to CHG0678912. HTML re-rendered. PPTX uploaded to release. Docs-only NFR patch. - **v1.9.6 (complete, tag `v1.9.6`):** consolidate both Marp decks to 10 high-impact slides. PW deck 16 → 10 (merged Problem+North Star+Anti-goals, merged Policy+Secure by Default, merged Audit+HITL, folded Observability/Environments/Portability into existing slides, added Vision Realized closing). DX deck 15 → 10 (merged What Dev Does+Contract+No Platform Code, merged Feedback+Deploy Outputs, merged Promotion+Rising Bar, cut Citizen Developer standalone, kept Versioned Releases/Onboarding/Decommission). Removed '5-line YAML' claim from both decks. Source markdown unchanged. Docs-only NFR patch. - **v1.9.7 (complete, tag `v1.9.7`):** talking points files + 4-step process. Created two talking points markdown files (one per deck) distilling the source of truth into presenter-ready cues indexed by the Marp deck's 10-slide structure. Each file has 3-6 talking point bullets + key takeaway per slide. README updated from 3-step to 4-step process (added Step 4: talking points). Directory layout, checklist, and decks table updated. Docs-only NFR patch. - **v1.0 demo URL:** https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html --- ## v1.0 (Prior — the demo, complete) Five-phase breakdown that took ACDL from empty repo to a reproducible 4-act executive demo. Milestone `v1.0-initial` covered the full demo build. Each phase produced a runnable increment and ended with a phase-completion commit + tag. All phases complete; demo archived to `demo/` in v1.1 Phase 06. ## Phases ### Phase 01 — repo-scaffolding - **Description:** Create the three repos under `continuous-intelligence` (`acdl-contracts`, `acdl-evidence`; `acdl` already exists), seed directory layouts, configure Pages on `acdl-evidence`, add environment protection for `qa` and `prod` on `acdl-contracts`. - **Status:** complete (v1.0.1) - **Depends on:** — - **Requirements:** REQ-01, REQ-09, REQ-10 - **Success Criteria:** - `acdl-contracts` and `acdl-evidence` exist and are pushable. - `acdl-evidence` Pages returns 200 with placeholder `index.html`. - `qa` and `prod` environments exist on `acdl-contracts`. ### Phase 02 — l1-modules - **Description:** Create all 8 L1 module folders under `acdl/modules/l1/`, each with `manifest.yaml` (declared inputs) and `mock_apply.sh` (uniform echo + 1s sleep + exit 0). - **Status:** complete (v1.0.2) - **Depends on:** [1] - **Requirements:** REQ-02, REQ-03 - **Success Criteria:** - All 8 L1s present; `mock_apply.sh` runs and exits 0 for each. - `manifest.yaml` validates against the L1 schema. ### Phase 03 — l2-modules-and-core-scripts - **Description:** Create the 4 L2 compositions under `acdl/modules/l2/` referencing L1s, plus the 5 core scripts in `acdl/scripts/` (`mock_executor.sh`, `policy_checker.py`, `confidence_signal.py`, `evidence_writer.py`, `l3b_agent_stub.py`). - **Status:** complete (v1.0.3) - **Depends on:** [2] - **Requirements:** REQ-04, REQ-05, REQ-06, REQ-07 - **Success Criteria:** - `mock_executor.sh` applies each L1 in an L2 and writes `state.json`. - `policy_checker.py` fails on `public-ingress: true` with `POLICY_VIOLATION:PUBLIC_INGRESS`. - `confidence_signal.py` returns 0.90 (pass) / 0.40 (fail). - `evidence_writer.py` appends an event with a valid hash chain. - `l3b_agent_stub.py` maps the Act 3 example issue to `l2-commodity-price-feed`. ### Phase 04 — pipeline-and-approval-gates - **Description:** Build the reusable pipeline workflow in `acdl/.gitea/workflows/` (Dev → QA → Prod → Finalize) plus the issue-triggered L3B workflow in `acdl-contracts/.gitea/workflows/`. Wire environment protection for QA and Prod. - **Status:** complete (v1.0.4) - **Depends on:** [3] - **Requirements:** REQ-08, REQ-09, REQ-10, REQ-12 - **Success Criteria:** - Pushing a valid `contract.yaml` runs Dev automatically and pauses at QA. - Approving QA moves to Prod; approving Prod finalizes. - Opening an Issue with the Act 3 text generates a `contract.yaml` commit and triggers the pipeline. ### Phase 05 — evidence-ui-and-demo-dry-run - **Description:** Build `index.html` (vanilla JS, fetches `audit.json`, renders timeline) and run all four acts end-to-end as a dry run. - **Status:** complete (v1.0.5) - **Depends on:** [4] - **Requirements:** REQ-11, REQ-13, REQ-14, REQ-15 - **Success Criteria:** - Pages timeline renders events from `audit.json`. - Act 2: valid contract passes through all gates; timeline shows the full flow. - Act 3: Issue text produces the expected `l2-commodity-price-feed` contract and triggers the pipeline. - Act 4: malicious `public-ingress: true` contract halts in Dev with confidence < 0.50 and a visible rejection reason on the timeline. --- ## v1.1 (Complete — architecture finalization + v1 spike, 2026-07-21, tag `v1.2.0`) Five-phase breakdown to finalize the architecture to v1.0 and prove the locked commitments with one end-to-end implementation spike. Milestone `v1.1-spike` covered the real platform's first materialization. Ship tag at milestone COMPLETE: **`v1.2.0`** (feature milestone, next minor per ship.md). **Status: COMPLETE — all 5 phases shipped (v1.1.1..v1.1.5) + verified; review READY TO SHIP (0 P0); audit CLEAN; Gitea release id 202. D-034 closed (root key deactivated by user).** ### Phase 06 — archive-demo-and-reorient - **Description:** Move the v1.0 demo (`modules/`, `scripts/`, `evidence-ui/`, `contracts/`, demo `.gitea/workflows/`) to `demo/`. Establish the new repo layout (`platform/`, `schemas/`, `adapters/`, `terraform/`, `modules-ir/`). Rewrite README to reflect the real platform. Verify the demo still runs from `demo/` (regression check). - **Status:** complete (v1.1.1) - **Depends on:** — - **Requirements:** (no new REQ; repo hygiene) - **Success Criteria:** - `demo/` contains the full v1.0 demo; `demo/scripts/run_demo.sh --no-upload` still exits 0. - New top-level dirs exist and are empty-but-scaffolded: `platform/`, `schemas/`, `adapters/`, `terraform/`, `modules-ir/`. - README reflects the real platform (vision + architecture links, new layout). ### Phase 07 — architecture-v1-finalization - **Description:** Resolve the 11 open decisions in `docs/architecture.md` §13 (already recorded in `PROJECT.md`). Author the locked schemas + designs: `schemas/ir.schema.json` (REQ-17), `schemas/policy_check_result.schema.json` (REQ-18), `schemas/contract.schema.json` (REQ-22), `platform/confidence_signal.py` spec (REQ-19), `platform/audit_ledger_design.md` (REQ-20), `platform/hitl_matrix_design.md` (REQ-21). Mark architecture v1.0. - **Status:** complete (v1.1.2) - **Depends on:** [06] - **Requirements:** REQ-16, REQ-17, REQ-18, REQ-19, REQ-20, REQ-21, REQ-22 - **Success Criteria:** - All 11 open decisions resolved and recorded in `PROJECT.md`. - All 6 schema/design files exist and validate (`ajv` / `python -m jsonschema`). - `docs/architecture.md` status note updated to v1.0 (or a `docs/architecture-v1.0.md` snapshot). ### Phase 08 — aws-oidc-bootstrap - **Description:** **Re-scoped per RESEARCH TARGET 1 + D-039.** Gitea Actions does not support `id-token: write` (conf 0.95), so real OIDC is deferred to v1.2. This phase instead: uses the temporary long-lived key (waiver D-034) once to create an S3 state bucket, a DynamoDB lock/outbox table, and an IAM user with a minimal scoped policy (S3 + DynamoDB + plan-only); stores the key as a Gitea Actions secret; implements `scripts/rotate_spike_key.sh` to rotate the key after each spike run. Real OIDC federation is tracked via go-gitea/gitea#36988 for v1.2. - **Status:** complete (v1.1.3) - **Depends on:** [07] - **Requirements:** REQ-23 (re-interpreted: AWS auth bootstrap + state backend; OIDC deferred to v1.2 per D-039) - **Success Criteria:** - S3 state bucket + DynamoDB lock/outbox table exist. - An IAM user with a minimal scoped policy exists; its access key is stored as a Gitea Actions secret. - `scripts/rotate_spike_key.sh` rotates the key (deactivates old, creates new, updates the secret) and is idempotent. - A workflow step authenticates to AWS with the rotated secret and runs `aws sts get-caller-identity` successfully. - D-034 is closed: the bootstrap long-lived key is rotated/deactivated (logged in `PROJECT.md`). ### Phase 09 — v1-spike-ir-and-l1-and-adapter - **Description:** Implement the Target Stack IR, one real L1 `l1-s3` (IR-typed interface, registered), and the Terraform adapter that compiles the IR → Terraform `variable`/`output` + root module and emits a real `terraform plan` against AWS (via the rotated-key secret per D-039; OIDC is v1.2). State in S3 + DynamoDB. - **Status:** complete (v1.1.4) - **Depends on:** [08] - **Requirements:** REQ-24, REQ-26 - **Success Criteria:** - `schemas/ir.schema.json` is satisfied by `modules-ir/l1/l1-s3/` interface. - The Terraform adapter translates `l1-s3` to a valid `terraform plan` (real AWS). - `terraform validate` + `terraform plan` succeed; no long-lived credential in the workflow. ### Phase 10 — v1-spike-l2-and-contract-e2e - **Description:** Implement `l2-static-assets` (thin-composition referencing `l1-s3`), the contract schema + contract→IR resolution, and one end-to-end contract submission (`contracts/spike.yaml` for `l2-static-assets`) flowing through schema validation → IR resolution → `terraform plan` → Checkov `PolicyCheckResult` → confidence signal → evidence event to the DynamoDB outbox. Verify the IR commitments hold (no polyglot mess). - **Status:** complete (v1.1.5) - **Depends on:** [09] - **Requirements:** REQ-25, REQ-27, REQ-28 - **Success Criteria:** - `l2-static-assets` references `l1-s3` only (depth 1). - One contract submission completes the full pipeline end-to-end. - `scripts/verify_phase10.sh` proves the adapter is the only engine-specific code. - Evidence event is written to the DynamoDB outbox. After Phase 10: COMPLETE gate — review → ship `v1.2.0` → audit. **DONE.** --- ## v1.2 (Complete — platform hardening + first real consumer deployment, 2026-07-21, tag `v1.3.0`) Six-phase breakdown to harden the v1.1 spike, simplify the setup, update the docs, and prove the platform delivers real value by deploying a basic microservice to AWS ECS Fargate end-to-end. Ship tag at milestone COMPLETE: **`v1.3.0`** (feature milestone, next minor per ship.md — v1.1 shipped `v1.2.0`). Phase patches `v1.2.1`..`v1.2.6`. **Status: COMPLETE — all 6 phases shipped (v1.2.1..v1.2.6) + verified; review READY TO SHIP (1 P0 operator action, 1 P1 deferred to v1.3); audit CLEAN. The terraform apply is blocked by the live IAM policy (P0-IAM, operator action); the platform flow is verified end-to-end up to terraform plan (13 to add).** ### Phase 11 — v1.2-research-and-readme - **Description:** Re-evaluate go-gitea/gitea#36988 (OIDC for Gitea Actions) — confirm still open (re-checked 2026-07-21: open, last updated 2026-05-27, not merged) and record the decision to extend D-039 as D-047. Audit the v1.1 spike for NFR gaps (least-privilege IAM, idempotency, error handling, rotation hygiene) and simplification opportunities (script consolidation, dead code, stale paths). Rewrite `README.md` to reflect v1.1 complete + the actual spike flow + how to run + the real repo layout + the v1.2 objective. - **Status:** complete (v1.2.1) - **Depends on:** — - **Requirements:** REQ-29 - **Success Criteria:** - `RESEARCH.md` has a v1.2 addendum with the #36988 re-check + NFR audit + simplification findings. - `README.md` reflects v1.1 complete; documents the spike flow, `scripts/run_platform.sh`, the repo layout, and the v1.2 objective; no stale "v1.1 (active)" framing. - D-047 is recorded in `PROJECT.md`. ### Phase 12 — nfr-harden-and-simplify - **Description:** Apply Phase 11's findings. Tighten `terraform/bootstrap/spike_runner_policy.json` to least-privilege (add ECS + ECR + ELB + IAM plan-only permissions for v1.2; audit for wildcards). Make `create_state_backend.py` and `create_iam_user.py` idempotent. Consolidate `run_spike_plan.sh` + `run_spike_e2e.sh` into a single `scripts/run_platform.sh` with proper exit codes and error handling. Redact P1-1 (the two AWS access key IDs in `.ciagent/VERIFY.md` Phase 09 narrative). Fix any remaining stale `platform/` paths in `.ciagent/`. The v1.1 spike still runs e2e after the refactor. - **Status:** complete (v1.2.2) - **Depends on:** [11] - **Requirements:** REQ-30 - **Success Criteria:** - `scripts/run_platform.sh` runs the full v1.1 spike e2e and exits 0. - `create_state_backend.py` / `create_iam_user.py` re-runs are idempotent (no duplicate resources; exit 0). - `spike_runner_policy.json` passes a least-privilege audit (no `*` actions beyond documented exceptions). - `.ciagent/VERIFY.md` Phase 09 narrative has no live AWS access key IDs. - No stale `platform/` paths remain in `.ciagent/`. ### Phase 13 — l1-catalog-for-ecs - **Description:** Author six IR-typed L1 modules for an ECS Fargate microservice: `l1-vpc` (VPC + subnets + route tables), `l1-ecs-cluster` (ECS Fargate cluster), `l1-ecs-service` (ECS service + task definition), `l1-iam-role` (task execution + task role), `l1-alb` (ALB + listener + target group), `l1-ecr` (ECR repository). Each has an `interface.json` valid against `schemas/ir.schema.json`. Register all six in `modules-ir/registry.json`. Expand the Terraform adapter `TYPE_MAP` to cover the new IR resource types. Each L1 produces a valid `terraform plan` fragment. - **Status:** complete (v1.2.3) - **Depends on:** [12] - **Requirements:** REQ-31 - **Success Criteria:** - All six L1s exist under `modules-ir/l1/` with `interface.json` valid against `schemas/ir.schema.json`. - `modules-ir/registry.json` lists all six. - The adapter `TYPE_MAP` covers all six IR resource types. - Each L1 produces a valid `terraform plan` fragment. ### Phase 14 — l2-microservice-and-contract-schema - **Description:** Author `l2-microservice` thin-composition under `modules-ir/l2/l2-microservice/` referencing the six ECS L1s (depth ≤ 5). Extend `schemas/contract.schema.json` with microservice inputs (`image: string`, `port: integer`, `env: map`, `healthcheck: object`). Verify contract→IR resolution yields a complete target stack. - **Status:** complete (v1.2.4) - **Depends on:** [13] - **Requirements:** REQ-32 - **Success Criteria:** - `l2-microservice` references the six ECS L1s only (depth ≤ 5). - `schemas/contract.schema.json` validates a `contracts/microservice.yaml` with the new inputs. - Contract→IR resolution yields a complete target stack (all six L1 instances + relationships). ### Phase 15 — consumer-repo-and-terraform-apply - **Description:** Create a new Gitea repo `acdl-consumer-microservice` under the `continuous-intelligence` org containing a basic HTTP microservice (tiny Python/Go server returning 200), a `Dockerfile`, an ECR push step, and a `contracts/microservice.yaml` submission for `l2-microservice` (dev environment). Lift the platform from `plan` to **`apply`** for the `dev` environment (autonomous per §10, confidence ≥ 0.50, no HITL). Submit the contract → pipeline → IR → plan → apply → a real ECS Fargate service running. - **Status:** complete (v1.2.5, PARTIAL — terraform apply blocked by IAM P0) - **Depends on:** [14] - **Requirements:** REQ-33 (partial), REQ-34 - **Success Criteria:** - `acdl-consumer-microservice` repo exists under `continuous-intelligence`. - The microservice builds into a Docker image and is pushed to ECR. - `terraform apply` (dev) creates real AWS resources (VPC, ECS cluster, ECR repo, ALB, ECS service). - The apply result is captured in the evidence stream. ### Phase 16 — v1.2-capstone-e2e - **Description:** End-to-end verification: consumer commit to `acdl-consumer-microservice` triggers the pipeline → contract→IR resolution → `terraform plan` → `terraform apply` (dev) → a live ECS Fargate service serving HTTP 200 on its ALB → evidence event written to the DynamoDB outbox → the event renders on the `acdl-evidence` timeline. Verify the NFR improvements from Phase 12 hold, the setup is simpler (one `scripts/run_platform.sh`), and the README is accurate. `scripts/verify_phase16.sh` proves the full flow green. - **Status:** complete (v1.2.6, capstone — terraform apply blocked by IAM P0, verified up to plan) - **Depends on:** [15] - **Requirements:** REQ-35 (partial — IAM-blocked) - **Success Criteria:** - One consumer commit produces a live ECS service serving HTTP 200. - An evidence event for the apply is in the DynamoDB outbox and renders on the timeline. - `scripts/verify_phase16.sh` exits 0. - README accurately documents the v1.2 platform flow. After Phase 16: COMPLETE gate — review → ship `v1.3.0` → audit. --- ## v1.3 (Complete — module documentation + thin-composition removal) The v1.3 milestone starts with simplification: removing the unsatisfactory thin-composition layer and building out proper module documentation. The L2 composition mechanism will be redesigned in a later phase. ### Phase 17 — remove-thin-composition-and-module-readmes - **Description:** Remove the L2 thin-composition layer completely (composition.json files, contract_resolver.py, contract schema, sample contracts) and build out proper module READMEs. Create a README template for both L1 and L2 modules, rewrite all 7 L1 module READMEs in plain language (no jargon, with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning sections), write 2 L2 placeholder READMEs noting the composition is under redesign, create a catalog index, and patch run_platform.sh to load a pre-existing IR instance instead of resolving a contract. Prune L2 entries from the registry. - **Status:** complete (v1.3.1) - **Depends on:** — - **Requirements:** REQ-36, REQ-37, REQ-38 - **Success Criteria:** - The thin-composition layer is fully removed (composition.json, contract_resolver.py, contract schema, contracts/). - run_platform.sh loads a pre-existing IR instance; the downstream adapter/checkov/confidence/outbox pipeline still works. - A README-TEMPLATE.md exists for both L1 and L2 modules. - Every L1 module has a README.md with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning. - Every L2 module has a placeholder README.md noting the composition is under redesign. - A modules-ir/README.md catalog index exists. ### Phase 18 — testing-and-cicd-pipelines - **Description:** Create a pytest test suite that reproduces the platform pipeline offline (adapter, confidence_signal, checkov_adapter, outbox_writer). Add an offline `--check-only` mode to `run_platform.sh` that runs the pipeline up to adapter emission without AWS/Checkov/outbox. Create identical CI/CD pipelines for both Gitea Actions (`.gitea/workflows/ci.yml`, dev environment) and GitHub Actions (`.github/workflows/ci.yml`, production) that run: lint, pytest, `run_platform.sh --check-only`. Add `pyproject.toml` + `requirements-test.txt` for dependency pinning. - **Status:** complete (v1.3.2) - **Depends on:** [17] - **Requirements:** REQ-39, REQ-40, REQ-41, REQ-42 - **Success Criteria:** - `pytest` runs and passes offline (no AWS, no Checkov, no DynamoDB). - `run_platform.sh --check-only` runs offline and exits 0. - `.gitea/workflows/ci.yml` and `.github/workflows/ci.yml` exist with identical job stages (lint, test, check-only). - `pyproject.toml` + `requirements-test.txt` pin test dependencies. After Phase 18: COMPLETE gate — review → ship `v1.3.2` → audit. --- ## v1.4 (Active — central pipeline contract + shell reproducibility + streaming) The v1.4 milestone makes the CI/CD pipeline a declarative contract rather than duplicated workflow copies, enables full shell reproducibility of the CI pipeline, and streams terraform/checkov output so users can see what the platform is doing. ### Phase 19 — central-pipeline-contract-and-shell-reproducibility - **Description:** Create a central pipeline contract (`schemas/pipeline.schema.json` JSON Schema + `pipelines/ci.yaml` YAML instance) that both `.gitea/workflows/ci.yml` (Gitea Actions, dev) and `.github/workflows/ci.yml` (GitHub Actions, production) implement. Create `scripts/run_ci.sh` that mirrors the CI pipeline locally (lint → test → check-only). Update `scripts/run_platform.sh` to stream terraform init/validate/plan output, Checkov compliance results, and PolicyCheckResult records to stdout by default (with `--quiet` for log-only mode). Add `tests/test_pipeline_contract.py` validating the contract schema, workflow conformance, and run_ci.sh. Update both workflow YAMLs with contract reference headers (staying byte-identical). - **Status:** complete (v1.4.1) - **Depends on:** [18] - **Requirements:** REQ-43, REQ-44, REQ-45 - **Success Criteria:** - `pipelines/ci.yaml` validates against `schemas/pipeline.schema.json`. - Both `.gitea/workflows/ci.yml` and `.github/workflows/ci.yml` are byte-identical. - A test parses both workflows and asserts their stages/commands match the contract. - `scripts/run_ci.sh` exits 0 and outputs "CI PIPELINE OK". - `scripts/run_platform.sh --check-only` streams the emitted Terraform to stdout. - `scripts/run_platform.sh --check-only --quiet` suppresses the Terraform stream. - `pytest` total count increases from 90 to 122 (32 new contract/streaming tests). After Phase 19: COMPLETE gate — review → ship `v1.4.1` → audit. --- ## v1.5 (Complete — consumer happy path + zero-trust docs + reusable deploy workflow, tag `v1.5.0`) The v1.5 milestone makes the consumer happy path self-evident, documents the zero-trust credential model, and provides a reusable deploy workflow so consumer repos never need to clone the platform repo or invoke its scripts locally. ### Phase 20 — consumer-happy-path-and-reusable-deploy-workflow - **Description:** Rewrite `README.md` so the consumer model is unambiguous (this repo is the platform source; a consumer owns only `contract.yaml` + app code). Convert the platform-flow diagram to a mermaid `flowchart TD`. Remove "L3A"/"L3B" + "spike" nomenclature from README prose. Rewrite the Credentials section for zero-trust OIDC + ABAC (with a static-key override + daily rotation; consumer rotates out of band when using `.env.secrets` locally). Replace `docs/consumer-guide-static-assets.md` with a generic `docs/CONSUMER_GUIDE.md` (all L2 modules, mermaid diagrams, versioned `uses:` floating MAJOR+MINOR, consumer-scoped prerequisites, run-time platform fetch via a reusable workflow). Create byte-identical `.gitea/workflows/deploy.yml` + `.github/workflows/deploy.yml` implementing `pipelines/deploy.yaml` — a reusable workflow invoked by consumer repos via `uses: acdl/.gitea/workflows/deploy.yml@v1.4` that checks out the consumer repo + the ACDL platform repo and runs `scripts/run_platform.sh`. Update `contracts/static-assets.yaml` to `uses: acdl/pipelines/deploy.yaml@v1.4`. Extend `tests/test_pipeline_contract.py` to validate the new deploy workflows (byte-identical, schema-conformant). - **Status:** complete (v1.5.0) - **Depends on:** [19] - **Requirements:** REQ-46, REQ-47, REQ-48, REQ-49, REQ-50, REQ-51 - **Success Criteria:** - `README.md` states the platform-source vs consumer-repo distinction up front; platform flow is a mermaid `flowchart TD`; `grep L3B README.md` returns 0 hits; `grep -i spike README.md` returns 0 prose hits (code paths in bash blocks allowed). - `docs/CONSUMER_GUIDE.md` exists; `docs/consumer-guide-static-assets.md` is deleted; `grep -R consumer-guide-static-assets` returns 0 dangling references; guide is generic (static-assets is the worked example, not the scope); diagrams are mermaid; `uses:` references use `@v1.4`. - `README.md` Credentials section describes OIDC + ABAC zero-trust as the default and the static-key override + daily rotation + consumer out-of-band rotation duty for local `.env.secrets`. - `.gitea/workflows/deploy.yml` and `.github/workflows/deploy.yml` exist, are byte-identical, conform to `schemas/deploy-pipeline.schema.json`, and are reusable (`on: workflow_call` with a `contract` input). - `contracts/static-assets.yaml` uses `uses: acdl/pipelines/deploy.yaml@v1.4`. - `tests/test_pipeline_contract.py` validates the deploy workflows (exist, byte-identical, schema-conformant); the extended test suite passes; `bash scripts/run_ci.sh` exits 0. After Phase 20: COMPLETE gate — review → ship `v1.5.0` → audit. --- ## v1.6 (Active — consumer-facing docs restructure + terminology normalization + environments concept) The v1.6 milestone restructures the consumer-facing documentation into a real GitHub Pages site, normalizes the terminology (L2 → "modules", L1 → "primitives", "composition" → "pattern", "forge" → "platform runners"), renames `acdl_platform/` to `core/` (platform/ shadows stdlib), rewrites the README (Features + Roadmap, restated repository roles, fixed mermaid, cleaned credentials section), removes all `.ciagent/` + `.gitea/` references from consumer surfaces, and introduces the concept of platform-managed environments with a minimal first-run onboarding scaffold. ### Phase 21 — docs-restructure-and-terminology-normalization - **Description:** Rename `acdl_platform/` → `core/` (directory + all code/test/script/pipeline/workflow references; tests green — `platform/` was the original target but shadows Python's stdlib `platform` module, so `core/` was chosen). Restructure `docs/` into a Jekyll-style GitHub Pages site (`_config.yml`, `index.md`, `modules/`, `contracts/`, `pipeline/`, `environments/`, `consumer-guide.md`, consolidated `architecture.md`, `vision.md`). Rewrite `README.md`: remove `.ciagent/` + `.gitea/workflows/` rows; restate consumer repo model (app code + 1+ contracts + CI definitions `uses:`-ing the central workflow); replace Status with Features + Roadmap (planned only); fix the mermaid (visible text, add security-checks stage before policy, no tool names, add infrastructure-apply stage); remove the environments table; clean the credentials section (no go-gitea/waivers, keep daily/out-of-band rotation); forge → platform runners/platform-managed. Update `docs/consumer-guide.md`: drop L2 (→ modules), composition → pattern (prose), remove `.gitea/` (GitHub only), forge → platform runners, mermaid updated. Update `modules/` READMEs: L1 → primitives, L2 → modules, composition → pattern (prose only, files kept); bump stale `@v1` → `@v1.4`. Consolidate `docs/architecture.md` + `docs/architecture-v1.0.md` into a single current-architecture `docs/architecture.md`. Add `docs/environments/index.md` (platform-managed AWS account/network/state/runner; consumer provides none). Add a minimal onboarding scaffold: `core/environments/` dir + sample `dev.json` + README, `core/environment_check.py`, wire-in at the top of `scripts/run_platform.sh`, friendly onboarding message when no environment is defined, `tests/test_environment_check.py`. Add a roadmap entry: "composition" will later describe the thin orchestration where consumers dynamically create a module directly from the contract file (future implementation, not this phase). - **Status:** complete (v1.6.0) - **Depends on:** [20] - **Requirements:** REQ-52, REQ-53, REQ-54, REQ-55, REQ-56, REQ-57, REQ-58, REQ-59, REQ-60, REQ-61 - **Success Criteria:** - `grep -R "\.ciagent" docs/ README.md` returns 0 hits; `grep -R "\.gitea" docs/ README.md modules/ contracts/` returns 0 hits. - `grep -R "acdl_platform" .` (excluding `.ciagent/`, `demo/`, `.git/`) returns 0 hits; the test suite passes after the rename. - `docs/` has the Jekyll structure (`_config.yml`, `index.md`, `modules/`, `contracts/`, `pipeline/`, `environments/`); no `.ciagent/` links in `docs/`. - Consumer-facing docs have no "L2"/"L1" labels (modules/primitives) and no "forge" term; "composition" → "pattern" in prose. - README.md has Features + Roadmap (no version changelog); repository roles restated; mermaid visible + security-checks + infrastructure-apply stages + no tool names; no environments table; credentials section has no go-gitea/waivers. - `docs/environments/index.md` exists; `core/environments/` + `dev.json` + `environment_check.py` + `run_platform.sh` wire-in + `tests/test_environment_check.py` exist and pass. - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes (154 + new environment-check tests). After Phase 21: COMPLETE gate — review → ship `v1.6.0` → audit. **DONE.** --- ## v1.7 (Complete — production platform + contract ingestion + pipeline maturation, tag `v1.7.0`) The v1.7 milestone takes the platform from a documented, environments-aware foundation to a production-grade platform with a production-ready `static-assets` stack (CloudFront + WAF), a contract-ingestion Lambda + DynamoDB store for historical/impact analysis, a uniform error-reporting pathway via the same Lambda, DX-friendly deploy outputs (SSM + PR comments), three dedicated platform pipelines (unit+integration, primitives plan, patterns plan), a release job with MAJOR.MINOR/MAJOR tag maintenance, new security adapters (Wiz, Kyverno), real tagging-standard enforcement (closing D-043), removal of the legacy consumer-repos directory (removed in v1.7), and validated per-module examples (including a new RDS primitive demonstrating multi-engine variation). The `uses:`/`ref:` tag advances from `@v1.4` to `@v1.6`; the floating `v1.6` + `v1` tags are created in Phase 22 (pointing at the v1.6.0 release) so the reference is never broken, and the release job (Phase 26) owns ongoing updates. ### Phase 22 — rename-and-production-static-assets-stack - **Description:** Rename `static-assets` → `static-assets` everywhere (D-048 — including `.ciagent/` historical narrative, overriding the v1.6 preservation precedent). Author two new primitives: `cloudfront` (distribution + OAC, stack types `aws:cloudfront:distribution` + `aws:cloudfront:originaccesscontrol`) and `waf` (WAFv2 web ACL, stack type `aws:wafv2:webacl`). Augment the `static-assets` module to a production-ready stack referencing s3 + cloudfront + waf (depth 1, D-049). Expand the Terraform adapter `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` for the new stack types. Bump `uses:`/`ref:` from `@v1.4` to `@v1.6` (D-056/D-057); create the floating `v1.6` + `v1` git tags pointing at `v1.6.0` so the reference resolves immediately. - **Status:** complete (v1.7.0) - **Depends on:** [21] - **Requirements:** REQ-62, REQ-63, REQ-64 - **Success Criteria:** - `grep -R "static-assets[^s]" .` (excluding `.git/`) returns 0 hits; `modules/l2/static-assets/` is renamed to `modules/l2/static-assets/`; `contracts/static-assets.yaml` → `contracts/static-assets.yaml`; registry key renamed; all `.ciagent/` references (incl. verbatim phase descriptions, REQ-25/27/50 text, D-036) rewritten to `static-assets`. - `modules/l1/cloudfront/` + `modules/l1/waf/` exist with `interface.json` valid against `schemas/stack.schema.json`; registered in `modules/registry.json`. - `modules/l2/static-assets/composition.json` references s3 + cloudfront + waf (depth 1). - `adapters/terraform/adapter.py` `TYPE_MAP` covers `aws:cloudfront:distribution`, `aws:cloudfront:originaccesscontrol`, `aws:wafv2:webacl`. - `contracts/static-assets.yaml` + `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` use `@v1.6`; git tags `v1.6` + `v1` exist pointing at `v1.6.0`. - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes; `bash scripts/run_platform.sh --check-only` exits 0. ### Phase 23 — tagging-standards-and-security-adapters - **Description:** Define a required-tag set (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`) in `schemas/tagging-standard.json` (D-054). Author a Checkov custom YAML rule at `adapters/terraform/policy/custom_rules/acdl_tagging.yaml` that fails when required tags are missing on taggable resources. Remove the `_emit_tag_naming_skipped()` placeholder in `checkov_adapter.py` (D-043 closure) and add `ACDL_TAG_NAMING` to `RULE_MAP` as a real rule. Author a Wiz adapter stub (`adapters/wiz/wiz_adapter.py`) translating Wiz API issues → `PolicyCheckResult` records (`engine: "wiz"`), degrading gracefully when unconfigured (D-052). Author a Kyverno K8s-native adapter (`adapters/kyverno/kyverno_adapter.py`) translating Kyverno `PolicyReport` results → `PolicyCheckResult` records (`engine: "kyverno"`), with sample policies as documentation; inactive for Terraform-only stacks, ready for the GitOps reconciler roadmap item (D-053). Add `wiz` + `kyverno` to the `schemas/policy_check_result.schema.json` engine enum. - **Status:** complete (v1.7.0) - **Depends on:** [22] - **Requirements:** REQ-65, REQ-66, REQ-67 - **Success Criteria:** - `adapters/terraform/policy/custom_rules/acdl-tagging.yaml` exists; Checkov loads it; `checkov_adapter.py` no longer emits a SKIPPED `ACDL_TAG_NAMING` placeholder (D-043 closed). - `adapters/wiz/wiz_adapter.py` + `tests/test_wiz_adapter.py` exist; tests pass offline (not-configured graceful degradation). - `adapters/kyverno/kyverno_adapter.py` + sample policies + `tests/test_kyverno_adapter.py` exist; tests pass offline. - `schemas/policy_check_result.schema.json` engine enum includes `checkov | kyverno | opa | wiz`. - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes. ### Phase 24 — platform-lambda-and-contract-ingestion - **Description:** Author a platform Lambda (`core/lambda/contract_ingestor.py`) invoked via a Function URL (IAM auth) that accepts `{ consumerRepo, contractId, contract, environment, action }` and writes contracts to a DynamoDB table `acdl-contracts` (PK `consumerRepo`, SK `contractId#submittedAt`, SSE via a customer-managed CMK) (D-051). Define the Terraform (`terraform/platform/main.tf`) for the table, Lambda, Function URL, KMS key, Secrets Manager secret (`acdl/github-token`), and Lambda execution role. Define the cross-account consumer-invoke IAM policy (`terraform/platform/consumer_invoke_policy.json`) granting the consumer's deploy role `lambda:InvokeFunctionUrl` on the Lambda ARN, scoped via ABAC. The `report_error` action (Phase 25) is prepared but not yet implemented. Update `docs/environments/index.md` to document that onboarding now also grants Lambda-invoke permission. - **Status:** complete (v1.7.0) - **Depends on:** [23] - **Requirements:** REQ-68 - **Success Criteria:** - `core/lambda/contract_ingestor.py` exists; handler writes contracts to DynamoDB (tested offline with moto). - `terraform/platform/main.tf` defines `acdl-contracts` DynamoDB table, `acdl-contract-ingestor` Lambda, Function URL (IAM auth), KMS CMK, Secrets Manager secret, Lambda execution role. - `terraform/platform/consumer_invoke_policy.json` exists (cross-account invoke policy template). - `tests/test_contract_ingestor.py` passes offline. - `bash scripts/run_ci.sh` exits 0. ### Phase 25 — deploy-pipeline-dx-outputs-and-error-reporting - **Description:** Add a `publish-outputs` step to `scripts/run_platform.sh` (after apply) that writes deploy outputs to SSM Parameter Store as `SecureString` (KMS-encrypted, namespaced `/acdl/{env}/{contractId}/{output_name}`) for runtime-injectable values, and a `comment-outputs` step that posts a structured GitHub PR comment / job summary with human-readable connection strings (D-050). Implement `core/output_publisher.py` (SSM write + GitHub comment formatting). Implement the Lambda `report_error` action (`core/lambda/contract_ingestor.py`) that creates a GitHub issue on the platform repo (`acdl/acdl`) via the GitHub API using a token from Secrets Manager; idempotent (comments on existing open issue rather than duplicating) (D-055). Add an `if: failure()` error-report step to `.github/workflows/deploy.yml` that invokes the Lambda via `aws lambda invoke-function-url` (SigV4-signed). Add a PR comment after every successful pipeline stage (D-055 extension) via `scripts/post_stage_comment.sh` (uses `GITHUB_TOKEN` + `gh api`; no-op when not in a PR context). Update `pipelines/deploy.yaml` + both deploy workflow YAMLs with the new stages (byte-identical). - **Status:** complete (v1.7.0) - **Depends on:** [24] - **Requirements:** REQ-69, REQ-70, REQ-71 - **Success Criteria:** - `scripts/run_platform.sh` has a `publish-outputs` step (SSM SecureString, tested offline with moto) + a `comment-outputs` step (GitHub PR comment formatting, tested offline). - `core/lambda/contract_ingestor.py` `report_error` action creates a GitHub issue (tested with mocked API); idempotent. - `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` (byte-identical) have an `if: failure()` error-report step invoking the Lambda + stage comments after each successful stage (PR context). - `pipelines/deploy.yaml` declares the new stages. - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes. ### Phase 26 — platform-pipelines-and-release-automation - **Description:** Author three platform pipelines (D-057): (1) `.github/workflows/platform-test.yml` (PR, lint + unit + integration + schema-validation — replaces `ci.yml` for PRs); (2) `.github/workflows/primitives-plan.yml` (PR, plan-only for all L1 primitives via matrix); (3) `.github/workflows/patterns-plan.yml` (PR, plan-only for all L2 modules via matrix). Author `scripts/run_primitive_plan.sh` + `scripts/run_pattern_plan.sh` (with `--check-only` mode for CI). Author the release job (`.github/workflows/release.yml`) that runs on merge to `main`, computes the next semver (PATCH per phase, MINOR on milestone COMPLETE), creates the MAJOR.MINOR.PATCH tag, force-moves the MAJOR.MINOR + MAJOR floating tags, creates a GitHub release with an auto-generated body. This is the mechanism that lets consumers on `@v1` or `@v1.7` receive updates. - **Status:** complete (v1.7.0) - **Depends on:** [25] - **Requirements:** REQ-72, REQ-73 - **Success Criteria:** - `.github/workflows/platform-test.yml` exists, runs lint + unit + integration + schema-validation on PR. - `.github/workflows/primitives-plan.yml` + `.github/workflows/patterns-plan.yml` exist, run plan-only (matrix) on PR. - `.github/workflows/release.yml` exists, computes next semver, creates + updates MAJOR.MINOR.PATCH / MAJOR.MINOR / MAJOR tags on merge. - `scripts/run_primitive_plan.sh` + `scripts/run_pattern_plan.sh` exit 0 in `--check-only` mode. - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes. ### Phase 27 — remove-legacy-consumer-repos-and-module-documentation-examples - **Description:** Delete the legacy consumer-repos directory entirely (a v1.2 artifact removed in v1.7; references in `.ciagent/` historical narrative are rewritten per D-048). Author a new RDS primitive (`modules/l1/rds/`) with an `engine` input (enum: postgres, mysql, etc.) demonstrating multi-engine variation (D-059). Expand the adapter `TYPE_MAP` for `aws:rds:instance` → `aws_db_instance`. For **each** module (primitives + patterns), add a `modules//examples/` directory with `simple.yaml` + `complex.yaml` (+ variation files) validated against `schemas/contract.schema.json` in the platform-test pipeline (Phase 26 schema-validation stage) (D-058). Each module's `README.md` `## Examples` section references + excerpts the validated files. Update `docs/modules/index.md` + `docs/consumer-guide.md` + `docs/contracts/index.md` with the new module names + examples. - **Status:** complete (v1.7.0) - **Depends on:** [26] - **Requirements:** REQ-74, REQ-75 - **Success Criteria:** - The legacy consumer-repos directory does not exist; a recursive grep for the legacy directory name (excluding `.git/`) returns 0 hits. - `modules/l1/rds/` exists with `interface.json` (`engine` enum) + `examples/`; registered; adapter emits `aws_db_instance`. - Every module README has a `## Examples` section; `modules//examples/{simple,complex}.yaml` exist and validate against `schemas/contract.schema.json`. - `docs/modules/index.md` links to all module READMEs (including cloudfront, waf, rds). - `bash scripts/run_ci.sh` exits 0; `python3 -m pytest tests/ -v` passes. After Phase 27: COMPLETE gate — review → ship `v1.7.0` → audit. **DONE.** --- ## v1.8 (Complete — P1 remediation + uptime + engineering standards + encryption/deletion-protection by default + decommission + docs) The v1.8 milestone clears all pending P1 issues from v1.5–v1.7 verify reviews AND delivers three user-directed tracks: encryption + deletion protection by default (with a decommission alias), uptime monitoring (uptime-kuma primitive deployed by default after L2 modules), and engineering standards + path documentation. Ship tag at milestone COMPLETE: **`v1.8.0`** (feature milestone, next minor per run.md — v1.7 shipped `v1.7.0`). Phase patches `v1.7.1`..`v1.7.9`. ### Phase 28 — adapter-waf-and-resolver-outputs - **Description:** Fix WAF HCL emission: custom `rules` input emits nested `rules { ... }` blocks (not `rules = [...]` attribute syntax — P1-4). Honor `default_action` input (allow/block) instead of hardcoding `allow {}` (P1-5). Implement L2 composition `outputs[]` processing in `resolve_l2()` — build `stack.outputs` dict + adapter emits `output` blocks (P1-7). Tests for all three fixes. - **Status:** complete (v1.8.0) - **Depends on:** — - **Requirements:** REQ-76, REQ-77 - **Success Criteria:** - WAF with custom rules emits nested `rules {` blocks, not `rules = [`. - WAF with `default_action: block` emits `block {}`; default (absent) emits `allow {}`. - L2 resolution of `static-assets` yields `stack.outputs.distribution_domain_name`, `bucket_arn`, `web_acl_arn`. - Adapter emits `output "distribution_domain_name" { value = ... }` blocks. - `pytest` passes; `run_platform.sh --check-only` exits 0. ### Phase 29 — ssm-kms-and-invoke-policy - **Description:** SSM publisher fails loud (`RuntimeError`) when `ACDL_KMS_KEY_ID` unset; `ACDL_ALLOW_DEFAULT_KMS=1` escape hatch for local testing (P1-3). Convert `consumer_invoke_policy.json` to a Terraform-rendered template using `data.aws_caller_identity` + `templatestring` — no `000000000000` placeholder (P1-6). Tests for both. - **Status:** complete (v1.8.0) - **Depends on:** [28] - **Requirements:** REQ-78, REQ-79 - **Success Criteria:** - SSM publisher raises `RuntimeError` when `ACDL_KMS_KEY_ID` unset; succeeds with `ACDL_ALLOW_DEFAULT_KMS=1`. - Rendered invoke policy contains the caller's live account ID, not `000000000000`. - `pytest` passes; `run_ci.sh` exits 0. ### Phase 30 — run-platform-isolation-and-api-portability - **Description:** `run_platform.sh` emits adapter output to `$WORK/tf` (per-run temp dir), not `terraform/spike/`; remove committed `terraform/spike/*.tf` (P1-8). `contract_ingestor.py` reads `GITHUB_API_BASE` env for forge-agnostic API URLs (GitHub + Gitea); `_forge_type()` branches search URL (P1-9). Deploy workflow `configure-aws-credentials` step restructured as single conditional step: OIDC when no static key, `access-key`/`secret-key` inputs when static key present (S1). Both deploy workflows remain byte-identical. - **Status:** complete (v1.8.0) - **Depends on:** [29] - **Requirements:** REQ-80, REQ-81, REQ-82 - **Success Criteria:** - `run_platform.sh --check-only` writes to a temp dir; no `terraform/spike/*.tf` committed. - `contract_ingestor.py` uses `GITHUB_API_BASE`; Gitea base URL produces correct API paths. - Deploy workflow static-key override wired to `configure-aws-credentials` inputs. - Both deploy workflows byte-identical; `pytest` + `run_ci.sh` green. ### Phase 31 — encryption-by-default-and-per-stack-cmk - **Description:** Create `kms-key` L1 primitive (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). Adapter emits `aws_kms_key` + `aws_kms_alias` + `enable_key_rotation = true`. Add `encryption_enabled` NFR (default true) + `kms_key_arn` input to all primitives. L2 modules wire a `kms-key` child + connect its output to all children. Managed KMS fallback when no CMK provided (with stderr warning). - **Status:** complete (v1.8.0) - **Depends on:** [30] - **Requirements:** REQ-83, REQ-84, REQ-85 - **Success Criteria:** - Every primitive has `encryption_enabled` NFR (default true) + optional `kms_key_arn` input. - L2 resolution wires per-stack CMK to all children. - Adapter emits encryption blocks (SSE, storage_encrypted, encryption_configuration) referencing the CMK. - `enable_key_rotation = true` on the CMK; no shared keys across stacks. - `pytest` + `run_ci.sh` green. ### Phase 32 — deletion-protection-by-default-and-l2-feature-flag - **Description:** Add `deletion_protection` NFR (boolean, default true) to every L1 primitive. Adapter emits `lifecycle { prevent_destroy = true }` when true; omits it when false. L2 modules expose `features.deletion_protection` flag (default true); resolver propagates to each child's NFR. Consumers can set `inputs.deletion_protection: false` in contract. Update contract schema. - **Status:** complete (v1.8.0) - **Depends on:** [31] - **Requirements:** REQ-86, REQ-87 - **Success Criteria:** - Every primitive has `deletion_protection` NFR defaulting to true. - Adapter emits `prevent_destroy = true` when true; omits when false. - L2 feature flag propagates to all children. - `pytest` + `run_ci.sh` green. ### Phase 33 — uptime-kuma-primitive - **Description:** Create `uptime` L1 primitive (ECS Fargate running `louislam/uptime-kuma:1`). Inputs: container_image, region, monitored_endpoints (array of {name, url, type, interval, timeout}), static_checks, alert_channels ({teams_webhook, email_addresses, sms_numbers, github_issue_repo}), feature_flag_enabled (default true), cpu, memory. Outputs: uptime_url, service_arn, task_definition_arn. NFRs: deletion_protection, encryption_enabled. Adapter emits ECS service + ALB + log group; no resources when feature_flag_enabled=false. Register in registry. Add `deploy-uptime` pipeline stage (separate state, after publish-outputs) to `pipelines/deploy.yaml` + both deploy workflows. `run_platform.sh` constructs synthetic uptime contract from L2 outputs + runs second terraform apply. Uptime URL published via PR comment. Feature flag from `inputs.uptime_enabled` (default true). - **Status:** complete (v1.8.0) - **Depends on:** [32] - **Requirements:** REQ-88, REQ-89, REQ-90, REQ-91 - **Success Criteria:** - Uptime primitive exists with feature flag, monitored endpoints, alert channels. - Deployed by default after L2 module (separate state); endpoints passed from L2 outputs. - Uptime URL published via PR comment. - Feature flag disables deployment (no resources emitted). - `deploy-uptime` stage in deploy contract + byte-identical workflows. - `pytest` + `run_ci.sh` green. ### Phase 34 — decommission-alias-and-cmdb-validation - **Description:** Add `mode: decommission` to deploy pipeline. Stages: validate-change-request (Lambda `validate_change_request` action queries DynamoDB `acdl-change-requests` table, asserts status=approved) → disable-deletion-protection (resolve contract with deletion_protection=false, terraform plan/apply, HITL SRE gate) → zero-counts (resolver `decommission_transform` zeroes all counts, terraform plan/apply, second HITL SRE gate) → confirm-decommission. Add `acdl-change-requests` DynamoDB table to terraform/platform/main.tf. Add `validate_change_request` to contract_ingestor.py. Document in `docs/CONSUMER_GUIDE.md`. - **Status:** complete (v1.8.0) - **Depends on:** [33] - **Requirements:** REQ-92, REQ-93, REQ-94 - **Success Criteria:** - Decommission mode works via existing deploy pipeline with 2-step HITL SRE gates. - CR ID validated against DynamoDB CMDB (status must be approved). - `decommission_transform` zeroes all counts. - Documented in consumer guide. - `pytest` + `run_ci.sh` green. ### Phase 35 — module-engineering-standards - **Description:** Scan all current modules to generate `modules/STANDARDS.md` — comprehensive L1+L2 authoring + code review standards: required files, interface schema, input/output/NFR conventions, encryption + deletion protection as mandatory NFRs, naming, multi-resource pattern, adapter extension pattern (TYPE_MAP + INPUT_MAP + OUTPUT_MAP + specialized branches), code review checklist. Fix `modules/README.md` catalog index (add rds + uptime + kms-key). Update `modules/README-TEMPLATE.md` with `## NFRs` section. Add `tests/test_module_standards.py` for automated enforcement. - **Status:** complete (v1.8.0) - **Depends on:** [34] - **Requirements:** REQ-95, REQ-96 - **Success Criteria:** - `modules/STANDARDS.md` exists with L1+L2 authoring + review standards. - Catalog index includes all primitives; template has NFRs section. - Automated standards test passes for all modules. - `pytest` + `run_ci.sh` green. ### Phase 36 — schemas-adapters-pipelines-readmes - **Description:** Author `schemas/README.md` (how to write schemas, wire into platform, test in CI, dependencies, existing catalog), `pipelines/README.md` (how to write pipeline contracts, wire into workflows, test, dependencies, catalog), `adapters/README.md` (how to write adapters, wire into platform, test, dependencies, catalog). Add `tests/test_docs_coverage.py` to validate presence + required sections. - **Status:** complete (v1.8.0) - **Depends on:** [35] - **Requirements:** REQ-97, REQ-98, REQ-99 - **Success Criteria:** - All 3 READMEs exist with comprehensive documentation. - CI validates their presence. - `pytest` + `run_ci.sh` green. ### Phase 37 — verify - **Description:** 4-layer verification (structural, behavioral, security, quality) of all v1.8 phases. Re-verify each P1 (P1-3..P1-9 + S1) is resolved. Verify all new features (encryption, deletion protection, uptime, decommission, standards, docs) have dedicated tests. - **Status:** complete (v1.8.0) - **Depends on:** [36] - **Requirements:** — - **Success Criteria:** - All 4 layers pass; each P1 fix + each new feature has a dedicated test. - `pytest` passes (~358 tests); `run_ci.sh` exits 0; `run_platform.sh --check-only` exits 0. ### Phase 38 — review-audit-complete - **Description:** Multi-persona code review across the full v1.8 diff. Audit (reconstruction, file discipline, branch hygiene, commit discipline). Complete: update REQUIREMENTS.md (REQ-76..99), ROADMAP.md (v1.8 complete), PROJECT.md. Tag `v1.8.0`. Update floating `v1.8` + `v1` tags. Bump `uses:`/`ref:` from `@v1.6` to `@v1.8`. - **Status:** complete (v1.8.0) - **Depends on:** [37] - **Requirements:** — - **Success Criteria:** - Review: 0 new P0/P1; all P1-3..P1-9 + S1 resolved; 3 new requirements delivered. - Audit: clean; 0 outstanding issues. - Tag `v1.8.0` created; floating tags updated. After Phase 38: COMPLETE gate — review → ship `v1.8.0` → audit. --- ## v1.9 (complete — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation, tag `v1.9.0`) The v1.9 milestone closes four gaps left by v1.8 (user-directed, 2026-07-23): stale design docs, no contract interpolation, promotion requires editing the `environment` field, and unimplemented stubs. It also closes P1-1 (adapter hardcoded defaults, deferred from v1.2). ### Phase 39 — design-doc-refresh-and-p1-1-parameterization - **Description:** Refresh `core/hitl_matrix_design.md` (no stale "dev-only spike"/"v1.2 wires the gates" framing; v1.9 wiring section; 8-concern matrix marked implemented offline-testable subset) + `core/audit_ledger_design.md` (outbox marked shipped+production since v1.8; S3 Object Lock + JWS + worker + DLQ + checkpoints deferred D-083). P1-1: move adapter ECS/ALB/VPC hardcoded defaults (`desired_count`, `launch_type`, `family`, `target_type`, `load_balancer_type`, `Name` tags) into L1 `interface.json` inputs with defaults; the adapter reads from inputs; the resolver routes wires to the sub-resource that declares the input. - **Status:** complete (v1.8.1) - **Depends on:** — - **Requirements:** REQ-100, REQ-101, REQ-102 - **Success Criteria:** - Both design docs refreshed; no stale framing; `test_design_docs_current.py` passes. - Adapter has no hardcoded ECS/ALB/VPC defaults; overrides flow through; `test_p1_1_adapter_parameterization.py` passes. - v1.1 S3 regression passes; `pytest` 371 (was 350, +21); `run_ci.sh` exits 0; `run_platform.sh --check-only` exits 0. ### Phase 40 — contract-interpolation - **Description:** `${env.}` + `${contract.}` resolver expansion from environment onboarding JSON (D-081). Environment JSON schema (`schemas/environment.schema.json`) + qa/prod/dr placeholder bindings. `core/environment_check.py` gains `load()`. Sample contracts use naming patterns that include region, account id, environment (e.g. `acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}`). Expansion is recursive (D-087), post-schema-validation, pre-IR-resolution; unknown tokens raise `ValueError`. `resolve()` accepts `environment_override` (D-088). - **Status:** complete (v1.8.2) - **Depends on:** [39] - **Requirements:** REQ-103, REQ-104 - **Success Criteria:** - `schemas/environment.schema.json` exists; 4 env files validate; `load()` works. - `_expand_vars` in resolver; unknown tokens raise; recursive over dicts/lists/strings. - Sample contracts use `${env.*}` + `${contract.*}` naming patterns; resolve to concrete values. - `tests/test_environment_schema.py` + `tests/test_interpolation.py` + `tests/test_sample_contracts_interpolate.py` pass. - `pytest` 406 (was 371, +35); `run_ci.sh` exits 0; `run_platform.sh --check-only` exits 0. ### Phase 41 — per-environment-ci-jobs - **Description:** Per-env contract files (static-assets + microservice × dev/qa/prod/dr, REQ-105) using interpolation. Deploy workflow (`.github` + `.gitea`, byte-identical) declares an `environment` `workflow_call` input (REQ-106); `run_platform.sh --environment ` overrides the contract's environment at load time (D-088, before schema validation + interpolation). `resolve()` accepts `environment_override`. Consumer guide documents the per-env caller-workflow pattern (4 jobs, one per environment) + HITL gate structure (approve_qa/approve_prod/approve_dr, D-042) + interpolation reference table. Promotion = running the matching job; no environment field editing. - **Status:** complete (v1.8.3) - **Depends on:** [40] - **Requirements:** REQ-105, REQ-106 - **Success Criteria:** - 8 per-env contract files exist + validate + resolve to correct env. - Deploy workflow has `environment` input (byte-identical Gitea + GitHub); `run_platform.sh --environment` overrides; resolver supports `environment_override`. - Consumer guide documents per-env caller workflows + promotion-without-editing + HITL gates + interpolation reference. - `tests/test_per_env_contracts.py` + `tests/test_deploy_workflow_env_input.py` + `tests/test_consumer_guide_per_env_section.py` pass. - `pytest` 446 (was 406, +40); `run_ci.sh` exits 0; both deploy workflows byte-identical. ### Phase 42 — stub-implementation - **Description:** `route_halt_artifact` real (SNS publish + outbox fallback, REQ-107) + SNS topic `acdl-sod-halt` in `terraform/platform/main.tf`. HITL attestation gates (`core/hitl_gates.py`, REQ-108) — records approver to outbox, runs SoD on prod, invokes the attestation matrix; `run_platform.sh` calls `attest` before apply for qa/prod/dr (dev skips). 8-concern attestation matrix (`core/attestation_matrix.py`, REQ-109, D-084) — offline-testable concerns run for real; operator-supplied concerns accept signed evidence artifacts validated for freshness + schema; signature skip when `ACDL_ATTESTATION_SIGNING_KEY_ID` unset (D-089). Wiz real API client (`WizClient`, REQ-110) — GraphQL queries + pagination + graceful degrade. Kyverno translator fleshed out (REQ-111) — full PolicyReport mapping + skip-with-reason + inactive-for-TF guard + `--kube-version` stub. - **Status:** complete (v1.8.4) - **Depends on:** [41] - **Requirements:** REQ-107, REQ-108, REQ-109, REQ-110, REQ-111 - **Success Criteria:** - `route_halt_artifact` publishes to SNS when ARN set; outbox fallback when unset; SNS topic in Terraform. - `hitl_gates.attest` records approver; SoD blocks on identity equality; dev skips; `run_platform.sh` has the HITL step. - `attestation_matrix.check` runs 8 concerns; offline concerns pass; operator-supplied missing → block for prod; expired → block; signature skip when key unset. - Wiz `WizClient` real client + pagination + graceful degrade; `fetch_and_adapt` translates. - Kyverno full mapping (pass/fail/skip/warn + severity + skip-with-reason + resource construction); inactive guard preserved; `--kube-version` parsed. - `tests/test_route_halt_artifact.py` + `test_hitl_gates.py` + `test_attestation_matrix.py` + `test_wiz_adapter_real_client.py` + expanded `test_kyverno_adapter.py` pass. - `pytest` 493 (was 446, +47); `run_ci.sh` exits 0; `run_platform.sh --check-only` exits 0. ### Phase 43 — verify-review-audit-complete - **Description:** 4-layer verify (structural, behavioral, security, quality) of all v1.9 phases. Multi-persona review (0 P0, 0 P1). Audit (reconstruction, file discipline, branch hygiene, commit discipline — all clean). REVIEW.md reconstructed (D-086). Complete: update REQUIREMENTS.md (REQ-100..111), ROADMAP.md, PROJECT.md. Tag `v1.9.0`; update floating `v1.9` + `v1` tags. Bump `uses:`/`ref:` from `@v1.6` → `@v1.9`. - **Status:** complete (v1.9.0) - **Depends on:** [42] - **Requirements:** — - **Success Criteria:** - 4-layer verify PASS; 493 tests; `run_ci.sh` + `run_platform.sh --check-only` green. - Review: 0 P0, 0 P1; REVIEW.md reconstructed with v1.9 content (D-086). - Audit: clean; all 12 v1.9 commits have `---ci---` blocks. - Tag `v1.9.0` created; floating tags updated; `uses:` bumped to `@v1.9`. After Phase 43: COMPLETE gate — review → ship `v1.9.0` → audit. **DONE.**