diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index be6413a..b119a8e 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,109 +1,91 @@ --- -phase: P60 -name: l1-lifecycle-pipeline-live-run +phase: P61 +name: l2-lifecycle-pipeline-author milestone: v1.11 -requirements: [REQ-127] -wave: 2 -depends_on: [P59] +requirements: [REQ-128] +wave: 3 +depends_on: [P60] --- -# P60 — L1 Module Lifecycle Pipeline (Live Run) +# P61 — L2 Lifecycle Pipeline (Author) -**Phase:** P60 +**Phase:** P61 **Milestone:** v1.11 (RESTART) -**Requirement:** REQ-127 (shared with P59) -**Wave:** 2 (the testing milestone — P59 authored the pipeline, P60 runs it live) -**Branch:** `milestone/v1.11-restart` (retrofit — see "Deviation note" below) +**Requirement:** REQ-128 +**Wave:** 3 (author the L2 lifecycle pipeline, P62 runs it live) +**Branch:** `milestone/v1.11-restart` ## Goal -Run the `modules-lifecycle` 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`, -`terraform/ci-vpc/`, `scripts/run_lifecycle_*.sh`, and rarely the adapter -assembler. No new Python files. +Extend the `modules-lifecycle` pipeline + 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). L2 = +composition only (no L2 terraform files); the composition must be +deterministic (same contract → same resolved stack → same state key). -## Deviation note (process audit) +## Tasks (single wave) -P60's execute deliverable was produced out-of-band: 13 `fix(...)` commits -landed on `milestone/v1.11-restart` between the P59 verify PASS (`3739037`) -and HEAD (`88ea408`), committed under `phase: P59, status: execute` rather -than a dedicated `phase/p60-*` branch. This retrofit PLAN formalizes that -work as P60's EXECUTE output. The phase branch deviation is documented for -the COMPLETE-stage audit; no commits are reverted (the fixes are correct -and were validated by terraform validate + 24 example contracts `--check-only`). +### Task 1 — Extend pipelines/modules-lifecycle.yml -## Tasks (already executed — retrofit) +Add L2 stages to the declarative pipeline contract: +- `l2-lifecycle-apply`: `run_platform.sh --apply modules/l2/${MODULE}/examples/simple.yml` +- `l2-lifecycle-modify`: `run_platform.sh --apply modules/l2/${MODULE}/examples/complex.yml` +- `l2-lifecycle-destroy`: `run_platform.sh --destroy modules/l2/${MODULE}/examples/complex.yml` -### Task 1 — CI VPC separation (commits 8071d6a, ad3cc5f, a55752e) +Add L2 matrix entries: `l2_modules: [static-assets, microservice]` -Created `terraform/ci-vpc/` — a short-lived VPC for L1 module lifecycle -testing, separate from the long-lived platform VPC. Created before -VPC-dependent modules (alb, ecs-service, rds, uptime), destroyed after. -Outputs (vpc_id, subnet_ids, sg_id, cluster_arn) read from S3 state by -each lifecycle job (no artifact passing — `upload-artifact@v4` unsupported -on Gitea/GHES). +### Task 2 — Extend .gitea/workflows/modules-lifecycle.yml + .github/workflows/modules-lifecycle.yml -- `8071d6a` — target only VPC resources in platform-vpc-apply/destroy -- `ad3cc5f` — separate short-lived CI VPC + fix 8 module lifecycle failures -- `a55752e` — read CI VPC outputs from S3 state instead of artifacts +Add an `l2-lifecycle` job (byte-identical in both forges) that matrix-runs +over `[static-assets, microservice]`. Each cell: +- Checkout + Python 3.12 + Terraform 1.9.* + AWS creds (from secrets). +- `run_platform.sh --apply modules/l2//examples/simple.yml` +- `run_platform.sh --apply modules/l2//examples/complex.yml` (same state key → modify) +- `run_platform.sh --destroy modules/l2//examples/complex.yml` -### Task 2 — Platform terraform fixes (commits 2f8c020, c4e94cf) +The `l2-lifecycle` job needs the CI VPC (for microservice which references +the platform VPC via `terraform_remote_state`). It runs after `ci-vpc-apply` +and before `ci-vpc-destroy`. -- `2f8c020` — quote `acdl:` tags + fix Lambda + replace interpolation -- `c4e94cf` — make Lambda conditional on zip existing +### Task 3 — Author modules/l2/static-assets/examples/complex.yml (modify variant) -### Task 3 — CI workflow fixes (commits 315a86d, 3597cf0, 75b56f5, 3ef3a82, 60f767d) +The complex example already exists and adds CloudFront + WAF. Verify it's a +valid modify variant (same state key, adds resources without forcing +replacement of the simple S3 bucket). If the bucket_name changes between +simple and complex, that forces replacement — fix to keep the same +bucket_name so terraform modifies in-place. -- `315a86d` — replace configure-aws-credentials with direct env vars -- `3597cf0` — install Terraform 1.9.* in test + check-only jobs -- `75b56f5` — recursive .terraform gitignore (covers all module + platform dirs) -- `3ef3a82` — skip terraform validate test when terraform binary not installed -- `60f767d` — 3 pipeline-readiness fixes (resolver id, schema inputs, CI creds) +### Task 4 — Author modules/l2/microservice/examples/complex.yml (modify variant) -### Task 4 — Module lifecycle fixes (commits ad3cc5f, 6795acc, fad6765, 88ea408) +The complex example already exists and adds ALB + env vars. The modify +variant should change `desired_count` (1→2) to demonstrate in-place modify. +Fix the complex example to keep the same `family` and `image` as simple +(so terraform modifies rather than replaces the ECS task definition). -8 module-specific fixes in `ad3cc5f`: -- **s3** — unique bucket names (acdl-ci-s3a-simple/complex) instead of - globally-taken 'my-simple-bucket' -- **kms-key** — alias name with no spaces (locals.tf → alias/acdl-ci-kms) -- **iam-role** — example contract uses role_name (not name, which the - interface doesn't declare) -- **ecs-service** — example contract uses family (not name); VPC inputs - (cluster_arn, subnets, security_group) injected by CI VPC wrapper -- **uptime** — added subnets, security_group, cluster_arn to interface + - module; network_configuration is dynamic (only when subnets provided) -- **rds** — added subnet_ids input + db_subnet_group resource (conditional - on subnet_ids being non-empty) -- **alb** — removed hardcoded placeholder sg/subnet values from examples; - vpc_id + subnets + security_group injected by CI VPC wrapper -- **cloudfront** — removed invalid placeholder WAF ARN from complex example +### Task 5 — Extend schemas/modules-lifecycle-pipeline.schema.json -Follow-up fixes: -- `6795acc` — ALB: `create_before_destroy` on target group + `depends_on` - on listener (fixes ResourceInUse when port changes simple 80 → complex 443) -- `fad6765` — kms-key deletion window 90→30 (AWS max); rds password policy - (added password var, default 'ACdlcI2026!') -- `88ea408` — uptime: add default for container_image variable (interface - declares default 'louislam/uptime-kuma:1' but module had no default) +Add `l2_modules` to the matrix properties. Add L2 stages to the stages array. + +### Task 6 — Extend tests/test_pipeline_contract.py + +Add a TestL2LifecyclePipeline class: +- L2 matrix lists both modules. +- L2 lifecycle job has apply/modify/destroy steps. +- L2 job depends on ci-vpc-apply. +- Pipeline contract validates against the extended schema. +- Gitea + GitHub workflows remain byte-identical. + +### Task 7 — Extend pipelines/README.md + +Add L2 lifecycle stages to the pipeline description. ## Success Criteria (phase gate) -1. Full L1 lifecycle matrix green: 12 modules × 2 examples = 24 cells, each - apply→modify→destroy exit 0. **Evidence = green PR check on - `modules-lifecycle.yml`** (PR opened from `milestone/v1.11-restart` → - `main` to trigger the `pull_request` event; or `workflow_dispatch`). -2. No live resources remain after the run (`ci-vpc-destroy` always runs, - `lifecycle` destroy step per module). -3. `primitives-plan.yml` (plan-only) still passes. -4. Full offline pytest suite green (479+ tests). - -## Verification approach - -- **Offline (this session)**: pytest + 24 example contracts `--check-only`. -- **Live-AWS (CI)**: open PR `milestone/v1.11-restart` → `main` via `tea`; - wait for `acdl-modules-lifecycle` workflow green across all 14 jobs - (1 ci-vpc-apply + 12 lifecycle + 1 ci-vpc-destroy). Read workflow run - status via `tea` or the Gitea API. Green = P60 verify evidence. \ No newline at end of file +1. `pipelines/modules-lifecycle.yml` validates against its schema. +2. `.gitea/workflows/modules-lifecycle.yml` and `.github/workflows/modules-lifecycle.yml` are byte-identical. +3. L2 matrix lists both `static-assets` and `microservice`. +4. L2 lifecycle job has apply→modify→destroy steps. +5. `test_pipeline_contract.py` passes (offline). +6. Composition resolution is deterministic (same contract → same stack). +7. Full offline pytest suite green. \ No newline at end of file