ee5c372e65
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---
22 KiB
22 KiB
phase, name, milestone, requirements, wave, depends_on
| phase | name | milestone | requirements | wave | depends_on | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P0 | pre-execution | v1.16 |
|
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 (P1–P20) →
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 (P1–P4): correctness + brand regression fixes. P1 first —
the state-bucket drift (
adapter.py:117emitsacdl-tfstate-*while the live bucket isnova-tfstate-*) and the Kyverno policy contradiction (enforcesacdl:*labels thatnova_tagging.pyhard- fails) are the highest-severity findings, both correctness regressions left by the rebrand. P2–P4 independent brand/dead-code/except work. - Wave 2 (P5–P9): 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 (P10–P14): 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 (P15–P17): developer experience. Independent; P17 last (reflects the consolidated path after P15/P16 land).
- Wave 5 (P18–P20): 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-simplificationand 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=plandefault; terraform changes validated viaterraform 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.shexits 0 at every phase boundary.
Wave 1 — Correctness + Brand Regression Fixes (P1–P4)
Phase P1 — state-bucket-and-kyverno-rebrand-fix (REQ-165)
- Lead: backend-engineer; Contributor: data-engineer (kyverno)
- Must-haves:
adapters/terraform/adapter.py:117state_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 titleRequire ACDL Resource Labels→Require Nova Resource Labels; rule namesrequire-acdl-owner-label/require-acdl-environment-label→require-nova-owner-label/require-nova-environment-label; messages + patternsacdl:owner/acdl:environment→nova:owner/nova:environment.- Update any test fixtures referencing the old bucket name / label keys.
- Verify:
terraform validate(adapter-emitted); pytest passes;run_ci.shexits 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,61onboarding message header/body "ACDL" → "Nova".core/lambda/contract_ingestor.py:145alert title[ACDL-ALERT]→[NOVA-ALERT];:191issue body "ACDL platform Lambda" → "Nova platform Lambda".scripts/post_stage_comment.sh:39PR comment header "ACDL Stage" → "Nova Stage";:46footer "ACDL deploy pipeline" → "Nova deploy pipeline".scripts/run_ci.sh:39CI 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.shexits 0.
Phase P3 — dead-code-and-stale-prefix-cleanup (REQ-167)
- Lead: lead-developer
- Must-haves:
scripts/run_platform.sh:153remove the deadexport 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 percore/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:214interpolation fixtureacdl-→nova-(or make it a clearly-generic token).
- Verify: pytest passes;
run_ci.shexits 0.
Phase P4 — migrate-ssm-except-narrowing (REQ-168)
- Lead: backend-engineer
- Must-haves:
scripts/migrate_ssm_paths.py:113except Exception: pass→ narrow toParameterNotFound+ structured log on the non- ParameterNotFound path.- Narrow
core/output_publisher.py:112,182except Exception→ specific(ClientError, OSError)+ structured stderr log. - Test that a non-ParameterNotFound error is raised (not swallowed).
- Verify: pytest passes;
run_ci.shexits 0.
Wave 2 — Simplify Without Regressions (P5–P9)
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).
- Extract
- Verify: pytest passes;
run_ci.shexits 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 functionrun_hitl_gate()invoked at both sites (~14 lines saved). scripts/run_platform.sh:145hardcodedCONTRACT_IDUUID →NOVA_CONTRACT_IDenv with the existing UUID as default.scripts/run_platform.sh:146WORK="/tmp/acdl_platform_run_v18"→WORK="${NOVA_WORK_DIR:-/tmp/nova_platform_run}"(drop the stalev18stamp +acdl_prefix).- Drop the stale brand comment
run_platform.sh:2"the ACDL platform pipeline" → "the Nova platform pipeline".
- Extract the duplicated HITL attestation block (
- Verify: pytest passes;
run_ci.shexits 0;run_platform.sh --check-onlyexits 0.
Phase P7 — contract-resolver-envloader-and-kind (REQ-171)
- Lead: backend-engineer
- Must-haves:
core/contract_resolver.py:50-68_load_env→ importcore/environment_check.py:load()(dedup; both load + placeholder warning).- Add a
kindfield ("l1"/"l2") to eachmodules/registry.jsonentry; the resolver readskinddirectly instead of the fragileis_l2 = "l2" in interface_path or "composition" in interface_pathheuristic (contract_resolver.py:540). - Collapse the redundant
kindcomputation (:584-589) →kind = "l2" if (multi_module or any_l2) else "l1"(after the registrykindfield is authoritative, simplify further).
- Verify: pytest passes;
run_ci.shexits 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 theworkflows-src/dir as the single source. - Replace the byte-identity assertions in
tests/test_pipeline_contract.pywith a "generated outputs match committed files" test (runsync_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).
- Author
- Verify:
python3 scripts/sync_workflows.py --checkexits 0; pytest passes;run_ci.shexits 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) intoscripts/run_decommission.sh(sourced or invoked). - Extract the uptime block (
:520-606) intoscripts/run_uptime.sh. run_platform.shinvokes the helpers; behavior unchanged.- G-112 binding: the helpers are
sourced (shared shell env), not invoked as subshells — the extracted blocks referencerun_platform.sh-local vars (NOVA_CONTRACT_ID/NOVA_WORK_DIRfrom P6); a subshell would not inherit them. - G-111 binding: update
core/regression_verify.pyCAP-015/016 checks — when the live resource is absent (ResourceNotFoundException/404), markSkipped (post-teardown, D-096)notDecayed, so a clean local run reports 20/20 Verified + 2 Skipped (not a strict-allfailure 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.
- Extract the decommission block (
- Verify: pytest passes;
run_ci.shexits 0;run_platform.sh --check-onlyexits 0; regression gate 20/22 Verified + 2 Skipped.
Wave 3 — Security + Maintainability (P10–P14)
Phase P10 — contract-ingestor-defense-in-depth (REQ-174)
- Lead: backend-engineer; Contributor: lead-developer (review)
- Must-haves:
core/lambda/contract_ingestor.py:251-252if 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:269hardcodedvalid_envs = {"dev","qa","prod","dr"}→ derive from thecore/environments/directory (list*.jsonfilenames).- 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.shexits 0.
Phase P11 — contract-ingestor-payload-validation (REQ-175)
- Lead: backend-engineer
- Must-haves:
submit_contract: size-cap thecontractblob (e.g. 256 KB) before the DynamoDB write; reject oversized payloads with 413.- Schema-validate the contract blob against
schemas/contract.schema.jsonbefore the write; reject invalid with 400. - Consistent caps:
errorandstackTraceuse the same cap (align the 10k vs 2k inconsistency). - Tests for size-limit + schema-rejection paths.
- Verify: pytest passes;
run_ci.shexits 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.pybecomes 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.
- Split
- Verify: pytest passes;
run_ci.shexits 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_regressionorchestration). core/regression_verify.pybecomes a thin re-export shim.- Behavior unchanged; the regression gate output is identical.
- Split
- Verify: pytest passes;
run_ci.shexits 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-55SAFE_OUTPUT_NAMEShardcoded set → derived frommodules/l1/*/interface.jsonoutputs[].sensitiveannotations (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.shexits 0.
Wave 4 — Developer Experience (P15–P17)
Phase P15 — run-platform-help-and-flags-doc (REQ-179)
- Lead: lead-developer
- Must-haves:
scripts/run_platform.shadd a real--help/-hflag that prints all flags + a one-line description each (--check-only,--plan-only,--apply,--destroy,--quiet,--deploy-uptime,--decommission,--local,--environment). The current:82reject-unknown-flags path must allow--helpto print + exit 0.- Document
--deploy-uptimein the header comment block (currently used at:532but absent from the header). - Surface
--local(D-092 local emulating tier) in the README "How to run" section.
- Verify:
run_platform.sh --helpexits 0 and lists all flags; pytest passes;run_ci.shexits 0.
Phase P16 — workflows-readme-catalog (REQ-180)
- Lead: lead-developer
- Must-haves:
- Author
.github/workflows/README.mdcataloging 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-workflowworkflow_callinputs), 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.pyassertion that the README exists- lists all 7 workflow filenames.
- Author
- Verify: pytest passes;
run_ci.shexits 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.mdfor the consumer contract model.
- Consolidate the README "How to run" into a single getting-started
section: offline happy path first (
- Verify: pytest passes;
run_ci.shexits 0.
Wave 5 — No Humans Onboarding Flow (P18–P20)
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 fieldsconsumerRepo(string, format),requestedEnvironment(string, enum from environments dir),ownerId(string),billingTag(string); optionalnotes. core/lambda/contract_ingestor.pyadd anonboard_consumeraction (D-119): validates the payload against the onboarding schema, writes apendingrow tonova-contracts(PKconsumerRepo, SKonboarding#<requestedEnvironment>#<timestamp>, statuspending). 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.
- Author
- Verify: pytest passes;
run_ci.shexits 0.
Phase P19 — onboarding-envfile-autogen (REQ-183)
- Lead: backend-engineer; Contributor: lead-developer (docs)
- Must-haves:
- Author
core/onboarding.pywithgenerate_env_file(request, template_env="dev")— produces a<env>.jsonfrom a consumer onboarding request (fillsaccount_idplaceholder,ownerId,billingTaginto the env template). Emits the file + a git patch / PR-branch instruction. - Rebrand
core/environment_check.py:57-77onboarding message to Nova; replace the "1. Contact the platform team" handoff with the self-service request path: "Runnova onboard(or POST to the Lambdaonboard_consumeraction) 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_fileproduces a valid env JSON; the rebranded message no longer says "contact the platform team".
- Author
- Verify: pytest passes;
run_ci.shexits 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.tfdefining the consumer deploy-role +nova:ownerABAC tag grant (cross-account IAM role + trust policy + tag-based permission boundary). Variables forconsumer_repo,owner_id,account_id. terraform validatepasses;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 validatefor the onboarding module; atest_onboarding_terraform.pyasserting the module validates.
- Author
- Verify:
terraform validate(onboarding module) passes; pytest passes;run_ci.shexits 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-ship→milestone/v1.16-nova-simplification; merge milestone →main; tagv1.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.shexits 0 at every phase boundary.- Review: 0 new P0; P1+ flagged or auto-fixed.
- Audit: clean; reconstruction test passes.
- Tag
v1.15.26created; milestone merged to main. - Onboarding request path implemented (P18–P20); real AWS provisioning explicitly deferred (D-113, D-114).