refactor(modules): remove thin-composition layer; rewrite all module READMEs

The L2 thin-composition layer (composition.json + contract_resolver.py +
contract schema + sample contracts) has been removed completely. The
implementation was unsatisfactory and is deferred for a later redesign.

- Delete: composition.json x2, contract_resolver.py, contracts/ x2,
  contract.schema.json
- Patch: run_platform.sh now loads a pre-existing IR instance instead of
  resolving a contract (the downstream adapter/checkov/confidence/outbox
  pipeline is unchanged)
- Prune: L2 entries removed from registry.json (L1 entries unchanged)
- Rewrite: all 7 L1 module READMEs in plain language (no jargon), each
  with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning
  sections derived from interface.json
- Add: 2 L2 placeholder READMEs noting the composition is under redesign
- Add: modules-ir/README.md catalog index + README-TEMPLATE.md

---ci---
project: acdl
phase: 17
milestone: v1.3
status: execute
---/ci---
This commit is contained in:
Jon Chery
2026-07-22 13:54:40 +00:00
parent f874879973
commit 3508671377
19 changed files with 565 additions and 767 deletions
+41 -69
View File
@@ -1,85 +1,57 @@
# l2-microservice — thin-composition (ECS Fargate microservice)
# l2-microservice — ECS Fargate microservice (composition being redesigned)
The v1.2 L2. A thin-composition that references 6 L1s (depth 1):
`l1-vpc`, `l1-ecs-cluster`, `l1-ecr`, `l1-iam-role`, `l1-alb`,
`l1-ecs-service`. The contract's inputs (`name`, `cidr`, `azs`,
`image`, `port`, `cpu`, `memory`, `env`, `protocol`, `region`,
`role_name`, `assume_role_policy`, `managed_policies`) map to the
children's inputs through two wire kinds.
> **Module kind:** L2 composition | **Version:** TBD | **Status:** Under redesign
## Composition (the IR-typed thin-composition tree)
A composition that references multiple L1 primitives to deploy an ECS
Fargate microservice end-to-end (VPC, cluster, ECR, IAM role, ALB,
ECS service).
See `composition.json`: `kind=l2`, `depth=1`, six children.
**The composition layer is being redesigned.** The previous
thin-composition implementation (a `composition.json` with children +
wires) has been removed. A new composition mechanism will be designed
in a later phase.
### Children
## Resources
| child id | L1 module | IR type(s) |
|----------|-----------|------------|
| `vpc` | `l1-vpc@1.0.0` | `aws:ec2:vpc`, `aws:ec2:subnet`, `aws:ec2:routetable` |
| `cluster` | `l1-ecs-cluster@1.0.0` | `aws:ecs:cluster` |
| `ecr` | `l1-ecr@1.0.0` | `aws:ecr:repository` |
| `roles` | `l1-iam-role@1.0.0` | `aws:iam:role` |
| `alb` | `l1-alb@1.0.0` | `aws:elbv2:loadbalancer`, `aws:elbv2:listener`, `aws:elbv2:targetgroup` |
| `service` | `l1-ecs-service@1.0.0` | `aws:ecs:task_definition`, `aws:ecs:service` |
TBD — the composition will reference these L1 primitives:
Multi-resource L1s (`vpc`, `alb`, `service`) declare a `resources`
array in their `interface.json`; the resolver expands each child into
one IR resource per `resources` entry (id scheme `<child_id>-<type_suffix>`
where `type_suffix` is the last segment of the IR type with underscores
stripped — e.g. `vpc-vpc`, `vpc-subnet`, `vpc-routetable`,
`alb-loadbalancer`, `alb-targetgroup`, `alb-listener`,
`service-taskdefinition`, `service-service`. The hyphen separator keeps
the id valid against `schemas/ir.schema.json`'s
`^[a-z][a-z0-9-]*$` resource id pattern). Single-resource L1s keep the
child id verbatim (`cluster`, `ecr`, `roles`).
| L1 module | Purpose | README |
|-----------|---------|--------|
| `l1-vpc` | VPC, subnets, routing | [README](../l1/l1-vpc/README.md) |
| `l1-ecs-cluster` | ECS Fargate cluster | [README](../l1/l1-ecs-cluster/README.md) |
| `l1-ecr` | ECR image repository | [README](../l1/l1-ecr/README.md) |
| `l1-iam-role` | IAM task execution role | [README](../l1/l1-iam-role/README.md) |
| `l1-alb` | Application Load Balancer | [README](../l1/l1-alb/README.md) |
| `l1-ecs-service` | ECS task definition + service | [README](../l1/l1-ecs-service/README.md) |
### Wire kinds
## Inputs
1. **Contract→child passthrough** — wire name = contract input name;
target = child id, input = child's input name. For contract inputs
that fan out to multiple children (`name`, `port`, `region`), the
wire value is an array of `{target, input}` objects; otherwise a
single object. Resolves to the concrete contract value.
TBD — will be defined when the composition mechanism is redesigned.
2. **Child→child references** — wire with `source: "child:<id>.<output>"`.
The value is only known at apply time, so the resolver emits the IR
input as the string `ref:<ir_resource_id>.<output>` (the IR resource
id of the *producing* child's first resource — for single-resource
L1s that is the child id, for multi-resource L1s it is
`<child_id>-<type_suffix>` of the first resource in the `resources`
array that declares the output). The adapter translates `ref:` to a
Terraform interpolation.
## Outputs
Wires used by this composition:
TBD — will be defined when the composition mechanism is redesigned.
- Passthrough: `name` (→vpc/cluster/ecr/alb), `cidr` (→vpc), `azs`
(→vpc), `image` (→service), `port` (→service/alb), `cpu` (→service),
`memory` (→service), `env` (→service), `protocol` (→alb), `region`
(→all 6), `role_name` (→roles), `assume_role_policy` (→roles),
`managed_policies` (→roles).
- Child→child: `cluster_arn` (cluster→service), `subnet_ids`
(vpc→service/alb `subnets`), `target_group_arn` (alb→service
`lb_target_group_arn`), `role_arn` (roles→service/alb
`security_group`).
## Usage
## IR → Terraform mapping (D-P10-1)
TBD — the composition mechanism is being redesigned. Until then, use
the L1 primitives directly. See each L1 module's README for usage
examples.
The Terraform adapter consumes the *resolved IR instance* (which has
`kind=l2` + all 6 L1s expanded into one IR resource per entry in each
L1's `resources` array, with `ref:` strings on the consumer inputs).
For a depth-1 thin-composition, the L2 root module **IS** the union of
the L1 resources — no separate `module "l1_x" { source = "..." }`
blocks. The existing adapter `TYPE_MAP` + `INPUT_MAP` + `OUTPUT_MAP`
tables handle every IR type. `ref:<id>.<output>` inputs are translated
to `${<tf_type>.<id>.<attr>}` (attribute mapped through `OUTPUT_MAP`
for the referenced resource's type). The `relationships` array records
the parent composition tree; ordering is implicit in the resource list.
## Compliance extension points
v1.3+ may emit real `module "l1_x" { source = "..." }` blocks once L1s
are published Terraform modules rather than inline resources.
The composition will need to wire compliance resources across L1s
when the compliance milestone (GDPR, SOX, SOC2, HIPAA, DORA) lands:
## Versioning (W3.D)
- **KMS key** — shared encryption key referenced by S3, ECR, CloudWatch Logs, and Secrets Manager.
- **CloudTrail** — management-plane audit trail for the entire stack.
- **VPC Flow Logs** — network audit trail.
- **Security groups** — proper network segmentation between ALB, service, and data tiers.
- **Private subnets** — ECS tasks in private subnets with NAT egress.
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
a 12-month deprecation window.
See each L1 module's README for per-module compliance extension points.
## Versioning
Versioning will be defined when the composition mechanism is
redesigned.
@@ -1,55 +0,0 @@
{
"name": "l2-microservice",
"version": "1.0.0",
"kind": "l2",
"depth": 1,
"description": "Thin-composition: an ECS Fargate microservice. References 6 L1s (vpc, cluster, ecr, roles, alb, service).",
"children": [
{"id": "vpc", "module": "l1-vpc@1.0.0"},
{"id": "cluster", "module": "l1-ecs-cluster@1.0.0"},
{"id": "ecr", "module": "l1-ecr@1.0.0"},
{"id": "roles", "module": "l1-iam-role@1.0.0"},
{"id": "alb", "module": "l1-alb@1.0.0"},
{"id": "service", "module": "l1-ecs-service@1.0.0"}
],
"wires": {
"name": [
{"target": "vpc", "input": "name"},
{"target": "cluster", "input": "name"},
{"target": "ecr", "input": "name"},
{"target": "alb", "input": "name"}
],
"cidr": {"target": "vpc", "input": "cidr"},
"azs": {"target": "vpc", "input": "azs"},
"image": {"target": "service", "input": "image"},
"port": [
{"target": "service", "input": "port"},
{"target": "alb", "input": "port"}
],
"cpu": {"target": "service", "input": "cpu"},
"memory": {"target": "service", "input": "memory"},
"env": {"target": "service", "input": "env"},
"protocol": {"target": "alb", "input": "protocol"},
"region": [
{"target": "vpc", "input": "region"},
{"target": "cluster", "input": "region"},
{"target": "ecr", "input": "region"},
{"target": "roles", "input": "region"},
{"target": "alb", "input": "region"},
{"target": "service", "input": "region"}
],
"role_name": {"target": "roles", "input": "role_name"},
"assume_role_policy": {"target": "roles", "input": "assume_role_policy"},
"managed_policies": {"target": "roles", "input": "managed_policies"},
"cluster_arn": {"target": "service", "input": "cluster_arn", "source": "child:cluster.cluster_arn"},
"subnet_ids": [
{"target": "service", "input": "subnets", "source": "child:vpc.subnet_ids"},
{"target": "alb", "input": "subnets", "source": "child:vpc.subnet_ids"}
],
"target_group_arn": {"target": "service", "input": "lb_target_group_arn", "source": "child:alb.target_group_arn"},
"role_arn": [
{"target": "service", "input": "security_group", "source": "child:roles.role_arn"},
{"target": "alb", "input": "security_group", "source": "child:roles.role_arn"}
]
}
}
+43 -23
View File
@@ -1,31 +1,51 @@
# l2-static-asset — thin-composition (S3 static asset)
# l2-static-asset — S3 static asset (composition being redesigned)
The v1.1 spike's L2. A thin-composition that references `l1-s3` only
(depth 1). The contract's inputs (`bucket_name`, `region`) map 1:1
through the wires to the L1's inputs.
> **Module kind:** L2 composition | **Version:** TBD | **Status:** Under redesign
## Composition (the IR-typed thin-composition tree)
A composition that references the `l1-s3` primitive to deploy a single
S3 bucket for static asset hosting.
See `composition.json`: `kind=l2`, `depth=1`, one child `l1-s3@1.0.0`,
wires `{bucket_name → s3.inputs.bucket_name, region → s3.inputs.region}`
(passthrough).
**The composition layer is being redesigned.** The previous
thin-composition implementation (a `composition.json` with children +
wires) has been removed. A new composition mechanism will be designed
in a later phase.
## IR → Terraform mapping (D-P10-1)
## Resources
The Terraform adapter consumes the *resolved IR instance* (which has
`kind=l2` + the L1 resource `s3` in its `resources` array). For a
depth-1 thin-composition, the L2 root module **IS** the L1's resource —
no separate `module "l1_s3" { source = "..." }` block. The existing
adapter `TYPE_MAP` + resource emission handle both l1 and l2 instances
(the resources array is the same shape). The `relationships` array is
ignored at the Terraform level for the spike (composition ordering is
implicit in the single resource).
TBD — the composition will reference this L1 primitive:
v1.2 may emit a real `module "l1_s3" { source = "..." }` block when L1s
become published Terraform modules rather than inline resources.
| L1 module | Purpose | README |
|-----------|---------|--------|
| `l1-s3` | S3 bucket | [README](../l1/l1-s3/README.md) |
## Versioning (W3.D)
## Inputs
`1.0.0` — interface MAJOR, behavior MINOR, lifecycle PATCH. MAJOR bumps
require a new registry entry (immutable publication); old entries enter
a 12-month deprecation window.
TBD — will be defined when the composition mechanism is redesigned.
## Outputs
TBD — will be defined when the composition mechanism is redesigned.
## Usage
TBD — the composition mechanism is being redesigned. Until then, use
`l1-s3` directly. See the [l1-s3 README](../l1/l1-s3/README.md) for a
usage example.
## Compliance extension points
The composition will need to wire compliance resources when the
compliance milestone (GDPR, SOX, SOC2, HIPAA, DORA) lands:
- **KMS key** — shared encryption key for S3 SSE.
- **S3 access logs** — access logging to a separate audit bucket.
- **Object Lock** — 7-year immutable retention for evidence.
- **Public access block** — prevent data exfiltration.
See the [l1-s3 README](../l1/l1-s3/README.md) for per-module compliance
extension points.
## Versioning
Versioning will be defined when the composition mechanism is
redesigned.
@@ -1,17 +0,0 @@
{
"name": "l2-static-asset",
"version": "1.0.0",
"kind": "l2",
"depth": 1,
"description": "Thin-composition: a single S3 bucket for static asset hosting. References l1-s3 only (depth 1).",
"children": [
{
"id": "s3",
"module": "l1-s3@1.0.0"
}
],
"wires": {
"bucket_name": {"target": "s3", "input": "bucket_name"},
"region": {"target": "s3", "input": "region"}
}
}