Files
acdl/.ciagent/PLAN.md
T
Jon Chery ee5c372e65 docs(P00): complete pre-execution phase — v1.16 NFR scope
Phase 0: SPECIFY → CLARIFY → RESEARCH → IDEATE → PLAN → GRILL.
NFR milestone v1.16 (Nova Simplification), 20 execution phases + final.
Tags on v1.15.x line: v1.15.5 (this phase) → v1.15.6..v1.15.25 (P1-P20) →
v1.15.26 (P21 final = release).

Scope (D-113..D-119): Simplify without regressions, Security,
Maintainability, User/Developer Experience, No Humans Onboarding Flow
(request-path only; real AWS provisioning deferred). Regression gate
(D-118, G-111) gates P9 + P21 at 20/22 Verified + 2 Skipped.

Grill: PASS-with-binding (G-111..G-113, E-002 deferred to P21).

---ci---
project: acdl
phase: 0
milestone: v1.16
status: complete
phase_role: pre_execution
requirements:
  covered: [REQ-165, REQ-166, REQ-167, REQ-168, REQ-169, REQ-170, REQ-171, REQ-172, REQ-173, REQ-174, REQ-175, REQ-176, REQ-177, REQ-178, REQ-179, REQ-180, REQ-181, REQ-182, REQ-183, REQ-184]
  partial: []
---/ci---
2026-07-30 15:12:32 +00:00

22 KiB
Raw Blame History

phase, name, milestone, requirements, wave, depends_on
phase name milestone requirements wave depends_on
P0 pre-execution v1.16
REQ-165
REQ-166
REQ-167
REQ-168
REQ-169
REQ-170
REQ-171
REQ-172
REQ-173
REQ-174
REQ-175
REQ-176
REQ-177
REQ-178
REQ-179
REQ-180
REQ-181
REQ-182
REQ-183
REQ-184
0

v1.16 — Nova Simplification Plan (20 execution phases + 1 final)

Milestone: v1.16 (Nova Simplification — NFR) Type: NFR (all phases fix/chore/docs/refactor/test). The final phase's patch IS the deliverable — no separate milestone tag. Tags run on the v1.15.x line: v1.15.5 (P0) → v1.15.6..v1.15.25 (P1P20) → v1.15.26 (P21 final = milestone release).

Objective: 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. Clears the fresh debt the v1.15 rebrand left, delivers genuine simplification, and implements the first self-service onboarding request path (request-path only; real AWS provisioning deferred, D-113).

Wave ordering

  • Wave 1 (P1P4): correctness + brand regression fixes. P1 first — the state-bucket drift (adapter.py:117 emits acdl-tfstate-* while the live bucket is nova-tfstate-*) and the Kyverno policy contradiction (enforces acdl:* labels that nova_tagging.py hard- fails) are the highest-severity findings, both correctness regressions left by the rebrand. P2P4 independent brand/dead-code/except work.
  • Wave 2 (P5P9): simplify without regressions. P5 before P6/P9 (regression-verify dedup is independent; P6/P9 both touch run_platform.sh). P8 changes the workflow byte-identity test → generator (D-115). P9 must run the regression gate (D-118) at the end of Wave 2 — 22/22 capabilities must stay Verified.
  • Wave 3 (P10P14): security + maintainability. P10 before P11 (identity enforcement before payload validation). P12/P13 independent file splits. P14 mid-milestone checkpoint (offline) at end of Wave 3.
  • Wave 4 (P15P17): developer experience. Independent; P17 last (reflects the consolidated path after P15/P16 land).
  • Wave 5 (P18P20): no-humans onboarding (request-path only). P18 (schema + Lambda action) before P19 (env-file autogen consumes the schema) before P20 (cross-account role, offline-proven per D-114).
  • Final (P21): review + audit + milestone ship.

Execution approach

  • Per-phase ship: each execution phase merges phase/NN-*milestone/v1.16-nova-simplification and tags a patch on the v1.15.x line (v1.15.6 = P1 ... v1.15.26 = P21).
  • Verification: 4-layer verify (structural/behavioral/security/ quality) per phase; the regression gate (D-091, 22 capabilities) runs at P9 (end of Wave 2) and P21 (milestone complete) per D-118.
  • No live AWS: NOVA_LIFECYCLE_MODE=plan default; terraform changes validated via terraform validate + --check-only. P20 cross-account Terraform is offline-proven only (D-114).
  • Test discipline: each phase that changes runtime code adds/updates tests; bash scripts/run_ci.sh exits 0 at every phase boundary.

