review(v1.5): READY TO SHIP — multi-persona code review
acdl-ci / Lint (push) Successful in 7s
acdl-ci / Test (push) Successful in 15s
acdl-ci / Platform check-only (offline) (push) Successful in 9s

---ci---
project: acdl
phase: 20
milestone: v1.5
status: review
verdict: READY TO SHIP
p0: 1 (fixed — contract path resolution in deploy workflow)
p1: 6 (flagged post-hoc)
---/ci---

Multi-persona review of v1.5 phase 20 (docs + reusable deploy workflow).

P0 (blocking) — AUTO-FIXED:
- C1: scripts/run_platform.sh contract path resolution broken in deploy
  workflow. The reusable workflow invokes run_platform.sh from the consumer
  workspace root with a relative contract path (.acdl/contract.yaml), but
  run_platform.sh does `cd "$ROOT"` (platform repo) early, so the relative
  path resolved against the platform repo and the pipeline could never run.
  Fix (commit 75c2274): capture CALLER_CWD before cd "$ROOT"; resolve
  caller-supplied relative paths against CALLER_CWD; default no-arg contract
  stays relative to ROOT (preserves platform-local CI). Reproduced pre-fix;
  verified post-fix.

P1 (important) — FLAGGED FOR POST-HOC REVIEW (do not block ship):
- C2: ref: v1.4 in the deploy workflow platform checkout — no v1.4 tag exists
  (only v1.4.0 / v1.4.1). Operator must create a floating v1.4 tag or change
  the ref to v1.4.1.
- C3: modules/l2/{static-asset,microservice}/README.md still use @v1 in their
  Usage examples; missed by the v1.4 bump.
- S1: static-key override is not wired. ACDL_AWS_* env vars on the OIDC step
  are not read by aws-actions/configure-aws-credentials@v4 (it reads AWS_*
  or its own access-key/secret-key inputs). The README/CONSUMER_GUIDE claim
  a working override that doesn't function as written. Needs a conditional
  step or renamed env vars + input wiring.
- S2: README overstates ABAC repo:org/repo:ref:... scoping. The workflow
  constructs a numeric role name (github.repository_id); the actual claim
  enforcement lives in the IAM trust policy, not in this workflow.
