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---
18 KiB
phase, name, milestone, requirements, wave, depends_on
| phase | name | milestone | requirements | wave | depends_on | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P0 | pre-execution | v1.14 |
|
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 (P1–P20) →
v1.13.24 (P21 = milestone release).
Branch: milestone/v1.14-refinement → phase/NN-<slug>
Wave ordering (D-098)
- 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.
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 (P1–P6)
P1 — adapter-dedup-diagnostic (REQ-135)
Persona: backend-engineer
Territory: adapters/terraform/adapter.py
Tasks:
- In the dedup loop (
adapter.py:159-170), whentf_dirisNone, raiseValueError(f"no terraform_dir in registry for module {module}")instead of silently skipping. - Verify registered-module dedup behavior preserved (multi-resource L1s
still merge into one
module "x" { ... }block). - 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:
- Wire
default_ttl/max_ttl/price_class/viewer_protocol_policyincomposition.jsonto the cloudfront child's inputs. - Add a
waf_enabledfeature flag (default true) to the static-assets composition; make the WAF child conditional on it. - Update
examples/complex.ymlto setwaf_enabled: true+ non-default TTLs so it resolves to a different resource set thansimple.yml. - Run
pytest+run_ci.sh.
P3 — lifecycle-script-arg-cleanup (REQ-137)
Persona: backend-engineer
Territory: scripts/run_l2_lifecycle_*.sh
Tasks:
- Remove the
[ci-vpc-outputs.json]token from the usage strings ofrun_l2_lifecycle_test.sh+run_l2_lifecycle_destroy.sh, OR add a comment documenting the L2-uses-remote-state design + parity reason. - 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:
- Add a
terraform validatestep to_check_lifecycle_module_terraform(or document why it's too slow + fall back to aterraform fmt -checksyntax probe). - Tighten CAPABILITY_INVENTORY + docstrings to "offline proxy; live apply/modify/destroy verified by the modules-lifecycle workflow run, not by this gate."
- Run the full regression gate immediately after P4 lands (G-105). Gate must pass clean before W2 begins.
- Run
pytest+run_ci.sh.
P5 — adapter-behavior-tests (REQ-139)
Persona: backend-engineer
Territory: tests/test_adapter.py
Tasks:
- Add
test_adapter_dedup_merges_same_module— two resources with the samemodulecollapse to onemodule "<first_id>" { ... }block with merged inputs. - Add
test_adapter_remote_state_key_override—ACDL_REMOTE_STATE_KEYoverrides the defaultplatform/terraform.tfstatekey in the emitteddata terraform_remote_stateblock. - Run
pytest+run_ci.sh.
P6 — alb-name-prefix-fix (REQ-140)
Persona: data-engineer
Territory: modules/l1/alb/terraform/main.tf
Tasks:
- Change
name_prefix = "tg-ci-"toname_prefix = "${var.name}-"so the consumer's name prefixes the target group. - Run
terraform validatein the alb module dir standalone. - 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:
local_emulators.py:374— narrowexcept Exception: passto catchAttributeError/TypeError(monkeypatch setup); log + re-raise if patching fails (prevents network egress).contract_ingestor.py:157— catchurllib.error.URLError/HTTPErrorspecifically; log the search failure; keepexisting = []only on404/network, re-raise on auth errors.create_state_backend.py:51— catchClientErrorwithNoSuchBucket/404error code; re-raise on permissions/network.output_publisher.py:100,168— catchClientError/HTTPErrorspecifically; log with context.apply_iam_baseline.py:78— catchNoSuchEntityExceptionon old-version delete; re-raise on other errors.- 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:
adapter.py:125,140— readACDL_AWS_ACCOUNT_IDenv; build the state-bucket name dynamically. Fallback constant =581513795199(the live account ID, NOT a placeholder — G-102). Documented for offline tests.apply_iam_baseline.py:33,create_state_backend.py:33,35— read from env (same fallback).push_consumer_image.py:32— read from env.- Terraform: use
data.aws_caller_identity.current.account_idfor resource ARNs inspike_runner_policy.json+ resource names. Exclude terraformbackend "s3"blocks (terraform/*/terraform.tf,terraform/ci-vpc/main.tf,terraform/platform/main.tf,terraform/microservice/terraform.tf) — backendbucketargs are static-config-only, evaluated pre-init (G-101). Leave backend blocks literal or move toterraform init -backend-config(separate change, not in P8 scope). - Lifecycle workflow env wiring (G-102): the
modules-lifecycle.ymlfull-mode jobs must setACDL_AWS_ACCOUNT_IDfromaws sts get-caller-identity --query Account --output textbefore anyrun_platform.sh/lifecycle invocation. No full-mode run proceeds with the env unset. - Run
pytest+run_ci.sh; verifygrep -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:
- Scope
iam:CreateRoleetc. (line 236) toarn:aws:iam::*:role/acdl-*. - Scope KMS (line 218) to
arn:aws:kms::*:key/acdl-*(oralias/acdl-*). - CloudFront (line 117) + WAFv2 (line 129) remain
Resource: "*"with a documented global-ARN constraint (CloudFront ARNs are global; cannot be account-scoped — G-104). - Verify acdl- naming (G-104):* grep/audit
modules/l1/*/terraform/main.tf+modules/l2/*/composition.jsonfor 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). - Add a regression test in
test_iam_policy_baseline.pyasserting no newResource: "*"on non-global actions. - 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:
- Add
contractIdformat validation (regex, ≤64 chars). - Add
environmentenum validation (dev/qa/prod/dr). - Add
errorlength cap (truncatestackTraceat a reasonable limit). - Document the ABAC reliance in the
_validate_caller_identitydocstring + add a note to ARCHITECTURE.md (P19 will land it). - Add a spoofing-resistance test (caller submits a
consumerRepothey don't own → rejected if ABAC misconfigured; documented best-effort). - 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:
- Add
"additionalProperties": falseto both schemas' top-level objects. - Add
maxItems/maxPropertiesbounds toinfrastructuremap +monitored_endpointsarray. - Add
patternvalidation forstate_backend.bucket(S3 naming rules: lowercase, 3-63 chars, no underscores). - Add
patternvalidation forrunner_role_arn(ARN format). - Add
patternvalidation forvpc_cidr(CIDR format). - Add tests asserting rejection of undocumented fields + malformed values.
- Run
pytest+run_ci.sh.
P12 — gitignore-credential-hygiene (REQ-146)
Persona: lead-developer
Territory: .gitignore, tests/test_no_secrets_tracked.py
Tasks:
- Add credential-pattern catch-all to
.gitignore:*.pem,*.key,*.p12,*.pfx,*.cer,*.crt,*.jks. - Create
tests/test_no_secrets_tracked.py— runsgit ls-files | grep -E '\.(pem|key|p12|pfx|cer|crt|jks)$'and asserts 0 hits. - Run
pytest+run_ci.sh.
Wave 3 — Stub / Test / CI / Hygiene (P13–P17)
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:
- Remove the
--kube-versionflag fromkyverno_adapter.py:11,115-116(G-103 — implementing version-aware policy selection would be a new feature, violating D-095). - Add a docstring documenting the deferral to the GitOps reconciler
roadmap (D-053): the Kyverno adapter is inactive for Terraform-only
stacks;
--kube-versionwill be relevant when the GitOps reconciler emits K8s manifests. - Update
test_kyverno_adapter.pyto remove the--kube-versiontest cases + assert the flag is absent. - 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:
- Delete the orphan
scripts/__pycache__/verify_deploy_microservice.cpython-312.pyc. - Fix
pyproject.tomlcoverage source:acdl_platform→core. - Bump
pyproject.tomlversion1.3.0→ current (v1.14). - Remove dead JS allowlist entries from
config.jsonbash_allowlist.allowed_commands(npm/node/npx/pnpm/yarn/jest/eslint/ tsc/prettier — no package.json). - Run
pytest+run_ci.sh.
P15 — untested-scripts-coverage (REQ-149)
Persona: backend-engineer
Territory: tests/ (new test files for 7 scripts)
Tasks:
tests/test_seed_uptime_monitors.py— mock the uptime-kuma API; assert monitor creation from a JSON file.tests/test_push_consumer_image.py— mocksubprocess.run(docker login/build/push) + boto3 ECR; assert the flow.tests/test_sync_to_gl.sh(shell test) — dry-run mode; assert the copy + push commands are constructed correctly.tests/test_post_stage_comment.sh(shell test) — no-op when not in a PR context; assert thegh apicall structure when in PR.tests/test_rotate_spike_key.sh(shell test) — mockaws iam; assert deactivate/create/update-secret flow.tests/test_create_state_backend.py— mock boto3 S3/DynamoDB; assert idempotent creation.tests/test_create_iam_user.py— mock boto3 IAM; assert idempotent user/policy/key creation.- 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:
- 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). - Add
set -euo pipefailtorotate_spike_key.sh(currently onlyset -u). - Add
set -euo pipefailtosync_to_gl.sh(currently nosetflags). - Run
pytest+run_ci.sh.
P17 — config-and-persona-hygiene (REQ-151)
Persona: lead-developer
Territory: .ciagent/config.json, .ciagent/PERSONAS.md
Tasks:
- Mark
frontend-engineerpersonaactive: falseinconfig.jsonpersonas.personas[](PERSONAS.md:80 already says inactive). - 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). - Configure
ollama-cloudbackend: setbase_urlto the actual endpoint OR add a comment documenting why it's intentionally unset (the runtime uses theglm-5.2model via the opencode backend, not thellm_backendsconfig). - Run
pytest+run_ci.sh.
Wave 4 — Standards / Docs / VPC (P18–P20)
P18 — module-standards-consistency (REQ-152)
Persona: data-engineer
Territory: modules/STANDARDS.md, modules/l1/{ecr,ecs-cluster,rds}/terraform/
Tasks:
- Either add
locals.tftoecr,ecs-cluster,rds(extract inlined locals frommain.tf), OR reconcile STANDARDS §9.4 to explicitly allow inlining for trivial single-resource modules. - Remove the stale
TYPE_MAPreference in STANDARDS §8 (deleted in the v1.11 stateless rewrite). - 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:
- 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.
- Bump stale
@v1.6–@v1.9→@v1.13acrossREADME.md:225,docs/consumer-guide.md(12 sites),docs/architecture.md:233,docs/pipeline/versioning.md:29,docs/pipeline/index.md:42. - Sync decks to v1.13.2 reality (version refs, capability claims).
- Update COST.md window to v1.11–v1.14 (lifecycle pipeline live-runs + teardown).
- 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 (plan-only default, config.json schema, v1.14 IAM scoping from P9).
- Run
pytest+run_ci.sh; verifygrep -rn "@v1\.[6-9]" docs/ README.mdreturns 0 hits.
P20 — platform-vpc-parameterization (REQ-154)
Persona: data-engineer
Territory: terraform/platform/main.tf
Tasks:
- Add a
vpc_cidrvariable (default10.0.0.0/16); replace the hardcodedcidr_block. - Replace
count = 2subnets withcount = length(data.aws_availability_zones.available.names). - Add a
data "aws_availability_zones" "available" {}block. - Document the
0.0.0.0/0ingress on port 80 (ALB-fronted, acceptable for a public-facing service; add a comment). - 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:
- 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.
- Audit: reconstruction test (git log vs
.ciagent/files), file discipline, branch hygiene, commit discipline. Fix critical issues in-phase. - Complete: update REQUIREMENTS.md (REQ-135..154 → complete), ROADMAP.md (v1.14 complete), PROJECT.md.
- Tag
v1.13.24(IS the milestone release). Mergemilestone/v1.14-refinement→main. Create Gitea release with full milestone summary.
Success Criteria (milestone gate)
- All 20 REQ-135..REQ-154 marked complete in REQUIREMENTS.md.
- Review: 0 new P0; all P1-1..P1-5 + P2-1..P2-4 resolved.
- Audit: clean; reconstruction test passes.
- Regression gate (D-091) clean against the v1.14 state.
pytestpasses;run_ci.shexits 0;run_platform.sh --check-onlyexits 0.- Tag
v1.13.24created; milestone merged to main.