Wave 1 — Correctness + Brand Regression Fixes (P1P4)

Phase P1 — state-bucket-and-kyverno-rebrand-fix (REQ-165)

  • Lead: backend-engineer; Contributor: data-engineer (kyverno)
  • Must-haves:
    • adapters/terraform/adapter.py:117 state_bucket = f"acdl-tfstate-{account_id}-us-east-1"f"nova-tfstate-{account_id}-us-east-1".
    • adapters/kyverno/policies/require-resource-labels.yml: annotation title Require ACDL Resource LabelsRequire Nova Resource Labels; rule names require-acdl-owner-label/require-acdl-environment-labelrequire-nova-owner-label/require-nova-environment-label; messages + patterns acdl:owner/acdl:environmentnova:owner/ nova:environment.
    • Update any test fixtures referencing the old bucket name / label keys.
  • Verify: terraform validate (adapter-emitted); pytest passes; run_ci.sh exits 0; regression gate 22/22 (run at P9, but P1 must not break any cap locally).

Phase P2 — user-facing-acdl-to-nova-sweep (REQ-166)

  • Lead: lead-developer; Contributor: backend-engineer
  • Must-haves:
    • core/environment_check.py:59,61 onboarding message header/body "ACDL" → "Nova".
    • core/lambda/contract_ingestor.py:145 alert title [ACDL-ALERT][NOVA-ALERT]; :191 issue body "ACDL platform Lambda" → "Nova platform Lambda".
    • scripts/post_stage_comment.sh:39 PR comment header "ACDL Stage" → "Nova Stage"; :46 footer "ACDL deploy pipeline" → "Nova deploy pipeline".
    • scripts/run_ci.sh:39 CI banner "ACDL CI Pipeline" → "Nova CI Pipeline".
    • Module docstrings: core/contract_resolver.py:1,474, core/confidence_signal.py:1, adapters/terraform/adapter.py:1, adapters/kyverno/kyverno_adapter.py:1, adapters/wiz/wiz_adapter.py:1, adapters/README.md:1, adapters/kyverno/README.md:4,18 → Nova.
    • Update tests that assert these strings.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P3 — dead-code-and-stale-prefix-cleanup (REQ-167)

  • Lead: lead-developer
  • Must-haves:
    • scripts/run_platform.sh:153 remove the dead export ACDL_ENVIRONMENT_OVERRIDE=... line (comment says "removed in P5" but the line is present).
    • Stale dual-read comments: drop the "ACDL_* fallback until P5" / "dual-read NOVA_* first, ACDL_* fallback per G-106" comments in core/local_emulators.py:15-16,503,505, core/regression_verify.py:318-319,333, and the lifecycle scripts (the G-106 fallback is retired per core/env.py:4-5).
    • acdl_* temp-dir prefixes → nova_*: core/local_emulators.py:71,252 (acdl_outbox_/acdl_tfstate_), core/regression_verify.py:183,234 (acdl_regr_/acdl_outbox_), scripts/run_pattern_plan.sh:29, scripts/run_primitive_plan.sh:29, scripts/run_lifecycle_test.sh:41, scripts/run_lifecycle_destroy.sh:36.
    • core/regression_verify.py:214 interpolation fixture acdl-nova- (or make it a clearly-generic token).
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P4 — migrate-ssm-except-narrowing (REQ-168)

  • Lead: backend-engineer
  • Must-haves:
    • scripts/migrate_ssm_paths.py:113 except Exception: pass → narrow to ParameterNotFound + structured log on the non- ParameterNotFound path.
    • Narrow core/output_publisher.py:112,182 except Exception → specific (ClientError, OSError) + structured stderr log.
    • Test that a non-ParameterNotFound error is raised (not swallowed).
  • Verify: pytest passes; run_ci.sh exits 0.

Wave 2 — Simplify Without Regressions (P5P9)