- T1: no deploy-workflow triggers conformance test (CI workflow has one;
  deploy doesn't). Minor — reusable workflows use workflow_call, not push
  triggers, but the contract's triggers field is then unenforced.
- A1: terraform/spike/terraform.tf uploaded as artifact leaks the AWS account
  ID via the state-backend bucket name. Recommend excluding terraform.tf or
  gating artifact upload to non-public repos.

P2 (nits) — listed for awareness: floating-tag terminology imprecision (M1),
  header comment "Gitea Actions" in the GitHub copy (M2, intentional byte-
  identical), pip install split (P1-perf), comment drift in pipelines/deploy.yaml
  header (C4), module README internal inconsistency (C5).

Verdict: READY TO SHIP. The one P0 is fixed. The 6 P1s are post-hoc items —
the deploy workflow is a scaffold whose first real consumer run requires
operator setup (tag, IAM role, secrets) that gates go-live. The P1s should
be addressed before any consumer invokes uses: acdl/.gitea/workflows/
deploy.yml@v1.4 in earnest.

Tests: 154 pass (19 new). run_ci.sh green.
This commit is contained in:
Jon Chery
2026-07-22 17:24:28 +00:00
parent 75c227429a
commit f68f85c9fd
44 changed files with 905 additions and 244 deletions
+19 -19
View File
@@ -33,7 +33,7 @@ Resolution session log (v1.0 snapshot — see PROJECT.md for full text):
| BA.C | On-call / operational ownership | ✅ RESOLVED — platform on-call = Infra & Ops; L3A/L3B halt → platform on-call (Sev2); consumer-visible outage → consumer on-call (Sev1) + platform support. |
| BA.D | Cost / capacity governance | ✅ RESOLVED — FinOps owns cloud cost; per-contract monthly reporting; runaway spend hard-halts at 120% of declared budget via the confidence signal; override = FinOps + SRE joint sign-off. |
| BA.E | Consumer onboarding | ✅ RESOLVED — developer (L3A): `getting-started` → contract schema + central pipeline template; citizen (L3B): scoped agent + skill catalog, no workflow authoring; both end in a sandbox dev submission that must pass the confidence gate. |
| BA.F | Cross-platform evolution | ✅ RESOLVED — contract schema, IR, PolicyCheckResult, confidence signal, audit stream are portable (forge-agnostic); forge-specific code = workflow YAML, OIDC trust, CODEOWNERS, Environments; a second forge needs a forge adapter + workflow-template translator, no change to L1/L2/IR/confidence/audit. |
| BA.F | Cross-platform evolution | ✅ RESOLVED — contract schema, stack, PolicyCheckResult, confidence signal, audit stream are portable (forge-agnostic); forge-specific code = workflow YAML, OIDC trust, CODEOWNERS, Environments; a second forge needs a forge adapter + workflow-template translator, no change to L1/L2/stack/confidence/audit. |
| Q1.3 | OpenTofu timing | ✅ RESOLVED (deferred) — not in v1 or v1.1; the substrate abstraction (§12) makes OpenTofu a future adapter, not an architecture change; revisit when an OpenTofu adapter is requested. |
---
@@ -74,7 +74,7 @@ Locked commitments (unchanged from v0.1):
✅ RESOLVED (see PROJECT.md W1.A): AI-refinement operational trigger — joint condition: N ≥ 50 consecutive changes with zero rollbacks AND no L1/L2 incident in last 6 months AND Infra & Ops holds a unilateral override.
✅ RESOLVED (sub-decision): The L1 module's interface field is defined against the Target Stack IR, not against Terraform's variable block directly. In v1, the IR is shaped to round-trip cleanly to Terraform, but the schema is substrate-agnostic. Pending v1 implementation details in Section 12.
✅ RESOLVED (sub-decision): The L1 module's interface field is defined against the Target Stack, not against Terraform's variable block directly. In v1, the stack is shaped to round-trip cleanly to Terraform, but the schema is substrate-agnostic. Pending v1 implementation details in Section 12.
## 3. Layer 2 — Composed Stacks
@@ -96,7 +96,7 @@ Locked commitments (unchanged from v0.1):
✅ RESOLVED (see PROJECT.md W1.B): Multi-stack edge case rule — permitted only for (a) DR-region mirror, (b) time-boxed experimental stack with TTL ≤ 30 days, (c) explicit Infra & Ops approval for a documented reason captured in multiStack.justification.
✅ RESOLVED (sub-decision): The L2 thin-composition tree's wires field is defined against the IR's relationship type, not against a Terraform module block. The IR → Terraform translation is the Terraform adapter's job (Section 12). The thin-composition pipeline itself is substrate-agnostic.
✅ RESOLVED (sub-decision): The L2 composition tree's wires field is defined against the stack's relationship type, not against a Terraform module block. The stack → Terraform translation is the Terraform adapter's job (Section 12). The composition pipeline itself is substrate-agnostic.
## 4. Layer 3A — Developer Consumer Surface
@@ -297,7 +297,7 @@ Purpose. The technical execution layer for the L1/L2 substrate, including the su
### 12.1 Substrate abstraction (locked this revision)
L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack Intermediate Representation (IR) — a substrate-neutral description of:
L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack — a substrate-neutral description of:
- Resources with typed input contracts, typed output contracts, and declared NFRs.
@@ -307,25 +307,25 @@ L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack I
- Policy hooks (the points in the composition where policy checks attach).
The L1 registry, the L2 thin-composition tree, the YML standard, and the policy check result schema are all defined against the IR. None of them is defined against any specific substrate.
The L1 registry, the L2 thin-composition tree, the YML standard, and the policy check result schema are all defined against the stack schema. None of them is defined against any specific substrate.
Substrate adapters are the only substrate-specific code. An adapter compiles the IR into a substrate execution plan. v1 ships exactly one adapter: the Terraform adapter. v2+ may add additional adapters (OpenTofu, Pulumi, K8s CRDs) without architectural change.
Substrate adapters are the only substrate-specific code. An adapter compiles the stack into a substrate execution plan. v1 ships exactly one adapter: the Terraform adapter. v2+ may add additional adapters (OpenTofu, Pulumi, K8s CRDs) without architectural change.
v1 implementation reality: the IR is shaped to round-trip cleanly to Terraform because there is no other adapter to differentiate from. The IR and the Terraform output are nearly isomorphic in v1. As additional adapters appear in v2+, the IR gets more expressive (e.g., substrate-specific output types) and the adapters gain translation logic, but the L1 module content, the YML standard, and the thin-composition tree do not change. This is the design that prevents the polyglot mess.
v1 implementation reality: the stack is shaped to round-trip cleanly to Terraform because there is no other adapter to differentiate from. The stack and the Terraform output are nearly isomorphic in v1. As additional adapters appear in v2+, the stack gets more expressive (e.g., substrate-specific output types) and the adapters gain translation logic, but the L1 module content, the YML standard, and the composition tree do not change. This is the design that prevents the polyglot mess.
Why not build the abstraction earlier? Building a substrate-agnostic IR before there is a second adapter to test against is speculative generality. The v1 commitment is: (1) the L1 module interface is defined against the IR even though the only adapter is Terraform, and (2) the central pipeline, registry, and policy schema consume the IR-typed contracts. The adapter is the only place where substrate terminology appears in v1.
Why not build the abstraction earlier? Building a substrate-agnostic stack before there is a second adapter to test against is speculative generality. The v1 commitment is: (1) the L1 module interface is defined against the stack schema even though the only adapter is Terraform, and (2) the central pipeline, registry, and policy schema consume the stack-typed contracts. The adapter is the only place where substrate terminology appears in v1.
### 12.2 Terraform adapter (v1)
The Terraform adapter:
- Translates the IR-typed L1 module interface to a Terraform variable block and a Terraform output block.
- Translates the stack-typed L1 module interface to a Terraform variable block and a Terraform output block.
- Translates the IR-typed L2 thin-composition tree to a Terraform root module that calls the L1 modules.
- Translates the stack-typed L2 composition tree to a Terraform root module that calls the L1 modules.
- Translates the IR-typed relationships to Terraform module references.
- Translates the stack-typed relationships to Terraform module references.
- Emits a Terraform plan from the IR.
- Emits a Terraform plan from the stack.
The adapter is a thin layer. It does not own L1/L2 content; it only translates.
@@ -372,7 +372,7 @@ Schema (canonical form, lives in the central pipeline repo):
"result": "pass | fail | skipped | error",
"message": "human-readable",
"evidence": { "...engine-specific payload, opaque to the signal..." },
"resourceRef": "IR-typed resource identifier"
"resourceRef": "stack-typed resource identifier"
}
```
@@ -380,11 +380,11 @@ The Checkov adapter runs in the same GitHub Actions step as Checkov itself and t
### 12.7 Registry maintenance
Locked: L1 module publication updates the L1 registry in the same PR as the module. Registry and module land together. The registry is the IR-typed contract, not a Terraform-specific variable schema. The L1 registry, the central pipeline, and the policy schema all consume the same IR-typed contract — there is one source of truth for the L1 interface, not multiple substrate-specific copies.
Locked: L1 module publication updates the L1 registry in the same PR as the module. Registry and module land together. The registry is the stack-typed contract, not a Terraform-specific variable schema. The L1 registry, the central pipeline, and the policy schema all consume the same stack-typed contract — there is one source of truth for the L1 interface, not multiple substrate-specific copies.
### 12.8 Contract-schema-to-IR resolution
### 12.8 Contract-schema-to-stack resolution
The contract schema declares the consumer's intent in IR-typed terms. The central pipeline resolves the contract to a target stack (a list of L1 module instances with their inputs and the relationships between them). The Terraform adapter compiles the target stack to a Terraform execution plan. This resolution is substrate-agnostic — the target stack is in the IR.
The contract schema declares the consumer's intent in stack-typed terms. The central pipeline resolves the contract to a target stack (a list of L1 module instances with their inputs and the relationships between them). The Terraform adapter compiles the target stack to a Terraform execution plan. This resolution is substrate-agnostic — the target stack is in the stack schema.
## 13. Consolidated Open Design Decisions
@@ -420,7 +420,7 @@ by `✅ RESOLVED (see PROJECT.md)`.
- (BA.E) Consumer onboarding. ✅ RESOLVED (see PROJECT.md) — developer (L3A): getting-started → contract schema + central pipeline template; citizen (L3B): scoped agent + skill catalog; both end in a sandbox dev submission that must pass the confidence gate.
- (BA.F) Cross-platform evolution. ✅ RESOLVED (see PROJECT.md) — contract schema, IR, PolicyCheckResult, confidence signal, audit stream are portable; forge-specific code = workflow YAML, OIDC trust, CODEOWNERS, Environments; a second forge needs a forge adapter + workflow-template translator.
- (BA.F) Cross-platform evolution. ✅ RESOLVED (see PROJECT.md) — contract schema, stack, PolicyCheckResult, confidence signal, audit stream are portable; forge-specific code = workflow YAML, OIDC trust, CODEOWNERS, Environments; a second forge needs a forge adapter + workflow-template translator.
- (Q1.3) OpenTofu timing. ✅ RESOLVED (deferred — see PROJECT.md) — not in v1 or v1.1; the substrate abstraction makes OpenTofu a future adapter, not an architecture change.
@@ -428,7 +428,7 @@ by `✅ RESOLVED (see PROJECT.md)`.
Status: **v1.0**. All 11 open items in §13 are resolved. The architecture is
internally consistent; the v1.1 implementation spike (ACDL Phases 08-10)
validates the locked substrate abstraction + contract→IR→adapter path
validates the locked substrate abstraction + contract→stack→adapter path
against real AWS via a per-run-rotated key (D-039; OIDC deferred to v1.2).
The v1.2 build-out (S3 Object Lock, JWS, HITL wiring, L3B skill catalog,
Kyverno/OPA, real OIDC federation, multi-region) is design-authored in
@@ -447,7 +447,7 @@ Phase 07):
| REQ | File | Owner persona |
|-----|------|--------------|
| REQ-17 | `schemas/ir.schema.json` | platform-engineer |
| REQ-17 | `schemas/stack.schema.json` | platform-engineer |
| REQ-18 | `schemas/policy_check_result.schema.json` + `adapters/terraform/policy/checkov_adapter.py` | security-engineer |
| REQ-19 | `platform/confidence_signal.py` | backend-engineer + security-engineer (co-authored) |
| REQ-20 | `platform/audit_ledger_design.md` | security-engineer |
+18 -18
View File
@@ -2,7 +2,7 @@
Three things to set up before I deliver the document, because they determine how I write the doc:
1. What is locked from the resolution session. Eight items: environment model (Path A — dev-only autonomous, no staging), substrate abstraction (Target Stack IR + adapter pattern, Terraform adapter in v1), policy toolchain (Checkov for Terraform plan, Kyverno for K8s, OPA last resort), separation of duties (CODEOWNERS for routing + DynamoDB outbox for identity distinctness), policy normalization PolicyCheckResult schema with engine adapters), HITL matrix (full 8-concern matrix with evidence, freshness, source), HITL timeout (1d warn, 2d freeze), HITL rollback (pre-execution model, audit chain extended, no partial deploy).
1. What is locked from the resolution session. Eight items: environment model (Path A — dev-only autonomous, no staging), substrate abstraction (Target Stack + adapter pattern, Terraform adapter in v1), policy toolchain (Checkov for Terraform plan, Kyverno for K8s, OPA last resort), separation of duties (CODEOWNERS for routing + DynamoDB outbox for identity distinctness), policy normalization PolicyCheckResult schema with engine adapters), HITL matrix (full 8-concern matrix with evidence, freshness, source), HITL timeout (1d warn, 2d freeze), HITL rollback (pre-execution model, audit chain extended, no partial deploy).
2. What is still open after the session. Eleven items, listed in the updated Section 13. They are the gating items for v1.0.
@@ -25,7 +25,7 @@ Resolution session log (this revision):
| ID | Question | Resolution |
|---|---|---|
| Q1 | Environment model | Path A locked. Dev is the only autonomous environment. QA HITL at qa. SRE HITL at prod and dr. Staging does not exist. |
| Q1.2 | Substrate trajectory | Substrate abstraction locked. L1/L2 are defined against a Target Stack IR. Substrate adapters compile the IR to a substrate execution plan. v1 ships only the Terraform adapter. |
| Q1.2 | Substrate trajectory | Substrate abstraction locked. L1/L2 are defined against a Target Stack. Substrate adapters compile the stack to a substrate execution plan. v1 ships only the Terraform adapter. |
| Q1.3 | OpenTofu timing | 🟡 OPEN (W3.D-adjacent). No specific version or trigger committed. |
| Q2.1 | Policy toolchain | Locked. Checkov for Terraform plan policy. Kyverno for K8s-native and platform-internal policy. OPA/Rego reserved for cross-resource cases; explicitly last resort due to Rego complexity. |
| Q2.2 | Separation of duties | Locked. GitHub CODEOWNERS routes the right reviewer to the right environment. Platform-internal identity record in DynamoDB outbox enforces qaApprover ≠ prodApprover for the same contract. |
@@ -76,7 +76,7 @@ Locked commitments (unchanged from v0.1):
🟡 OPEN (W1.A): AI-refinement operational trigger. The criterion for flipping aiRefinement from false to true needs a falsifiable operational signal. Recommendation: joint condition — N ≥ 50 consecutive changes with zero rollbacks AND no L1/L2 incident in the last 6 months AND Infra & Ops holds a unilateral override. Pending sign-off.
🟡 OPEN (sub-decision surfaced this revision): The L1 module's interface field is defined against the Target Stack IR, not against Terraform's variable block directly. In v1, the IR is shaped to round-trip cleanly to Terraform, but the schema is substrate-agnostic. Pending v1 implementation details in Section 12.
🟡 OPEN (sub-decision surfaced this revision): The L1 module's interface field is defined against the Target Stack, not against Terraform's variable block directly. In v1, the stack is shaped to round-trip cleanly to Terraform, but the schema is substrate-agnostic. Pending v1 implementation details in Section 12.
## 3. Layer 2 — Composed Stacks
@@ -98,7 +98,7 @@ Locked commitments (unchanged from v0.1):
🟡 OPEN (W1.B): Multi-stack edge case rule. The multiStack: true exception needs a falsifiable rule. Recommendation: permitted only for (a) DR-region mirror of the primary stack, (b) time-boxed experimental stack with TTL ≤ 30 days, (c) explicit Infra & Ops approval for a documented reason captured in multiStack.justification. Pending sign-off.
🟡 OPEN (sub-decision surfaced this revision): The L2 thin-composition tree's wires field is defined against the IR's relationship type, not against a Terraform module block. The IR → Terraform translation is the Terraform adapter's job (Section 12). The thin-composition pipeline itself is substrate-agnostic.
🟡 OPEN (sub-decision surfaced this revision): The L2 composition tree's wires field is defined against the stack's relationship type, not against a Terraform module block. The stack → Terraform translation is the Terraform adapter's job (Section 12). The composition pipeline itself is substrate-agnostic.
## 4. Layer 3A — Developer Consumer Surface
@@ -301,7 +301,7 @@ Purpose. The technical execution layer for the L1/L2 substrate, including the su
### 12.1 Substrate abstraction (locked this revision)
L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack Intermediate Representation (IR) — a substrate-neutral description of:
L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack — a substrate-neutral description of:
- Resources with typed input contracts, typed output contracts, and declared NFRs.
@@ -311,25 +311,25 @@ L1/L2 are substrate-agnostic in shape. The architecture defines a Target Stack I
- Policy hooks (the points in the composition where policy checks attach).
The L1 registry, the L2 thin-composition tree, the YML standard, and the policy check result schema are all defined against the IR. None of them is defined against any specific substrate.
The L1 registry, the L2 composition tree, the YML standard, and the policy check result schema are all defined against the stack schema. None of them is defined against any specific substrate.
Substrate adapters are the only substrate-specific code. An adapter compiles the IR into a substrate execution plan. v1 ships exactly one adapter: the Terraform adapter. v2+ may add additional adapters (OpenTofu, Pulumi, K8s CRDs) without architectural change.
Substrate adapters are the only substrate-specific code. An adapter compiles the stack into a substrate execution plan. v1 ships exactly one adapter: the Terraform adapter. v2+ may add additional adapters (OpenTofu, Pulumi, K8s CRDs) without architectural change.
v1 implementation reality: the IR is shaped to round-trip cleanly to Terraform because there is no other adapter to differentiate from. The IR and the Terraform output are nearly isomorphic in v1. As additional adapters appear in v2+, the IR gets more expressive (e.g., substrate-specific output types) and the adapters gain translation logic, but the L1 module content, the YML standard, and the thin-composition tree do not change. This is the design that prevents the polyglot mess.
v1 implementation reality: the stack is shaped to round-trip cleanly to Terraform because there is no other adapter to differentiate from. The stack and the Terraform output are nearly isomorphic in v1. As additional adapters appear in v2+, the stack gets more expressive (e.g., substrate-specific output types) and the adapters gain translation logic, but the L1 module content, the YML standard, and the composition tree do not change. This is the design that prevents the polyglot mess.
Why not build the abstraction earlier? Building a substrate-agnostic IR before there is a second adapter to test against is speculative generality. The v1 commitment is: (1) the L1 module interface is defined against the IR even though the only adapter is Terraform, and (2) the central pipeline, registry, and policy schema consume the IR-typed contracts. The adapter is the only place where substrate terminology appears in v1.
Why not build the abstraction earlier? Building a substrate-agnostic stack before there is a second adapter to test against is speculative generality. The v1 commitment is: (1) the L1 module interface is defined against the stack schema even though the only adapter is Terraform, and (2) the central pipeline, registry, and policy schema consume the stack-typed contracts. The adapter is the only place where substrate terminology appears in v1.
### 12.2 Terraform adapter (v1)
The Terraform adapter:
- Translates the IR-typed L1 module interface to a Terraform variable block and a Terraform output block.
- Translates the stack-typed L1 module interface to a Terraform variable block and a Terraform output block.
- Translates the IR-typed L2 thin-composition tree to a Terraform root module that calls the L1 modules.
- Translates the stack-typed L2 composition tree to a Terraform root module that calls the L1 modules.
- Translates the IR-typed relationships to Terraform module references.
- Translates the stack-typed relationships to Terraform module references.
- Emits a Terraform plan from the IR.
- Emits a Terraform plan from the stack.
The adapter is a thin layer. It does not own L1/L2 content; it only translates.
@@ -367,7 +367,7 @@ Schema (canonical form, lives in the central pipeline repo):
"result": "pass | fail | skipped | error",
"message": "human-readable",
"evidence": { "...engine-specific payload, opaque to the signal..." },
"resourceRef": "IR-typed resource identifier"
"resourceRef": "stack-typed resource identifier"
}
```
@@ -375,11 +375,11 @@ The Checkov adapter runs in the same GitHub Actions step as Checkov itself and t
### 12.7 Registry maintenance
Locked: L1 module publication updates the L1 registry in the same PR as the module. Registry and module land together. The registry is the IR-typed contract, not a Terraform-specific variable schema. The L1 registry, the central pipeline, and the policy schema all consume the same IR-typed contract — there is one source of truth for the L1 interface, not multiple substrate-specific copies.
Locked: L1 module publication updates the L1 registry in the same PR as the module. Registry and module land together. The registry is the stack-typed contract, not a Terraform-specific variable schema. The L1 registry, the central pipeline, and the policy schema all consume the same stack-typed contract — there is one source of truth for the L1 interface, not multiple substrate-specific copies.
### 12.8 Contract-schema-to-IR resolution
### 12.8 Contract-schema-to-stack resolution
The contract schema declares the consumer's intent in IR-typed terms. The central pipeline resolves the contract to a target stack (a list of L1 module instances with their inputs and the relationships between them). The Terraform adapter compiles the target stack to a Terraform execution plan. This resolution is substrate-agnostic — the target stack is in the IR.
The contract schema declares the consumer's intent in stack-typed terms. The central pipeline resolves the contract to a target stack (a list of L1 module instances with their inputs and the relationships between them). The Terraform adapter compiles the target stack to a Terraform execution plan. This resolution is substrate-agnostic — the target stack is in the stack schema.
🟡 OPEN (W3.D): L1/L2 standard versioning details, including pin model and evolution compatibility contract.
@@ -429,7 +429,7 @@ To finalize to v1.0:
1. Resolve the 11 open items in Section 13.
2. Validate the locked substrate abstraction against a real v1 implementation spike (one L1 module, one L2 thin-composition, one Terraform adapter, one contract submission end-to-end). The spike validates that the IR-shaped commitments do not require a polyglot mess.
2. Validate the locked substrate abstraction against a real v1 implementation spike (one L1 module, one L2 composition, one Terraform adapter, one contract submission end-to-end). The spike validates that the stack commitments do not require a polyglot mess.
3. Validate the locked HITL matrix against a tabletop exercise with QA and SRE.