From 533a9d7bcb287869dd21af600748761a6740a291 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Thu, 30 Jul 2026 00:03:03 +0000 Subject: [PATCH] =?UTF-8?q?docs(P00):=20create=20phase=20plans=20=E2=80=94?= =?UTF-8?q?=20v1.15-Nova=20(4=20exec=20+=201=20final)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLAN.md: vertical-slice task decomposition for P1-P5. Wave ordering: W1 docs/decks/prose (P1, lead-developer) → W2 code/env-vars/consumer-path (P2, backend+lead, dual-read core/env.py helper D-108) → W3 ssm/tagkeys (P3, data+backend, parallel-tag ABAC + nova_tagging hard mode) → W4 aws-resource-migration (P4, data+lead, staged terraform migration + runbook) → W5 final-review-ship (P5, lead, remove dual-read fallback). Binding constraint: regression gate stays 16/16 Verified throughout. 9 success criteria incl. grep-zero checks on ACDL_/acdl- remnants. ---ci--- project: acdl phase: 0 milestone: v1.15 status: plan ---/ci--- --- .ciagent/CHECKPOINT.json | 4 +- .ciagent/PLAN.md | 643 ++++++++++++++++++--------------------- 2 files changed, 292 insertions(+), 355 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 41c618f..dc0ec19 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,9 +1,9 @@ { "phase": 0, - "stage": "plan", + "stage": "grill", "milestone": "v1.15", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-07-30T00:03:00Z", + "updated_at": "2026-07-30T00:04:00Z", "milestone_complete": false } \ No newline at end of file diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 1dec1e1..d5abe62 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,393 +1,330 @@ --- phase: P0 name: pre-execution -milestone: v1.14 -requirements: [REQ-135, REQ-136, REQ-137, REQ-138, REQ-139, REQ-140, REQ-141, REQ-142, REQ-143, REQ-144, REQ-145, REQ-146, REQ-147, REQ-148, REQ-149, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154] +milestone: v1.15 +requirements: [REQ-155, REQ-156, REQ-157, REQ-158, REQ-159, REQ-160, REQ-161, REQ-162, REQ-163, REQ-164] wave: 0 depends_on: [] --- -# v1.14 — NFR Refinement Plan (20 execution phases + 1 final) +# v1.15 — Nova Rebrand Plan (4 execution phases + 1 final) -**Milestone:** v1.14 (NFR — bug fixes, security, stubs, tests, docs) -**Type:** NFR (all phases fix/test/docs/chore/refactor). Final patch IS -the release. Tags: `v1.13.3` (P0) → `v1.13.4..v1.13.23` (P1–P20) → -`v1.13.24` (P21 = milestone release). -**Branch:** `milestone/v1.14-refinement` → `phase/NN-` +**Milestone:** v1.15 (Nova Rebrand — Major/breaking) +**Type:** Major (breaking — consumer path, env vars, SSM path, tag keys, +AWS resource names all change). Final patch IS the milestone release. +Tags: `v1.14.0` (P0) → `v1.14.1..v1.14.4` (P1–P4) → `v1.14.5` (P5 = +milestone release). +**Branch:** `milestone/v1.15-nova` → `phase/NN-` -## Wave ordering (D-098) +## Wave ordering (D-098 v1.15 analogue) -- **Wave 1 (P1–P6):** bug fixes. P1→P2 sequential (composition depends - on dedup correctness); P3–P6 independent. **G-105: full regression - gate run after P4** (validates the hardened gate before W2). -- **Wave 2 (P7–P12):** security. P8→P9 sequential (IAM ARNs reference - externalized account ID); rest independent. **G-106: mid-milestone - regression-gate checkpoint after P12** (offline gate run; non-Verified - halts W3 until fixed). -- **Wave 3 (P13–P17):** stub/test/CI/hygiene. P15 depends on P7 - (hardened errors before script tests); P17 depends on P14 (both touch - config.json); P13 independent. -- **Wave 4 (P18–P20):** standards/docs/VPC. P19 depends on P1–P18 - (reflects all prior phases); P18 + P20 independent. +- **Wave 1 (P1):** docs/decks/prose — no runtime impact; establishes + the Nova vocabulary + ships the consumer migration guide. REQ-155, + REQ-156, REQ-157. Independent (first phase). +- **Wave 2 (P2):** code + env vars (dual-read) + consumer path — + deployments don't break during the transition window. REQ-158, + REQ-159, REQ-160. Depends on P1 (docs establish the guide P2 changes + are announced in). +- **Wave 3 (P3):** SSM path + tag keys — SSM copy/read/delete; tag keys + parallel-tag → policy swap → remove old. REQ-161, REQ-162. Depends on + P2 (env var dual-read + nova_tagging.py warn mode must land first). +- **Wave 4 (P4):** AWS resource names — staged terraform migration. + REQ-163. Depends on P3 (tag keys nova:* enforced hard before resource + recreation; nova_tagging.py hard mode). +- **Wave 5 (P5):** final-review-ship — remove dual-read fallback, review, + audit, milestone ship. REQ-164. Depends on P1–P4. ## Execution approach Each phase: EXECUTE (persona-assigned task groups) → VERIFY (4 layers + -regression gate at milestone complete) → SHIP (patch tag). Phase +regression gate stays 16/16) → SHIP (patch tag on v1.14.x line). Phase boundary checkpoint resets context. The execute workflow reads this -PLAN.md + ROADMAP.md §v1.14 + PERSONAS.md for task decomposition. +PLAN.md + ROADMAP.md §v1.15 + PERSONAS.md §v1.15 for task decomposition. + +**Binding constraint (capability gate):** the regression gate +(CAP-001..CAP-016, `scripts/run_regression.sh`) MUST stay 16/16 Verified +throughout the rebrand. Each phase updates test fixtures that reference +`ACDL`/`acdl` so the gate stays green. No capability is added, removed, +or reclassified — the rebrand is nomenclature + identifiers, not +behavior. --- -## Wave 1 — Bug Fixes (P1–P6) +## Wave 1 — Docs / Decks / Prose (P1) -### P1 — adapter-dedup-diagnostic (REQ-135) -**Persona:** backend-engineer -**Territory:** `adapters/terraform/adapter.py` -**Tasks:** -1. In the dedup loop (`adapter.py:159-170`), when `tf_dir` is `None`, - raise `ValueError(f"no terraform_dir in registry for module - {module}")` instead of silently skipping. -2. Verify registered-module dedup behavior preserved (multi-resource L1s - still merge into one `module "x" { ... }` block). -3. Run `pytest tests/test_adapter.py` + `run_ci.sh`. - -### P2 — static-assets-wiring-fix (REQ-136) -**Persona:** data-engineer -**Territory:** `modules/l2/static-assets/` -**Tasks:** -1. Wire `default_ttl`/`max_ttl`/`price_class`/`viewer_protocol_policy` - in `composition.json` to the cloudfront child's inputs. -2. Add a `waf_enabled` feature flag (default true) to the - static-assets composition; make the WAF child conditional on it. -3. Update `examples/complex.yml` to set `waf_enabled: true` + non-default - TTLs so it resolves to a different resource set than `simple.yml`. -4. Run `pytest` + `run_ci.sh`. - -### P3 — lifecycle-script-arg-cleanup (REQ-137) -**Persona:** backend-engineer -**Territory:** `scripts/run_l2_lifecycle_*.sh` -**Tasks:** -1. Remove the `[ci-vpc-outputs.json]` token from the usage strings of - `run_l2_lifecycle_test.sh` + `run_l2_lifecycle_destroy.sh`, OR add a - comment documenting the L2-uses-remote-state design + parity reason. -2. Run `pytest` + `run_ci.sh`. - -### P4 — regression-gate-evidence-hardening (REQ-138) -**Persona:** backend-engineer -**Territory:** `core/regression_verify.py`, `.ciagent/CAPABILITY_INVENTORY.md` -**Binding decisions:** G-105 (gate must pass clean post-P4 before W2) -**Tasks:** -1. Add a `terraform validate` step to - `_check_lifecycle_module_terraform` (or document why it's too slow + - fall back to a `terraform fmt -check` syntax probe). -2. Tighten CAPABILITY_INVENTORY + docstrings to "offline proxy; live - apply/modify/destroy verified by the modules-lifecycle workflow run, - not by this gate." -3. **Run the full regression gate immediately after P4 lands** (G-105). - Gate must pass clean before W2 begins. -4. Run `pytest` + `run_ci.sh`. - -### P5 — adapter-behavior-tests (REQ-139) -**Persona:** backend-engineer -**Territory:** `tests/test_adapter.py` -**Tasks:** -1. Add `test_adapter_dedup_merges_same_module` — two resources with the - same `module` collapse to one `module "" { ... }` block with - merged inputs. -2. Add `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. -3. Run `pytest` + `run_ci.sh`. - -### P6 — alb-name-prefix-fix (REQ-140) -**Persona:** data-engineer -**Territory:** `modules/l1/alb/terraform/main.tf` -**Tasks:** -1. Change `name_prefix = "tg-ci-"` to `name_prefix = "${var.name}-"` so - the consumer's name prefixes the target group. -2. Run `terraform validate` in the alb module dir standalone. -3. Run `pytest` + `run_ci.sh`. - ---- - -## Wave 2 — Security (P7–P12) - -### P7 — swallowed-error-hardening (REQ-141) -**Persona:** backend-engineer -**Territory:** `core/local_emulators.py`, `core/lambda/contract_ingestor.py`, - `terraform/bootstrap/create_state_backend.py`, `core/output_publisher.py`, - `terraform/bootstrap/apply_iam_baseline.py` -**Tasks:** -1. `local_emulators.py:374` — narrow `except Exception: pass` to catch - `AttributeError`/`TypeError` (monkeypatch setup); log + re-raise if - patching fails (prevents network egress). -2. `contract_ingestor.py:157` — catch `urllib.error.URLError`/ - `HTTPError` specifically; log the search failure; keep `existing = []` - only on `404`/network, re-raise on auth errors. -3. `create_state_backend.py:51` — catch `ClientError` with - `NoSuchBucket`/`404` error code; re-raise on permissions/network. -4. `output_publisher.py:100,168` — catch `ClientError`/`HTTPError` - specifically; log with context. -5. `apply_iam_baseline.py:78` — catch `NoSuchEntityException` on - old-version delete; re-raise on other errors. -6. Run `pytest` + `run_ci.sh`. - -### P8 — account-id-externalization (REQ-142) -**Persona:** backend-engineer + data-engineer -**Territory:** `adapters/terraform/adapter.py`, `terraform/bootstrap/`, - `scripts/push_consumer_image.py`, terraform resource ARNs -**Binding decisions:** G-101 (grep excludes backend blocks), G-102 - (fallback bound to live account ID + workflow env wiring) -**Tasks:** -1. `adapter.py:125,140` — read `ACDL_AWS_ACCOUNT_ID` env; build the - state-bucket name dynamically. **Fallback constant = `581513795199`** - (the live account ID, NOT a placeholder — G-102). Documented for - offline tests. -2. `apply_iam_baseline.py:33`, `create_state_backend.py:33,35` — read - from env (same fallback). -3. `push_consumer_image.py:32` — read from env. -4. Terraform: use `data.aws_caller_identity.current.account_id` for - **resource ARNs** in `spike_runner_policy.json` + resource names. - **Exclude terraform `backend "s3"` blocks** (`terraform/*/terraform.tf`, - `terraform/ci-vpc/main.tf`, `terraform/platform/main.tf`, - `terraform/microservice/terraform.tf`) — backend `bucket` args are - static-config-only, evaluated pre-init (G-101). Leave backend blocks - literal or move to `terraform init -backend-config` (separate change, - not in P8 scope). -5. **Lifecycle workflow env wiring (G-102):** the `modules-lifecycle.yml` - full-mode jobs must set `ACDL_AWS_ACCOUNT_ID` from - `aws sts get-caller-identity --query Account --output text` before - any `run_platform.sh`/lifecycle invocation. No full-mode run proceeds - with the env unset. -6. Run `pytest` + `run_ci.sh`; verify - `grep -rn "581513795199" adapters/ scripts/ terraform/bootstrap/ core/` - returns 0 hits (excluding tests + docs + terraform backend blocks). - -### P9 — iam-policy-least-privilege (REQ-143) -**Persona:** data-engineer -**Territory:** `terraform/bootstrap/spike_runner_policy.json`, - `tests/test_iam_policy_baseline.py`, `modules/l1/*/terraform/main.tf`, - `modules/l2/*/composition.json` -**Binding decisions:** G-104 (verify acdl-* naming before merge) -**Tasks:** -1. Scope `iam:CreateRole` etc. (line 236) to - `arn:aws:iam::*:role/acdl-*`. -2. Scope KMS (line 218) to `arn:aws:kms::*:key/acdl-*` (or - `alias/acdl-*`). -3. CloudFront (line 117) + WAFv2 (line 129) remain `Resource: "*"` with - a documented global-ARN constraint (CloudFront ARNs are global; - cannot be account-scoped — G-104). -4. **Verify acdl-* naming (G-104):** grep/audit - `modules/l1/*/terraform/main.tf` + `modules/l2/*/composition.json` - for every IAM role + KMS key name created by the lifecycle pipeline. - If any non-`acdl-*` name is found, rename the resource or widen that - one statement (documented). -5. Add a regression test in `test_iam_policy_baseline.py` asserting no - new `Resource: "*"` on non-global actions. -6. Run `pytest` + `run_ci.sh`. - -### P10 — contract-ingestor-identity-validation (REQ-144) -**Persona:** backend-engineer -**Territory:** `core/lambda/contract_ingestor.py`, `tests/test_contract_ingestor.py` -**Tasks:** -1. Add `contractId` format validation (regex, ≤64 chars). -2. Add `environment` enum validation (dev/qa/prod/dr). -3. Add `error` length cap (truncate `stackTrace` at a reasonable limit). -4. Document the ABAC reliance in the `_validate_caller_identity` - docstring + add a note to ARCHITECTURE.md (P19 will land it). -5. Add a spoofing-resistance test (caller submits a `consumerRepo` they - don't own → rejected if ABAC misconfigured; documented best-effort). -6. Run `pytest` + `run_ci.sh`. - -### P11 — schema-input-validation-hardening (REQ-145) -**Persona:** backend-engineer -**Territory:** `schemas/contract.schema.json`, `schemas/environment.schema.json`, - `tests/test_environment_schema.py`, `tests/test_contract_schema.py` -**Tasks:** -1. Add `"additionalProperties": false` to both schemas' top-level - objects. -2. Add `maxItems`/`maxProperties` bounds to `infrastructure` map + - `monitored_endpoints` array. -3. Add `pattern` validation for `state_backend.bucket` (S3 naming - rules: lowercase, 3-63 chars, no underscores). -4. Add `pattern` validation for `runner_role_arn` (ARN format). -5. Add `pattern` validation for `vpc_cidr` (CIDR format). -6. Add tests asserting rejection of undocumented fields + malformed - values. -7. Run `pytest` + `run_ci.sh`. - -### P12 — gitignore-credential-hygiene (REQ-146) +### P1 — docs-decks-prose (REQ-155, REQ-156, REQ-157) **Persona:** lead-developer -**Territory:** `.gitignore`, `tests/test_no_secrets_tracked.py` +**Territory:** `README.md`, `docs/**`, `.ciagent/*.md`, deck +`.md`/`-marp.md`/`-talking-points.md`/`.html`, +`docs/presentations/assets/mmd/*.mmd` (+ PNG re-export), `pyproject.toml`, +`schemas/*.schema.json` `$id` (D-110), `docs/NOVA_MIGRATION.md` (NEW), +`.github/workflows/release.yml` title, `.gitea/workflows/release.yml` +(if present), `modules/STANDARDS.md`, `contracts/**` prose **Tasks:** -1. Add credential-pattern catch-all to `.gitignore`: - `*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.cer`, `*.crt`, `*.jks`. -2. Create `tests/test_no_secrets_tracked.py` — runs - `git ls-files | grep -E '\.(pem|key|p12|pfx|cer|crt|jks)$'` and - asserts 0 hits. -3. Run `pytest` + `run_ci.sh`. +1. **Prose rebrand (REQ-155).** Find/replace across all docs + .ciagent + markdown: `ACDL` → `Nova`, `Agentic Cloud Delivery Platform` → `Nova` + (full phrase). Preserve historical narrative (e.g. "formerly ACDL" + in any changelog-style section is acceptable; otherwise full swap). + Update `pyproject.toml` `name` → `nova`, `description` → Nova. + Update `release.yml` release-title prefix `ACDL ` → `Nova `. + Update illustrative URLs in docs: `github.com/acdl/...` → + `github.com/nova/...`, `git.cloudinit.dev/continuous-intelligence/acdl*` + → `.../nova*` (prose only; config.json `release.gitea.repo` stays + `acdl` per D-105). +2. **Schema $id rebrand (D-110, REQ-155).** Update `$id` in all + `schemas/*.schema.json` + `schemas/tagging-standard.json`: + `https://acdl.cloudinit.dev/schemas/...` → + `https://nova.cloudinit.dev/schemas/...`. Update test fixtures that + assert the `$id` value. +3. **Deck + mermaid rebrand (REQ-156).** Edit both deck markdown + sources (`docs/presentations/how-the-platform-works.md`, + `the-developer-experience.md` + their `-marp.md` + `-talking-points.md` + variants): `ACDL` → `Nova` in slide content + mermaid cluster labels + (`["ACDL — infrastructure only"]` → `["Nova — infrastructure only"]`). + Edit the 5 `.mmd` sources (`docs/presentations/assets/mmd/*.mmd`): + `ACDL` → `Nova`. Re-export the PNG diagrams from the edited `.mmd` + sources so the committed PNGs match the new labels (use the deck + README's documented process: mmdc CLI or the render script). +4. **Nova tagline insertion (REQ-157).** Add the tagline "The New Dawn + of DevSecOps — security as a seamless enabler of fast deployments" to: + the README header (below the title), both deck title slides (as the + subtitle, replacing "Agentic Cloud Delivery Platform"), and + `docs/vision.md` (top of the Vision section). Retain the existing + "North Star" / "consumers declare intent" framing — do NOT remove + it (D-106). +5. **Consumer migration guide (REQ-155/160).** Create + `docs/NOVA_MIGRATION.md` announcing the 5 breaking changes coming in + P2–P4: (a) `.acdl/contract.yml` → `.nova/contract.yml` (P2); (b) + `ACDL_*` env vars → `NOVA_*` (P2, dual-read fallback); (c) SSM path + `/acdl/` → `/nova/` (P3); (d) AWS tag keys `acdl:*` → `nova:*` (P3); + (e) AWS resource names `acdl-*` → `nova-*` (P4, maintenance window). + Include the dual-read fallback window (P2–P4) + the cutoff (P5 + removes fallback). +6. **HTML re-render (REQ-156).** Re-render both deck HTML files from + the updated `-marp.md` sources (self-contained, base64 images, S&P + theme unchanged per D-107). Commit the re-rendered HTML. +7. **Regress gate.** `bash scripts/run_regression.sh` — expect 16/16 + Verified (fixtures referencing `ACDL`/`acdl` in paths are updated in + P2; P1 only touches prose/decks/schema-$id, so the gate should stay + green. If a test asserts an `ACDL` string in a doc it reads, update + the assertion to `Nova`). --- -## Wave 3 — Stub / Test / CI / Hygiene (P13–P17) +## Wave 2 — Code / Env Vars / Consumer Path (P2) -### P13 — kyverno-kube-version-resolution (REQ-147) -**Persona:** backend-engineer -**Territory:** `adapters/kyverno/kyverno_adapter.py`, `tests/test_kyverno_adapter.py` -**Binding decisions:** G-103 (removal+documentation path, NOT implementation) +### P2 — code-envvars-consumer-path (REQ-158, REQ-159, REQ-160) +**Persona:** backend-engineer (lead) + lead-developer (docs/runbook) +**Territory:** `core/env.py` (NEW), `core/*.py`, `scripts/*.py` + +`*.sh`, `adapters/**`, `tests/**`, `.gitea/workflows/**` + +`.github/workflows/**`, `.env` + `.env.secrets` (key rename), +`schemas/tagging-standard.json`, +`adapters/terraform/policy/custom_rules/acdl_tagging.py` → +`nova_tagging.py` **Tasks:** -1. **Remove the `--kube-version` flag** from - `kyverno_adapter.py:11,115-116` (G-103 — implementing version-aware - policy selection would be a new feature, violating D-095). -2. Add a docstring documenting the deferral to the GitOps reconciler - roadmap (D-053): the Kyverno adapter is inactive for Terraform-only - stacks; `--kube-version` will be relevant when the GitOps reconciler - emits K8s manifests. -3. Update `test_kyverno_adapter.py` to remove the `--kube-version` test - cases + assert the flag is absent. -4. Run `pytest` + `run_ci.sh`. - -### P14 — orphan-artifact-and-dead-config-cleanup (REQ-148) -**Persona:** lead-developer -**Territory:** `scripts/__pycache__/`, `pyproject.toml`, `.ciagent/config.json` -**Tasks:** -1. Delete the orphan - `scripts/__pycache__/verify_deploy_microservice.cpython-312.pyc`. -2. Fix `pyproject.toml` coverage source: `acdl_platform` → `core`. -3. Bump `pyproject.toml` version `1.3.0` → current (v1.14). -4. Remove dead JS allowlist entries from `config.json` - `bash_allowlist.allowed_commands` (npm/node/npx/pnpm/yarn/jest/eslint/ - tsc/prettier — no package.json). -5. Run `pytest` + `run_ci.sh`. - -### P15 — untested-scripts-coverage (REQ-149) -**Persona:** backend-engineer -**Territory:** `tests/` (new test files for 7 scripts) -**Tasks:** -1. `tests/test_seed_uptime_monitors.py` — mock the uptime-kuma API; - assert monitor creation from a JSON file. -2. `tests/test_push_consumer_image.py` — mock `subprocess.run` (docker - login/build/push) + boto3 ECR; assert the flow. -3. `tests/test_sync_to_gl.sh` (shell test) — dry-run mode; assert the - copy + push commands are constructed correctly. -4. `tests/test_post_stage_comment.sh` (shell test) — no-op when not in - a PR context; assert the `gh api` call structure when in PR. -5. `tests/test_rotate_spike_key.sh` (shell test) — mock `aws iam`; - assert deactivate/create/update-secret flow. -6. `tests/test_create_state_backend.py` — mock boto3 S3/DynamoDB; - assert idempotent creation. -7. `tests/test_create_iam_user.py` — mock boto3 IAM; assert idempotent - user/policy/key creation. -8. Run `pytest` + `run_ci.sh`. - -### P16 — workflow-parity-and-script-flags (REQ-150) -**Persona:** backend-engineer -**Territory:** `.gitea/workflows/`, `scripts/rotate_spike_key.sh`, - `scripts/sync_to_gl.sh` -**Tasks:** -1. Either mirror the 4 GitHub-only workflows (patterns-plan, - platform-test, primitives-plan, release) to `.gitea/workflows/`, or - add a README documenting the Gitea limitation (Gitea runners don't - use release/primitives-plan/patterns-plan; release is GitHub-only by - design). -2. Add `set -euo pipefail` to `rotate_spike_key.sh` (currently only - `set -u`). -3. Add `set -euo pipefail` to `sync_to_gl.sh` (currently no `set` - flags). -4. Run `pytest` + `run_ci.sh`. - -### P17 — config-and-persona-hygiene (REQ-151) -**Persona:** lead-developer -**Territory:** `.ciagent/config.json`, `.ciagent/PERSONAS.md` -**Tasks:** -1. Mark `frontend-engineer` persona `active: false` in `config.json` - `personas.personas[]` (PERSONAS.md:80 already says inactive). -2. Fix `branching_strategy: "phase"` — either change to `"flat"` or - document that the field is advisory + the project uses flat workflow - (committed directly to main per established convention). -3. Configure `ollama-cloud` backend: set `base_url` to the actual - endpoint OR add a comment documenting why it's intentionally unset - (the runtime uses the `glm-5.2` model via the opencode backend, not - the `llm_backends` config). -4. Run `pytest` + `run_ci.sh`. +1. **Dual-read env helper (D-108, REQ-159).** Create `core/env.py` with + `get_env(name, default=None)` that reads `NOVA_` then falls + back to `ACDL_`, returning `default` if neither. Add unit + tests in `tests/test_env_helper.py` covering: both set (NOVA wins), + only NOVA set, only ACDL set (fallback), neither set (default). +2. **Env var rename (REQ-159).** Migrate all 21 `ACDL_*` env var + references → `NOVA_*` across `core/*.py`, `scripts/*.py` + `*.sh`, + `adapters/**`, `tests/**`, `.gitea/workflows/**`, + `.github/workflows/**`. Use the `core/env.py` helper at Python call + sites (replace `os.environ.get("ACDL_X")` → + `env.get_env("X")`); for shell scripts, use `${NOVA_X:-$ACDL_X}` + dual-read inline. Rename keys in `.env` + `.env.secrets` (KEY names + only — VALUES/secret material stay). Leave a comment in `.env.secrets` + noting the legacy `ACDL_*` keys are the dual-read fallback source + until P5. +3. **Gitea secrets rotation (REQ-159).** Use the Gitea API + (`scripts/rotate_spike_key.sh` pattern or a new + `scripts/rename_gitea_secrets.py`) to create `NOVA_*` secrets + mirroring the `ACDL_*` values, then (after P5) delete the old + `ACDL_*` secrets. For P2, just create the `NOVA_*` aliases; deletion + is P5. +4. **Checkov rule rename (D-109 warn mode, REQ-158).** Rename + `adapters/terraform/policy/custom_rules/acdl_tagging.py` → + `nova_tagging.py`. Update the Checkov registration in + `schemas/tagging-standard.json` (line 5 + the `description`) and the + adapter config (`adapters/terraform/policy/checkov_adapter.py`). + The rule enforces `nova:*` tag keys BUT in **warn mode** for P2 + (existing resources still carry `acdl:*` until P3) — log a warning, + don't fail the check. Update `ACDL_TAG_NAMING` → `NOVA_TAG_NAMING`. +5. **Consumer path rename (REQ-160).** Rename the consumer on-disk + contract path `.acdl/contract.yml` → `.nova/contract.yml` across: + `core/contract_resolver.py` (any default path), the deploy workflow + `default:` field (`.gitea/workflows/deploy.yml` + + `.github/workflows/deploy.yml` line 54), `schemas/contract.schema.json` + description, `tests/test_pipeline_contract.py:313` assertion, and + consumer docs (`docs/consumer-guide.md`, `docs/modules/index.md`). + Also `.acdl/static-assets.*.yml` → `.nova/...` + `.acdl/contract.yaml` + → `.nova/contract.yaml`. +6. **Test fixture update (binding).** Update all test fixtures in + `tests/**` that reference `ACDL`/`acdl` (env var names, paths, table + names, tag keys) to the new `NOVA`/`nova` values — EXCEPT fixtures + that assert the dual-read fallback behavior (those keep `ACDL_*` as + the fallback source). `pytest` must pass. +7. **Regress gate.** `bash scripts/run_regression.sh` — 16/16 Verified. --- -## Wave 4 — Standards / Docs / VPC (P18–P20) +## Wave 3 — SSM Path + Tag Keys (P3) -### P18 — module-standards-consistency (REQ-152) -**Persona:** data-engineer -**Territory:** `modules/STANDARDS.md`, `modules/l1/{ecr,ecs-cluster,rds}/terraform/` +### P3 — ssm-tagkeys (REQ-161, REQ-162) +**Persona:** data-engineer (lead) + backend-engineer (readers) +**Territory:** `core/output_publisher.py`, `core/contract_resolver.py`, +`scripts/migrate_ssm_paths.py` (NEW), `terraform/**` (tag keys), +`adapters/terraform/policy/custom_rules/nova_tagging.py` (hard mode), +ABAC session-policy terraform **Tasks:** -1. Either add `locals.tf` to `ecr`, `ecs-cluster`, `rds` (extract - inlined locals from `main.tf`), OR reconcile STANDARDS §9.4 to - explicitly allow inlining for trivial single-resource modules. -2. Remove the stale `TYPE_MAP` reference in STANDARDS §8 (deleted in - the v1.11 stateless rewrite). -3. Run `pytest` + `run_ci.sh`. - -### P19 — documentation-sync-v1.14 (REQ-153) -**Persona:** lead-developer -**Territory:** `.ciagent/ARCHITECTURE.md`, `docs/`, `README.md`, - `.ciagent/COST.md`, `.ciagent/GRILL.md`, `.ciagent/IAM_POLICY.md`, - `docs/presentations/` -**Tasks:** -1. ARCHITECTURE.md: add v1.11 addendum (stateless adapter, platform VPC, - ACDL_LIFECYCLE_MODE), v1.12 addendum (CAP-013 fix, plan-only - default), v1.13 addendum (config.json schema migration, badge - cleanup, platform-architecture diagram), v1.14 addendum (all 20 - phases). Record D-083 deferral explicitly. -2. Bump stale `@v1.6`–`@v1.9` → `@v1.13` across `README.md:225`, - `docs/consumer-guide.md` (12 sites), `docs/architecture.md:233`, - `docs/pipeline/versioning.md:29`, `docs/pipeline/index.md:42`. -3. Sync decks to v1.13.2 reality (version refs, capability claims). -4. Update COST.md window to v1.11–v1.14 (lifecycle pipeline live-runs + - teardown). -5. Resolve G-005/G-008 in GRILL.md (CAP-017..022 now Verified via - lifecycle pipeline; COST.md now exists + covers v1.11+). -6. Update IAM_POLICY.md for v1.12/v1.13/v1.14 (plan-only default, - config.json schema, v1.14 IAM scoping from P9). -7. Run `pytest` + `run_ci.sh`; verify - `grep -rn "@v1\.[6-9]" docs/ README.md` returns 0 hits. - -### P20 — platform-vpc-parameterization (REQ-154) -**Persona:** data-engineer -**Territory:** `terraform/platform/main.tf` -**Tasks:** -1. Add a `vpc_cidr` variable (default `10.0.0.0/16`); replace the - hardcoded `cidr_block`. -2. Replace `count = 2` subnets with - `count = length(data.aws_availability_zones.available.names)`. -3. Add a `data "aws_availability_zones" "available" {}` block. -4. Document the `0.0.0.0/0` ingress on port 80 (ALB-fronted, acceptable - for a public-facing service; add a comment). -5. Run `terraform validate` + `pytest` + `run_ci.sh`. +1. **SSM path migration (REQ-161).** Update `core/output_publisher.py`: + the SSM parameter path prefix `/acdl/{env}/{contractId}/{output}` → + `/nova/{env}/{contractId}/{output}`. Update `core/contract_resolver.py` + SSM reads. Update consumer docs. Create + `scripts/migrate_ssm_paths.py` that: (a) lists `/acdl/...` + parameters, (b) copies each to `/nova/...` (same value/type), (c) + verifies the copy, (d) deletes the old `/acdl/...` parameters. The + script is idempotent + dry-run by default (`--apply` to execute). +2. **Tag keys: parallel-tag (REQ-162).** Update terraform tagging + (`terraform/platform/main.tf`, `terraform/microservice/main.tf`, + `terraform/ci-vpc/main.tf`, `modules/l1/*/terraform/main.tf`, + `modules/l2/*/composition.json` tag defaults) to emit **both** + `nova:*` and `acdl:*` tag keys during P3 (parallel-tag period). The + `acdl:cost-center` default `acdl-default` → `nova-default` for the + `nova:cost-center` key (keep `acdl-default` on the `acdl:cost-center` + key during the parallel period). +3. **Tag keys: ABAC policy swap (REQ-162).** Update the ABAC session + policies (the deploy role's inline policy in + `terraform/platform/main.tf` + `terraform/bootstrap/**`) to match + `nova:*` tags (the `StringEquals`/`Resource` tag conditions reference + `nova:owner`/`nova:environment`/etc.). Keep the `acdl:*` match as a + secondary condition during the parallel period so neither old nor + new consumers break. +4. **Checkov rule: hard mode (D-109, REQ-162).** Update + `nova_tagging.py` from warn → hard mode: enforce `nova:*` tag keys + (hard fail on missing `nova:*` or presence of `acdl:*`-only tags). + Update `schemas/tagging-standard.json` tag keys → `nova:*`. +5. **Tag keys: remove old (REQ-162).** Once the parallel-tag period is + verified (terraform validate passes; the ABAC policy matches + `nova:*`), remove the `acdl:*` tag emissions from terraform. (Live + removal of `acdl:*` tags from existing AWS resources is a + documentation/runbook step — the terraform `null_resource` or a + script `scripts/untag_acdl_keys.py` can do it with live AWS access; + without live access, this is documented in the P4 runbook as a + runtime step.) +6. **Test fixture + regress gate.** Update test fixtures asserting + `acdl:*` tag keys → `nova:*`. `pytest` passes; + `bash scripts/run_regression.sh` — 16/16 Verified. --- -## Final Phase — P21 (review + audit + ship) +## Wave 4 — AWS Resource Name Migration (P4) -**Persona:** lead-developer (review coordination) + ci-code-reviewer + - ci-debugger (audit) +### P4 — aws-resource-migration (REQ-163) +**Persona:** data-engineer (lead) + lead-developer (runbook) +**Territory:** `terraform/platform/main.tf`, +`terraform/microservice/main.tf`, `terraform/ci-vpc/main.tf`, +`terraform/bootstrap/**`, `modules/l1/alb/instance.json`, +`scripts/migrate_dynamodb_data.py` (NEW), +`docs/NOVA_AWS_MIGRATION.md` (NEW runbook), +`core/lambda/contract_ingestor.py` (default table names, D-111) **Tasks:** -1. Multi-persona code review across all v1.14 phases (P1–P20). Auto-apply - P0 fixes; flag P1+ for post-hoc review. If P1+ found, fix in-phase. -2. Audit: reconstruction test (git log vs `.ciagent/` files), file - discipline, branch hygiene, commit discipline. Fix critical issues - in-phase. -3. Complete: update REQUIREMENTS.md (REQ-135..154 → complete), - ROADMAP.md (v1.14 complete), PROJECT.md. -4. Tag `v1.13.24` (IS the milestone release). Merge - `milestone/v1.14-refinement` → `main`. Create Gitea release with full - milestone summary. +1. **Runbook (REQ-163).** Create `docs/NOVA_AWS_MIGRATION.md` — the + maintenance-window + rollback runbook. Documents each resource rename, + the migration command, the verification step, and the rollback + procedure. Orders the migration: KMS alias (cheap) → SNS/SG (recreate) + → Lambda (recreate) → DynamoDB (scan+copy) → ECR (re-push) → IAM + (re-bootstrap) → state bucket (`-migrate-state`) → ALB (recreate, + brief downtime, last). +2. **Terraform resource names (REQ-163).** Rename all `acdl-*` resource + names/labels → `nova-*` in `terraform/platform/main.tf`, + `terraform/microservice/main.tf`, `terraform/ci-vpc/main.tf`, + `terraform/bootstrap/**`, `modules/l1/alb/instance.json`: + - DynamoDB: `acdl-contracts` → `nova-contracts`, + `acdl-change-requests` → `nova-change-requests` + - Secrets Manager: `acdl/github-token` → `nova/github-token` + - Lambda: `acdl-contract-ingestor` (role/policy/function) → + `nova-contract-ingestor` + - SNS: `acdl-sod-halt` → `nova-sod-halt` + - SG: `acdl-ecs-sg` → `nova-ecs-sg` + - KMS: `alias/acdl-platform` → `alias/nova-platform` + - ECS: `acdl-microservice` (cluster/service/task/role) → + `nova-microservice` + - ECR: `acdl-microservice` → `nova-microservice` + - IAM: `acdl-spike-runner` (+policy) → `nova-spike-runner` + - S3 state bucket: `acdl-tfstate-581513795199-us-east-1` → + `nova-tfstate-581513795199-us-east-1` + - ALB: `acdl-alb` → `nova-alb` +3. **Lambda default table names (D-111, REQ-163).** Update + `core/lambda/contract_ingestor.py` default env-var values: + `CONTRACTS_TABLE` default `acdl-contracts` → `nova-contracts`, + `CHANGE_REQUESTS_TABLE` `acdl-change-requests` → + `nova-change-requests`, `GITHUB_TOKEN_SECRET_ID` `acdl/github-token` + → `nova/github-token`, `PLATFORM_REPO` `acdl/acdl` → `nova/acdl` + (prose consistency; real repo unchanged). +4. **State bucket migration (REQ-63).** Update the terraform backend + config (`terraform/{platform,microservice,ci-vpc}/terraform.tf` + + `bootstrap/create_state_backend.py` + `bootstrap/.bootstrap_state.json`) + to the new `nova-tfstate-...` bucket. Document the + `terraform init -migrate-state` command in the runbook (back up the + state JSON first). +5. **DynamoDB data-migration script (REQ-163).** Create + `scripts/migrate_dynamodb_data.py` — scan+copy all items from + `acdl-contracts` → `nova-contracts` + `acdl-change-requests` → + `nova-change-requests`. Verify row counts match. Keep old tables + until verified (deletion is a manual post-verification step, + documented in the runbook). +6. **terraform validate + regress gate.** `terraform validate` passes + for platform/microservice/ci-vpc. `grep -rn "acdl-" terraform/` + returns 0 hits. `pytest` passes; `bash scripts/run_regression.sh` — + 16/16 Verified. + +--- + +## Wave 5 — Final Review + Ship (P5) + +### P5 — final-review-ship (REQ-164) +**Persona:** lead-developer (lead) + all active (review) +**Territory:** `.ciagent/**`, `core/env.py` (remove fallback), +`nova_tagging.py` (hard-fail `acdl:*`), review + audit +**Tasks:** +1. **Remove dual-read fallback (REQ-164).** Update `core/env.py` + `get_env()` to read `NOVA_*` only (remove the `ACDL_*` fallback). + Update shell scripts to `${NOVA_X}` only (remove `:-$ACDL_X`). + Update `nova_tagging.py` to hard-fail on any `acdl:*` tag key (no + warn). Delete the `ACDL_*` secrets from Gitea (the `NOVA_*` aliases + created in P2 are now the only source). Remove the legacy comment + from `.env.secrets`. +2. **Multi-persona review.** Run `ciagent-review` across all v1.15 + phases (P1–P4 changes). Auto-apply P0 fixes; flag P1+ for post-hoc. + If P1+ found, fix in this phase. +3. **Audit.** Run `ciagent-audit` — reconstruction test (git log matches + `.ciagent/` files), file discipline, branch hygiene, commit + discipline. If critical issues, fix in this phase. +4. **Finalize consumer migration guide (REQ-164).** Update + `docs/NOVA_MIGRATION.md` to mark the migration complete (cutoff + passed; `ACDL_*` fallback removed). +5. **Complete milestone.** Update `REQUIREMENTS.md` (REQ-155..164 → + complete), `ROADMAP.md` (v1.15 complete), `PROJECT.md`. Tag + `v1.14.5` (IS the milestone release). Merge `milestone/v1.15-nova` + → `main`. Create Gitea release with full milestone summary. + +--- ## Success Criteria (milestone gate) -1. All 20 REQ-135..REQ-154 marked complete in REQUIREMENTS.md. -2. Review: 0 new P0; all P1-1..P1-5 + P2-1..P2-4 resolved. +1. All 10 REQ-155..REQ-164 marked complete in REQUIREMENTS.md. +2. Review: 0 new P0; all P1+ flagged or auto-fixed. 3. Audit: clean; reconstruction test passes. -4. Regression gate (D-091) clean against the v1.14 state. -5. `pytest` passes; `run_ci.sh` exits 0; `run_platform.sh --check-only` - exits 0. -6. Tag `v1.13.24` created; milestone merged to main. \ No newline at end of file +4. Regression gate (D-091) 16/16 Verified throughout + at milestone + complete. +5. `grep -rni "ACDL\|Agentic Cloud Delivery" README.md docs/ .ciagent/*.md` + returns 0 hits (except explicit "formerly ACDL" historical notes). +6. `grep -rn "ACDL_" core/ scripts/ adapters/ tests/ .gitea/ .github/` + returns 0 hits (except the removed-fallback test in P5 that asserts + the fallback is gone). +7. `grep -rn "acdl-" terraform/` returns 0 hits. +8. `pytest` passes; `run_ci.sh` exits 0; `terraform validate` passes + for platform/microservice/ci-vpc. +9. Tag `v1.14.5` created; milestone merged to main. \ No newline at end of file