Files
nova-platform/.ciagent/CLARIFY.md
CIAgent 2443909362 docs(milestone): complete v1.0-nova-platform (release v0.1.6)
---ci---
project: nova-platform
milestone: v1.0
status: complete
requirements:
  covered: [REQ-01,REQ-02,REQ-03,REQ-04,REQ-05,REQ-06,REQ-07,REQ-08,REQ-09,REQ-10,REQ-11,REQ-12,REQ-13,REQ-14,REQ-15,REQ-16,REQ-17,REQ-18,REQ-19,REQ-20,REQ-21,REQ-22,REQ-23,REQ-24,REQ-25,REQ-26,REQ-27,REQ-28,REQ-29,REQ-30,REQ-31,REQ-32,REQ-33,REQ-34,REQ-35,REQ-36,REQ-37,REQ-38]
  partial: []
---/ci---

v1.0 milestone complete: simplified infrastructure-delivery platform
derived from Nova (acdl). 6 phases (P0-P5 + P6 final). 38 REQ-IDs.
38 decisions (D-001..D-038). 76 tests pass. Engine boundary holds.
Happy paths green (check-only + CI). 13 L1 + 2 L2 modules. 5 terraform
roots. Shell reproducibility. Zero OOS files.

Tags: v0.1.0 (P0) → v0.1.1..v0.1.5 (P1..P5) → v0.1.6 (P6 = milestone
release on v0.1 patch line).
2026-08-25 02:18:35 +00:00

10 KiB

CLARIFY — Nova Platform v1.0 (Phase 0)

25 decisions (D-011..D-035) resolving remaining specification ambiguities. Init already locked D-001..D-010. Autonomy: supervised (present + wait for human review).

Architecturally significant (highest impact)

D-011: Resolver purity vs file I/O

resolve() is declared pure (no I/O) in REQ-03 but must load interface.json / composition data from disk.

  • Default: Add modules_dir: Path as 3rd param. "No I/O" means no network/side-effects — local file reads for module metadata are permitted. The registry provides paths; the resolver reads the files.
  • Confidence: 0.82
  • Alternatives: [pre-enrich registry inline (truly pure); caller pre-loads interfaces as 4th dict; take contract_path string like ref]

D-012: L2 representation — opaque vs expanded

