Files
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
..

Nova Modules

Nova ships a two-tier module library. Modules are engine-agnostic: their contract is declared in interface.json (stack types like aws:s3:bucket), and an adapter translates the contract to a concrete IaC engine (Terraform today; Pulumi/CDK possible later). All L1 modules in this repo ship a Terraform adapter under terraform/.

L1 vs L2

Tier What it is Composes Examples
L1 A single primitive resource (or tightly-coupled resource group) on a cloud One stack resource s3, vpc, ecs-cluster, alb
L2 A composition of L1s expressing an architectural pattern Multiple L1 modules microservice, static-assets
  • L1 = one entry in the flat stack. Even multi-resource L1s (e.g. vpc, ecs-service, alb) emit a single stack entry; their interface.json lists the child resources in a resources[] array for documentation, but the resolver does not expand them (D-012).
  • L2 = also one opaque entry in the flat stack. The L2's terraform/main.tf composes L1 modules internally via module blocks (D-012). The L2 exposes its own L2-level inputs/outputs; children and wiring live in terraform, not in the interface.

Registry format

modules/registry.json maps module_name -> version -> entry:

{
  "s3": {
    "1.0.0": {
      "interface": "modules/l1/s3/interface.json",
      "terraform_dir": "modules/l1/s3/terraform",
      "published_at": "2026-08-20T00:00:00Z",
      "deprecated": false,
      "kind": "l1"
    }
  }
}
  • interface — path to the interface.json declaring the contract.
  • terraform_dir — path to the adapter's Terraform module directory (the flat stack's source field).
  • kind"l1" or "l2".
  • deprecated — when true, the resolver warns and selects the latest non-deprecated version unless the caller pins a version.

interface.json shape (D-014)

{
  "name": "s3",
  "version": "1.0.0",
  "kind": "l1",
  "type": "aws:s3:bucket",
  "description": "...",
  "inputs":  { "<name>": { "type": "...", "required": true, "description": "..." } },
  "outputs": { "<name>": { "type": "...", "description": "..." } },
  "resources": [ { "type": "aws:ec2:vpc", "inputs": [...], "outputs": [...] } ]
}
  • type is stack-typedaws:<service>:<resource> (e.g. aws:s3:bucket), not the Terraform resource name (aws_s3_bucket). The adapter performs the translation.
  • resources[] is present only on multi-resource L1s (vpc, ecs-service, alb); it documents the child stack types but does not drive resolution.
  • Dropped per D-014: nfrs (confidence signal, out of scope) and intra_refs (wire engine, eliminated by D-012). Do not re-add them.

Conventions shared by all L1 Terraform adapters

  • terraform/versions.tf pins required_version = ">= 1.9, < 1.10" and aws ~> 5.0.
  • Every resource is guarded by count = var.enabled ? 1 : 0; the enabled input defaults to true.
  • locals.tf merges module-default tags with caller-supplied var.tags:
    tags = merge({ "nova:owner" = "nova", "nova:environment" = "dev" }, var.tags)
    
  • Every interface.json input has a matching variable block; every output has a matching output block. Outputs return null (or []) when enabled = false.

How to add a module

  1. Pick the tier. New primitive → L1. New pattern composing existing L1s → L2.
  2. Create modules/l1/<name>/ (or modules/l2/<name>/).
  3. Author interface.json (L1) or interface.json + L2 terraform that composes L1s via module blocks. Use modules/README-TEMPLATE.md as the per-module doc template.
  4. Author terraform/{main,variables,outputs,versions,locals}.tf following the conventions above.
  5. Add an entry to modules/registry.json and a row to the catalog at docs/modules/index.md.
  6. Verify: python3 -c "import json; json.load(open('modules/l1/<name>/interface.json'))" and terraform validate inside terraform/.

L1 primitives (13)

Module Stack type Multi-resource? Description
s3 aws:s3:bucket no S3 bucket with versioning + SSE-KMS
vpc aws:ec2:vpc yes VPC + subnets + route table + IGW
ecs-cluster aws:ecs:cluster no ECS cluster
ecs-service aws:ecs:service yes ECS task definition + service
iam-role aws:iam:role no IAM role with assume-role policy
alb aws:alb yes ALB + target group + listener
ecr aws:ecr:repository no ECR repository with scan-on-push
cloudfront aws:cloudfront:distribution no CloudFront distribution with a single origin
waf aws:waf:web_acl no WAFv2 web ACL (regional, default allow)
rds aws:rds:instance no RDS Postgres DB instance
kms-key aws:kms:key no KMS CMK with alias
dynamodb aws:dynamodb:table no DynamoDB table (PAY_PER_REQUEST default)
uptime aws:uptime:monitor no Uptime monitor (CloudWatch alarm stand-in)

L2 compositions (2)

Module Composes Description
microservice vpc + ecs-cluster + ecs-service + iam-role + ecr + alb Container microservice with public ALB (D-038)
static-assets s3 + cloudfront + kms-key Static site fronted by CloudFront (D-038)