---ci--- project: nova-platform phase: 0 milestone: v1.0 status: complete phase_role: pre_execution ---/ci--- Phase 0 complete: 5 pre-execution stages. SPECIFY: 38 REQ-IDs validated. CLARIFY: D-011..D-035 (3 escalated). RESEARCH: 22 in-scope items + PERSONAS.md. PLAN: 6 phases, ~45 tasks, 13 waves. GRILL: PROCEED-WITH-CONDITIONS (0.82) → PROCEED (6 conditions resolved). MVP/UX CHECK: PASS (3 sections in PLAN.md). Grill fixes: D-037 (adapter loads registry), D-038 (L2 children locked).
24 KiB
PLAN — Nova Platform v1.0
Task-level, wave-ordered, persona-assigned plan for the 5 execution phases (P1..P5) + the final phase (P6). Consumed by the execute workflow. Derived from ROADMAP.md phase breakdown + REQUIREMENTS.md REQ coverage + PERSONAS.md assignments + CLARIFY.md D-011..D-035 + RESEARCH.md reference shapes.
User-Facing Surface
The platform's user-facing surfaces are entirely offline-runnable — no CI required, no AWS credentials required for the primary verification path:
scripts/run_platform.sh --check-only— Offline validation entrypoint.bash scripts/run_platform.sh --check-only contracts/static-assets.yml→ exit 0 +=== PLATFORM CHECK OK ===iff contract validates → resolves → stack is schema-valid → adapter compiles to structurally-valid HCL. No AWS calls.scripts/run_platform.sh(default mode) — Full apply path. LoadsNOVA_AWS_*→AWS_*, runs terraform init/validate/plan/apply, prints=== PLATFORM APPLY OK ===.--plan-onlystops before apply.scripts/run_ci.sh— Local CI mirror. lint (py_compile) → test (pytest) → check-only. Prints=== CI PIPELINE OK ===.docs/consumer-guide.md— Consumer happy-path walkthrough.README.mdquickstart — operator/dev quickstart..feature-equivalent scenarios —tests/test_run_platform_check_only.pytests/test_run_ci.pyencode the happy path as executable pytest cases.
Happy Path
Two end-to-end scenarios, written BEFORE execute, verified by automated tests in P5:
Scenario A — Offline contract validation (primary gate)
bash scripts/run_platform.sh --check-only contracts/static-assets.yml
# expected: === PLATFORM CHECK OK === ; exit 0
Steps: load core/environments/dev.json → parse contract → validate
against contract schema → resolve to stack (interpolation) → adapt to
HCL → validate output structure → print banner → exit 0. No AWS SDK
calls, no terraform binary, no network.
Scenario B — Local CI mirror
bash scripts/run_ci.sh
# expected: === CI PIPELINE OK === ; exit 0
Steps: (1) lint py_compile $(find core/ adapters/ scripts/ -name '*.py');
(2) test pytest; (3) check-only run_platform.sh --check-only. Print
banner → exit 0.
UX Acceptance Criteria
v1.0 is accepted iff ALL hold:
- AC-1 (offline validation works):
run_platform.sh --check-only contracts/static-assets.ymlexits 0 + stdout contains=== PLATFORM CHECK OK ===. (tests/test_run_platform_check_only.py) - AC-2 (local CI works):
run_ci.shexits 0 + stdout contains=== CI PIPELINE OK ===. (tests/test_run_ci.py) - AC-3 (contract schema is the API): all 10 sample contracts validate against contract.schema.json. (tests/test_contract_schema.py)
- AC-4 (resolver pure + correct):
resolve()returns stack validating against stack.schema.json; raisesModuleNotFoundError/VersionNotFoundError. (tests/test_contract_resolver.py + test_stack_schema.py) - AC-5 (adapter compiles + boundary holds):
adapt(stack, repo_root)(C-1 fix) emits valid HCL; no.pyoutsideadapters/terraform/contains forbidden strings. (tests/test_terraform_adapter.py + test_engine_boundary.py) - AC-6 (module catalog complete): registry.json has 13 L1 + 2 L2 =
15 entries; all interface.json + terraform/main.tf exist; L2 entries
include
terraform_dir(D-013). - AC-7 (Terraform roots + bootstrap exist): terraform/{bootstrap,
ci-vpc,platform,microservice,onboarding}/ per REQ-14..19 + D-022..D-025.
Lock table
nova-tfstate-locks; account parameterized. - AC-8 (docs cover consumer journey): README + docs/{architecture,
consumer-guide,modules/index,environments/index,contracts/index}.md
exist, no OOS sections. Mechanically checked by grep for OOS section
headings ("Security", "Compliance", "OIDC", "Attestation", "ABAC")
inside
docs/*.md+modules/*/README.md— zero matches (C-3 fix). - AC-9 (reproducibility): requirements-test.txt pins 5 deps;
pyproject.toml no
[project.scripts]; rotate_spike_key.sh writes .env.secrets (0600); .gitignore covers .env*/terraform state. - AC-10 (engine-agnostic invariant): engine-boundary test passes.
Phase 1 — Contract Surface + Schemas + Resolver
Goal: A contract can be validated, resolved to a stack, environment checked, stack validated — all offline, no apply, no engine terms in contract/core layer.
REQs: REQ-01, REQ-02, REQ-03, REQ-04, REQ-05, REQ-06, REQ-23, REQ-24, REQ-27, REQ-28.
Personas: backend-engineer (contract schema, resolver, environment_check, contracts, tests); data-engineer (stack schema, environment schema, dev.json).
Ships as: v0.1.1 on phase/01-contract-surface-schemas-resolver.
Wave 1 (parallel — schemas + env data)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P1-W1-T1 | backend | REQ-01, D-015 | schemas/contract.schema.json |
Draft 2020-12; required:[id,name,environment,infrastructure]; id pattern ^[a-z][a-z0-9-]{2,5}$; infrastructure ARRAY (D-015) items {module,version?,inputs}; no engine terms. |
| P1-W1-T2 | data | REQ-04, D-012 | schemas/stack.schema.json |
Flat per D-012; required:[contract_id,contract_name,environment,resources]; resources {module,version,source,inputs}; no stack wrapper/relationships/nfrs. |
| P1-W1-T3 | data | D-017, D-018 | schemas/environment.schema.json |
required:[name,account_id,region,state_backend,network]; no runner_role_arn/autonomy/confidence_threshold; additionalProperties:false. |
| P1-W1-T4 | data | REQ-06, D-018 | core/environments/dev.json |
Validates against environment schema; name:"dev", placeholder account, us-east-1, state_backend, network. |
Wave 2 (resolver + env_check — depends on W1)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P1-W2-T1 | backend | REQ-03, D-011, D-016, D-037 | core/contract_resolver.py |
resolve(contract, registry, modules_dir) -> dict (D-011). Interpolation kept (D-016). Named exceptions ModuleNotFoundError/VersionNotFoundError. L2 opaque (D-012). No source in stack (D-037/C-1 fix) — stack is engine-agnostic {contract_id, contract_name, environment, resources:[{module,version,inputs}]}. No engine terms. |
| P1-W2-T2 | backend | REQ-05, D-019 | core/environment_check.py |
check(env_name, environments_dir) -> dict (D-019). Raises EnvironmentNotFoundError. No tuple/onboarding_message/CLI. No engine terms. |
Wave 3 (sample contracts — depends on W1+W2)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P1-W3-T1 | backend | REQ-02, D-033, D-035 | contracts/static-assets.{yaml,dev.yml,qa.yml,prod.yml,dr.yml} |
Validate against contract schema; static-assets L2; inputs incl bucket_name/index_document (D-035); per-env differ only in environment (D-033); interpolation tokens. |
| P1-W3-T2 | backend | REQ-02, D-033 | contracts/microservice.{yaml,dev.yml,qa.yml,prod.yml,dr.yml} |
Validate; microservice L2; per-env differ only in environment; interpolation. |
Wave 4 (parallel — tests, depends on W1-W3)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P1-W4-T1 | backend | REQ-23 | tests/test_contract_resolver.py |
Happy path, ModuleNotFoundError, VersionNotFoundError, empty infra. Pass. |
| P1-W4-T2 | backend | REQ-24 | tests/test_environment_check.py |
check("dev",...) returns dict; missing → EnvironmentNotFoundError; malformed. Pass. |
| P1-W4-T3 | backend | REQ-27 | tests/test_contract_schema.py |
All 10 contracts validate; negative cases raise. Pass. |
| P1-W4-T4 | backend | REQ-28 | tests/test_stack_schema.py |
resolve() stack validates; negative cases. Pass. |
Must-haves
- 3 schemas parse as valid JSON Schema draft 2020-12.
resolve()+check()exposed with named exceptions; no engine terms.dev.json+ 10 contracts validate.pytest -q tests/test_contract_resolver.py tests/test_environment_check.py tests/test_contract_schema.py tests/test_stack_schema.pyexit 0.
Phase 2 — Terraform Adapter + Engine Boundary
Goal: A resolved stack compiles to valid HCL via the stateless adapter; engine boundary enforced by grep test.
REQs: REQ-07, REQ-08, REQ-09, REQ-25, REQ-26.
Personas: backend-engineer (adapter + tests).
Ships as: v0.1.2 on phase/02-terraform-adapter-engine-boundary.
Dependency (C-4 fix): P2 depends on P3-W1 (registry.json). The adapter loads
registry.jsoninternally (C-1 fix). Reorder: run P3-W1 (registry.json only) before P2-W1, then continue P3-W2 (L1 terraform dirs) in parallel with P2.
Wave 1 (adapter — depends on P3-W1 registry.json)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P2-W1-T1 | backend | REQ-07, REQ-08, D-013, D-037 | adapters/terraform/adapter.py, adapters/terraform/__init__.py |
adapt(stack, repo_root) -> str (C-1/D-037 fix). Loads modules/registry.json internally to map module → terraform_dir. Stateless, <250 lines. Emits module "x" { source; <inputs> } per resource. L2 terraform_dir from registry (D-013). __init__.py re-exports. ONLY place engine terms appear. |
Wave 2 (parallel — tests)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P2-W2-T1 | backend | REQ-25 | tests/test_terraform_adapter.py |
Single/multi resource, input passthrough, HCL validity. Pass. |
| P2-W2-T2 | backend | REQ-09, REQ-26, D-034 | tests/test_engine_boundary.py |
Grep .py in core/schemas/contracts/tests/scripts/root; exclude adapters/terraform/ + modules/ + .tf/.md/.json; zero matches for forbidden strings. Pass. |
Must-haves
adapt()stateless, <250 lines, returns HCL.__init__.pyre-exports.- Both tests pass; boundary proven.
Phase 3 — L1 Primitives + Registry
Goal: Full module catalog — registry.json indexing 13 L1 + 2 L2, each L1 with interface.json + terraform/ (main/variables/outputs/versions/locals).
REQs: REQ-10, REQ-11, REQ-13.
Personas: data-engineer (registry, 13 L1 interface.json + terraform, READMEs, docs/modules/index); backend-engineer (registry test, conftest).
Ships as: v0.1.3 on phase/03-l1-primitives-registry.
Wave 1 (parallel — registry + 13 L1 interface.json + READMEs + docs index)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P3-W1-T1 | data | REQ-10, D-013 | modules/registry.json |
15 entries; L1 {interface,terraform_dir,published_at,deprecated,kind:"l1"}; L2 includes terraform_dir (D-013). |
| P3-W1-T2..T14 | data | REQ-11, D-014 | modules/l1/{s3,vpc,ecs-cluster,ecs-service,iam-role,alb,ecr,cloudfront,waf,rds,kms-key,dynamodb,uptime}/interface.json |
{name,version,kind:"l1",type,description,inputs,outputs} + resources[] for multi-resource. No nfrs/intra_refs (D-014). s3 stays ref interface (D-035). |
| P3-W1-T15 | data | REQ-13, D-029 | modules/README.md, modules/README-TEMPLATE.md |
L1/L2 distinction, registry format, add-a-module. 13+2 tables. Trimmed of security/compliance. DROP NFRs + Compliance sections. No STANDARDS.md. |
| P3-W1-T16 | data | REQ-34, D-028 | docs/modules/index.md |
Catalog table → links to modules/l1/<name>/README.md + modules/l2/<name>/README.md. 15 rows. |
Wave 2 (parallel — 13 L1 terraform/ dirs)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P3-W2-T1..T13 | data | REQ-11 | modules/l1/<name>/terraform/{main,variables,outputs,versions,locals}.tf |
count = var.enabled ? 1 : 0; required_version = ">= 1.9, < 1.10"; aws ~> 5.0; variables match interface.json inputs. |
Wave 3 (registry test + conftest)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P3-W3-T1 | backend | REQ-10 | tests/test_registry.py |
15 entries, L2 has terraform_dir, interface paths resolve, terraform_dir/main.tf exist. Pass. |
| P3-W3-T2 | backend | (support) | tests/conftest.py (partial) |
repo_root + registry fixtures. No stack_instance/policy_check_result_schema. |
Must-haves
- registry.json valid, 15 entries, L2 has
terraform_dir. - 13 L1 interface.json + terraform dirs exist, conform to D-014.
- READMEs trimmed; docs/modules/index links to all 15.
- test_registry.py + conftest fixtures pass.
Phase 4 — L2 Patterns + Terraform Bootstrap + Platform
Goal: Two L2 patterns composing L1 internally; AWS bootstrap scripted; platform/ci-vpc/microservice/onboarding roots exist.
REQs: REQ-12, REQ-14, REQ-15, REQ-16, REQ-17, REQ-18, REQ-19.
Personas: data-engineer (L2 interfaces + terraform, bootstrap policy + README, 4 terraform roots); backend-engineer (bootstrap py scripts, rotate_spike_key.sh).
Ships as: v0.1.4 on phase/04-l2-patterns-bootstrap-platform.
Wave 1 (parallel — L2 interfaces + bootstrap policy + 4 roots + README)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P4-W1-T1 | data | REQ-12, D-012, D-013 | modules/l2/microservice/interface.json |
{name,version,kind:"l2",description,inputs,outputs} — L2-level only, no children/wires. |
| P4-W1-T2 | data | REQ-12, D-012, D-035 | modules/l2/static-assets/interface.json |
Inputs incl bucket_name/index_document (D-035). |
| P4-W1-T3 | data | REQ-15, D-026 | terraform/bootstrap/spike_runner_policy.json |
Account parameterized (NOT hardcoded). Grants S3/DynamoDB lock/ECS/ECR/ELB/IAM/EC2/CloudFront/WAF/KMS. DROP Lambda/Secrets/SNS/CostExplorer/OIDC. |
| P4-W1-T4 | data | REQ-16, D-024 | terraform/ci-vpc/main.tf |
Short-lived test VPC; VPC+2 subnets+IGW+route table+ECS SG+cluster; 4 outputs; state key spike/ci-vpc/terraform.tfstate. |
| P4-W1-T5 | data | REQ-17, D-023 | terraform/platform/main.tf |
ONLY shared VPC per D-023; VPC+2 subnets+IGW+route table+ECS SG; outputs vpc_id/subnet_ids/ecs_security_group_id. DROP Lambda/DynamoDB/KMS/Secrets/SNS. |
| P4-W1-T6 | data | REQ-18 | terraform/microservice/main.tf |
Instantiates L2 module + data.terraform_remote_state to platform VPC. State key spike/microservice/<env>/terraform.tfstate. |
| P4-W1-T7 | data | REQ-19, D-025 | terraform/onboarding/main.tf |
IAM ROLE (not user) per D-025. Cross-account sts:AssumeRole. NO OIDC. consumer_repo/owner_id vars. DROP lambda:InvokeFunctionUrl. Outputs role arn/name. |
| P4-W1-T8 | data | REQ-14, D-022 | terraform/bootstrap/README.md |
Documents nova-tfstate-locks (D-022 — NOT nova-outbox), nova-spike-runner, parameterized account, NOVA_BOOTSTRAP_AWS_*. |
Wave 2 (parallel — 2 L2 terraform composing L1, depends on W1 + P3)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P4-W2-T1 | data | REQ-12, D-012, D-038 | modules/l2/microservice/terraform/{main,variables,outputs,versions}.tf |
module "vpc"{source="../../l1/vpc/terraform"} + cluster/service/role/ecr/alb (6 L1s per D-038). Variables match L2 interface. |
| P4-W2-T2 | data | REQ-12, D-012, D-035, D-038 | modules/l2/static-assets/terraform/{main,variables,outputs,versions}.tf |
module "s3"{source="../../l1/s3/terraform"} + cloudfront + kms (3 L1s per D-038, drops waf). index_document → s3 website. |
Wave 3 (parallel — bootstrap py scripts + rotate, depends on W1 policy)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P4-W3-T1 | backend | REQ-14, D-022 | terraform/bootstrap/create_state_backend.py |
S3 nova-tfstate-<account>-<region> + DynamoDB nova-tfstate-locks. Idempotent. NOVA_BOOTSTRAP_AWS_*→NOVA_AWS_*→AWS_*. py_compile clean. No engine-boundary violation (boto3, not HCL). |
| P4-W3-T2 | backend | REQ-15, D-026 | terraform/bootstrap/create_iam_user.py |
nova-spike-runner + policy + key. Prints NOVA_AWS_*. Idempotent. py_compile clean. No HCL strings. |
| P4-W3-T3 | backend | REQ-22, D-032 | scripts/rotate_spike_key.sh |
Rotates key → .env.secrets (0600). NOVA_AWS_* (D-032). bash -n clean. |
Must-haves
- Both L2 interface.json + terraform exist; compose L1 via
moduleblocks with../../l1/.... - bootstrap/ has 4 files; policy account-parameterized; lock table
nova-tfstate-locks. - 4 terraform roots exist per D-023/D-024/D-025.
- rotate_spike_key.sh syntax-valid.
- Bootstrap py
py_compileclean, no engine-boundary violation.
Phase 5 — Shell Reproducibility + Test Suite + Docs
Goal: Platform fully reproducible from shell — run_platform.sh --check-only + run_ci.sh exit 0 with banners; full test suite
passes; docs complete. Happy path green.
REQs: REQ-20, REQ-21, REQ-22 (verify), REQ-29, REQ-30, REQ-31, REQ-32, REQ-33, REQ-34, REQ-35, REQ-36, REQ-37, REQ-38.
Personas: backend-engineer (shell scripts, shell tests, conftest final, pyproject, requirements); lead-developer (README, architecture, consumer-guide); data-engineer (docs/modules/index finalize, environments/index, contracts/index).
Ships as: v0.1.5 on phase/05-shell-reproducibility-tests-docs.
Wave 1 (parallel — scripts + deps + docs)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P5-W1-T1 | backend | REQ-20, D-020, D-031, D-032 | scripts/run_platform.sh |
Flags: --check-only/--plan-only/--quiet/--help. check-only: env_check→validate→resolve→adapter→validate output→=== PLATFORM CHECK OK ===. plan-only: +creds (NOVA_AWS_*→AWS_* then unset)→init/validate/plan→=== PLATFORM PLAN OK ===. default: +apply→=== PLATFORM APPLY OK ===. bash -n clean. check-only exits 0 offline. |
| P5-W1-T2 | backend | REQ-21, D-021 | scripts/run_ci.sh |
3 stages: lint (glob py_compile)→test (pytest)→check-only. === CI PIPELINE OK ===. --quiet. bash -n clean. |
| P5-W1-T3 | backend | REQ-31, D-027 | pyproject.toml, requirements-test.txt |
No [project.scripts], no nova/ dir. 5 test deps. addopts="-v --tb=short". markers=[offline,slow]. packages.find: core,core.*,adapters.*. |
| P5-W1-T4 | backend | REQ-38 | .gitignore |
Verify/extend: .env*, terraform state, credentials, __pycache__/, .ciagent/logs/, nova_platform.egg-info/. |
| P5-W1-T5 | lead | REQ-32 | README.md |
What platform is, run offline, run tests, run against AWS, repo layout, credentials (static-key only), consumer-guide pointer. No security/identity sections. |
| P5-W1-T6 | lead | REQ-33 | docs/architecture.md |
Mirrors .ciagent/ARCHITECTURE.md. 4 layers + boundary + OOS list + catalog. No cross-cutting sections. |
| P5-W1-T7 | lead | REQ-37 | docs/consumer-guide.md |
Infra-only: create repo, write contract, run check-only, run against AWS. Interpolation table. DROP OIDC/reusable-workflow/decommission/compliance. |
| P5-W1-T8 | data | REQ-34, D-028 | docs/modules/index.md (finalize) |
Catalog table → 15 module READMEs. |
| P5-W1-T9 | data | REQ-36, D-018 | docs/environments/index.md |
Env model: account/network/state backend — NO IAM/ABAC. Autonomy table: dev autonomous; qa/prod/dr manual. No HITL gates. |
| P5-W1-T10 | data | REQ-35, D-033 | docs/contracts/index.md |
Array-based infrastructure schema (D-015) + samples + per-env variants (D-033). Interpolation table. |
Wave 2 (parallel — shell tests + conftest, depends on W1)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P5-W2-T1 | backend | REQ-29 | tests/test_run_platform_check_only.py |
subprocess run_platform.sh --check-only contracts/static-assets.yml; assert exit 0 + === PLATFORM CHECK OK ===. Pass. |
| P5-W2-T2 | backend | REQ-30 | tests/test_run_ci.py |
subprocess run_ci.sh; assert exit 0 + === CI PIPELINE OK ===. Pass. |
| P5-W2-T3 | backend | (support) | tests/conftest.py (finalize) |
repo_root, registry, stack_schema, contract_schema fixtures. sys.path.insert for core/ + adapters/. |
Wave 3 (full-suite green — depends on W1-W2)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P5-W3-T1 | backend | (gate) | none | pytest -q all pass. bash scripts/run_ci.sh exit 0 + banner. |
Must-haves (MVP/UX gate)
run_platform.sh --check-only contracts/static-assets.ymlexit 0 +=== PLATFORM CHECK OK ===.run_ci.shexit 0 +=== CI PIPELINE OK ===.- Full
pytestsuite passes. - pyproject + requirements configure pytest/py_compile, no CLI.
- .gitignore covers all patterns.
- 6 docs exist, no OOS sections.
Phase 6 — Final Review + Ship
Goal: Review v1.0 against AC-1..AC-10, audit for boundary leaks +
OOS-creep, ship: merge phase/06→milestone/v1.0-nova-platform→main,
tag v1.0.0 (major — initial release per D-001), Gitea release, delete
branches.
REQs: none new.
Personas: lead-developer (review, audit, ship); backend/data consulted for fix-forward.
Ships as: v1.0.0 (major tag).
Wave 1 (review)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P6-W1-T1 | lead | AC-1..AC-10 | none | Walk all 10 ACs. Record pass/fail. All must PASS before proceeding. Escalate on failure (supervised). |
Wave 2 (fix-forward, conditional)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P6-W2-T1..Tn | backend/data | (varies) | (varies) | Fix specific AC failures. Re-verify. Max 2 revision iterations. |
Wave 3 (audit)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P6-W3-T1 | lead | REQ-09, OOS list | none | (1) pytest -q tests/test_engine_boundary.py pass. (2) Grep repo for OOS file names (policy_engine, confidence_signal, outbox_writer, abac_, pat_, jws_, kms_signing, hitl_, attestation_, separation_, submission_, env_transition, decommission_, mode_resolver, onboarding.py, regression_verify*, metrics/, pipelines/, .github/workflows/, adapters/kyverno-json, adapters/wiz, adapters/checkov, schemas/pipeline*, schemas/deploy-pipeline*, schemas/policy_check_result*, schemas/metrics_*). ZERO matches. (3) No STANDARDS.md, no PPTX/marp. |
Wave 4 (ship)
| Task | Persona | REQs | Files | Must-have |
|---|---|---|---|---|
| P6-W4-T1 | lead | D-001, D-009 | git refs | Merge phase/06-final-review-ship→milestone/v1.0-nova-platform. Merge milestone→main. Tag v1.0.0 on main. confirm_before_ship=true per D-009 — escalate before tagging. Gitea release via NOVA_FORGE_TOKEN. Delete phase/0*+1* branches. Verify tag + release URL. |
Must-haves
- All 10 ACs PASS.
- Engine boundary passes; zero OOS files.
v1.0.0tag on main.- Gitea release
v1.0.0created. - All phase branches deleted.
Cross-phase invariants (hold after EVERY phase)
- Engine boundary: no
.pyoutsideadapters/terraform/containsaws_/module "/terraform/provider "/resource "(REQ-09/D-034). - No OOS-creep: no file from PROJECT.md/REQUIREMENTS.md OOS list created in any phase.
- Structural conventions: directory names, file roles, interface shape, registry shape, banner strings, state key, tag convention preserved without deviation.
- Tests stay green: once a test file exists, subsequent phases must
not break it.
pytest -qpasses at end of every phase. - Supervised escalation:
ship(P6-W4-T1) + verification failures escalate to human perescalation_timeout_ms=300000.
Wave dependency graph
P1: W1(schemas+env) → W2(resolver+env_check) → W3(contracts) → W4(tests)
P3-W1(registry.json ONLY) → P2: W1(adapter loads registry) → W2(adapter tests + boundary) [C-4 fix: P3-W1 before P2-W1]
P3: W1(registry+13 L1 interface+READMEs+docs) → W2(13 L1 terraform) → W3(registry test+conftest) [W1 split: registry.json first, then rest]
P4: W1(L2 interfaces+bootstrap policy+4 roots+README) → W2(2 L2 terraform per D-038) → W3(2 bootstrap py+rotate) [deps P3 L1 terraform]
P5: W1(2 scripts+pyproject+reqs+gitignore+README+arch+consumer-guide+3 docs) → W2(2 shell tests+conftest) → W3(full-suite green) [deps P1-P4]
P6: W1(review AC-1..10) → [W2 fix-forward] → W3(audit + docs OOS grep C-3) → W4(ship v1.0.0) [deps P5]
Concurrency note (C-5): P3-W1 (13 L1 interface.json tasks) + P3-W2 (13 L1 terraform tasks) + P4-W1 (8 tasks) exceed
max_concurrent_agents=5. These waves batch-serialize into 3-5 rounds. Schedule estimate reflects ~2-3× wall-clock for P3.
Total: 6 phases, ~45 tasks across ~13 waves, 3 active personas (max concurrency 5). No wave has >5 parallel tasks.