Phase P5 — regression-verify-dedup (REQ-169)

  • Lead: backend-engineer
  • Must-haves:
    • Extract _check_live_terraform_plan(contract_path, label) from the two ~95% identical methods _check_live_terraform_plan_microservice
      • _check_live_terraform_plan_static_assets (~35 lines saved).
    • Extract _check_resolver(contract_path) from _check_resolver_static_assets + _check_resolver_microservice.
    • Extract _assert_contracts_resolve(module_dir) from the duplicated lifecycle-contract-resolve block in _check_lifecycle_module_terraform + _check_lifecycle_l2_module.
    • Behavior preserved (the regression gate output is unchanged).
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P6 — run-platform-deadcode-and-hitl-fn (REQ-170)

  • Lead: lead-developer
  • Must-haves:
    • Extract the duplicated HITL attestation block (:336-350 + :452-466) into a shell function run_hitl_gate() invoked at both sites (~14 lines saved).
    • scripts/run_platform.sh:145 hardcoded CONTRACT_ID UUID → NOVA_CONTRACT_ID env with the existing UUID as default.
    • scripts/run_platform.sh:146 WORK="/tmp/acdl_platform_run_v18"WORK="${NOVA_WORK_DIR:-/tmp/nova_platform_run}" (drop the stale v18 stamp + acdl_ prefix).
    • Drop the stale brand comment run_platform.sh:2 "the ACDL platform pipeline" → "the Nova platform pipeline".
  • Verify: pytest passes; run_ci.sh exits 0; run_platform.sh --check-only exits 0.

Phase P7 — contract-resolver-envloader-and-kind (REQ-171)

  • Lead: backend-engineer
  • Must-haves:
    • core/contract_resolver.py:50-68 _load_env → import core/environment_check.py:load() (dedup; both load + placeholder warning).
    • Add a kind field ("l1" / "l2") to each modules/registry.json entry; the resolver reads kind directly instead of the fragile is_l2 = "l2" in interface_path or "composition" in interface_path heuristic (contract_resolver.py:540).
    • Collapse the redundant kind computation (:584-589) → kind = "l2" if (multi_module or any_l2) else "l1" (after the registry kind field is authoritative, simplify further).
  • Verify: pytest passes; run_ci.sh exits 0; resolver behavior unchanged (all contracts still resolve to the same stacks).

Phase P8 — workflow-generator-dedup (REQ-172)

  • Lead: lead-developer; Contributor: backend-engineer (test)
  • Must-haves:
    • Author scripts/sync_workflows.py — reads one source workflow per pair (e.g. workflows-src/ci.yml, workflows-src/deploy.yml, workflows-src/modules-lifecycle.yml) and writes byte-identical copies to both .gitea/workflows/ and .github/workflows/. Establish the workflows-src/ dir as the single source.
    • Replace the byte-identity assertions in tests/test_pipeline_contract.py with a "generated outputs match committed files" test (run sync_workflows.py --check → exit 0 if the committed files match the generated output, non-zero + diff if drift).
    • Migrate the 3 existing pairs to the workflows-src/ source; remove the hand-maintained duplicates (the generator owns them).
  • Verify: python3 scripts/sync_workflows.py --check exits 0; pytest passes; run_ci.sh exits 0; the 4 GitHub-only workflows are untouched (they have no pair).

Phase P9 — run-platform-split (REQ-173)

  • Lead: lead-developer
  • Must-haves:
    • Extract the decommission block (scripts/run_platform.sh:180-237) into scripts/run_decommission.sh (sourced or invoked).
    • Extract the uptime block (:520-606) into scripts/run_uptime.sh.
    • run_platform.sh invokes the helpers; behavior unchanged.
    • G-112 binding: the helpers are sourced (shared shell env), not invoked as subshells — the extracted blocks reference run_platform.sh-local vars (NOVA_CONTRACT_ID/NOVA_WORK_DIR from P6); a subshell would not inherit them.
    • G-111 binding: update core/regression_verify.py CAP-015/016 checks — when the live resource is absent (ResourceNotFoundException/404), mark Skipped (post-teardown, D-096) not Decayed, so a clean local run reports 20/20 Verified + 2 Skipped (not a strict-all failure on the known teardown state).
    • Run the regression gate (D-118, end of Wave 2): 20/22 Verified is the passing bar (CAP-015/016 Skipped — post-v1.11-teardown steady state, D-096; re-provisioning is a future feature, not an NFR). Any non-Verified/non-Skipped capability halts Wave 3.
  • Verify: pytest passes; run_ci.sh exits 0; run_platform.sh --check-only exits 0; regression gate 20/22 Verified + 2 Skipped.

Wave 3 — Security + Maintainability (P10P14)

