Files
acdl/.ciagent/PLAN.md
T
Jon Chery 71bd61ceb1 docs(P00): complete pre-execution phase — v1.14 NFR Refinement milestone established
Phase 0 (pre-execution) complete. All pre-execution stages shipped:
SPECIFY -> CLARIFY -> RESEARCH -> IDEATE -> PLAN -> GRILL.

Established v1.14 NFR Refinement milestone (20 execution phases + 1
final). NFR milestone — final patch IS the release. Tags on v1.13.x
line: v1.13.3 (this phase) -> v1.13.24 (P21 = milestone release).

6 grill binding decisions (G-101..G-106) applied to PLAN.md. 1
escalation (E-001) auto-resolved at full autonomy (D-101).

---ci---
project: acdl
phase: 0
milestone: v1.14
status: complete
---/ci---
2026-07-29 20:13:49 +00:00

18 KiB
Raw Permalink Blame History

phase, name, milestone, requirements, wave, depends_on
phase name milestone requirements wave depends_on
P0 pre-execution v1.14
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
0

v1.14 — NFR Refinement Plan (20 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 (P1P20) → v1.13.24 (P21 = milestone release). Branch: milestone/v1.14-refinementphase/NN-<slug>

Wave ordering (D-098)

  • Wave 1 (P1P6): bug fixes. P1→P2 sequential (composition depends on dedup correctness); P3P6 independent. G-105: full regression gate run after P4 (validates the hardened gate before W2).
  • Wave 2 (P7P12): 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 (P13P17): 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 (P18P20): standards/docs/VPC. P19 depends on P1P18 (reflects all prior phases); P18 + P20 independent.

Execution approach

Each phase: EXECUTE (persona-assigned task groups) → VERIFY (4 layers + regression gate at milestone complete) → SHIP (patch tag). Phase boundary checkpoint resets context. The execute workflow reads this PLAN.md + ROADMAP.md §v1.14 + PERSONAS.md for task decomposition.


Wave 1 — Bug Fixes (P1P6)

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 "<first_id>" { ... } block with merged inputs.
  2. Add test_adapter_remote_state_key_overrideACDL_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 (P7P12)

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)

Persona: lead-developer Territory: .gitignore, tests/test_no_secrets_tracked.py 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.

Wave 3 — Stub / Test / CI / Hygiene (P13P17)

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) 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_platformcore.
  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.

Wave 4 — Standards / Docs / VPC (P18P20)

P18 — module-standards-consistency (REQ-152)

Persona: data-engineer Territory: modules/STANDARDS.md, modules/l1/{ecr,ecs-cluster,rds}/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.11v1.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.

Final Phase — P21 (review + audit + ship)

Persona: lead-developer (review coordination) + ci-code-reviewer + ci-debugger (audit) Tasks:

  1. Multi-persona code review across all v1.14 phases (P1P20). 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-refinementmain. 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.
  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.