Does the resolver expand L2 compositions into individual L1 stack resources, or treat L2 as a single opaque resource?

  • Default: L2 is a single opaque resource. Stack has one entry: {module:"microservice", version, source:"modules/l2/microservice/terraform", inputs}. The L2's terraform/main.tf composes L1 internally via module blocks. Resolver does NOT expand children.
  • Confidence: 0.88
  • Alternatives: [keep reference expansion (children/wires, needs richer stack schema — contradicts REQ-04's flat shape); hybrid]

D-013: L2 file naming + registry terraform_dir

REQ-12 says L2 has interface.json (reference uses composition.json). Reference L2 registry entries omit terraform_dir but the flat stack needs source.

  • Default: L2 uses interface.json (L2-level inputs/outputs, no children/wires — those are in terraform/main.tf). L2 registry entries DO include terraform_dir: "modules/l2/<name>/terraform" (deviation from ref L2 entries which omit it — required by flat stack source). kind: "l2" retained.
  • Confidence: 0.80
  • Alternatives: [keep composition.json name but simplified content; keep ref L2 shape exactly]

Contract / schema details

D-015: Contract field constraints

  • Default: Keep ref id pattern ^[a-z][a-z0-9-]{2,5}$, name minLength:3. version OPTIONAL (defaults to latest non-deprecated). infrastructure[] items: module (required), version (optional, semver ^\d+\.\d+\.\d+$), inputs (required, object, additionalProperties:false).
  • Confidence: 0.85

D-016: Interpolation ${env.*} / ${contract.*}

  • Default: KEEP interpolation. Resolver expands ${env.<field>} and ${contract.<field>} after environment_check loads env JSON. Sample contracts use ${env.region}, ${env.account_id} for naming. Unknown tokens raise ValueError.
  • Confidence: 0.78

D-017: schemas/environment.schema.json — keep or drop?

  • Default: KEEP but simplify to match reduced field set (D-018). Validates core/environments/*.json.
  • Confidence: 0.70 (below supervised threshold — escalate)

D-033: Per-env contract variants

  • Default: Variants differ ONLY in environment field. All other fields identical. Interpolation resolves per-env at resolver time.
  • Confidence: 0.85

D-035: index_document input — L1 s3 or L2 static-assets?

  • Default: index_document is an L2 static-assets input (passthrough to s3 website config in L2 terraform). L1 s3 does NOT gain it (stays ref interface: bucket_name/region/kms_key_arn/ enabled).
  • Confidence: 0.80

Resolver / adapter / interface

D-014: L1 interface.json field set

  • Default: Keep name, version, kind, type, description, inputs, outputs, resources (multi-resource array for vpc/ ecs-service/alb). Drop nfrs (feeds confidence signal — OOS) and intra_refs (feeds wire engine — eliminated by D-012).
  • Confidence: 0.72 (below threshold — escalate)

Environment model

D-018: core/environments/dev.json field set

  • Default: Keep name, description, account_id, region, state_backend (bucket, lock_table), network (vpc_cidr, azs). Drop runner_role_arn (ABAC OOS), autonomy (HITL OOS), confidence_threshold (OOS).
  • Confidence: 0.80

D-019: environment_check.check() signature

  • Default: Use REQ-05 signature: check(env_name: str, environments_dir: Path) -> dict. Raises EnvironmentNotFoundError. Drop ref's (ok, message) tuple + onboarding prompt printing.
  • Confidence: 0.90

Shell scripts

D-020: run_platform.sh stages (policy/confidence/outbox dropped)

  • Default:
    • --check-only (offline): env_check → validate contract → resolve → adapter compiles → validate output structure → print === PLATFORM CHECK OK === → exit 0
    • --plan-only (AWS): above + load creds → terraform init → validate → plan → print === PLATFORM PLAN OK ===
    • default (AWS, apply): above + terraform apply -auto-approve → print === PLATFORM APPLY OK ===
    • --quiet: suppresses TF streaming. --help: flags.
  • Confidence: 0.85

D-021: run_ci.sh Stage 1 py_compile

  • Default: Glob: python3 -m py_compile $(find core/ adapters/ scripts/ -name '*.py'). No hardcoded file list (no OOS Python files exist).
  • Confidence: 0.82

D-031: run_platform.sh flag set

  • Default: Keep only REQ-20's four: --check-only, --plan-only, --quiet, --help (+-h). Default = apply. Drop --apply, --destroy, --local, --decommission, --deploy-uptime, --environment.
  • Confidence: 0.87

Terraform / bootstrap

D-022: Bootstrap DynamoDB table

  • Default: Dedicated lock table nova-tfstate-locks (S3 backend lock_table points to it). NO nova-outbox table (outbox OOS). S3 state bucket nova-tfstate-<account>-<region> with versioning kept.
  • Confidence: 0.78

D-023: terraform/platform/main.tf content

  • Default: ONLY shared platform VPC: aws_vpc.nova_shared, aws_subnet.nova_shared (count=2), IGW, route table, ECS SG, outputs (vpc_id, subnet_ids, ecs_security_group_id). State backend references. Drop Lambda, DynamoDB contracts, KMS, Secrets, SNS, consumer_invoke_policy — all OOS.
  • Confidence: 0.83

D-024: terraform/ci-vpc/main.tf role

  • Default: Short-lived test VPC for module lifecycle testing (ref convention preserved). The shared platform VPC lives in terraform/platform/main.tf (D-023). REQ-16's description was a mischaracterization.
  • Confidence: 0.86

D-025: Onboarding static-key alternative

  • DECISION (human override): terraform/onboarding/main.tf creates an IAM ROLE (not a user) with a trust policy allowing the platform's runner user to assume it (cross-account assume role pattern). No OIDC. consumer_repo/owner_id vars kept for tagging. README documents this is dev-only static-key (OIDC is production path, OOS for v1.0). The consumer's CI runner assumes this role via sts assume-role using the platform runner's static credentials.
  • Confidence: 0.72 → locked by human review at 1.0

D-026: IAM runner policy scoping

  • Default: Static inline policy terraform/bootstrap/ spike_runner_policy.json scoped to platform account+region, granting Terraform-deployable resource permissions. NOT ABAC-scoped. Account ID parameterized via variable (not hardcoded). Attached to nova-spike-runner user by create_iam_user.py.
  • Confidence: 0.75

Python packaging / naming / docs / tests

D-027: pyproject.toml — CLI package or scripts only?

  • Default: No CLI package. pyproject.toml configures pytest + py_compile + project metadata. No [project.scripts]. No nova/ package dir. Invoked via shell scripts. Python modules run as scripts.
  • Confidence: 0.85

D-028: docs/modules/ layout

  • Default: docs/modules/index.md (catalog table linking to modules/l1/<name>/README.md and modules/l2/<name>/README.md). Per-module docs live in modules/, not docs/modules/. Mirrors ref exactly.
  • Confidence: 0.82

D-029: modules/STANDARDS.md + README-TEMPLATE.md

  • Default: Keep modules/README.md (REQ-13, trimmed of security/attestation). Keep modules/README-TEMPLATE.md (per-module template). Drop modules/STANDARDS.md (673 lines, mostly security/compliance/attestation — OOS).
  • Confidence: 0.75

D-030: moto usage in tests

  • Default: moto pinned in requirements-test.txt (REQ-31) but used minimally. Check-only is offline (no AWS). Most tests are pure (resolver, adapter, schemas). moto kept for future AWS-touching tests. If unused, harmless pinned dep.
  • Confidence: 0.68 (below threshold — escalate)

D-032: NOVA_* env var naming

  • Default: Keep NOVA_* prefix: NOVA_AWS_ACCESS_KEY_ID, NOVA_AWS_SECRET_ACCESS_KEY, NOVA_BOOTSTRAP_AWS_*, NOVA_FORGE_TOKEN. .env.secrets uses NOVA_AWS_* keys. run_platform.sh copies NOVA_AWS_* to AWS_* env vars.
  • Confidence: 0.88

D-034: Engine-boundary test (REQ-09) file scope

  • Default: Scan .py files only (in core/, schemas/, contracts/, tests/, scripts/, root). Exclude adapters/terraform/ (the boundary), modules/, .tf, .md, .json in modules/envs (data files with terraform_dir paths — not engine logic).
  • Confidence: 0.83

Grill fixes (D-037, D-038 — locked from GRILL.md conditions)

D-037: Resolver-source / engine-boundary / adapter-signature (C-1 fix)

  • DECISION (human-locked): Match the reference design. Drop source from stack.schema.json (REQ-04). Change adapt(stack, modules_dir)adapt(stack, repo_root) (REQ-07). The adapter loads registry.json internally to map moduleterraform_dir — this happens inside the engine boundary (adapters/terraform/), so it's permitted. The resolver never writes Terraform paths into the stack. Stack is engine-agnostic: {contract_id, contract_name, environment, resources: [{module, version, inputs}]}. Side effect (C-4): P2 (adapter) gains a dependency on P3-W1 (registry.json) — reorder P3-W1 before P2-W1.
  • Confidence: 1.0 (human-locked grill fix)
  • Alternatives: [keep source + relax boundary test (fragile); rename to module_path (doesn't fix the substring match)]

D-038: L2 child set (C-2 fix)

  • DECISION (human-locked): Lock the ARCHITECTURE.md compositions as D-036. microservice = vpc + ecs-cluster + ecs-service + iam-role + ecr + alb (6 L1s). static-assets = s3 + cloudfront + kms-key (3 L1s, drops waf from reference). These are fresh compositions under the opaque L2 model (D-012) — not reference mirrors.
  • Confidence: 1.0 (human-locked grill fix)
  • Alternatives: [match reference children exactly (microservice no vpc, static-assets keeps waf); microservice + kms (7 L1s)]