Phase P10 — contract-ingestor-defense-in-depth (REQ-174)

  • Lead: backend-engineer; Contributor: lead-developer (review)
  • Must-haves:
    • core/lambda/contract_ingestor.py:251-252 if not caller_arn: pass → fail closed: return a 401/403 with a clear message when IAM identity is absent (defense-in-depth; ABAC layer still the primary control).
    • core/lambda/contract_ingestor.py:269 hardcoded valid_envs = {"dev","qa","prod","dr"} → derive from the core/environments/ directory (list *.json filenames).
    • Document the ABAC reliance explicitly in the function docstring + ARCHITECTURE.md.
    • Test: a request without IAM identity is rejected; a request with an unknown environment is rejected.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P11 — contract-ingestor-payload-validation (REQ-175)

  • Lead: backend-engineer
  • Must-haves:
    • submit_contract: size-cap the contract blob (e.g. 256 KB) before the DynamoDB write; reject oversized payloads with 413.
    • Schema-validate the contract blob against schemas/contract.schema.json before the write; reject invalid with 400.
    • Consistent caps: error and stackTrace use the same cap (align the 10k vs 2k inconsistency).
    • Tests for size-limit + schema-rejection paths.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P12 — split-contract-resolver (REQ-176)

  • Lead: backend-engineer
  • Must-haves:
    • Split core/contract_resolver.py (638 lines) into: core/contract_resolve.py (the resolve + interpolation core), core/decommission_transform.py (the decommission zero-counts transform), core/contract_resolver_cli.py (the __main__ CLI).
    • core/contract_resolver.py becomes a thin re-export shim for backwards compat (existing imports keep working).
    • G-113 binding: import direction is one-way — split modules import only each other + stdlib; the re-export shim imports the split modules; nothing imports the shim except external callers (prevents the latent cycle shim → split → split → shim).
    • Behavior unchanged; all tests pass without modification.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P13 — split-regression-verify (REQ-177)

  • Lead: backend-engineer
  • Must-haves:
    • Split core/regression_verify.py (670 lines) into: core/regression_capabilities.py (the CAP-001..022 checks), core/regression_live_plan.py (the shared live-plan helpers from P5), core/regression_verify_cli.py (the __main__ CLI + run_regression orchestration).
    • core/regression_verify.py becomes a thin re-export shim.
    • Behavior unchanged; the regression gate output is identical.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P14 — schema-driven-outputs-and-cache (REQ-178)

  • Lead: backend-engineer; Contributor: data-engineer (interface.json)
  • Must-haves:
    • core/output_publisher.py:38-55 SAFE_OUTPUT_NAMES hardcoded set → derived from modules/l1/*/interface.json outputs[].sensitive annotations (non-sensitive outputs are safe to publish).
    • core/contract_resolver.py:498,617 (now in the split module) — cache loaded JSON schemas in a module-level dict (avoid re-reading from disk each resolve call).
    • Mid-milestone checkpoint (offline): regression gate spot-check (not the full P9/P21 gate); confirm Wave 3 introduced no regressions.
  • Verify: pytest passes; run_ci.sh exits 0.

Wave 4 — Developer Experience (P15P17)

Phase P15 — run-platform-help-and-flags-doc (REQ-179)

  • Lead: lead-developer
  • Must-haves:
    • scripts/run_platform.sh add a real --help / -h flag that prints all flags + a one-line description each (--check-only, --plan-only, --apply, --destroy, --quiet, --deploy-uptime, --decommission, --local, --environment). The current :82 reject-unknown-flags path must allow --help to print + exit 0.
    • Document --deploy-uptime in the header comment block (currently used at :532 but absent from the header).
    • Surface --local (D-092 local emulating tier) in the README "How to run" section.
  • Verify: run_platform.sh --help exits 0 and lists all flags; pytest passes; run_ci.sh exits 0.

Phase P16 — workflows-readme-catalog (REQ-180)

  • Lead: lead-developer
  • Must-haves:
    • Author .github/workflows/README.md cataloging all 7 workflows: ci.yml, deploy.yml, platform-test.yml, primitives-plan.yml, patterns-plan.yml, release.yml, modules-lifecycle.yml. For each: trigger (on:), inputs (reusable-workflow workflow_call inputs), required secrets, and one-line purpose.
    • Note which 3 are byte-identical Gitea mirrors (post-P8, generated by sync_workflows.py) and which 4 are GitHub-only (Gitea act_runner feature gaps).
    • Add a tests/test_docs_coverage.py assertion that the README exists
      • lists all 7 workflow filenames.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P17 — getting-started-consolidation (REQ-181)

  • Lead: lead-developer
  • Must-haves:
    • Consolidate the README "How to run" into a single getting-started section: offline happy path first (bash scripts/run_ci.sh + bash scripts/run_platform.sh --check-only / --local — no AWS needed), then the AWS path (bootstrap + --apply).
    • Remove the fragmented 3-step bootstrap as the lead; demote it to the AWS-path subsection.
    • Cross-link docs/CONSUMER_GUIDE.md for the consumer contract model.
  • Verify: pytest passes; run_ci.sh exits 0.

Wave 5 — No Humans Onboarding Flow (P18P20)

Phase P18 — onboarding-schema-and-lambda-action (REQ-182)

  • Lead: backend-engineer; Contributor: lead-developer (schema)
  • Must-haves:
    • Author schemas/onboarding.schema.json (JSON Schema draft 2020-12): required fields consumerRepo (string, format), requestedEnvironment (string, enum from environments dir), ownerId (string), billingTag (string); optional notes.
    • core/lambda/contract_ingestor.py add an onboard_consumer action (D-119): validates the payload against the onboarding schema, writes a pending row to nova-contracts (PK consumerRepo, SK onboarding#<requestedEnvironment>#<timestamp>, status pending). No AWS resources created (D-113).
    • Tests: valid onboarding request writes a pending row; invalid request rejected with 400; offline-testable via moto/local Lambda stub.
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P19 — onboarding-envfile-autogen (REQ-183)

  • Lead: backend-engineer; Contributor: lead-developer (docs)
  • Must-haves:
    • Author core/onboarding.py with generate_env_file(request, template_env="dev") — produces a <env>.json from a consumer onboarding request (fills account_id placeholder, ownerId, billingTag into the env template). Emits the file + a git patch / PR-branch instruction.
    • Rebrand core/environment_check.py:57-77 onboarding message to Nova; replace the "1. Contact the platform team" handoff with the self-service request path: "Run nova onboard (or POST to the Lambda onboard_consumer action) to request an environment; the platform generates a binding + opens a PR."
    • Update core/environments/README.md:34-37 — self-service request path is now implemented (real provisioning still a future feature).
    • Tests: generate_env_file produces a valid env JSON; the rebranded message no longer says "contact the platform team".
  • Verify: pytest passes; run_ci.sh exits 0.

Phase P20 — cross-account-role-automation-offline (REQ-184)

  • Lead: data-engineer; Contributor: backend-engineer (ABAC)
  • Must-haves:
    • Author terraform/onboarding/ (new dir): main.tf defining the consumer deploy-role + nova:owner ABAC tag grant (cross-account IAM role + trust policy + tag-based permission boundary). Variables for consumer_repo, owner_id, account_id.
    • terraform validate passes; terraform plan (offline / no live apply per D-114) produces the expected role + policy.
    • Document the onboarding Terraform in docs/ONBOARDING.md — the request path (P18) → env-file autogen (P19) → role grant (P20, this phase, offline-proven; live apply deferred).
    • Tests: terraform validate for the onboarding module; a test_onboarding_terraform.py asserting the module validates.
  • Verify: terraform validate (onboarding module) passes; pytest passes; run_ci.sh exits 0.

Final Phase — P21 — final-review-ship

  • Lead: lead-developer; Contributors: all active (review)
  • Must-haves:
    • Multi-persona code review across all v1.16 phases (ci-code-reviewer). Auto-apply P0 fixes; flag P1+ for post-hoc review. If P1+ found, fix in this phase (not loop back to EXECUTE).
    • Audit (ciagent-audit): reconstruction test (git log matches .ciagent/ files), file discipline, branch hygiene, commit discipline. Fix critical issues in this phase.
    • Run the regression gate (D-118, milestone complete): 20/22 Verified (CAP-015/016 Skipped — post-teardown steady state, D-096).
    • Update .ciagent/REQUIREMENTS.md — mark REQ-165..184 complete.
    • Update .ciagent/ROADMAP.md — mark v1.16 complete.
    • Update .ciagent/PROJECT.md — v1.16 complete summary.
    • Ship: merge phase/21-final-review-shipmilestone/v1.16-nova-simplification; merge milestone → main; tag v1.15.26 (= milestone release); create Gitea release with full milestone summary.
    • Clear CHECKPOINT.json (milestone complete).

Success Criteria (milestone gate)

  • All 20 requirements (REQ-165..184) satisfied; 0 partial.
  • Regression gate 20/22 Verified + 2 Skipped at P9 + P21 (D-118, G-111; CAP-015/016 are the post-v1.11-teardown steady state, D-096).
  • bash scripts/run_ci.sh exits 0 at every phase boundary.
  • Review: 0 new P0; P1+ flagged or auto-fixed.
  • Audit: clean; reconstruction test passes.
  • Tag v1.15.26 created; milestone merged to main.
  • Onboarding request path implemented (P18P20); real AWS provisioning explicitly deferred (D-113, D-114).