# Nova — 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.9.8 (complete, tag `v1.9.8`):** full presentation rework — scope, story arc, visuals, appendix. 6 new mermaid diagrams (scope boundary x2, confidence signal, attestation flow, promotion journey, road to north star). Both decks restructured to 10 main + 6 appendix slides. NEW scope slide clarifying ACDL is infrastructure only. Story beat lines on every slide. Contract examples fixed (image: removed, infra inputs instead). QA attestation reclassified (Design tested → Planned). Confidence signal + attestation flow + promotion journey visuals added. Road to the North Star phased timeline in appendix. Full Testing vs. Planned inventory + glossary in appendix. Source markdown + talking points + README all updated. Docs-only NFR patch. **Last deck-polish phase before the v1.10 deck-freeze.** - **v1.10 (complete, tag `v1.10.0`):** pipeline regression fix + capability re-verification + verified-reality rewrite. The v1.9.1–v1.9.8 deck work is **superseded-by-reverification**: the decks presented advertised capability as current without disclosing that the platform had decayed (7 adapter defects prevented `terraform init/validate/plan` against live AWS). v1.10 re-verified every advertised capability, fixed all 7 defects in-sweep (D-090: no cap), and rewrote PROJECT/ROADMAP/decks to match verified reality. Decks unfrozen only after Phase 55 lands. See the v1.10 section below for the 4-phase breakdown. - **v1.10.1 (complete, tag `v1.10.1`):** post-v1.10 NFR patch — adversarial grill review (12 challenges, 10 binding decisions, 2 escalations: G-005 risks, G-008 budget), 4-layer verify gate (PASS), multi-persona code review (1 P1 auto-fixed: mis-citation PROJECT.md:6 → PROJECT.md:487). ACDL reclassified as OSS reference implementation (G-003). Docs-only; 518 tests pass; regression gate 16/16 Verified. Gitea release id 236. - **v1.10.2 (complete, tag `v1.10.2`):** contract surface redesign + rename + .yml repo-wide + deck polish. Breaking contract schema change: new top-level fields `id`/`name`/`infrastructure`; dropped `uses:`/`module:`/`inputs:`. All 44 `.yaml` → `.yml`. Code review: 3 P0 auto-fixed, 2 P1+ flagged. 494 tests pass. Gitea release id 237. - **v1.11 (complete, tag `v1.11.0`):** RESTART — stateless adapter + pipeline-driven module lifecycle testing. Closes G-005 (CAP-017..022 deploy-unverified) and G-008 (no cost docs) via a corrected architecture, not the failed v1.11 first attempt (which produced 4 drifted VPCs, ran terraform apply from Python, and had no module lifecycle tests). The restart branches off `v1.10.2` and rebuilds v1.11 on three corrections: (1) the terraform adapter becomes a stateless assembler — each L1 module ships a real `terraform/` module dir (variables/locals/main/outputs) owning its resource shape, nested blocks, and defaults; the adapter deletes `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` and all 39 type-specific branches, becoming a ~80-line assembler that emits `module "x" { source = ... }` blocks; (2) lifecycle is owned by terraform via the shell orchestrator (`run_platform.sh --apply`/`--destroy`), never by Python — `verify_deploy_microservice.py` is deleted; (3) testing is pipeline-driven — a `modules-lifecycle` pipeline (Gitea + GitHub, byte-identical) matrix-runs each L1 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS; no per-module Python. A single platform VPC (`terraform/platform`) is shared by all stacks via `data` source — no per-contract VPC. State keys are deterministic and env-aware (`spike/{id}/{env}/terraform.tfstate`), stable across lifecycle changes. 13 phases (P56a–P65). See the v1.11 section below for the phase breakdown. - **v1.12 (complete, tag `v1.12.0`):** Presentation Refinement — the leadership decks synced to the v1.11-verified reality (22/22 Verified, stateless adapter, lifecycle pipeline, cost figures, pre-mortem). Includes the CAP-013 adapter dedup fix + 2 probe fixes (required to make the deck claims true) + the ACDL_LIFECYCLE_MODE CI flag (lifecycle tests default to plan-only, full on override). 6 phases (P66–P70). See the v1.12 section below. - **v1.13 (complete, tag `v1.13.0`):** Presentation Polish — both leadership decks polished across all 4 pipeline layers (source .md → -marp.md → .html → -talking-points.md). Action headlines replace category names; story-arc restructure (Intro ~10% / Body ~80% / Conclusion ~10%); removed all transition story lines; bullets ≤12 words, 3–4 per main slide; larger fonts (body 26px, h1 40px, h2 32px); 6 new mermaid diagrams (frictions 2×2, north-star before/after, zero-trust flow, catalog primitives→modules, decommission gates, semver timeline). Code review: 0 P0, 2 P1 auto-fixed (slide-count metadata + README directory layout). 522 tests pass. Docs-only NFR patch. 1 phase (P71). See the v1.13 section below. - **v1.13.1 (complete, tag `v1.13.1`):** config.json schema migration — regenerate `.ciagent/config.json` to the updated CIAgent v2 config structure (drop removed fields, migrate `gitea`→`release.gitea`, add `secrets`/`ship`/`backend`/`ideation`/`personas`/`logging`/`telemetry` sections). Code review: 0 P0, 2 P1/P2 auto-fixed. Docs-only NFR patch (no code changes). Gitea release id 253. - **v1.13.2 (complete, tag `v1.13.2`):** presentation badge cleanup + platform architecture diagram — removed all `testing`/`agentic` maturity badges from both decks (only `planned` retained); added a new Slide 3 "The platform at a glance" with a shared high-level logical architecture diagram (consumer surfaces → contract → central pipeline → cross-cutting components → AWS) to both decks; renumbered subsequent slides 4–11; synced talking points + README. Docs-only NFR patch (no code changes). - **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.** --- ## v1.10 (complete — pipeline regression fix + capability re-verification + verified-reality rewrite, tag `v1.10.0`) The v1.10 milestone corrects a structural defect and a credibility gap surfaced in the 2026-07-27 CLARIFY/RESEARCH stages: 1. **VERIFY is diff-scoped** — it checks the phase diff only, never re-runs underlying capability. 8 NFR-patch phases (v1.9.1→v1.9.8) passed VERIFY while the platform decayed underneath. 2. **Advertised capability is not currently reproducible** — v1.2 ECS E2E and v1.7 pipelines ran once historically but decayed; decks presented them as current without disclosing the decay. 3. **Deck work was sequenced backwards** — re-verify → rewrite → polish is the honest order; v1.9.x did it backwards for 8 phases. User decisions: D-090 (no cap on sweep; fix everything; unbounded risk accepted), D-091 (regression-class VERIFY), D-092 (local emulating adapters), D-093 (re-verify v1.1→v1.8; v1.0 demo excluded), D-094 (rewrite docs/decks to verified reality; unfreeze decks). ### Phase 52 — pipeline-regression-verify-fix - **Description:** Add a regression-class VERIFY that re-runs capability checks (not just diff checks), at minimum on milestone completion. Regression run executes the local-emulator tier for every capability marked Verified in prior milestones; any failure blocks milestone completion. Records `regression: { capability, status }` in `---ci---` blocks. - **Status:** complete (v1.9.9) - **Depends on:** — - **Requirements:** REQ-112 - **Success Criteria:** - VERIFY supports `regression` mode; milestone completion requires a clean regression run. - A regression run against current code surfaces decay (fails closed). - `tests/test_verify_regression_mode.py` passes. ### Phase 53 — local-emulating-adapters - **Description:** Build local emulating adapters so the platform is fully locally testable without cloud credentials: flat-file DynamoDB outbox, local ECS emulator (synthetic HTTP 200 from local shell), local S3 state backend (flat-file tfstate), local Lambda stub (in-process handler invocation). Same interfaces as the live adapters. - **Status:** complete (v1.9.10) - **Depends on:** [52] - **Requirements:** REQ-113 - **Success Criteria:** - All local adapters exist; headline E2E runs end-to-end against the local tier with no cloud credentials. - `tests/test_local_emulating_adapters.py` passes. - `run_platform.sh --local` runs the full pipeline locally. ### Phase 54 — v1.1-v1.8 capability-reverification-sweep - **Description:** Enumerate every capability advertised in v1.1→v1.8 PROJECT/ROADMAP to `.ciagent/CAPABILITY_INVENTORY.md`. Re-verify each: headline E2E at both tiers (live AWS + local emulator, both must pass); all other capabilities at the local tier via emulating adapters. Tag each Verified/Decayed/Broken. Fix every Decayed/Broken capability in-sweep (D-090: no cap; all must end Verified) until Verified. v1.0 demo excluded as archived/superseded. - **Status:** complete (v1.9.11) - **Depends on:** [53] - **Requirements:** REQ-114 - **Success Criteria:** - Every v1.1→v1.8 advertised capability is tagged Verified in `CAPABILITY_INVENTORY.md`. - Headline E2E passes at both tiers. - Regression run (Phase 52) is clean against the re-verified state. ### Phase 55 — rewrite-to-verified-reality - **Description:** Rewrite PROJECT.md (add "Capability Status (Re-Verified 2026-07-27)" section + decay disclosure), ROADMAP.md (v1.9.x entries noted as deck-freeze / superseded-by-reverification), and both leadership decks so every capability claim reflects the re-verified status. Remove any claim that cannot be demonstrated live. Re-render HTML; upload PPTX to the v1.10.0 release. Decks unfrozen only after this lands. - **Status:** complete (v1.9.12) - **Depends on:** [54] - **Requirements:** REQ-115 - **Success Criteria:** - PROJECT/ROADMAP/decks match `CAPABILITY_INVENTORY.md` exactly. - `ci-doc-verifier` confirms no stale capability claims remain. - Decks unfrozen; v1.10.0 tagged; Gitea release published. After Phase 55: COMPLETE gate — review → ship `v1.10.0` (next minor; fix/test/docs, not a breaking schema change) → audit. **DONE.** --- ## v1.11 (complete — RESTART: stateless adapter + pipeline-driven module lifecycle testing, tag `v1.11.0`) The v1.11 milestone closes the two GRILL escalations blocking the leadership pitch: G-005 (6 IAM-gated cloud capabilities CAP-017..022 deploy-unverified) and G-008 (no cost documentation despite live AWS resources). **Why a restart.** The first v1.11 attempt (P56 IAM re-bootstrap + P57 live-deploy-microservice, branches `phase/56-iam-re-bootstrap` + `phase/57-live-deploy-microservice`, now abandoned) produced five defects: (1) 4 VPCs created when 1 should have — the adapter emitted per-contract state keys with no VPC sharing; (2) Python scripts made lifecycle changes directly to the cloud (`verify_deploy_microservice.py` ran `terraform apply -auto-approve`); (3) no L1 module lifecycle testing — `tests/test_adapter.py` only string-validated HCL, never ran terraform apply/modify/destroy; (4) no L2 integration testing; (5) lifecycle was managed by Python, not terraform. The restart branches off `v1.10.2` and rebuilds v1.11 on three corrections. **The three corrections.** 1. **Stateless adapter.** `adapters/terraform/adapter.py` (918 lines, 3 hardcoded constant tables `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP`, 39 type-specific branches) is rewritten to a ~80-line stateless assembler. Each L1 module ships a real `terraform/` module dir (`versions.tf`/`variables.tf`/`locals.tf`/`main.tf`/`outputs.tf`) owning its resource shape, nested HCL blocks, and defaults. The adapter reads the registry, emits a root `main.tf` instantiating each L1 as `module "x" { source = "..." ... }` with resolved inputs and wired refs. `interface.json` stays engine-agnostic; the terraform dir is the engine binding. Defaults move into `locals.tf` (heavy interpolation of vars against sensible defaults). 2. **Terraform owns lifecycle.** `scripts/run_platform.sh` gains `--apply` and `--destroy` modes. Python never runs terraform. `scripts/verify_deploy_microservice.py` is deleted. The shell owns all apply/modify/destroy; Python only orchestrates the shell (and may use boto3 for read-only verify probes in a future QA milestone, not this one). 3. **Pipeline-driven testing.** A `modules-lifecycle` pipeline (Gitea + GitHub, byte-identical) matrix-runs each L1 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS. No per-module Python/pytest. The "test" = the pipeline cell going green (terraform apply exit 0 → modify exit 0 → destroy exit 0). **Single platform VPC.** `terraform/platform/main.tf` owns ONE VPC; the microservice composition drops its `vpc` child and references the platform VPC via `data` source. The standalone `vpc` L1 module stays (consumers deploy their own VPCs). State keys are deterministic and env-aware (`spike/{contract.id}/{contract.environment}/terraform.tfstate`), stable across apply/modify/destroy — the same contract+env always hits the same state key, so terraform modifies rather than duplicates. **L2 = composition only.** L2 modules keep `composition.json` only (no L2 terraform files). The composition must be deterministic: same contract → same resolved stack → same state key, every time. **Versioning.** Feature milestone (P56a/P56b/P57/P58/P59/P60/P61/P62 are feat). Ship tag at milestone COMPLETE: `v1.11.0` (v1.10.2 → v1.11.0). **Wave ordering.** Wave 1 (P56a → P56b → P57 → P58) is sequential — the stateless adapter, shell lifecycle modes, and platform VPC are prerequisites for all testing. Wave 2 (P59 → P60) authors then runs the L1 lifecycle pipeline. Wave 3 (P61 → P62) authors then runs the L2 lifecycle pipeline. Wave 4 (P63 → P64 → P65) closes G-005/G-008 + teardown + deck rewrite. ### Phase P56a — stateless-adapter-rewrite (Wave 1) - **Description:** Rewrite `adapters/terraform/adapter.py` from a 918-line monolith (3 constant tables + 39 type-specific branches) to a ~80-line stateless assembler. Author `modules/l1/s3/terraform/` (`versions.tf`/`variables.tf`/`locals.tf`/`main.tf`/`outputs.tf`) as the reference module proving the assembly path end-to-end. Extend `modules/registry.json` with a `terraform_dir` field. Rewrite `modules/STANDARDS.md` §8 from "three tables + specialized branches" to "stateless assembler + per-module terraform dir". Rewrite `tests/test_adapter.py` to assert module-instantiation assembly (root `main.tf` contains `module "x" { source = ... }` blocks with correct inputs + refs), not HCL string matching. - **Status:** active - **Depends on:** — - **Requirements:** REQ-123 - **Success Criteria:** - `grep -n "TYPE_MAP\|INPUT_MAP\|OUTPUT_MAP\|rtype ==" adapters/terraform/adapter.py` returns nothing. - `wc -l adapters/terraform/adapter.py` < 100. - `modules/l1/s3/terraform/` passes `terraform init + validate` standalone. - Adapter, given the s3 instance, emits a root `main.tf` that `terraform init + validate` accepts. ### Phase P56b — l1-module-terraform-authoring (Wave 1) - **Description:** Author the remaining 11 L1 module terraform subdirs (`vpc`, `ecs-cluster`, `ecs-service`, `iam-role`, `alb`, `ecr`, `cloudfront`, `waf`, `rds`, `kms-key`, `uptime`) with the full `versions.tf`/`variables.tf`/`locals.tf`/`main.tf`/`outputs.tf` split. Defaults currently hardcoded in the adapter (CIDR blocks, assume_role_policy JSON, ECR/logs inline policy, Fargate requires_compatibilities, assign_public_ip, listener/target ports) move into `locals.tf` as heavy interpolation of vars against sensible defaults. Multi-resource modules get the full split; trivial single-resource modules (kms-key, ecr) may inline locals in main.tf. Each module's `interface.json` stays engine-agnostic. Add `terraform_dir` to each registry entry. - **Status:** pending - **Depends on:** [P56a] - **Requirements:** REQ-124 - **Success Criteria:** - All 12 `terraform/` subdirs pass `terraform init + validate` standalone. - No defaults remain in the adapter. - Each registry entry has a `terraform_dir` field. ### Phase P57 — shell-orchestrator-lifecycle-modes (Wave 1) - **Description:** `scripts/run_platform.sh` gains `--apply ` and `--destroy ` modes. `--apply` runs resolve → adapter → `terraform init` → `terraform apply -auto-approve` (HITL gate for qa/prod/dr). `--destroy` runs resolve → adapter → `terraform destroy -auto-approve` (gated behind `--decommission` + CR validation, D-070 two-step). `--modify` is implicit (a second `--apply` with a changed contract produces a terraform diff). Delete `scripts/verify_deploy_microservice.py` (the offending script that ran `terraform apply` from Python). - **Status:** pending - **Depends on:** [P56b] - **Requirements:** REQ-125 - **Success Criteria:** - `run_platform.sh --apply` and `--destroy` modes exist and are the ONLY path to terraform apply/destroy. - `grep -rn "terraform apply\|terraform destroy" scripts/*.py` returns nothing. - `verify_deploy_microservice.py` no longer exists. ### Phase P58 — single-platform-vpc-deterministic-state (Wave 1) - **Description:** Add a single VPC (`aws_vpc.acdl_shared` 10.0.0.0/16, 2 public subnets, IGW, route table, ECS security group) to `terraform/platform/main.tf`; output `vpc_id`, `public_subnet_ids`, `ecs_security_group_id`. `modules/l2/microservice/composition.json` drops the `vpc` child and references the platform VPC via a `data_sources` block. `core/contract_resolver.py` resolves `data:platform/vpc` references. The adapter emits `data "terraform_remote_state" "platform"` + `data "aws_vpc"`/`data "aws_subnets"` blocks, never an inline `aws_vpc` for the microservice stack. State key fix: `spike/{contract.id}/{contract.environment}/terraform.tfstate` (deterministic, env-aware, stable across lifecycle). Add `state_key` derivation to `schemas/contract.schema.json`. - **Status:** pending - **Depends on:** [P57] - **Requirements:** REQ-126 - **Success Criteria:** - `terraform/platform` apply creates exactly ONE VPC. - `contracts/microservice.yml` resolution produces NO `aws:ec2:vpc` resource. - Two contract applies (dev + prod) → ONE VPC, two state keys, two ECS services. - Same contract+env re-applied → same state key → terraform modifies, never duplicates. ### Phase P59 — l1-lifecycle-pipeline-author (Wave 2) - **Description:** Author `pipelines/modules-lifecycle.yml` (declarative contract: validate → resolve → apply → modify → destroy) + byte-identical `.gitea/workflows/modules-lifecycle.yml` + `.github/workflows/modules-lifecycle.yml`. Matrix over 12 L1 modules × {simple, complex} example contracts. Each cell: `run_platform.sh --apply examples/simple.yml` → `run_platform.sh --apply examples/complex.yml` (same state key → terraform modifies) → `run_platform.sh --destroy examples/complex.yml`. VPC-dependent L1s (alb, ecs-service, rds, uptime) reference the platform VPC applied by a prerequisite job; standalone `vpc` L1 applies its own. Trigger: `pull_request: [main]` + `workflow_dispatch`. Author `schemas/modules-lifecycle-pipeline.schema.json`. Extend `tests/test_pipeline_contract.py` (offline: validate schema + byte-identical). - **Status:** pending - **Depends on:** [P58] - **Requirements:** REQ-127 - **Success Criteria:** - Pipeline YAML validates against its schema. - Gitea + GitHub workflows are byte-identical. - `test_pipeline_contract.py` passes (offline). - Matrix lists all 12 L1 modules × 2 examples. ### Phase P60 — l1-lifecycle-pipeline-live-run (Wave 2) - **Description:** Run the P59 pipeline against live AWS; fix every module whose apply/modify/destroy fails. Each failing cell is a module defect: bad `terraform/` subdir (resource shape, nested blocks, defaults), bad example contract, or bad adapter assembly. Fixes land in `modules/l1//terraform/*.tf`, `modules/l1//examples/*.yml`, and rarely the adapter assembler. No new Python files. - **Status:** pending - **Depends on:** [P59] - **Requirements:** REQ-127 - **Success Criteria:** - Full L1 lifecycle matrix green: 12 modules × 2 examples = 24 cells, each apply→modify→destroy exit 0. - No live resources remain after the run (destroy enforced). - `primitives-plan.yml` (plan-only) still passes. ### Phase P61 — l2-lifecycle-pipeline-author (Wave 3) - **Description:** Extend `pipelines/modules-lifecycle.yml` + both forge workflows with an L2 matrix: `static-assets` × `contracts/static-assets.yml` (apply → modify: add WAF rule → destroy) and `microservice` × `contracts/microservice.yml` (apply → modify: `desired_count` 1→2 → destroy, references platform VPC). Author `modules/l2/static-assets/examples/complex.yml` + `modules/l2/microservice/examples/complex.yml` (modify variants, defined within the modules). L2 = composition only (no L2 terraform files); the composition must be deterministic (same contract → same resolved stack → same state key, every time). - **Status:** pending - **Depends on:** [P60] - **Requirements:** REQ-128 - **Success Criteria:** - L2 matrix lists both modules with apply→modify→destroy cells. - Composition resolution is deterministic (same contract → same stack, byte-identical). ### Phase P62 — l2-lifecycle-pipeline-live-run (Wave 3) - **Description:** Run the L2 lifecycle pipeline live; fix composition wiring + adapter assembly until green. This replaces the deleted `verify_deploy_microservice.py` — the pipeline IS the verify. CAP-017..022 boto3 probes are deferred to a future QA milestone. Fixes land in `modules/l2//composition.json`, `modules/l2//examples/*.yml`, `core/contract_resolver.py`, and rarely the adapter. No new Python files. - **Status:** pending - **Depends on:** [P61] - **Requirements:** REQ-128 - **Success Criteria:** - L2 matrix green: static-assets + microservice, each apply→modify→destroy exit 0. - Microservice apply creates NO inline VPC (references platform VPC). - Same state key across apply/modify/destroy (deterministic). - `patterns-plan.yml` (plan-only) still passes. ### Phase P63 — regression-registry-cost-docs (Wave 4) - **Description:** Add CAP-017..022 to `core/regression_verify.py` registry (evidence = lifecycle pipeline green, not boto3 probes). Author `.ciagent/COST.md` (AWS Cost Explorer 6-day window query: v1.0 ship 2026-07-21 → v1.10 complete 2026-07-27; document monthly + per-day if available). Closes G-008. - **Status:** pending - **Depends on:** [P62] - **Requirements:** REQ-119, REQ-121 - **Success Criteria:** - Regression registry includes CAP-017..022 with "lifecycle pipeline green" evidence. - `COST.md` documents the v1.0→v1.10 spend window. ### Phase P64 — pre-mortem-teardown (Wave 4) - **Description:** Author `.ciagent/PRE_MORTEM.md` (v1.10 decay root cause + forward pre-mortem for the OSS reference + leadership pitch). `run_platform.sh --decommission` with CR CHG0680001 — tears down ALL deployed stacks INCLUDING the 4 drifted VPCs from the failed first attempt. HITL SRE gates (D-070 two-step). D-096 enforced (live resources do not persist past v1.11). - **Status:** pending - **Depends on:** [P63] - **Requirements:** REQ-120, REQ-122 - **Success Criteria:** - `PRE_MORTEM.md` documents the decay root cause + forward pre-mortem. - All deployed stacks torn down; zero live ACDL resources remain. ### Phase P65 — rewrite-caps-decks (Wave 4) - **Description:** Rewrite `CAPABILITY_INVENTORY.md`, `PROJECT.md` §Capability Status, and both leadership decks: CAP-017..022 → "Verified live-aws via lifecycle pipeline ; torn down to zero-cost steady state." Remove the IAM-drift framing. Add the cost appendix slide (P63) + pre-mortem reference (P64). Re-render HTML; upload PPTX to the v1.11.0 release. `ci-doc-verifier` confirms no stale "deploy-unverified" claims remain. - **Status:** pending - **Depends on:** [P64] - **Requirements:** REQ-116, REQ-118 - **Success Criteria:** - CAPABILITY_INVENTORY + PROJECT + decks all reflect "Verified live-aws via lifecycle pipeline; torn down to zero-cost." - `ci-doc-verifier` confirms no stale "deploy-unverified" claims. - HTML re-rendered; PPTX uploaded to v1.11.0 release. After Phase P65: COMPLETE gate — review → ship `v1.11.0` (next minor; feature milestone) → audit. **DONE.** ## v1.12 (complete — Presentation Refinement, tag `v1.12.0`) The v1.12 milestone refines the leadership presentation decks to reflect the verified reality after v1.11. The v1.11 P65 deck-rewrite task did not fully land on the deck artifacts: the rendered HTML still claimed 6 cloud capabilities were "deploy-unverified (IAM drift)", the road-to-north-star diagram still showed v1.10 as "NEXT", and the v1.11 architecture stories (stateless adapter, pipeline-driven lifecycle testing) were absent. The v1.10 decay lesson (PRE_MORTEM.md FM-3) requires decks to match verified reality exactly, not outrun it. **Scope:** leadership decks only (`docs/presentations/`) across all four layers (source markdown, Marp deck, rendered HTML, talking points) + diagrams + README. Plus one real adapter fix + two probe fixes required to make the deck claims true, and a CI lifecycle-mode flag (REQ-134) that defaults the lifecycle tests to plan-only. **Why the code fixes.** The v1.12 regression gate run (Phase 66) found CAP-013 (a real adapter dedup defect — multi-resource L1s produced invalid Terraform) + CAP-017/018 (two regression-probe bugs). The inventory's "22/22 Verified" claim was overstated until CAP-013 was fixed. The pre- mortem mitigation (verified-only claims) made the fixes mandatory. **Why the lifecycle flag.** The lifecycle pipeline defaulted to full apply→modify→destroy, which requires AWS credentials + cost on every PR. REQ-134 adds the `ACDL_LIFECYCLE_MODE` CI variable (workflow_dispatch input `lifecycle_mode`, default `plan`) so the pipeline runs plan-only on every PR (fast, no AWS mutation, no cost) and full only on override. ### Phase breakdown (6 phases) - **P66 — init + research.** Drift audit (9 items) comparing `docs/presentations/*` against v1.11-verified reality. Regression gate (D-091) re-run surfaced 3 Broken capabilities; root-cause analysis classified CAP-013 (real adapter defect), CAP-017/018 (probe bugs). REQ-129..133 added. - **P67 — fix adapter dedup + 2 probe bugs (REQ-129/130).** The adapter's module-call dedup logic rewritten: multi-resource L1s (ecs-service, alb) now emit ONE module block named by the composition child id, with expanded sub-ids rewritten via id_remap (stack outputs + cross-module ref: inputs). terraform validate succeeds for the microservice; adapter 192 lines (< 200 gate). CAP-017 probe: locals.tf conditional on local.* usage. CAP-018 probe: LocalLambdaStub constructed with the required outbox arg. Regression gate: 22/22 Verified. - **P67b — lifecycle tests plan-only default + ACDL_LIFECYCLE_MODE flag (REQ-134).** The four lifecycle scripts dispatch to --plan-only (plan mode, default) or --apply/--destroy (full mode). Both workflows (byte-identical) expose lifecycle_mode as a workflow_dispatch input; CI VPC jobs skipped in plan mode. 24 new tests. - **P68 — sync decks source .md (REQ-131/132).** Re-verification headers → 22/22 Verified. De-duplicated story-beat lines. Version refs @v1.10 → @v1.11. road-to-north-star.mmd re-rendered. New A6 (real COST.md figures + pre-mortem) + A7 (stateless adapter + lifecycle pipeline + plan-only default) in both decks. - **P69 — Marp + talking points + HTML render (REQ-133).** Re-synthesized both Marp decks (10 main + 7 appendix = 17 slides). Re-distilled both talking-points files (added the missing A6/A7 sections). Re-rendered both HTML (committed). Exported both PPTX (held for the v1.12.0 release). - **P70 — verify + review + complete.** Multi-persona code review: no P0; 2 P1 testing gaps remediated (6 CAP-013 regression tests added — terraform validate + dedup unit assertions). Audit clean. 522 tests pass. Ship v1.12.0. **Outcome:** the decks now honestly claim 22/22 Verified (backed by the regression gate), reflect the v1.11 architecture (stateless adapter + lifecycle pipeline), carry the real cost figures + pre-mortem, and the lifecycle pipeline defaults to plan-only. The v1.10 "deploy-unverified (IAM drift)" framing is disclosed as closed, not hidden. Ship tag at milestone COMPLETE: `v1.12.0` (v1.11.0 → v1.12.0; feature milestone — includes the adapter fix + lifecycle flag). **DONE.** ## v1.13 (complete — Presentation Polish, tag `v1.13.0`) The v1.13 milestone polishes both leadership decks for clarity, impact, and storytelling best practices. It is a docs-only NFR patch — no code, no capability claims changed, no schema changes. **Why.** The v1.12 decks were factually correct but rhetorically flat: category-name headlines ("The Contract-Driven Model", "Zero-Trust by Default"), dense 5–6 bullet slides, formulaic italic transition lines on every slide, and body fonts at 22px (below the 24pt readability floor). v1.13 applies the storytelling + design best practices the leadership audience requires. **What changed.** Both decks (`how-the-platform-works` + `the-developer-experience`) across all 4 pipeline layers (source `.md` → `-marp.md` → `.html` → `-talking-points.md`): - **Action headlines** replace category names — each slide title states the takeaway, not the topic ("One YAML file. The platform owns everything else." not "The Contract-Driven Model"). - **Story-arc restructure** — Intro ~10% / Body ~80% (3–5 points) / Conclusion ~10%. Before/after 2-slide sequence on Problem → North Star. - **Removed all `` transition lines** — flow now carried by action headlines + talking points (saved ~15–20 words × 17 slides). - **Bullets ≤12 words, 3–4 per main slide** (was 5–6). Cut parentheticals, sub-clauses, redundant restatements. - **Larger fonts** — body 22→26px, h1 34→40px, h2 26→32px, blockquote 20→24px. High contrast preserved, no animations, maturity badges intact. - **6 new mermaid diagrams** → PNGs: - `platform-works-02-frictions` (2×2 quadrant of the four frictions) - `platform-works-03-north-star` (before/after: today's queue vs. ACDL) - `platform-works-07-zero-trust` (OIDC + ABAC flow) - `developer-experience-05-catalog` (primitives → composed modules) - `developer-experience-07-decommission` (6-node gate flow with 2 SRE gates) - `developer-experience-08-semver` (floating/pinned/major-only timeline) - **Appendix expanded** — "Security by Construction" (formerly a dense main slide) moved to appendix A3; platform deck now 10 main + TOC + 8 appendix (19 slides); developer deck 10 main + TOC + 7 appendix (18 slides). **Phases:** - **P71 — deck polish (single phase).** Restructured both decks across all 4 layers. Created 6 new `.mmd` + 6 new `.png` files. Re-rendered both HTML. Re-distilled both talking-points to match the new slide structure. Multi-persona code review: 0 P0, 2 P1 auto-fixed (slide-count metadata in source `.md` headers + `README.md` directory layout drifted — both synced). 522 tests pass. No code files touched. **Outcome:** the decks now read as a story (problem → solution → evidence), each slide has one idea with an action headline, the body is scannable in 2 seconds, and the visuals carry the mechanism where bullets undersold it. 22/22 Verified framing, badge statuses, and capability claims preserved verbatim from v1.12. No factual drift. Ship tag at milestone COMPLETE: `v1.13.0` (v1.12.0 → v1.13.0; docs-only NFR patch — final patch IS the deliverable, no separate milestone tag). **DONE.** ### v1.13.1 (complete, tag `v1.13.1`): config.json schema migration NFR patch: regenerated `.ciagent/config.json` to the updated CIAgent v2 config structure. The old config used the pre-v2 schema (`mode` field, `projects[].milestone/status/branch/tag`, top-level `gitea` block, missing `secrets`/`release`/`ship`/`backend`/`ideation`/`personas`/`logging`/`telemetry` sections). The new config conforms to `CIAgentConfig` (config.ts:156) and passes `validateConfig()` + `loadConfig()` deep-merge. Multi-persona code review: 0 P0, 2 P1/P2 auto-fixed (`.ciagent/logs/` gitignored, trailing newline restored). Gitea release id 253. Docs-only NFR patch (no code changes). ### v1.13.2 (complete, tag `v1.13.2`): presentation badge cleanup + platform architecture diagram NFR patch (docs-only). Two presentation changes across both leadership decks (`how-the-platform-works` + `the-developer-experience`): 1. **Badge cleanup** — removed all `testing` and `agentic` maturity badges from every deck layer (source `.md`, Marp `-marp.md`, rendered `.html`, talking-points). Only the `planned` badges are retained where relevant. The Marp inline `style:` CSS dropped the `.testing` / `.agentic` rules (kept `.planned`). The README maturity-framing section updated to describe only the `Planned` badge. Empty table cells (dev environment Maturity row) normalized to `—`. 2. **Platform architecture diagram** — added a new Slide 3 "The platform at a glance" to both decks, right after the problem statement. A shared mermaid source (`assets/mmd/platform-architecture.mmd`) renders to `assets/png/platform-architecture.png` and is embedded in both Marp decks. The diagram shows the full logical topology: consumer surfaces (technical dev + citizen dev) → contract schema → central pipeline (8 fixed stages) → cross-cutting components (module catalog, stateless engine adapter, platform-managed environments, HITL gates, hash-chained evidence stream) → downstream AWS resources. All subsequent slides renumbered 4–11; talking points + README directory layout + slide counts (10→11 main, 19→20 / 18→19 total) synced. Both HTML decks re-rendered via Marp. Docs-only NFR patch (no code changes). --- ## v1.14 (complete — NFR Refinement: bug fixes, security, stubs, tests, docs, tag `v1.13.24`) The v1.14 milestone is a 20-phase NFR sweep — no new features. It clears the open P1/P2 backlog from the v1.11 review, hardens the security posture (swallowed errors, hardcoded account ID, IAM wildcards, schema validation, credential hygiene), resolves stub/missing functionality (Kyverno `--kube-version`, orphan artifacts), adds test coverage for 7 untested scripts, and refines all documentation (ARCHITECTURE.md v1.11–v1.14 addenda, stale `@v1.6–1.9` → `@v1.13` refs, COST.md/GRILL/ IAM_POLICY.md sync, STANDARDS.md reconciliation). **Milestone type:** NFR (all phases fix/test/docs/chore/refactor). The final phase's patch IS the release — no separate milestone tag. Tags run on the v1.13.x line: `v1.13.3` (P0) → `v1.13.4..v1.13.23` (P1–P20) → `v1.13.24` (P21 final = milestone release). **Wave ordering:** - Wave 1 (P1–P6): bug fixes — P1 before P2 (composition depends on dedup correctness); P3–P6 independent. - Wave 2 (P7–P12): security — P8 before P9 (externalized account ID for IAM ARNs); rest independent. - Wave 3 (P13–P17): stub/test/CI/hygiene — P15 benefits from P7 landing first; P17 after P14 (both touch config.json). - Wave 4 (P18–P20): standards/docs/VPC — P19 last (reflects all prior phases). ### Phase P1 — adapter-dedup-diagnostic (Wave 1) - **Description:** Fix P1-1 from the v1.11 review. The adapter dedup loop (`adapters/terraform/adapter.py:159-170`) silently drops resources whose module is not in the registry — a typo'd `module` field vanishes without diagnostic. Raise `ValueError` (preserving the pre-dedup contract) so the misconfiguration surfaces instead of being silently omitted. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-135 - **Success Criteria:** - A resource with `module: nonexistent@1.0.0` raises `ValueError` with a descriptive message, not a silent drop. - Existing registered-module dedup behavior preserved (multi-resource L1s still merge into one `module "x" { ... }` block). - `pytest` passes; `run_ci.sh` exits 0. ### Phase P2 — static-assets-wiring-fix (Wave 1) - **Description:** Fix P1-2. `modules/l2/static-assets/composition.json` drops `default_ttl`/`max_ttl`/`price_class`/`viewer_protocol_policy` (accepted by `cloudfront/interface.json` but never wired) and WAF is unconditionally present (no `features`/conditional). Wire the cloudfront inputs; make WAF conditional via a `waf_enabled` feature flag so `examples/complex.yml` is a real modify (adds CDN + WAF), not a no-op re-apply. - **Status:** pending - **Depends on:** [P1] - **Requirements:** REQ-136 - **Success Criteria:** - `complex.yml` resolves to a resource set that differs from `simple.yml` (WAF + CDN TTLs present when `waf_enabled: true`, absent when false). - The L2 static-assets lifecycle cell's "modify" step exercises a real terraform diff, not idempotent re-apply. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P3 — lifecycle-script-arg-cleanup (Wave 1) - **Description:** Fix P1-3. `scripts/run_l2_lifecycle_test.sh` and `run_l2_lifecycle_destroy.sh` advertise `[ci-vpc-outputs.json]` ($3) in their usage strings but never read it (the L2 path uses `terraform_remote_state`, not the file). Remove the vestigial arg or document that the L2 path uses remote state and the arg is accepted-but-ignored for workflow-argument parity with the L1 scripts. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-137 - **Success Criteria:** - Usage strings no longer advertise a feature the scripts don't provide, OR a comment explains the L2-uses-remote-state design + parity reason. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P4 — regression-gate-evidence-hardening (Wave 1) - **Description:** Fix P1-5. `core/regression_verify.py:432-519` CAP-017..022 checks are offline proxies (files exist + contracts resolve) — a module with broken HCL would pass as long as files exist. Add a `terraform validate` step to `_check_lifecycle_module_terraform` so at least HCL syntax is verified at the gate. Tighten the CAPABILITY_INVENTORY wording to "offline proxy; live apply/modify/destroy verified by the modules-lifecycle workflow run, not by this gate." - **Status:** pending - **Depends on:** — - **Requirements:** REQ-138 - **Success Criteria:** - `_check_lifecycle_module_terraform` runs `terraform validate` (or documents why it's too slow + falls back to a syntax probe). - CAPABILITY_INVENTORY + docstrings reflect the offline-proxy caveat honestly. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P5 — adapter-behavior-tests (Wave 1) - **Description:** Fix P2-2. Add `test_adapter_dedup_merges_same_module` (two resources with the same `module` collapse to one `module "" { ... }` block with merged inputs) and `test_adapter_remote_state_key_override` (`ACDL_REMOTE_STATE_KEY` overrides the default `platform/terraform.tfstate` key in the emitted `data terraform_remote_state` block). - **Status:** pending - **Depends on:** [P1] - **Requirements:** REQ-139 - **Success Criteria:** - Both unit tests exist in `tests/test_adapter.py` and pass. - `pytest` count increases; `run_ci.sh` exits 0. ### Phase P6 — alb-name-prefix-fix (Wave 1) - **Description:** Fix P2-1. `modules/l1/alb/terraform/main.tf:9` uses `name_prefix = "tg-ci-"` (hardcoded literal) which discards `var.name` entirely — the target group name is non-configurable and inconsistent with the LB name. Change to `name_prefix = "${var.name}-"` so the consumer's name prefixes the target group while preserving uniqueness. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-140 - **Success Criteria:** - Target group `name_prefix` derives from `var.name`. - `terraform validate` passes for the alb module standalone. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P7 — swallowed-error-hardening (Wave 2) - **Description:** Narrow 6 over-broad `except ...: pass`/`except Exception:` sites: `core/local_emulators.py:374` (fake_urlopen swallow → network egress risk if patching fails), `core/lambda/contract_ingestor.py:157` (GitHub search failure → duplicate issues), `terraform/bootstrap/create_state_backend.py:51` (over-broad → spurious create_bucket), `core/output_publisher.py:100,168`, `terraform/bootstrap/apply_iam_baseline.py:78`. Catch specific `ClientError`/`NoSuch*` exceptions; log + re-raise where silent failure masks a real defect. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-141 - **Success Criteria:** - No bare `except Exception: pass` remains in the targeted files (grep clean for the 6 sites). - Specific exception types caught; errors logged with context. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P8 — account-id-externalization (Wave 2) - **Description:** Externalize the hardcoded account ID `581513795199` from 15+ sites: `adapters/terraform/adapter.py:125,140`, `terraform/bootstrap/apply_iam_baseline.py:33`, `terraform/bootstrap/create_state_backend.py:33,35`, `scripts/push_consumer_image.py:32`, terraform state-bucket names, ECR image refs. Read from `ACDL_AWS_ACCOUNT_ID` env (code) / `data.aws_caller_identity` (terraform); fall back to env for offline. Keep the COST.md account ID (accepted exposure per P2-4) but centralize the code-side. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-142 - **Success Criteria:** - `grep -rn "581513795199" adapters/ scripts/ terraform/ core/` returns 0 hits (excluding tests + docs). - `ACDL_AWS_ACCOUNT_ID` env read with a clear default/fallback. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P9 — iam-policy-least-privilege (Wave 2) - **Description:** Scope 6 `Resource: "*"` statements in `terraform/bootstrap/spike_runner_policy.json` (cloudfront, wafv2, kms, iam) to `acdl-*` ARNs. Scope `iam:CreateRole` etc. to `arn:aws:iam::...:role/acdl-*`; scope KMS to `arn:aws:kms:...:key/acdl-*`; narrow CloudFront/WAF where possible. Add a regression test asserting no new `Resource:"*"` on non-global actions. - **Status:** pending - **Depends on:** [P8] - **Requirements:** REQ-143 - **Success Criteria:** - `Resource: "*"` remains only on actions that require it (sts, ce). - IAM/KMS/CloudFront/WAF scoped to `acdl-*` ARNs. - Regression test in `tests/test_iam_policy_baseline.py` asserts the scoping. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P10 — contract-ingestor-identity-validation (Wave 2) - **Description:** Harden `core/lambda/contract_ingestor.py:221-245` `_validate_caller_identity` — currently best-effort (validates `consumerRepo` format only, doesn't verify the caller owns the repo). Add `contractId` format validation, `environment` enum validation, `error` length cap. Document the ABAC reliance explicitly. Add a spoofing-resistance test. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-144 - **Success Criteria:** - `contractId`, `environment`, `error` validated; malformed input rejected with 400. - ABAC reliance documented in the function docstring + ARCHITECTURE.md. - Spoofing-resistance test in `tests/test_contract_ingestor.py` passes. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P11 — schema-input-validation-hardening (Wave 2) - **Description:** Add `additionalProperties: false` to `schemas/contract.schema.json` + `schemas/environment.schema.json` (currently allows undocumented fields silently). Add `maxItems`/ `maxProperties` bounds. Validate `state_backend.bucket` S3 naming rules, `runner_role_arn` ARN format, `vpc_cidr` CIDR format. Add tests asserting rejection of malformed input. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-145 - **Success Criteria:** - Both schemas reject undocumented top-level fields. - Format validation (bucket/ARN/CIDR) rejects malformed values. - New tests in `tests/test_environment_schema.py` + `tests/test_contract_schema.py` pass. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P12 — gitignore-credential-hygiene (Wave 2) - **Description:** `.gitignore` covers `.env*`/`*.tfstate*` but lacks a credential-pattern catch-all (`*.pem`/`*.key`/`*.p12`/`*.pfx`). Add credential patterns. Add `tests/test_no_secrets_tracked.py` asserting no credential-looking file is tracked by git. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-146 - **Success Criteria:** - `.gitignore` has credential-pattern catch-all. - `test_no_secrets_tracked.py` passes (grep `git ls-files` for credential patterns → 0 hits). - `pytest` passes; `run_ci.sh` exits 0. ### Phase P13 — kyverno-kube-version-resolution (Wave 3) - **Description:** Resolve the discarded `--kube-version` flag in `adapters/kyverno/kyverno_adapter.py:11,115-116` (`_ = kube_version`). Either implement version-aware policy selection (select policies by k8s version) or remove the flag and document why it's deferred to the GitOps reconciler roadmap. Resolve the ambiguity either way. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-147 - **Success Criteria:** - `--kube-version` is either used (version-aware policy selection) or removed with a documented deferral rationale. - `tests/test_kyverno_adapter.py` updated to match. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P14 — orphan-artifact-and-dead-config-cleanup (Wave 3) - **Description:** Clean up orphan artifacts + dead config: the orphan `scripts/__pycache__/verify_deploy_microservice.cpython-312.pyc` (source deleted in v1.11); stale `pyproject.toml` coverage source `acdl_platform` → `core` (renamed in v1.6); `pyproject.toml` version `1.3.0` → current; dead JS allowlist entries in `config.json` (npm/node/jest/eslint/tsc — no package.json). - **Status:** pending - **Depends on:** — - **Requirements:** REQ-148 - **Success Criteria:** - No orphan `.pyc` for a deleted source file. - `pyproject.toml` coverage source = `core`; version = current. - `config.json` bash_allowlist has no JS-only entries. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P15 — untested-scripts-coverage (Wave 3) - **Description:** Add unit tests for 7 scripts with no test coverage: `scripts/seed_uptime_monitors.py`, `scripts/push_consumer_image.py`, `scripts/sync_to_gl.sh`, `scripts/post_stage_comment.sh`, `scripts/rotate_spike_key.sh`, `terraform/bootstrap/create_state_backend.py`, `terraform/bootstrap/create_iam_user.py`. Mock boto3/subprocess for offline-testable coverage. Add `--check-only`/dry-run modes where missing. - **Status:** pending - **Depends on:** [P7] - **Requirements:** REQ-149 - **Success Criteria:** - Each of the 7 scripts has a corresponding test file with ≥1 passing test. - `pytest` count increases by ≥7; `run_ci.sh` exits 0. ### Phase P16 — workflow-parity-and-script-flags (Wave 3) - **Description:** 4 GitHub-only workflows (patterns-plan, platform-test, primitives-plan, release) have no Gitea mirror — either mirror them or document the Gitea limitation. Fix `scripts/rotate_spike_key.sh` (only `set -u`, no `-e`/`pipefail`) and `scripts/sync_to_gl.sh` (no `set` flags at all) — add `set -euo pipefail`. - **Status:** pending - **Depends on:** — - **Requirements:** REQ-150 - **Success Criteria:** - Gitea workflow parity resolved (mirrored or documented). - `rotate_spike_key.sh` + `sync_to_gl.sh` have `set -euo pipefail`. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P17 — config-and-persona-hygiene (Wave 3) - **Description:** Fix `config.json` hygiene: `branching_strategy: "phase"` mismatch with flat-workflow practice; empty `ollama-cloud` base_url (no `glm` model configured); `frontend-engineer` persona `active: false` in config.json (PERSONAS.md:80 already says inactive). Align config.json with PERSONAS.md + actual runtime. - **Status:** pending - **Depends on:** [P14] - **Requirements:** REQ-151 - **Success Criteria:** - `config.json` persona block matches PERSONAS.md (frontend-engineer inactive). - `branching_strategy` reflects actual practice (or documented). - `ollama-cloud` backend configured or documented as intentionally unset. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P18 — module-standards-consistency (Wave 4) - **Description:** 3 L1 modules (`ecr`, `ecs-cluster`, `rds`) lack `locals.tf`; `modules/STANDARDS.md` §9.4 requires the full 5-file split but §489-492 allows inlining — internally inconsistent. Either add `locals.tf` to all 3 or reconcile STANDARDS §9.4 with the inline allowance. Remove the stale `TYPE_MAP` reference in §8 (deleted in the v1.11 stateless rewrite). - **Status:** pending - **Depends on:** — - **Requirements:** REQ-152 - **Success Criteria:** - STANDARDS.md internally consistent (§8 + §9.4 agree). - No stale `TYPE_MAP` reference. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P19 — documentation-sync-v1.14 (Wave 4) - **Description:** ARCHITECTURE.md: add v1.11/v1.12/v1.13/v1.14 addenda (stateless adapter, platform VPC, ACDL_LIFECYCLE_MODE, all v1.14 changes; record D-083 deferral explicitly). Bump stale `@v1.6–1.9` → `@v1.13` across `README.md`, `docs/consumer-guide.md` (12 sites), `docs/architecture.md`, `docs/pipeline/`. Sync decks to v1.13.2 reality. Update COST.md window to v1.11–v1.14. Resolve G-005/G-008 in GRILL.md (CAP-017..022 now Verified via lifecycle pipeline; COST.md now exists + covers v1.11+). Update IAM_POLICY.md for v1.12/v1.13/v1.14. - **Status:** pending - **Depends on:** [P1-P18] - **Requirements:** REQ-153 - **Success Criteria:** - ARCHITECTURE.md has v1.11–v1.14 addenda; D-083 deferral recorded. - `grep -rn "@v1\.[6-9]" docs/ README.md` returns 0 hits (bumped to @v1.13). - GRILL G-005/G-008 marked resolved with evidence. - COST.md window covers v1.11–v1.14. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P20 — platform-vpc-parameterization (Wave 4) - **Description:** `terraform/platform/main.tf:255` hardcodes `cidr_block = "10.0.0.0/16"` (not `var.vpc_cidr`); `count = 2` subnets hardcoded (not data-driven AZs). Parameterize; document the `0.0.0.0/0` ingress on port 80 (ALB-fronted, acceptable but should be explicit). - **Status:** pending - **Depends on:** — - **Requirements:** REQ-154 - **Success Criteria:** - VPC CIDR is a variable (default `10.0.0.0/16`); subnet count is data-driven (`length(data.aws_availability_zones.available)`). - `0.0.0.0/0` ingress documented. - `terraform validate` passes; `pytest` passes; `run_ci.sh` exits 0. ### Phase P21 — final-review-ship (Final Phase) - **Description:** Multi-persona code review across all v1.14 phases. Audit (reconstruction test, file discipline, branch hygiene, commit discipline). Complete: update REQUIREMENTS.md (REQ-135..154 marked complete), ROADMAP.md (v1.14 complete), PROJECT.md. Tag final patch `v1.13.24` (IS the milestone release). Merge `milestone/v1.14` → `main`. - **Status:** pending - **Depends on:** [P1-P20] - **Requirements:** — - **Success Criteria:** - Review: 0 new P0; all P1-1..P1-5 + P2-1..P2-4 resolved. - Audit: clean; reconstruction test passes. - Tag `v1.13.24` created; milestone merged to main. After Phase P21: milestone COMPLETE — `v1.13.24` IS the v1.14 release. --- ## v1.15 (complete — Nova Rebrand, tag `v1.15.4`) A full rebrand from **ACDL** / "Agentic Cloud Delivery Platform" → **Nova** / "The New Dawn of DevSecOps — security as a seamless enabler of fast deployments." The rebrand applies across docs, decks, code, configs, CI, env var prefixes, the consumer contract path, SSM parameter paths, AWS tag keys, and AWS resource names — with a staged infrastructure migration to avoid breakage. The Nova tagline is added alongside (not replacing) the existing "North Star" / "consumers declare intent" framing; the S&P Global Energy visual theme (`sp-theme.json`) is a client brand and is **not** touched. **Milestone type:** Major (breaking — consumer-facing path, env var prefixes, SSM path, AWS tag keys, and AWS resource names all change). Per the branch-strategy precedent (breaking/feature milestones tag on their OWN minor line), v1.15 tags run on the **v1.15.x minor line**: `v1.15.0` (P0) → `v1.15.1..v1.15.4` (P1–P4) → `v1.15.4` (P5 final = milestone release). (G-104 binding.) **Brand mapping:** - Name: `ACDL` / `Agentic Cloud Delivery Platform` → `Nova` - Tagline (added): "The New Dawn of DevSecOps — security as a seamless enabler of fast deployments" - Env var prefix: `ACDL_*` → `NOVA_*` (dual-read fallback in P2; removed in P5) - Consumer path: `.acdl/contract.yml` → `.nova/contract.yml` - SSM path: `/acdl/{env}/{contractId}/{output}` → `/nova/{env}/{contractId}/{output}` - AWS tag keys: `acdl:owner|environment|contract|cost-center|ref` → `nova:*` - AWS resource names: `acdl-*` → `nova-*` (with migration, P4) - Illustrative URLs in docs: `github.com/acdl/...` → `github.com/nova/...` (prose only; real repo name unchanged) - Gitea release titles going forward: `ACDL vX.Y.Z` → `Nova vX.Y.Z` - S&P visual theme: unchanged (client branding) **Wave ordering:** - Wave 1 (P1): docs/decks/prose — no runtime impact; establishes new vocabulary. REQ-155, REQ-156, REQ-157. - Wave 2 (P2): code + env vars + consumer path — rename in code with a dual-read env fallback so deployments don't break during the transition window. REQ-158, REQ-159, REQ-160. - Wave 3 (P3): SSM path + tag keys — SSM: copy `/acdl/...` → `/nova/...`, update readers, delete old. Tag keys: parallel-tag period (`nova:*` added, ABAC policy swapped, `acdl:*` removed). REQ-161, REQ-162. - Wave 4 (P4): AWS resource names — the big migration (KMS alias, SNS, SG, Lambda, DynamoDB data migration, ECR re-push, IAM re-bootstrap, state bucket migration, ALB recreate). Maintenance window + rollback runbook. REQ-163. - Wave 5 (P5): final-review-ship — remove dual-read fallback, consumer migration guide finalized, review + audit + milestone ship. REQ-164. ### Phase P1 — docs-decks-prose (Wave 1) - **Description:** Rebrand all prose, titles, headers, comments, deck markdown sources, mermaid `.mmd` sources, `pyproject.toml` name/description, and `release.yml` release-title prefix from `ACDL`/`Agentic Cloud Delivery Platform` → `Nova`. Add the Nova tagline ("The New Dawn of DevSecOps — security as a seamless enabler of fast deployments") to the README header, both deck title slides, and `docs/vision.md` — alongside the existing "North Star" framing. Re-export the mermaid PNG diagrams so committed PNGs match new labels. Re-render the deck HTML. Update illustrative URLs in docs (`github.com/acdl/...` → `github.com/nova/...`, `git.cloudinit.dev/continuous-intelligence/acdl*` → `.../nova*` for prose). Ship a consumer migration guide (`docs/NOVA_MIGRATION.md`) announcing the `.acdl/`→`.nova/` path, `ACDL_*`→`NOVA_*` env vars, `/acdl/`→`/nova/` SSM path, `acdl:*`→`nova:*` tag keys, and `acdl-*`→`nova-*` AWS resource names changes coming in P2–P4. - **Status:** complete (v1.15.1) - **Depends on:** — - **Requirements:** REQ-155, REQ-156, REQ-157 - **Success Criteria:** - `grep -rni "ACDL\|Agentic Cloud Delivery" README.md docs/ .ciagent/*.md` returns 0 hits (except historical narrative marked as historical). - `pyproject.toml` `name` = `nova`; `description` mentions Nova. - `release.yml` release title prefix is `Nova `. - Both decks' title-slide subtitle is `Nova — The New Dawn of DevSecOps`; mermaid `.mmd` sources use `Nova`; PNGs re-exported; HTML re-rendered. - `docs/vision.md` and README header carry the Nova tagline alongside the North Star. - `docs/NOVA_MIGRATION.md` exists and lists the 5 breaking changes. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P2 — code-envvars-consumer-path (Wave 2) - **Description:** Rename `adapters/terraform/policy/custom_rules/acdl_tagging.py` → `nova_tagging.py` (+ Checkov custom-rule registration in `schemas/tagging-standard.json` + adapter config). Rename all 21 `ACDL_*` env var prefixes → `NOVA_*` across `scripts/`, `core/`, `adapters/`, `tests/`, workflows (`.gitea/`, `.github/`), `.env`, `.env.secrets` (key names only — values stay), and consumer docs. Implement a **dual-read fallback** (`NOVA_X` preferred, fall back to `ACDL_X`) in the env/config loader so deployments don't break during the transition window. Rename the consumer on-disk contract path `.acdl/contract.yml` → `.nova/contract.yml` (and `.acdl/static-assets.*.yml`, `.acdl/contract.yaml`) across the contract resolver, deploy workflow checkout path, consumer docs, and the contract schema description. Rotate Gitea repo secrets via API (rename keys `ACDL_*` → `NOVA_*`, values stay). - **Status:** complete (v1.15.2) - **Depends on:** [P1] - **Requirements:** REQ-158, REQ-159, REQ-160 - **Success Criteria:** - `nova_tagging.py` exists; `acdl_tagging.py` removed; Checkov registration updated; rule enforces `nova:*` tag keys (tag-key enforcement of `nova:*` lands here; existing resources still carry `acdl:*` until P3 parallel-tag — rule warns during P2). - No `ACDL_` env var references remain in code/scripts/workflows/tests except the dual-read fallback in the loader + `.env.secrets` legacy comment. - Dual-read fallback implemented and unit-tested. - Contract resolver reads `.nova/contract.yml`; deploy workflow checks out `.nova/`; docs updated. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P3 — ssm-tagkeys (Wave 3) - **Description:** SSM path migration: rename the parameter path prefix `/acdl/{env}/{contractId}/{output}` → `/nova/{env}/{contractId}/{output}` across `core/output_publisher`, the contract resolver, and consumer docs. Add a migration script (`scripts/migrate_ssm_paths.py`) that copies existing `/acdl/...` parameters → `/nova/...`, then readers are updated, then old parameters are deleted. Tag key migration: add `nova:*` tags to all AWS resources (parallel-tag period), update the ABAC session policies to match `nova:*`, update `nova_tagging.py` to enforce `nova:*` (hard, no warn), then remove `acdl:*` tags once consumers are verified. Terraform tagging updated to emit `nova:*`. - **Status:** complete (v1.15.3) - **Depends on:** [P2] - **Requirements:** REQ-161, REQ-162 - **Success Criteria:** - SSM readers use `/nova/...`; migration script copies + deletes; test asserts new path. - `nova_tagging.py` enforces `nova:*` (hard fail on `acdl:*`). - ABAC session policies match `nova:*`; terraform emits `nova:*` tags. - `acdl:*` tags removed from all resources (verified via `aws` CLI or documented deferred if no live AWS access). - `pytest` passes; `run_ci.sh` exits 0. ### Phase P4 — aws-resource-migration (Wave 4) - **Description:** Rename all `acdl-*` AWS resources → `nova-*` via terraform with a staged migration: KMS alias `alias/acdl-platform` → `alias/nova-platform` (repoint), SNS `acdl-sod-halt` → `nova-sod-halt` (recreate), SG `acdl-ecs-sg` → `nova-ecs-sg` (recreate), Lambda `acdl-contract-ingestor` → `nova-contract-ingestor` (recreate), DynamoDB `acdl-contracts`/ `acdl-change-requests` → `nova-contracts`/`nova-change-requests` (scan+copy data migration, verify row counts, keep old tables until verified), ECR `acdl-microservice` → `nova-microservice` (re-push images), IAM user/policy `acdl-spike-runner` → `nova-spike-runner` (re-bootstrap with new key), state bucket `acdl-tfstate-...` → `nova-tfstate-...` (`terraform init -migrate-state` to new backend, state JSON backed up first), ALB name prefix `acdl-alb` → `nova-alb` (recreate, brief downtime). Publish a maintenance window + rollback runbook (`docs/NOVA_AWS_MIGRATION.md`). For the offline/local tier, the terraform `name`/`resource` labels change so `terraform validate` passes; live apply/modify/destroy is exercised by the modules-lifecycle workflow when `ACDL_LIFECYCLE_MODE` (now `NOVA_LIFECYCLE_MODE`) is set to full. - **Status:** complete (v1.15.4) - **Depends on:** [P3] - **Requirements:** REQ-163 - **Success Criteria:** - All terraform resource names/labels use `nova-*`; `terraform validate` passes for platform/microservice/ci-vpc. - State bucket name → `nova-tfstate-...`; `terraform init -migrate-state` documented + tested offline. - DynamoDB data-migration script exists (scan+copy, row-count verify). - `docs/NOVA_AWS_MIGRATION.md` runbook exists (maintenance window, rollback steps). - `grep -rn "acdl-" terraform/` returns 0 hits. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P5 — final-review-ship (Final Phase) - **Description:** Multi-persona code review across all v1.15 phases. Audit (reconstruction test, file discipline, branch hygiene, commit discipline). Remove the dual-read env var fallback (`ACDL_*`→`NOVA_*`) once all consumers are migrated; finalize the consumer migration guide; `nova_tagging.py` no longer accepts `acdl:*` tag keys. Complete: update REQUIREMENTS.md (REQ-155..164 marked complete), ROADMAP.md (v1.15 complete), PROJECT.md. Tag final patch `v1.14.5` (IS the milestone release). Merge `milestone/v1.15-nova` → `main`. - **Status:** complete (v1.15.4, milestone release) - **Depends on:** [P1-P4] - **Requirements:** REQ-164 - **Success Criteria:** - Review: 0 new P0; all P1+ flagged or auto-fixed. - Audit: clean; reconstruction test passes. - Dual-read fallback removed; `nova_tagging.py` hard-fails `acdl:*`. - Tag `v1.15.4` created; milestone merged to main. After Phase P5: milestone COMPLETE — `v1.15.4` IS the v1.15 release. --- ## v1.16 (complete — Nova Simplification, tag `v1.15.26`) A 20-phase NFR sweep (no new features) themed around five user-directed axes: **Simplify without regressions**, **Security**, **Maintainability**, **User/Developer Experience**, **No Humans Onboarding Flow**. The v1.15 rebrand left a fresh debt layer (stale brand strings, a state-bucket drift, a Kyverno policy contradicting the Nova tagging standard, dead code) that this milestone cleared, alongside genuine simplification (dedup helpers, a workflow generator, file splits) and the first self-service onboarding request path (request-path only; real AWS provisioning deferred, D-113). **Milestone type:** NFR (all phases fix/chore/docs/refactor/test). The final phase's patch IS the deliverable. Tags on the v1.15.x line: `v1.15.5` (P0) → `v1.15.6..v1.15.25` (P1–P20) → `v1.15.26` (P21 final = milestone release). **Regression gate (D-118, G-111):** 18 Verified + 4 Skipped (CAP-013..016 live-AWS caps are the post-v1.11-teardown steady state, D-096; re- provisioning is a future feature). 0 Decayed/Broken at P9 + P21. **Grill:** PASS-with-binding (G-111..G-113, E-002 deferred to P21). G-111: gate criterion restated 18V+4S + Skipped logic. G-112: P9 source model pinned. G-113: P12/P13 import direction documented. **Wave outcomes:** - Wave 1 (P1–P4): state-bucket + Kyverno rebrand fix (correctness regression), user-facing ACDL→Nova sweep, dead-code cleanup, except narrowing. - Wave 2 (P5–P9): regression-verify dedup (~70 lines), run-platform HITL fn + config, contract-resolver envloader + registry kind, workflow generator (sync_workflows.py + workflows-src/), run-platform split (decommission + uptime helpers). Gate PASS at P9. - Wave 3 (P10–P14): ingestor defense-in-depth (fail closed on missing IAM), payload validation (size cap + schema), split contract-resolver (decommission + CLI modules), split regression-verify (CLI module), schema-driven outputs + schema cache. Mid-milestone checkpoint clean. - Wave 4 (P15–P17): run-platform --help + flags doc, workflows README catalog (7 workflows), getting-started consolidation (offline-first). - Wave 5 (P18–P20): onboarding schema + onboard_consumer Lambda action, env-file autogen (core/onboarding.py), cross-account role Terraform (offline-proven, D-114). **Outcome:** 20 requirements (REQ-165..184) satisfied; ~630 tests pass; regression gate 18V+4S; the onboarding request path is self-service (no "contact the platform team" handoff); real AWS provisioning explicitly deferred (D-113/D-114). Ship tag at milestone COMPLETE: `v1.15.26` (NFR milestone; final patch IS the release). **DONE.** ## v1.18 (complete — Citizen Developer & Production-Grade Guidance, tag line `v1.17.x`) Nova advances from a platform that governs infrastructure delivery to one that **instructs the citizen developer on production-grade engineering** and defines a **clear, machine-checkable contract for what is acceptable to start**. Five user-directed inputs drive the milestone: 1. **S&P Global theme restoration** (P1) — the v1.17 P5 deck rebuild lost the S&P Global Energy brand visual identity (introduced v1.9.2 / P45). The Marp `style:` block (`#D6002A` red, `#1B1B1B` grey-90, Akkurat Pro, 8px accent bar) is restored to the unified deck. 2. **PDLC-upstream scope** (P2) — promotes Core Tenet #2 + Anti-Goal #1 from buried tenets to a dedicated, unmissable scope statement: the PDLC is upstream of Nova; Nova governs infra + delivery only. 3. **RACI matrix** (P2) — three-role responsibility matrix (Citizen Developer / Platform / Release Management co-owned) clarifies who owns what, with the compliance-standard-equivalence note. 4. **Nova input contract** (P3) — `schemas/submission-readiness.schema.json` + `core/submission_readiness.py` validator define "what is acceptable to start" as a superset gate above contract-schema validity. 5. **Atelier integration** (P4+P5) — skills (markdown, extending BA.A) + an MCP server (plugin-registry, vendored Atelier, agentic validation beyond Wiz/Checkmarx/Mend). **Milestone type:** Feature (P1 theme restoration + P3 schema/validator + P5 MCP server are new code). Tags run on the v1.17.x patch line: `v1.17.0` (P0) → `v1.17.1..v1.17.6` (P1–P6) → `v1.17.7` (P7 final = milestone release). **Deck automation (cross-cutting, REQ-228):** any phase modifying `docs/presentations/*-marp.md` or `docs/presentations/assets/` re-renders HTML + PPTX, commits the PPTX binary to git, and attaches it to the phase's Gitea release. **Phase count:** 8 (P0 pre-execution + 6 execution + 1 final). **Phases:** - **P1 — sp-theme-restoration** (feat): restore S&P Global Marp theme to unified deck + HTML re-render + PPTX commit + release attach. REQ-214,228. - **P2 — pdlc-scope-raci** (docs): PDLC-upstream scope + RACI matrix + 2 deck slides + HTML/PPTX re-render. REQ-215,216,228. - **P3 — submission-readiness** (feat): JSON Schema + validator + docs + tests. REQ-217,218,219,220. - **P4 — atelier-skills** (docs): 9 Atelier-derived skill files + index + BA.A extension. REQ-221,222. - **P5 — atelier-mcp** (feat): plugin-registry MCP server + vendored Atelier + 4 tools + tests. REQ-223,224,225. - **P6 — deck-slides-atelier** (docs): 3 new deck slides (scope/RACI/atelier) → 21 slides + talking points + HTML/PPTX re-render + README. REQ-226,227,228. - **P7 — final-review-ship** (final): review + audit + milestone ship. **Requirements:** REQ-214..228 (15 requirements). See `.ciagent/REQUIREMENTS.md` §v1.18. **Open decisions to lock (CLARIFY/GRILL):** D-133 (validator location), D-134 (deck slide budget), D-135 (MCP transport), D-136 (Atelier vendoring), D-137 (MCP server language), D-138 (skill format), D-139 (RACI roles), D-140 (MCP plugin-registry), D-141 (PPTX storage), D-142 (deck render trigger). **Outcome:** 15 requirements (REQ-214..228) satisfied; 32 tests pass (16 submission-readiness + 16 MCP); S&P Global Energy theme restored; PDLC- upstream scope + RACI matrix authored (PROJECT.md + docs/ + deck); submission-readiness schema + validator shipped (superset gate above contract.schema.json); 9 Atelier-derived skills + docs/skills.md; MCP server (plugin-registry, stdio, vendored Atelier v0.3.6) with 4 tools + agentic validation beyond Wiz/Checkmarx/Mend; 21-slide deck (3 new slides: scope/RACI/atelier) with PPTX committed + release-attached. 10 decisions locked (D-133..D-142). Ship tag at milestone COMPLETE: `v1.17.7` (feature milestone; final patch IS the release). **DONE.** ## v1.19 (complete — Nova 2nd-Release Sync, tag line `v1.18.x`) > **NFR-only chore milestone.** Single execution phase. Establishes the > manual-only "2nd release" pipeline `~/acdl → ~/nova` (GitLab > `jonathanchery/nova`, separate repo + history, consumer/platform-team > audience). Replaces the old `~/gl/acdl` mirror sync. ### Phase P1 — nova-sync-script (Wave 1) - **Description:** Replace `scripts/sync_to_gl.sh` (kitchen-sink mirror sync into `~/gl/acdl`) with `scripts/sync_to_nova.sh` — a manual-only, consumer-subset, domain-committed 2nd-release pipeline into `~/nova`. Excludes `.ciagent/`, `terraform/`, `demo/`, runtime metrics, and internal-only scripts. Protects `~/nova/.git`. Commits per domain in a fixed order using positional `-m` conventional-commit messages. Validates conventional format. Never triggerable by CI (`--release` gate). - **Status:** complete - **Depends on:** — - **Requirements:** REQ-229 - **Success Criteria:** - `scripts/sync_to_nova.sh` exists with `set -euo pipefail`. - Refuses without `--release` (exit 2); `--list-domains` prints 13 domains. - rsync excludes `.ciagent`, `terraform`, `demo`, internal scripts, runtime metrics; protects destination `.git`. - Domain commits in fixed order; positional `-m` mapping; conventional format validated. - `scripts/sync_to_gl.sh` removed. - `pytest` passes; `run_ci.sh` exits 0. ### Phase P2 — final-review-ship (Final Phase) - **Description:** Final review + audit + milestone ship. Merge to main, tag `v1.18.0` (first patch on the v1.18.x line), create Gitea release. - **Status:** complete - **Depends on:** [P1] - **Requirements:** REQ-229 - **Success Criteria:** - Review + audit clean (no P0). - `phase/02-final-review-ship` merged to `milestone/v1.19-nova-sync` then to `main`. - Tag `v1.18.0` created; release notes summarize REQ-229. - Milestone branches deleted; CHECKPOINT cleared. Ship tag at milestone COMPLETE: `v1.18.1` (NFR milestone; final patch IS the release). **DONE.** --- ## v1.20 — Consumer Cleanup + Transparent Terraform + Slide Pipeline > **Multi-concern milestone.** Four user-directed inputs: (1) remove all > gitea/gitlab from synced files — the platform team must never know about > the dev forge; (2) radically simplify documentation for the Platform Team > audience; (3) make terraform runs transparent in workflows with feature-flag > client differentiation; (4) dedicated S&P-themed slide render pipeline + > 12-month product roadmap slides. > > Tags run on the v1.19.x line (milestone v1.20 → tags v1.19.x). ### Phase P0 — pre-execution - **Description:** Specify → clarify → research → plan. Validate v1.20 requirements (REQ-230..244). Establish milestone version in config.json. - **Status:** complete - **Requirements:** REQ-230..244 - **Success Criteria:** - `.ciagent/REQUIREMENTS.md` has v1.20 section with all 15 requirements. - `.ciagent/config.json` has `active_milestone: "v1.20"`. - Checkpoint written. ### Phase P1 — consumer-cleanup (gitea removal + doc simplification) - **Description:** Remove all gitea/gitlab mentions from synced files. Genericize forge-detection code. Drop `.gitea/` byte-identity test assertions. Add `test_no_forge_mentions.py` guard test. Simplify documentation: delete completed migration docs, move thesis to `.ciagent/`, strip ciagent-internal provenance from synced docs. - **Status:** complete - **Requirements:** REQ-230, REQ-231, REQ-232 - **Success Criteria:** - `tests/test_no_forge_mentions.py` passes — zero gitea/gitlab mentions in synced subset. - `pytest` passes — all existing tests green after genericization. - Synced docs stripped of REQ-/D-/P- IDs, milestone headers, `.ciagent/` citations. - `docs/NOVA_MIGRATION.md` + `docs/NOVA_AWS_MIGRATION.md` deleted. - `docs/NO_HUMANS_THESIS.md` moved to `.ciagent/`. ### Phase P2 — slide-pipeline (S&P theme + render automation) - **Description:** Create dedicated S&P theme CSS, render_slides.sh pipeline, CI workflow, tests. Update Marp frontmatter to use dedicated theme. Fix README directory layout. - **Status:** complete - **Requirements:** REQ-239, REQ-240, REQ-241, REQ-242, REQ-243 - **Success Criteria:** - `docs/presentations/assets/nova-sp-theme.css` exists with S&P colors. - Marp deck frontmatter references the theme CSS. - `scripts/render_slides.sh` renders mermaid PNGs + HTML + PPTX. - `workflows-src/slides.yml` + `.github/workflows/slides.yml` exist. - `tests/test_slides_pipeline.py` passes. - `docs/presentations/README.md` updated (no retired decks). ### Phase P3 — product-roadmap (12-month slides) - **Description:** Add 12-month product roadmap as Slide 20 + Slide 21 to the deck. Add matching talking-points sections. Render via new pipeline. - **Status:** complete - **Requirements:** REQ-244 - **Success Criteria:** - Slide 20 + 21 in `nova-no-humans-platform-marp.md` + source-of-truth + talking-points. - HTML + PPTX re-rendered via `render_slides.sh`. - 4-quarter product arc grounded in NORTH_STAR + deferred metrics. ### Phase P4 — transparent-terraform (workflow refactor + feature flags) - **Description:** Split run_platform.sh → run_codegen.sh + run_postapply.sh. Rewrite deploy.yml with native terraform steps. Add var.enabled to all L1 modules + L2 composition toggles. Wire forge repo variables as feature flags. Fix stale artifact path. - **Status:** complete - **Requirements:** REQ-233, REQ-234, REQ-235, REQ-236, REQ-237, REQ-238 - **Success Criteria:** - `scripts/run_codegen.sh` + `scripts/run_postapply.sh` exist. - `deploy.yml` has native terraform init/validate/plan/apply steps. - Every L1 module has `variable "enabled"` + `count = var.enabled ? 1 : 0`. - L2 `composition.json` supports per-child `enabled`. - `deploy.yml` reads `vars.ENABLE_*` as `-var` flags. - Stale `/tmp/acdl_platform_run_v18` path fixed to `NOVA_WORK_DIR`. - `pytest` passes; `run_platform.sh` shim backward-compat verified. ### Phase P5 — final-review-ship (Final Phase) - **Description:** Final review + audit + milestone ship. Merge to main, tag `v1.19.4` (final patch = milestone release), create release. - **Status:** complete - **Depends on:** [P1, P2, P3, P4] - **Requirements:** REQ-230..244 - **Success Criteria:** - Review + audit clean (no P0). - Milestone branches merged to main. - Tag `v1.19.4` created; release notes summarize all 15 requirements. - CHECKPOINT cleared; milestone branches deleted. ## v1.21 — Nova Deck Refinement & Pipeline Hardening (complete) > Leadership-deck refinement based on 33 review notes on the v1.20 deck. > Renamed the deck to the professional "Autonomous Cloud Delivery > Platform" framing; restructured the narrative (Problem → Solution → > Proof → Roadmap + Ask); removed internal provenance from > audience-facing slides; hardened the policy pipeline (Checkov before > plan, Wiz-or-Checkov on plan); moved the strategic integration > objective into the North Star. > > Tags run on the v1.20.x line (milestone v1.21 → tags v1.20.0..v1.20.6). > Flat workflow: commits on main, tags per phase. ### Phase P0 — pre-execution (complete, tag v1.20.0) - SPECIFY → CLARIFY → RESEARCH → PLAN. Validated v1.21 requirements (REQ-245..253). Established `active_milestone: "v1.21"`. Synced PROJECT.md strategic-direction pillar. ### Phase P1 — strategic-docs (complete, tag v1.20.1) - `git mv .ciagent/NO_HUMANS_THESIS.md .ciagent/AUTONOMY_THESIS.md` + reframe content (autonomy in operations, not "removing humans"). - `NORTH_STAR.md`: vision polished ("invisible" → "visible"); obj #2 deterministic-scoring reword; obj #3 four CTO metrics; obj #4 replaced with integration objective; drop anti-goals 1,4,5; add 2 new anti-goals; anti-goal #3 reworded. - `docs/raci.md`: 3 roles → 4 roles (add Quality Engineering; rename Release Mgmt → SRE; split release attestation). - `docs/scope.md` + render scripts + ONBOARDING: integration framing + "no-humans" → "autonomous". ### Phase P2 — slides source-of-truth (complete, tag v1.20.2) - `git mv` all 5 deck files `nova-no-humans-platform*` → `nova-autonomous-cloud-delivery*`. - Rewrote source of truth to 18 main + 1 appendix slides, 4-beat arc. All 33 review notes applied. Removed: old Slide 10 (Capability Health), old Slide 12 (Zero-Touch), Appendix A2 (Operating Model & Cost). Global: tech-leadership benefits; no D-###/REQ-###/.py paths in audience slides; no badges; no version in footer. ### Phase P3 — marp deck + talking points + README (complete, tag v1.20.3) - Synthesized Marp deck from updated source; frontmatter — title "Nova — The Autonomous Cloud Delivery Platform", footer without version + without "Act N/5", title-slide subtitle "Product Development & Citizen Developer Overview"; no badges. - Re-distilled talking points to 18-slide + A1 structure. - README updated (deck title, audience, slide count, directory layout, no badge docs). - Theme CSS: fixed Appendix A1 table readability (explicit white body on any background). - Tests: added v1.21 assertions (no badges, no version, 18+1 slides, no D-###/REQ-###/.py paths, old files removed, default deck renamed). ### Phase P4 — pipeline hardening (complete, tag v1.20.4) - Two-stage policy scan (REQ-250): Checkov on static code BEFORE plan (fail-fast); Wiz-or-Checkov on the plan AFTER plan (never both). Implemented in run_platform.sh + run_codegen.sh + run_postapply.sh. - `adapters/wiz/wiz_adapter.py`: added --plan mode CLI. - `pipelines/contract.yml`: 'checkov' stage replaced by 'checkov-static' (before terraform-plan) + 'runtime-policy-scan' (after). 9 → 10 stages. - Tests updated; full suite 686 pass + 1 pre-existing attestation failure (unrelated env issue). ### Phase P5 — render + verify (complete, tag v1.20.5) - New mermaid diagrams: platform-pipeline.mmd/.png (slide 6), telemetry-live-ops.mmd/.png (slide 9). - Re-rendered HTML + PPTX (20 slides, 21 media files). - Verify: 101 v1.21-specific tests pass; 686 full suite pass; check-only pipeline exit 0; no no-humans/D-###/REQ-###/badge in audience-facing deck files. ### Phase P6 — final-review-ship (Final Phase, complete, tag v1.20.6) - Multi-file audit: git log matches `.ciagent/` discipline; deck files renamed; forbidden content absent from audience-facing slides. - Ship: tag `v1.20.6` (final patch = milestone release). Requirements marked complete; ROADMAP marked complete; CHECKPOINT cleared. - **Requirements:** REQ-245..253 (9 requirements, all complete). ## v1.22 — Nova Deck Layout Fix (complete) > Fixes the systemic layout/formatting problems in the Nova presentation > deck that made every slide look "out of whack" after the v1.21 P5 > re-render. Root cause (per investigation): `nova-sp-theme.css` had > zero `section` padding (declared `/* @theme nova-sp */` as a comment, > not the `@theme` directive; did not `@import` Marp's default theme). > Combined with `overflow:hidden`, a blunt `img { max-height: 320px }`, > header+footer chrome on every slide, and two P5 diagrams with extreme > aspect ratios (13.52× and 0.63×), 8 of 19 slides overflowed. > > Tags run on the v1.21.x line (milestone v1.22 → tags v1.21.0..v1.21.6). ### Phase P0 — pre-execution (complete, tag v1.21.0) - SPECIFY → CLARIFY → RESEARCH → PLAN → GRILL. Validated v1.22 requirements (REQ-254..262). 8 research findings persisted to RESEARCH.md. 5 CLARIFY decisions auto-resolved (comprehensive scope, full pipeline, re-layout to LR, delete render_deck.sh, split slides 3+8). Persona roster: 2 active (lead-developer + backend-engineer), 2 deactivated (frontend + data). Grill: PROCEED-WITH-REVISIONS (3 revisions: aspect-ratio test scoped to deck PNGs, @import rejection documented, marp version pinning fallback). ### Phase P1 — theme-css (complete, tag v1.21.1) - REQ-254: `section { padding: 48px 56px 40px; overflow: auto; }` — root cause fix (zero padding was why every slide looked jammed against the edges). - REQ-255: `img { max-width: 100%; max-height: 380px; object-fit: contain; }` + `.wide`/`.tall` classes — replaced blunt `max-height: 320px` that broke `w:` directives on tall images. - REQ-256: `section.title header/footer { display: none; }` — title chrome suppression. `h2 + p { margin-top: 0.2em; }`, `p { margin: 0.4em 0; }` — spacing tightening. `ol` styling. `table.dense` class. `@media print { section { overflow: hidden; } }` for PPTX. ### Phase P2 — render-scripts (complete, tag v1.21.2) - REQ-257: deleted `scripts/render_deck.sh` (omitted `--theme`, produced unthemed output). Pinned marp-cli@4.5.0 + mermaid-cli@ 11.16.0 in `render_slides.sh`. Removed references from README, sync_to_nova.sh, test_no_forge_mentions.py. - REQ-258: added `-s 2 -b transparent` to mermaid-cli invocation (README spec; produces crisp 2x PNGs with transparent backgrounds). ### Phase P3 — mermaid-relayout (complete, tag v1.21.3) - REQ-259: `telemetry-live-ops.mmd` kept as `flowchart TB` (the 3-way branch makes LR too wide at 4.22 aspect; TB gives 0.63 which is legible at h:480 with img.tall class). Re-rendered at 2x transparent (1024x1628). - REQ-260: `platform-pipeline.mmd` restructured from 10-node LR chain (aspect 13.52, illegible 1000x74 strip) to 4-node TB with combined nodes. Re-rendered at 2x transparent (552x1116, aspect 0.49). - Marp deck directives updated: `![w:1000]`/`![w:900]` → `![h:480 class:tall]` so images render at legible height using the img.tall class budget (480px). - Aspect-ratio bounds revised from [1.2, 2.5] to [0.4, 4.0] (accepts both tall and wide diagrams; still catches original outliers). ### Phase P4 — deck-content (complete, tag v1.21.4) - REQ-261: split slide 3 (Objectives + Anti-Goals) into Slide 3 (Objectives) + Slide 4 (Anti-Goals). Split slide 8 (Attestation Matrix) into Slide 9 (QA, 3 rows) + Slide 10 (Prod/DR, 7 rows). Main slide count 18 → 20. - Trimmed: slide 7 (Pipeline) to 3 bullets. slide 11 (Telemetry) to 3 bullets. slide 14 (Deferred) merged 3 Live-AWS rows into 1 (8→6 rows). slide 17 (Quarter-by-Quarter) dropped Grounding column (5→4 cols). Global table cell padding reduced (6px 10px → 4px 8px). - Removed `header:` from frontmatter (keep `footer:` + `paginate` only). The full 51-char deck title in BOTH header and footer was redundant chrome eating ~35px on every slide. - Source `.md` and talking-points re-synced to 20-slide structure. - Updated `test_marp_deck_slide_count` (18→20 main + 1 appendix). Updated README slide-count convention (all 6 references). ### Phase P5 — render-and-test (complete, tag v1.21.5) - REQ-262: re-rendered HTML + PPTX via `render_slides.sh` (pinned marp-cli@4.5.0, mermaid-cli@11.16.0, 2x transparent PNGs). 22 slides (title + 20 main + 1 appendix), 23 media files embedded. Theme embedded in HTML (--sp-red + padding confirmed). - Added 9 tests to `test_slides_pipeline.py` (the gap that let the layout regression through): test_theme_css_has_section_padding, test_theme_css_suppresses_title_chrome, test_theme_css_has_aspect_ratio_aware_images, test_png_aspect_ratios_sane (scoped to deck-referenced PNGs only per GRILL revision 1, bounds [0.4, 4.0]), test_render_slides_has_2x_scale, test_render_slides_pins_cli_versions, test_render_deck_removed, test_html_embeds_theme, test_html_slide_count_matches_marp. - 32 slide tests pass (23 original + 9 new). 94 key-file tests pass. `run_platform.sh --check-only` exit 0. ### Phase P6 — final-review-ship (Final Phase, complete, tag v1.21.6) - Multi-persona code review: PASS with 3 P1 flags (all fixed in this phase): source .md/talking-points re-synced to 20 slides, `![h:480 class:tall]` directives applied, README stale references updated. - Audit: git log matches `.ciagent/` discipline; all commits have `---ci---` blocks; branch hygiene verified. - Ship: tag `v1.21.6` (final patch = milestone release). Merge `milestone/v1.22-deck-layout-fix` → `main`. Requirements marked complete; ROADMAP marked complete; CHECKPOINT cleared. - **Requirements:** REQ-254..262 (9 requirements, all complete).