Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e2d213c39 | |||
| de1657394e | |||
| 06dea7a176 | |||
| 7ea9a07be8 | |||
| cf44040009 | |||
| 4b8577df2e | |||
| 9aa9ece1df | |||
| 0f6d10a2b6 | |||
| 6d8c098205 | |||
| e33d6c890f | |||
| ec74060664 | |||
| 41c3377b96 | |||
| 76364c33c2 | |||
| aebc63127d |
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"run_id": "regr-1785177468",
|
||||
"run_at_utc": "2026-07-27T18:37:48Z",
|
||||
"run_id": "regr-1785329757",
|
||||
"run_at_utc": "2026-07-29T12:55:57Z",
|
||||
"milestone": "v1.10",
|
||||
"phase": 52,
|
||||
"summary": {
|
||||
"Verified": 16,
|
||||
"Verified": 22,
|
||||
"Decayed": 0,
|
||||
"Broken": 0
|
||||
},
|
||||
@@ -16,7 +16,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; 2 sample contracts validate",
|
||||
"tier": "local",
|
||||
"duration_ms": 245
|
||||
"duration_ms": 252
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-002",
|
||||
@@ -24,7 +24,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; env schema validates",
|
||||
"tier": "local",
|
||||
"duration_ms": 195
|
||||
"duration_ms": 196
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-003",
|
||||
@@ -32,7 +32,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; ",
|
||||
"tier": "local",
|
||||
"duration_ms": 260
|
||||
"duration_ms": 258
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-004",
|
||||
@@ -48,7 +48,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; ",
|
||||
"tier": "local",
|
||||
"duration_ms": 332
|
||||
"duration_ms": 314
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-006",
|
||||
@@ -56,7 +56,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; interpolation ok",
|
||||
"tier": "local",
|
||||
"duration_ms": 216
|
||||
"duration_ms": 223
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-007",
|
||||
@@ -64,7 +64,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; confidence band=pass",
|
||||
"tier": "local",
|
||||
"duration_ms": 90
|
||||
"duration_ms": 80
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-008",
|
||||
@@ -72,15 +72,15 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; outbox hash chain ok",
|
||||
"tier": "local",
|
||||
"duration_ms": 326
|
||||
"duration_ms": 358
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-009",
|
||||
"name": "offline pytest suite passes",
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; [ 98%]\ntests/test_wiz_adapter_real_client.py ......... [100%]\n\n====================== 475 passed, 2 deselected in 14.26s ======================",
|
||||
"detail": "exit 0; [ 98%]\ntests/test_wiz_adapter_real_client.py ......... [100%]\n\n====================== 462 passed, 2 deselected in 34.63s ======================",
|
||||
"tier": "local",
|
||||
"duration_ms": 15683
|
||||
"duration_ms": 36065
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-010",
|
||||
@@ -88,23 +88,23 @@
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; resource(s))\n\n=== PLATFORM CHECK OK ===\ncontract -> resolver -> stack -> adapter -> structure validated (offline, no AWS)\ncheck-only: OK\n\n=== CI PIPELINE OK ===\n3 stages passed: lint, test, check-only",
|
||||
"tier": "local",
|
||||
"duration_ms": 19489
|
||||
"duration_ms": 40668
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-011",
|
||||
"name": "headline E2E runs against the local emulating tier (microservice)",
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; al-emulator\",\n \"desired_count\": 1,\n \"running_count\": 1\n },\n \"outbox_dir\": \"/tmp/acdl_local_e2e_92qknwvi/outbox\",\n \"outbox_events\": 2,\n \"outbox_chain_verified\": true,\n \"lambda_status\": 200\n}",
|
||||
"detail": "exit 0; al-emulator\",\n \"desired_count\": 1,\n \"running_count\": 1\n },\n \"outbox_dir\": \"/tmp/acdl_local_e2e_416d0fmr/outbox\",\n \"outbox_events\": 2,\n \"outbox_chain_verified\": true,\n \"lambda_status\": 200\n}",
|
||||
"tier": "local",
|
||||
"duration_ms": 1076
|
||||
"duration_ms": 583
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-012",
|
||||
"name": "local E2E on the static-assets stack (no ECS)",
|
||||
"status": "Verified",
|
||||
"detail": "exit 0; acdl_local_e2e_ntp1b581/tf\",\n \"backend\": \"local\",\n \"ecs\": null,\n \"outbox_dir\": \"/tmp/acdl_local_e2e_ntp1b581/outbox\",\n \"outbox_events\": 2,\n \"outbox_chain_verified\": true,\n \"lambda_status\": 200\n}",
|
||||
"detail": "exit 0; acdl_local_e2e_ijhcj1z8/tf\",\n \"backend\": \"local\",\n \"ecs\": null,\n \"outbox_dir\": \"/tmp/acdl_local_e2e_ijhcj1z8/outbox\",\n \"outbox_events\": 2,\n \"outbox_chain_verified\": true,\n \"lambda_status\": 200\n}",
|
||||
"tier": "local",
|
||||
"duration_ms": 500
|
||||
"duration_ms": 489
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-013",
|
||||
@@ -112,7 +112,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "terraform init+validate+plan OK (live AWS, microservice)",
|
||||
"tier": "live-aws",
|
||||
"duration_ms": 28354
|
||||
"duration_ms": 28811
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-014",
|
||||
@@ -120,7 +120,7 @@
|
||||
"status": "Verified",
|
||||
"detail": "terraform init+validate+plan OK (live AWS, static-assets)",
|
||||
"tier": "live-aws",
|
||||
"duration_ms": 32121
|
||||
"duration_ms": 31772
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-015",
|
||||
@@ -128,15 +128,63 @@
|
||||
"status": "Verified",
|
||||
"detail": "acdl-outbox exists, item_count=9",
|
||||
"tier": "live-aws",
|
||||
"duration_ms": 564
|
||||
"duration_ms": 477
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-016",
|
||||
"name": "S3 state bucket exists + readable (live AWS)",
|
||||
"status": "Verified",
|
||||
"detail": "state bucket exists, keys=['spike/l2-microservice/terraform.tfstate']",
|
||||
"detail": "state bucket exists, keys=['platform/terraform.tfstate', 'spike/alb/dev/terraform.tfstate', 'spike/cdn/dev/terraform.tfstate', 'spike/ci-vpc/terraform.tfstate', 'spike/clus/dev/terraform.tfstate']",
|
||||
"tier": "live-aws",
|
||||
"duration_ms": 434
|
||||
"duration_ms": 324
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-017",
|
||||
"name": "DynamoDB acdl-contracts table (lifecycle pipeline evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "terraform files present + simple/complex contracts resolve",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 520
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-018",
|
||||
"name": "Lambda contract-ingestor (local stub + lifecycle evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "LocalLambdaStub instantiates (local tier evidence)",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 137
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-019",
|
||||
"name": "ECS cluster + service (L2 microservice lifecycle evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "L2 composition resolves (simple + complex contracts)",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 534
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-020",
|
||||
"name": "CloudFront + WAF (L2 static-assets lifecycle evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "L2 composition resolves (simple + complex contracts)",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 567
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-021",
|
||||
"name": "uptime-kuma (L1 uptime lifecycle evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "terraform files present + simple/complex contracts resolve",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 606
|
||||
},
|
||||
{
|
||||
"capability_id": "CAP-022",
|
||||
"name": "OIDC role (L1 iam-role lifecycle evidence)",
|
||||
"status": "Verified",
|
||||
"detail": "terraform files present + simple/complex contracts resolve",
|
||||
"tier": "lifecycle-pipeline",
|
||||
"duration_ms": 529
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,45 +1,51 @@
|
||||
# Regression Report — v1.10 Phase 52
|
||||
|
||||
- **Run ID:** `regr-1785177468`
|
||||
- **Run at (UTC):** 2026-07-27T18:37:48Z
|
||||
- **Summary:** {'Verified': 16, 'Decayed': 0, 'Broken': 0}
|
||||
- **Run ID:** `regr-1785329757`
|
||||
- **Run at (UTC):** 2026-07-29T12:55:57Z
|
||||
- **Summary:** {'Verified': 22, 'Decayed': 0, 'Broken': 0}
|
||||
- **Passed (milestone gate):** True
|
||||
|
||||
| Capability | Name | Tier | Status | Duration (ms) | Detail |
|
||||
|-----------|------|------|--------|--------------|--------|
|
||||
| CAP-001 | contract.schema.json validates sample contracts | local | **Verified** | 245 | exit 0; 2 sample contracts validate |
|
||||
| CAP-002 | environment.schema.json validates env files | local | **Verified** | 195 | exit 0; env schema validates |
|
||||
| CAP-003 | contract_resolver resolves static-assets | local | **Verified** | 260 | exit 0; |
|
||||
| CAP-001 | contract.schema.json validates sample contracts | local | **Verified** | 252 | exit 0; 2 sample contracts validate |
|
||||
| CAP-002 | environment.schema.json validates env files | local | **Verified** | 196 | exit 0; env schema validates |
|
||||
| CAP-003 | contract_resolver resolves static-assets | local | **Verified** | 258 | exit 0; |
|
||||
| CAP-004 | contract_resolver resolves microservice | local | **Verified** | 264 | exit 0; |
|
||||
| CAP-005 | terraform adapter emits .tf files | local | **Verified** | 332 | exit 0; |
|
||||
| CAP-006 | contract interpolation expands env/contract tokens | local | **Verified** | 216 | exit 0; interpolation ok |
|
||||
| CAP-007 | confidence_signal.compute returns a band | local | **Verified** | 90 | exit 0; confidence band=pass |
|
||||
| CAP-008 | outbox_writer builds a hash-chained item | local | **Verified** | 326 | exit 0; outbox hash chain ok |
|
||||
| CAP-009 | offline pytest suite passes | local | **Verified** | 15683 | exit 0; [ 98%]
|
||||
| CAP-005 | terraform adapter emits .tf files | local | **Verified** | 314 | exit 0; |
|
||||
| CAP-006 | contract interpolation expands env/contract tokens | local | **Verified** | 223 | exit 0; interpolation ok |
|
||||
| CAP-007 | confidence_signal.compute returns a band | local | **Verified** | 80 | exit 0; confidence band=pass |
|
||||
| CAP-008 | outbox_writer builds a hash-chained item | local | **Verified** | 358 | exit 0; outbox hash chain ok |
|
||||
| CAP-009 | offline pytest suite passes | local | **Verified** | 36065 | exit 0; [ 98%]
|
||||
tests/test_wiz_adapter_real_client.py ......... [100%]
|
||||
|
||||
====================== 475 passe |
|
||||
| CAP-010 | run_ci.sh reproduces CI pipeline locally | local | **Verified** | 19489 | exit 0; resource(s))
|
||||
====================== 462 passe |
|
||||
| CAP-010 | run_ci.sh reproduces CI pipeline locally | local | **Verified** | 40668 | exit 0; resource(s))
|
||||
|
||||
=== PLATFORM CHECK OK ===
|
||||
contract -> resolver -> stack -> adapter -> structure validated (offline, no AWS)
|
||||
check-only: OK
|
||||
|
||||
=== CI PIPELIN |
|
||||
| CAP-011 | headline E2E runs against the local emulating tier (microservice) | local | **Verified** | 1076 | exit 0; al-emulator",
|
||||
| CAP-011 | headline E2E runs against the local emulating tier (microservice) | local | **Verified** | 583 | exit 0; al-emulator",
|
||||
"desired_count": 1,
|
||||
"running_count": 1
|
||||
},
|
||||
"outbox_dir": "/tmp/acdl_local_e2e_92qknwvi/outbox",
|
||||
"outbox_dir": "/tmp/acdl_local_e2e_416d0fmr/outbox",
|
||||
"outbox_events": 2,
|
||||
"outbox |
|
||||
| CAP-012 | local E2E on the static-assets stack (no ECS) | local | **Verified** | 500 | exit 0; acdl_local_e2e_ntp1b581/tf",
|
||||
| CAP-012 | local E2E on the static-assets stack (no ECS) | local | **Verified** | 489 | exit 0; acdl_local_e2e_ijhcj1z8/tf",
|
||||
"backend": "local",
|
||||
"ecs": null,
|
||||
"outbox_dir": "/tmp/acdl_local_e2e_ntp1b581/outbox",
|
||||
"outbox_dir": "/tmp/acdl_local_e2e_ijhcj1z8/outbox",
|
||||
"outbox_events": 2,
|
||||
"outbox |
|
||||
| CAP-013 | terraform init+validate+plan live AWS (microservice) | live-aws | **Verified** | 28354 | terraform init+validate+plan OK (live AWS, microservice) |
|
||||
| CAP-014 | terraform init+validate+plan live AWS (static-assets) | live-aws | **Verified** | 32121 | terraform init+validate+plan OK (live AWS, static-assets) |
|
||||
| CAP-015 | DynamoDB outbox table exists (live AWS) | live-aws | **Verified** | 564 | acdl-outbox exists, item_count=9 |
|
||||
| CAP-016 | S3 state bucket exists + readable (live AWS) | live-aws | **Verified** | 434 | state bucket exists, keys=['spike/l2-microservice/terraform.tfstate'] |
|
||||
| CAP-013 | terraform init+validate+plan live AWS (microservice) | live-aws | **Verified** | 28811 | terraform init+validate+plan OK (live AWS, microservice) |
|
||||
| CAP-014 | terraform init+validate+plan live AWS (static-assets) | live-aws | **Verified** | 31772 | terraform init+validate+plan OK (live AWS, static-assets) |
|
||||
| CAP-015 | DynamoDB outbox table exists (live AWS) | live-aws | **Verified** | 477 | acdl-outbox exists, item_count=9 |
|
||||
| CAP-016 | S3 state bucket exists + readable (live AWS) | live-aws | **Verified** | 324 | state bucket exists, keys=['platform/terraform.tfstate', 'spike/alb/dev/terraform.tfstate', 'spike/cdn/dev/terraform.tfstate', 'spike/ci-vpc/terraform.tfstate', |
|
||||
| CAP-017 | DynamoDB acdl-contracts table (lifecycle pipeline evidence) | lifecycle-pipeline | **Verified** | 520 | terraform files present + simple/complex contracts resolve |
|
||||
| CAP-018 | Lambda contract-ingestor (local stub + lifecycle evidence) | lifecycle-pipeline | **Verified** | 137 | LocalLambdaStub instantiates (local tier evidence) |
|
||||
| CAP-019 | ECS cluster + service (L2 microservice lifecycle evidence) | lifecycle-pipeline | **Verified** | 534 | L2 composition resolves (simple + complex contracts) |
|
||||
| CAP-020 | CloudFront + WAF (L2 static-assets lifecycle evidence) | lifecycle-pipeline | **Verified** | 567 | L2 composition resolves (simple + complex contracts) |
|
||||
| CAP-021 | uptime-kuma (L1 uptime lifecycle evidence) | lifecycle-pipeline | **Verified** | 606 | terraform files present + simple/complex contracts resolve |
|
||||
| CAP-022 | OIDC role (L1 iam-role lifecycle evidence) | lifecycle-pipeline | **Verified** | 529 | terraform files present + simple/complex contracts resolve |
|
||||
|
||||
@@ -513,3 +513,100 @@ the restart branches off `v1.10.2`.
|
||||
- Operator-supplied evidence.
|
||||
- Pilot onboarding (G-001).
|
||||
- Boto3 post-deploy verification probes (CAP-017..022 live-verify via boto3) — deferred to a future QA milestone. The lifecycle pipeline apply→destroy IS the verification for v1.11.
|
||||
|
||||
---
|
||||
|
||||
## Milestone v1.12 — Presentation Refinement (REQ-129..REQ-133)
|
||||
|
||||
**Objective:** Refine the leadership presentation decks to reflect the
|
||||
verified reality after v1.11 — the stateless adapter, pipeline-driven
|
||||
lifecycle testing, the cost operating model, the pre-mortem, and the
|
||||
teardown to zero-cost. The v1.11 P65 deck-rewrite task did not fully land
|
||||
on the deck artifacts: the rendered HTML still claims 6 cloud
|
||||
capabilities are "deploy-unverified (IAM drift)", the road-to-north-star
|
||||
diagram still shows v1.10 as "NEXT", and the v1.11 architecture stories
|
||||
are absent. The v1.10 decay lesson (PRE_MORTEM.md FM-3) requires decks
|
||||
to match verified reality exactly, not outrun it. The v1.12 regression
|
||||
gate run (Phase 66) surfaced 3 Broken capabilities — one real adapter
|
||||
defect (CAP-013) and two regression-probe bugs (CAP-017, CAP-018) — that
|
||||
must be fixed before the decks can honestly claim 22/22 Verified.
|
||||
|
||||
**Surface:** leadership decks only (`docs/presentations/`) — both decks
|
||||
across all four layers (source markdown, Marp deck, rendered HTML,
|
||||
talking points) + diagrams + README. Plus the one real adapter fix and
|
||||
two probe fixes required to make the deck claims true.
|
||||
|
||||
### Requirements
|
||||
|
||||
- **REQ-129** — The adapter's module-call dedup logic
|
||||
(`adapters/terraform/adapter.py`) is fixed so multi-resource L1s with
|
||||
stack outputs (e.g. `ecs-service`, `alb`) produce valid Terraform:
|
||||
`terraform validate` succeeds for the microservice stack (CAP-013
|
||||
Verified live-aws). The regression gate re-runs and confirms 22/22
|
||||
Verified. (Phase 67)
|
||||
- **REQ-130** — The two regression-probe bugs are fixed: CAP-017's
|
||||
probe no longer requires `locals.tf` for modules that legitimately
|
||||
omit it (`core/regression_verify.py`); CAP-018's probe instantiates
|
||||
`LocalLambdaStub` with the required `outbox` arg. The regression gate
|
||||
re-runs clean (19 Verified + 3 fixed → 22/22 Verified). (Phase 67)
|
||||
- **REQ-131** — Both leadership decks' capability claims match
|
||||
`CAPABILITY_INVENTORY.md` exactly: 22/22 Verified, no
|
||||
"deploy-unverified" / "IAM drift" / "design-verified" framing. The
|
||||
decks reflect "Verified live-aws via lifecycle pipeline; torn down to
|
||||
zero-cost." A grep-based doc verification (successor to the planned
|
||||
`ci-doc-verifier`) confirms zero stale claims across
|
||||
`docs/presentations/`. (Phase 68, Phase 70)
|
||||
- **REQ-132** — Both decks reflect v1.11's architecture as
|
||||
leadership-relevant stories: (a) the stateless adapter
|
||||
(918→~80 lines, defaults centralized in per-module `terraform/`
|
||||
dirs, the adapter is an assembler); (b) pipeline-driven lifecycle
|
||||
testing (a `modules-lifecycle` pipeline matrix-runs each module
|
||||
apply→modify→destroy against live AWS — the green cell IS the
|
||||
verification). The `road-to-north-star` diagram + both decks' roadmap
|
||||
appendix slides reflect v1.11 complete (v1.10 no longer "NEXT").
|
||||
Version refs in deck examples bump from `@v1.10` → `@v1.11` (and
|
||||
`@v1.12` at Phase 70 complete after the tag exists). (Phase 68)
|
||||
- **REQ-133** — Both decks' "Operating Model & Cost" appendix slide
|
||||
carries the real `COST.md` figures ($0.001883 / 8 days, ~$0.007/mo,
|
||||
S3-dominated, zero BAU compute) + the zero-cost-steady-state /
|
||||
D-096 teardown claim, and references the pre-mortem
|
||||
(`PRE_MORTEM.md`: v1.10 decay root cause + four forward failure modes
|
||||
+ structural mitigations). Both rendered HTML decks re-rendered and
|
||||
committed; both talking-points files re-distilled to match the updated
|
||||
Marp structure (including the A6 Operating Model & Cost section that
|
||||
was missing from the talking points). PPTX exported to the v1.12.0
|
||||
release. (Phase 69, Phase 70)
|
||||
- **REQ-134** — The `modules-lifecycle` pipeline defaults to **plan-only**
|
||||
(fast, no AWS mutation) so it runs on every PR without cost or AWS
|
||||
credentials. A CI variable `ACDL_LIFECYCLE_MODE` (workflow input
|
||||
`lifecycle_mode`, default `plan`) overrides to `full` for the real
|
||||
apply→modify→destroy against live AWS. The four lifecycle scripts
|
||||
(`run_lifecycle_test.sh`, `run_lifecycle_destroy.sh`,
|
||||
`run_l2_lifecycle_test.sh`, `run_l2_lifecycle_destroy.sh`) read the
|
||||
flag and dispatch to `--plan-only` (plan mode) or `--apply`/`--destroy`
|
||||
(full mode). Both forge workflows (`.github` + `.gitea`, byte-identical)
|
||||
expose `lifecycle_mode` as a `workflow_dispatch` input and pass it via
|
||||
`env:` to every lifecycle step; the CI VPC apply/destroy jobs are
|
||||
skipped in plan mode. `pipelines/modules-lifecycle.yml` + the schema
|
||||
document the `default_mode: plan` field. Tests assert the plan-only
|
||||
default, the override path, the byte-identity of both workflows, and
|
||||
the CI VPC skip in plan mode. (Phase 67b)
|
||||
|
||||
### v1.12 Traceability
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| REQ-129 | P67 | complete |
|
||||
| REQ-130 | P67 | complete |
|
||||
| REQ-134 | P67b | complete |
|
||||
| REQ-131 | P68, P70 | complete |
|
||||
| REQ-132 | P68 | complete |
|
||||
| REQ-133 | P69, P70 | complete |
|
||||
|
||||
### Out of Scope (v1.12)
|
||||
- docs/ site, README.md, consumer-guide, module READMEs (decks only).
|
||||
- Structural deck rework (re-ordering, adding/removing main slides) —
|
||||
v1.12 keeps the 10 main + 6 appendix structure to avoid the
|
||||
backwards-sequencing failure mode (PRE_MORTEM.md FM-3).
|
||||
- New capability claims beyond what v1.11 verified.
|
||||
- Per-phase regression hardening (G-007, unchanged).
|
||||
|
||||
@@ -538,4 +538,158 @@ All v1.11 binding decisions (D-097..D-107) were committed in the CLARIFY
|
||||
stage (`80b7286`) before this research ran. This research *grounds* those
|
||||
decisions with codebase evidence; it does not surface new binding
|
||||
decisions. The decisions are summarized in §Background above and
|
||||
documented in full in the CLARIFY commit.
|
||||
documented in full in the CLARIFY commit.
|
||||
|
||||
---
|
||||
|
||||
# v1.12 Addendum — Presentation Refinement Research
|
||||
|
||||
> Generated: 2026-07-29. Phase 66. Milestone v1.12.
|
||||
> Mode: docs-only NFR milestone focused on the leadership decks.
|
||||
> Surface: `docs/presentations/` (PW + DX, all four layers) + one real
|
||||
> adapter fix + two probe fixes required to make deck claims true.
|
||||
|
||||
## Background — why v1.12 exists
|
||||
|
||||
v1.11 (P56a–P65) landed the stateless adapter, pipeline-driven
|
||||
lifecycle testing, single platform VPC, `COST.md`, `PRE_MORTEM.md`, and
|
||||
a teardown to zero-cost. P65's plan (REQ-118) required the decks to be
|
||||
rewritten to "Verified live-aws via lifecycle pipeline; torn down to
|
||||
zero-cost." That rewrite did not fully land on the deck artifacts. This
|
||||
research is a drift audit: a systematic comparison of the deck artifacts
|
||||
against the v1.11-verified reality.
|
||||
|
||||
## FINDING 1 — Drift audit (9 items)
|
||||
|
||||
Systematic comparison of `docs/presentations/*` against
|
||||
`.ciagent/CAPABILITY_INVENTORY.md`, `.ciagent/COST.md`,
|
||||
`.ciagent/PRE_MORTEM.md`, `.ciagent/ROADMAP.md`, and `git log`.
|
||||
|
||||
1. **Wrong verification status.** Both rendered HTML decks still say
|
||||
"6 cloud capabilities are design-verified + locally emulated,
|
||||
deploy-unverified (IAM drift)" (PW "Testing vs. Planned" slide;
|
||||
DX slide A6). `CAPABILITY_INVENTORY.md` says 22/22 Verified and the
|
||||
IAM-drift framing was *removed* in P65. The decks contradict the
|
||||
inventory. Verified: `grep -c "deploy-unverified\|IAM drift\|design-verified"
|
||||
docs/presentations/*.html` → 3 hits per deck.
|
||||
2. **Re-verification header stale.** Both source `.md` headers say
|
||||
"Re-verification (2026-07-27)… v1.10 Phase 54… 16/16… 6 IAM-gated
|
||||
escalated." Should reflect v1.11: 22/22 Verified, torn down.
|
||||
3. **Road to the North Star diagram stale.**
|
||||
`docs/presentations/assets/mmd/road-to-north-star.mmd` shows v1.10 as
|
||||
"NEXT" with "HITL wiring / all-runner OIDC / regulatory ledger". v1.11
|
||||
is complete; the diagram must advance.
|
||||
4. **Rendered HTML not re-rendered.** `git log` shows the HTML was last
|
||||
touched at `10b87a6` (P57), *before* v1.11. P65's "re-render HTML"
|
||||
task did not reach the rendered artifacts.
|
||||
5. **Version refs stale.** Decks reference `@v1.10` in deploy.yml `uses:`
|
||||
snippets (Safe Promotion Path, Safe Decommission). Ship tag is now
|
||||
`v1.11.0`; will be `v1.12.0` at Phase 70 complete.
|
||||
6. **Cost story has no real numbers.** `COST.md` exists ($0.001883 over
|
||||
8 days, ~$0.007/mo, S3-dominated, zero BAU compute) but the decks' A6
|
||||
"Operating Model & Cost" slide is generic prose with no figures.
|
||||
7. **Pre-mortem unreferenced.** P65 planned to add a pre-mortem
|
||||
reference; `PRE_MORTEM.md` exists (v1.10 decay root cause + four
|
||||
forward failure modes) but no deck slide references it.
|
||||
8. **Two v1.11 stories absent.** (a) Architectural simplicity: adapter
|
||||
918→~80 lines, defaults centralized in per-module `terraform/` dirs.
|
||||
(b) Verifiable deploys: a `modules-lifecycle` pipeline matrix-runs
|
||||
each module apply→modify→destroy against live AWS. Neither is in the
|
||||
decks.
|
||||
9. **Duplicated story-beat lines.** `how-the-platform-works.md` slides
|
||||
3–10 each repeat their intro line twice (a copy-paste artifact).
|
||||
|
||||
## FINDING 2 — Regression gate surfaces real decay (D-091)
|
||||
|
||||
The v1.12 regression gate run (Phase 66) re-ran the D-091 regression
|
||||
gate to back every deck claim. It found **3 Broken capabilities**:
|
||||
`{'Verified': 19, 'Decayed': 0, 'Broken': 3}`.
|
||||
|
||||
### CAP-013 — live-aws — REAL platform defect (Class A)
|
||||
|
||||
`adapters/terraform/adapter.py:159-172` (the `seen` dedup loop)
|
||||
collapses the two `ecs-service` sub-resources (`service-task-definition`
|
||||
+ `service-service`, both module `ecs-service@1.0.0`) into ONE
|
||||
`module "service-task-definition"` block. But the stack output
|
||||
`service_arn` (resolver `from: "service-service"`) is emitted as
|
||||
`value = module.service-service.service_arn` — referencing a module
|
||||
call that was never emitted. `terraform validate` fails: "No module
|
||||
call name." The same defect silently breaks the `alb` L1 too. Static-
|
||||
assets (CAP-014) doesn't hit it because its L1s are single-resource.
|
||||
**Classification A — real platform defect.** The adapter produces
|
||||
invalid Terraform for any multi-resource L1 with stack-level outputs.
|
||||
**Fix required before decks can claim 22/22 Verified.**
|
||||
|
||||
### CAP-017 — lifecycle-pipeline — regression-probe bug (Class B/C)
|
||||
|
||||
`core/regression_verify.py:444` hardcodes
|
||||
`required = ["versions.tf", "variables.tf", "locals.tf", "main.tf",
|
||||
"outputs.tf"]`. The CAP-017 probe targets the `rds` L1 module, whose
|
||||
`main.tf` uses only `var.*` and `aws_db_subnet_group.this` — no `local.*`
|
||||
references, so `locals.tf` is legitimately absent. The probe is over-
|
||||
strict. The rds module is correctly structured; the capability works.
|
||||
**Classification B/C — trivial probe fix.** Drop `locals.tf` from the
|
||||
required list, or make it conditional on `local.` usage.
|
||||
|
||||
### CAP-018 — lifecycle-pipeline — regression-probe bug (Class B/C)
|
||||
|
||||
`core/local_emulators.py:273` defines `LocalLambdaStub` as a dataclass
|
||||
with one required field `outbox: FlatFileOutbox`. Every real caller
|
||||
passes it (`core/local_emulators.py:464`, the tests). The CAP-018 probe
|
||||
at `core/regression_verify.py:486-491` is the *only* caller that
|
||||
instantiates it bare: `LocalLambdaStub()` → `TypeError`. The probe was
|
||||
added in P63 and never aligned with the real signature. The capability
|
||||
is exercised green by CAP-011. **Classification B/C — trivial probe
|
||||
fix.** Pass an `outbox` to the constructor.
|
||||
|
||||
### Implication for the decks
|
||||
|
||||
`CAPABILITY_INVENTORY.md` claims 22/22 Verified, but the regression
|
||||
gate (D-091 — the exact mechanism PRE_MORTEM.md FM-3 says backs every
|
||||
deck claim) shows CAP-013 is genuinely broken. **The inventory
|
||||
overstates.** v1.12 cannot ship decks claiming 22/22 until CAP-013 is
|
||||
fixed and the gate re-runs clean. This is the structural mitigation the
|
||||
pre-mortem requires (verified-only claims; decks unfrozen only after
|
||||
re-verification). The user decision: fix the defect inside v1.12
|
||||
(Phase 67), then the decks can honestly claim 22/22.
|
||||
|
||||
## FINDING 3 — Talking points structure gap
|
||||
|
||||
Both talking-points files have only 5 appendix sections (A1–A5) while
|
||||
the Marp decks have 6 (A6 = "Operating Model & Cost"). The A6 content
|
||||
exists in the Marp deck and source markdown but was never distilled
|
||||
into the talking points. The re-distill step (Phase 69) must add the
|
||||
A6 section to both talking-points files.
|
||||
|
||||
## FINDING 4 — Versioning facts
|
||||
|
||||
- Current ship tag: `v1.11.0` (v1.11 complete).
|
||||
- `deploy.yml` still references `v1.9` in comments + `ref: v1.9` —
|
||||
v1.11 apparently did not bump the deploy workflow `uses:` tag (the
|
||||
bump is a separate concern; decks use the current ship tag).
|
||||
- Decks should show `@v1.11` in examples (current state); Phase 70
|
||||
bumps to `@v1.12` after the tag exists.
|
||||
|
||||
## Assumptions logged
|
||||
|
||||
- No automated `ci-doc-verifier` script exists in the repo. The plan's
|
||||
"ci-doc-verifier confirms" is satisfied by a manual grep-based
|
||||
verification recorded in the Phase 70 VERIFY step (consistent with how
|
||||
prior NFR-patch phases handled it). Confidence 0.90 — verified by
|
||||
`ls scripts/ | grep doc` and `grep -rl deck tests/`.
|
||||
- PPTX export requires Chromium + Marp CLI; the environment has it
|
||||
(`/root/.cache/ms-playwright/chromium-1217/chrome-linux64/chrome`).
|
||||
PPTX is uploaded to the Gitea release, not committed. Confidence
|
||||
0.85 — README documents the path; the chromium binary exists.
|
||||
|
||||
## Decisions surfaced (research → bound in CLARIFY-equivalent)
|
||||
|
||||
- **D-108** — v1.12 includes one real adapter fix (CAP-013) and two
|
||||
probe fixes (CAP-017, CAP-018) as Phase 67 prerequisites, so the decks
|
||||
can honestly claim 22/22 Verified. The milestone is "presentation
|
||||
refinement" but the verified-only-claims pre-mortem mitigation makes
|
||||
the fixes mandatory. The user confirmed this scope (interactive
|
||||
decision, 2026-07-29).
|
||||
- **D-109** — Decks use `@v1.11` in examples during Phase 68 (current
|
||||
state), bumped to `@v1.12` at Phase 70 complete after the tag exists.
|
||||
Avoids a dangling reference to a tag that doesn't exist yet.
|
||||
@@ -22,7 +22,9 @@
|
||||
- **v1.10 (complete, tag `v1.10.0`):** pipeline regression fix + capability re-verification + verified-reality rewrite. The v1.9.1–v1.9.8 deck work is **superseded-by-reverification**: the decks presented advertised capability as current without disclosing that the platform had decayed (7 adapter defects prevented `terraform init/validate/plan` against live AWS). v1.10 re-verified every advertised capability, fixed all 7 defects in-sweep (D-090: no cap), and rewrote PROJECT/ROADMAP/decks to match verified reality. Decks unfrozen only after Phase 55 lands. See the v1.10 section below for the 4-phase breakdown.
|
||||
- **v1.10.1 (complete, tag `v1.10.1`):** post-v1.10 NFR patch — adversarial grill review (12 challenges, 10 binding decisions, 2 escalations: G-005 risks, G-008 budget), 4-layer verify gate (PASS), multi-persona code review (1 P1 auto-fixed: mis-citation PROJECT.md:6 → PROJECT.md:487). ACDL reclassified as OSS reference implementation (G-003). Docs-only; 518 tests pass; regression gate 16/16 Verified. Gitea release id 236.
|
||||
- **v1.10.2 (complete, tag `v1.10.2`):** contract surface redesign + rename + .yml repo-wide + deck polish. Breaking contract schema change: new top-level fields `id`/`name`/`infrastructure`; dropped `uses:`/`module:`/`inputs:`. All 44 `.yaml` → `.yml`. Code review: 3 P0 auto-fixed, 2 P1+ flagged. 494 tests pass. Gitea release id 237.
|
||||
- **v1.11 (active, tag `v1.11.0`):** RESTART — stateless adapter + pipeline-driven module lifecycle testing. Closes G-005 (CAP-017..022 deploy-unverified) and G-008 (no cost docs) via a corrected architecture, not the failed v1.11 first attempt (which produced 4 drifted VPCs, ran terraform apply from Python, and had no module lifecycle tests). The restart branches off `v1.10.2` and rebuilds v1.11 on three corrections: (1) the terraform adapter becomes a stateless assembler — each L1 module ships a real `terraform/` module dir (variables/locals/main/outputs) owning its resource shape, nested blocks, and defaults; the adapter deletes `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` and all 39 type-specific branches, becoming a ~80-line assembler that emits `module "x" { source = ... }` blocks; (2) lifecycle is owned by terraform via the shell orchestrator (`run_platform.sh --apply`/`--destroy`), never by Python — `verify_deploy_microservice.py` is deleted; (3) testing is pipeline-driven — a `modules-lifecycle` pipeline (Gitea + GitHub, byte-identical) matrix-runs each L1 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS; no per-module Python. A single platform VPC (`terraform/platform`) is shared by all stacks via `data` source — no per-contract VPC. State keys are deterministic and env-aware (`spike/{id}/{env}/terraform.tfstate`), stable across lifecycle changes. 13 phases (P56a–P65). See the v1.11 section below for the phase breakdown.
|
||||
- **v1.11 (complete, tag `v1.11.0`):** RESTART — stateless adapter + pipeline-driven module lifecycle testing. Closes G-005 (CAP-017..022 deploy-unverified) and G-008 (no cost docs) via a corrected architecture, not the failed v1.11 first attempt (which produced 4 drifted VPCs, ran terraform apply from Python, and had no module lifecycle tests). The restart branches off `v1.10.2` and rebuilds v1.11 on three corrections: (1) the terraform adapter becomes a stateless assembler — each L1 module ships a real `terraform/` module dir (variables/locals/main/outputs) owning its resource shape, nested blocks, and defaults; the adapter deletes `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` and all 39 type-specific branches, becoming a ~80-line assembler that emits `module "x" { source = ... }` blocks; (2) lifecycle is owned by terraform via the shell orchestrator (`run_platform.sh --apply`/`--destroy`), never by Python — `verify_deploy_microservice.py` is deleted; (3) testing is pipeline-driven — a `modules-lifecycle` pipeline (Gitea + GitHub, byte-identical) matrix-runs each L1 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS; no per-module Python. A single platform VPC (`terraform/platform`) is shared by all stacks via `data` source — no per-contract VPC. State keys are deterministic and env-aware (`spike/{id}/{env}/terraform.tfstate`), stable across lifecycle changes. 13 phases (P56a–P65). See the v1.11 section below for the phase breakdown.
|
||||
- **v1.12 (complete, tag `v1.12.0`):** Presentation Refinement — the leadership decks synced to the v1.11-verified reality (22/22 Verified, stateless adapter, lifecycle pipeline, cost figures, pre-mortem). Includes the CAP-013 adapter dedup fix + 2 probe fixes (required to make the deck claims true) + the ACDL_LIFECYCLE_MODE CI flag (lifecycle tests default to plan-only, full on override). 6 phases (P66–P70). See the v1.12 section below.
|
||||
- **v1.13 (complete, tag `v1.13.0`):** Presentation Polish — both leadership decks polished across all 4 pipeline layers (source .md → -marp.md → .html → -talking-points.md). Action headlines replace category names; story-arc restructure (Intro ~10% / Body ~80% / Conclusion ~10%); removed all transition story lines; bullets ≤12 words, 3–4 per main slide; larger fonts (body 26px, h1 40px, h2 32px); 6 new mermaid diagrams (frictions 2×2, north-star before/after, zero-trust flow, catalog primitives→modules, decommission gates, semver timeline). Code review: 0 P0, 2 P1 auto-fixed (slide-count metadata + README directory layout). 522 tests pass. Docs-only NFR patch. 1 phase (P71). See the v1.13 section below.
|
||||
- **v1.0 demo URL:** https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html
|
||||
|
||||
---
|
||||
@@ -886,3 +888,134 @@ Wave 4 (P63 → P64 → P65) closes G-005/G-008 + teardown + deck rewrite.
|
||||
|
||||
After Phase P65: COMPLETE gate — review → ship `v1.11.0` (next minor;
|
||||
feature milestone) → audit. **DONE.**
|
||||
|
||||
## v1.12 (complete — Presentation Refinement, tag `v1.12.0`)
|
||||
|
||||
The v1.12 milestone refines the leadership presentation decks to reflect
|
||||
the verified reality after v1.11. The v1.11 P65 deck-rewrite task did not
|
||||
fully land on the deck artifacts: the rendered HTML still claimed 6 cloud
|
||||
capabilities were "deploy-unverified (IAM drift)", the road-to-north-star
|
||||
diagram still showed v1.10 as "NEXT", and the v1.11 architecture stories
|
||||
(stateless adapter, pipeline-driven lifecycle testing) were absent. The
|
||||
v1.10 decay lesson (PRE_MORTEM.md FM-3) requires decks to match verified
|
||||
reality exactly, not outrun it.
|
||||
|
||||
**Scope:** leadership decks only (`docs/presentations/`) across all four
|
||||
layers (source markdown, Marp deck, rendered HTML, talking points) +
|
||||
diagrams + README. Plus one real adapter fix + two probe fixes required to
|
||||
make the deck claims true, and a CI lifecycle-mode flag (REQ-134) that
|
||||
defaults the lifecycle tests to plan-only.
|
||||
|
||||
**Why the code fixes.** The v1.12 regression gate run (Phase 66) found
|
||||
CAP-013 (a real adapter dedup defect — multi-resource L1s produced invalid
|
||||
Terraform) + CAP-017/018 (two regression-probe bugs). The inventory's
|
||||
"22/22 Verified" claim was overstated until CAP-013 was fixed. The pre-
|
||||
mortem mitigation (verified-only claims) made the fixes mandatory.
|
||||
|
||||
**Why the lifecycle flag.** The lifecycle pipeline defaulted to full
|
||||
apply→modify→destroy, which requires AWS credentials + cost on every PR.
|
||||
REQ-134 adds the `ACDL_LIFECYCLE_MODE` CI variable (workflow_dispatch
|
||||
input `lifecycle_mode`, default `plan`) so the pipeline runs plan-only on
|
||||
every PR (fast, no AWS mutation, no cost) and full only on override.
|
||||
|
||||
### Phase breakdown (6 phases)
|
||||
|
||||
- **P66 — init + research.** Drift audit (9 items) comparing
|
||||
`docs/presentations/*` against v1.11-verified reality. Regression gate
|
||||
(D-091) re-run surfaced 3 Broken capabilities; root-cause analysis
|
||||
classified CAP-013 (real adapter defect), CAP-017/018 (probe bugs).
|
||||
REQ-129..133 added.
|
||||
- **P67 — fix adapter dedup + 2 probe bugs (REQ-129/130).** The adapter's
|
||||
module-call dedup logic rewritten: multi-resource L1s (ecs-service, alb)
|
||||
now emit ONE module block named by the composition child id, with
|
||||
expanded sub-ids rewritten via id_remap (stack outputs + cross-module
|
||||
ref: inputs). terraform validate succeeds for the microservice; adapter
|
||||
192 lines (< 200 gate). CAP-017 probe: locals.tf conditional on local.*
|
||||
usage. CAP-018 probe: LocalLambdaStub constructed with the required
|
||||
outbox arg. Regression gate: 22/22 Verified.
|
||||
- **P67b — lifecycle tests plan-only default + ACDL_LIFECYCLE_MODE flag
|
||||
(REQ-134).** The four lifecycle scripts dispatch to --plan-only (plan
|
||||
mode, default) or --apply/--destroy (full mode). Both workflows
|
||||
(byte-identical) expose lifecycle_mode as a workflow_dispatch input;
|
||||
CI VPC jobs skipped in plan mode. 24 new tests.
|
||||
- **P68 — sync decks source .md (REQ-131/132).** Re-verification headers
|
||||
→ 22/22 Verified. De-duplicated story-beat lines. Version refs
|
||||
@v1.10 → @v1.11. road-to-north-star.mmd re-rendered. New A6 (real
|
||||
COST.md figures + pre-mortem) + A7 (stateless adapter + lifecycle
|
||||
pipeline + plan-only default) in both decks.
|
||||
- **P69 — Marp + talking points + HTML render (REQ-133).** Re-synthesized
|
||||
both Marp decks (10 main + 7 appendix = 17 slides). Re-distilled both
|
||||
talking-points files (added the missing A6/A7 sections). Re-rendered
|
||||
both HTML (committed). Exported both PPTX (held for the v1.12.0
|
||||
release).
|
||||
- **P70 — verify + review + complete.** Multi-persona code review: no P0;
|
||||
2 P1 testing gaps remediated (6 CAP-013 regression tests added —
|
||||
terraform validate + dedup unit assertions). Audit clean. 522 tests
|
||||
pass. Ship v1.12.0.
|
||||
|
||||
**Outcome:** the decks now honestly claim 22/22 Verified (backed by the
|
||||
regression gate), reflect the v1.11 architecture (stateless adapter +
|
||||
lifecycle pipeline), carry the real cost figures + pre-mortem, and the
|
||||
lifecycle pipeline defaults to plan-only. The v1.10 "deploy-unverified
|
||||
(IAM drift)" framing is disclosed as closed, not hidden.
|
||||
|
||||
Ship tag at milestone COMPLETE: `v1.12.0` (v1.11.0 → v1.12.0; feature
|
||||
milestone — includes the adapter fix + lifecycle flag). **DONE.**
|
||||
|
||||
## v1.13 (complete — Presentation Polish, tag `v1.13.0`)
|
||||
|
||||
The v1.13 milestone polishes both leadership decks for clarity, impact, and
|
||||
storytelling best practices. It is a docs-only NFR patch — no code, no
|
||||
capability claims changed, no schema changes.
|
||||
|
||||
**Why.** The v1.12 decks were factually correct but rhetorically flat:
|
||||
category-name headlines ("The Contract-Driven Model", "Zero-Trust by
|
||||
Default"), dense 5–6 bullet slides, formulaic italic transition lines on
|
||||
every slide, and body fonts at 22px (below the 24pt readability floor).
|
||||
v1.13 applies the storytelling + design best practices the leadership
|
||||
audience requires.
|
||||
|
||||
**What changed.** Both decks (`how-the-platform-works` + `the-developer-experience`)
|
||||
across all 4 pipeline layers (source `.md` → `-marp.md` → `.html` →
|
||||
`-talking-points.md`):
|
||||
|
||||
- **Action headlines** replace category names — each slide title states the
|
||||
takeaway, not the topic ("One YAML file. The platform owns everything
|
||||
else." not "The Contract-Driven Model").
|
||||
- **Story-arc restructure** — Intro ~10% / Body ~80% (3–5 points) /
|
||||
Conclusion ~10%. Before/after 2-slide sequence on Problem → North Star.
|
||||
- **Removed all `<em class="story">` transition lines** — flow now carried
|
||||
by action headlines + talking points (saved ~15–20 words × 17 slides).
|
||||
- **Bullets ≤12 words, 3–4 per main slide** (was 5–6). Cut parentheticals,
|
||||
sub-clauses, redundant restatements.
|
||||
- **Larger fonts** — body 22→26px, h1 34→40px, h2 26→32px, blockquote
|
||||
20→24px. High contrast preserved, no animations, maturity badges intact.
|
||||
- **6 new mermaid diagrams** → PNGs:
|
||||
- `platform-works-02-frictions` (2×2 quadrant of the four frictions)
|
||||
- `platform-works-03-north-star` (before/after: today's queue vs. ACDL)
|
||||
- `platform-works-07-zero-trust` (OIDC + ABAC flow)
|
||||
- `developer-experience-05-catalog` (primitives → composed modules)
|
||||
- `developer-experience-07-decommission` (6-node gate flow with 2 SRE gates)
|
||||
- `developer-experience-08-semver` (floating/pinned/major-only timeline)
|
||||
- **Appendix expanded** — "Security by Construction" (formerly a dense main
|
||||
slide) moved to appendix A3; platform deck now 10 main + TOC + 8 appendix
|
||||
(19 slides); developer deck 10 main + TOC + 7 appendix (18 slides).
|
||||
|
||||
**Phases:**
|
||||
|
||||
- **P71 — deck polish (single phase).** Restructured both decks across all
|
||||
4 layers. Created 6 new `.mmd` + 6 new `.png` files. Re-rendered both
|
||||
HTML. Re-distilled both talking-points to match the new slide structure.
|
||||
Multi-persona code review: 0 P0, 2 P1 auto-fixed (slide-count metadata in
|
||||
source `.md` headers + `README.md` directory layout drifted — both
|
||||
synced). 522 tests pass. No code files touched.
|
||||
|
||||
**Outcome:** the decks now read as a story (problem → solution → evidence),
|
||||
each slide has one idea with an action headline, the body is scannable in
|
||||
2 seconds, and the visuals carry the mechanism where bullets undersold it.
|
||||
22/22 Verified framing, badge statuses, and capability claims preserved
|
||||
verbatim from v1.12. No factual drift.
|
||||
|
||||
Ship tag at milestone COMPLETE: `v1.13.0` (v1.12.0 → v1.13.0; docs-only NFR
|
||||
patch — final patch IS the deliverable, no separate milestone tag).
|
||||
**DONE.**
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
{
|
||||
"mode": "single",
|
||||
"projects": [
|
||||
{
|
||||
"slug": "acdl",
|
||||
"name": "Agentic Cloud Delivery Platform",
|
||||
"milestone": "v1.11",
|
||||
"status": "active",
|
||||
"restart": true,
|
||||
"restart_branch": "milestone/v1.11-restart",
|
||||
"restart_base": "v1.10.2"
|
||||
"default": true
|
||||
}
|
||||
],
|
||||
"active_project": "acdl",
|
||||
"active_projects": ["acdl"],
|
||||
"autonomy": {
|
||||
"level": "full",
|
||||
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"],
|
||||
@@ -37,22 +33,176 @@
|
||||
"security": {
|
||||
"auto_accept_low_severity": true,
|
||||
"auto_mitigate_medium_severity": true,
|
||||
"escalate_high_severity": true
|
||||
"escalate_high_severity": true,
|
||||
"bash_allowlist": {
|
||||
"allowed_commands": [
|
||||
"npm", "node", "npx", "pnpm", "yarn",
|
||||
"git", "ls", "cat", "head", "tail", "wc",
|
||||
"echo", "mkdir", "cp", "mv", "rm", "touch",
|
||||
"pwd", "which", "env", "printenv",
|
||||
"jest", "eslint", "tsc", "prettier",
|
||||
"curl", "wget",
|
||||
"docker", "docker-compose",
|
||||
"ts-node", "tsx"
|
||||
],
|
||||
"max_output_bytes": 1048576,
|
||||
"timeout_ms": 30000,
|
||||
"blocked_env_vars": [
|
||||
"HOME", "PATH", "USER", "SHELL",
|
||||
"AWS_*", "*_TOKEN", "*_KEY", "*_SECRET",
|
||||
"*_PASSWORD", "*_CREDENTIAL",
|
||||
"GITHUB_TOKEN", "GITHUB_API_KEY",
|
||||
"OPENAI_API_KEY", "ANTHROPIC_API_KEY",
|
||||
"OLLAMA_CLOUD_API_KEY"
|
||||
]
|
||||
}
|
||||
},
|
||||
"git": {
|
||||
"branching_strategy": "phase",
|
||||
"auto_commit": true,
|
||||
"auto_push": true
|
||||
},
|
||||
"secrets": {
|
||||
"sources": [".env", ".env.secrets", ".env.*"],
|
||||
"disallow": ["shell_env", "netrc", "keychain", "rc_files", "global_config"],
|
||||
"scopes": {
|
||||
"gitea": "ACDL_GITEA_TOKEN",
|
||||
"github": "GITHUB_TOKEN",
|
||||
"gitlab": "GITLAB_TOKEN",
|
||||
"openai": "OPENAI_API_KEY",
|
||||
"anthropic": "ANTHROPIC_API_KEY",
|
||||
"ollama_cloud": "OLLAMA_CLOUD_API_KEY"
|
||||
}
|
||||
},
|
||||
"release": {
|
||||
"forge": "gitea",
|
||||
"gitea": {
|
||||
"base_url": "https://git.cloudinit.dev",
|
||||
"owner": "continuous-intelligence",
|
||||
"repo": "acdl",
|
||||
"token_scope": "gitea"
|
||||
},
|
||||
"github": {
|
||||
"owner": "",
|
||||
"repo": "",
|
||||
"token_scope": "github"
|
||||
},
|
||||
"gitlab": {
|
||||
"base_url": "",
|
||||
"owner": "",
|
||||
"repo": "",
|
||||
"token_scope": "gitlab"
|
||||
}
|
||||
},
|
||||
"ship": {
|
||||
"per_phase": true,
|
||||
"require_release": true,
|
||||
"allow_skip": false,
|
||||
"confirm_before_ship": false,
|
||||
"max_release_retries": 3,
|
||||
"release_blocking": false
|
||||
},
|
||||
"backend": {
|
||||
"provider": "auto",
|
||||
"agent_backends": {
|
||||
"opencode": { "enabled": true },
|
||||
"codex": { "enabled": true },
|
||||
"claude-code": { "enabled": true },
|
||||
"hermes": { "enabled": true }
|
||||
},
|
||||
"llm_backends": {
|
||||
"openai": {
|
||||
"base_url": "https://api.openai.com/v1",
|
||||
"api_key_env": "OPENAI_API_KEY",
|
||||
"model": "gpt-4o",
|
||||
"model_profile": "quality",
|
||||
"timeout_ms": 60000
|
||||
},
|
||||
"ollama-local": {
|
||||
"base_url": "http://localhost:11434",
|
||||
"model_profile": "balanced"
|
||||
},
|
||||
"ollama-cloud": {
|
||||
"base_url": "",
|
||||
"api_key_env": "OLLAMA_CLOUD_API_KEY",
|
||||
"model_profile": "quality",
|
||||
"timeout_ms": 60000
|
||||
},
|
||||
"anthropic": {
|
||||
"base_url": "https://api.anthropic.com",
|
||||
"api_key_env": "ANTHROPIC_API_KEY",
|
||||
"model": "claude-sonnet-4-20250514",
|
||||
"api_version": "2023-06-01",
|
||||
"model_profile": "quality",
|
||||
"timeout_ms": 60000
|
||||
}
|
||||
}
|
||||
},
|
||||
"ideation": {
|
||||
"enabled": true,
|
||||
"categories": ["security", "quality", "architecture", "coverage", "improvement"],
|
||||
"confidence_threshold": 0.6,
|
||||
"max_ideas": 20,
|
||||
"external_signals": {
|
||||
"npm_audit": true,
|
||||
"osv_advisories": true,
|
||||
"dependency_staleness": true
|
||||
},
|
||||
"cross_project": {
|
||||
"enabled": false,
|
||||
"similarity_weight": 0.5
|
||||
},
|
||||
"chaos": {
|
||||
"enabled": true,
|
||||
"scenarios": ["backend_unavailable", "requirement_change", "test_coverage_drop"]
|
||||
}
|
||||
},
|
||||
"sessions": {
|
||||
"max_concurrent_sessions": 3,
|
||||
"session_timeout_ms": 3600000,
|
||||
"session_isolation": "branch"
|
||||
},
|
||||
"gitea": {
|
||||
"base_url": "https://git.cloudinit.dev",
|
||||
"api_token_env": "ACDL_GITEA_TOKEN",
|
||||
"owner": "continuous-intelligence",
|
||||
"repo": "acdl"
|
||||
"personas": {
|
||||
"enabled": true,
|
||||
"territory_enforcement": "warn",
|
||||
"personas": [
|
||||
{
|
||||
"name": "lead-developer",
|
||||
"domain": "coordination",
|
||||
"frameworks": [],
|
||||
"constraints": ["pragmatic", "battle-tested defaults"],
|
||||
"territory": []
|
||||
},
|
||||
{
|
||||
"name": "data-engineer",
|
||||
"domain": "data",
|
||||
"frameworks": ["drizzle", "postgresql"],
|
||||
"constraints": ["schema-first", "type-safe ORM", "migration-driven"],
|
||||
"territory": ["**/migrations/**", "**/schema/**", "**/models/**", "**/db/**", "prisma/schema.prisma", "drizzle/**", "**/*.sql"]
|
||||
},
|
||||
{
|
||||
"name": "backend-engineer",
|
||||
"domain": "backend",
|
||||
"frameworks": ["fastify", "hono"],
|
||||
"constraints": ["api-first", "strict-typing", "dependency-injection"],
|
||||
"territory": ["**/api/**", "**/routes/**", "**/services/**", "**/middleware/**", "**/controllers/**", "**/auth/**"]
|
||||
},
|
||||
{
|
||||
"name": "frontend-engineer",
|
||||
"domain": "frontend",
|
||||
"frameworks": ["react", "next.js"],
|
||||
"constraints": ["component-first", "server-components", "minimal-client-js"],
|
||||
"territory": ["**/components/**", "**/pages/**", "**/hooks/**", "**/styles/**", "**/*.tsx", "**/*.css", "**/*.vue"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"logging": {
|
||||
"level": "info",
|
||||
"format": "json",
|
||||
"file": ".ciagent/logs/ciagent.jsonl"
|
||||
},
|
||||
"telemetry": {
|
||||
"enabled": true,
|
||||
"persist": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
# This workflow implements pipelines/modules-lifecycle.yml (byte-identical
|
||||
# in .gitea/workflows/ and .github/workflows/).
|
||||
#
|
||||
# Lifecycle mode (REQ-134, v1.12): the `lifecycle_mode` input defaults to
|
||||
# "plan" — the lifecycle scripts run `run_platform.sh --plan-only` (fast,
|
||||
# no AWS mutation, validates the contract->resolver->adapter->plan chain
|
||||
# for every module on every PR, with no AWS credentials or cost). Set to
|
||||
# "full" via workflow_dispatch (or the ACDL_LIFECYCLE_MODE repo variable)
|
||||
# to run the real apply→modify→destroy against live AWS. In plan mode the
|
||||
# short-lived CI VPC apply/destroy jobs are skipped (nothing is applied).
|
||||
#
|
||||
# A short-lived CI VPC (terraform/ci-vpc/) is created before testing VPC-dependent
|
||||
# modules (alb, ecs-service, rds, uptime, and L2 microservice) and destroyed
|
||||
# after all tests complete. The CI VPC is separate from the long-lived platform
|
||||
@@ -22,15 +30,26 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
lifecycle_mode:
|
||||
description: "Lifecycle mode: 'plan' (default, fast, no AWS mutation) or 'full' (real apply→modify→destroy against live AWS)"
|
||||
required: false
|
||||
default: "plan"
|
||||
type: choice
|
||||
options:
|
||||
- plan
|
||||
- full
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Prerequisite: apply the short-lived CI VPC (needed by VPC-dependent L1s + L2 microservice)
|
||||
# Skipped in plan mode (no resources are applied, so no VPC is needed).
|
||||
ci-vpc-apply:
|
||||
name: CI VPC apply
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.lifecycle_mode != 'plan' && vars.ACDL_LIFECYCLE_MODE != 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Terraform 1.9.*
|
||||
@@ -52,11 +71,14 @@ jobs:
|
||||
lifecycle:
|
||||
name: L1 lifecycle (${{ matrix.module }})
|
||||
needs: ci-vpc-apply
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
module: [s3, kms-key, ecr, ecs-cluster, iam-role, cloudfront, waf, vpc, alb, ecs-service, rds, uptime]
|
||||
env:
|
||||
ACDL_LIFECYCLE_MODE: ${{ github.event.inputs.lifecycle_mode || vars.ACDL_LIFECYCLE_MODE || 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Free disk space
|
||||
@@ -75,6 +97,7 @@ jobs:
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt-get update && sudo apt-get install -y terraform=1.9.*
|
||||
- name: Read CI VPC outputs
|
||||
if: ${{ env.ACDL_LIFECYCLE_MODE == 'full' }}
|
||||
working-directory: terraform/ci-vpc
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID }}
|
||||
@@ -106,11 +129,14 @@ jobs:
|
||||
l2-lifecycle:
|
||||
name: L2 lifecycle (${{ matrix.module }})
|
||||
needs: ci-vpc-apply
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
module: [static-assets, microservice]
|
||||
env:
|
||||
ACDL_LIFECYCLE_MODE: ${{ github.event.inputs.lifecycle_mode || vars.ACDL_LIFECYCLE_MODE || 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Free disk space
|
||||
@@ -129,6 +155,7 @@ jobs:
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt-get update && sudo apt-get install -y terraform=1.9.*
|
||||
- name: Read CI VPC outputs
|
||||
if: ${{ env.ACDL_LIFECYCLE_MODE == 'full' }}
|
||||
working-directory: terraform/ci-vpc
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID }}
|
||||
@@ -156,12 +183,12 @@ jobs:
|
||||
AWS_DEFAULT_REGION: us-east-1
|
||||
run: bash scripts/run_l2_lifecycle_destroy.sh ${{ matrix.module }} /tmp/ci-vpc-outputs.json
|
||||
|
||||
# Cleanup: destroy the CI VPC (always runs, even if lifecycle fails)
|
||||
# Cleanup: destroy the CI VPC (always runs in full mode, even if lifecycle fails)
|
||||
ci-vpc-destroy:
|
||||
name: CI VPC destroy
|
||||
needs: [lifecycle, l2-lifecycle]
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
if: ${{ always() && github.event.inputs.lifecycle_mode != 'plan' && vars.ACDL_LIFECYCLE_MODE != 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Terraform 1.9.*
|
||||
|
||||
@@ -11,6 +11,14 @@
|
||||
# This workflow implements pipelines/modules-lifecycle.yml (byte-identical
|
||||
# in .gitea/workflows/ and .github/workflows/).
|
||||
#
|
||||
# Lifecycle mode (REQ-134, v1.12): the `lifecycle_mode` input defaults to
|
||||
# "plan" — the lifecycle scripts run `run_platform.sh --plan-only` (fast,
|
||||
# no AWS mutation, validates the contract->resolver->adapter->plan chain
|
||||
# for every module on every PR, with no AWS credentials or cost). Set to
|
||||
# "full" via workflow_dispatch (or the ACDL_LIFECYCLE_MODE repo variable)
|
||||
# to run the real apply→modify→destroy against live AWS. In plan mode the
|
||||
# short-lived CI VPC apply/destroy jobs are skipped (nothing is applied).
|
||||
#
|
||||
# A short-lived CI VPC (terraform/ci-vpc/) is created before testing VPC-dependent
|
||||
# modules (alb, ecs-service, rds, uptime, and L2 microservice) and destroyed
|
||||
# after all tests complete. The CI VPC is separate from the long-lived platform
|
||||
@@ -22,15 +30,26 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
lifecycle_mode:
|
||||
description: "Lifecycle mode: 'plan' (default, fast, no AWS mutation) or 'full' (real apply→modify→destroy against live AWS)"
|
||||
required: false
|
||||
default: "plan"
|
||||
type: choice
|
||||
options:
|
||||
- plan
|
||||
- full
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Prerequisite: apply the short-lived CI VPC (needed by VPC-dependent L1s + L2 microservice)
|
||||
# Skipped in plan mode (no resources are applied, so no VPC is needed).
|
||||
ci-vpc-apply:
|
||||
name: CI VPC apply
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.lifecycle_mode != 'plan' && vars.ACDL_LIFECYCLE_MODE != 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Terraform 1.9.*
|
||||
@@ -52,11 +71,14 @@ jobs:
|
||||
lifecycle:
|
||||
name: L1 lifecycle (${{ matrix.module }})
|
||||
needs: ci-vpc-apply
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
module: [s3, kms-key, ecr, ecs-cluster, iam-role, cloudfront, waf, vpc, alb, ecs-service, rds, uptime]
|
||||
env:
|
||||
ACDL_LIFECYCLE_MODE: ${{ github.event.inputs.lifecycle_mode || vars.ACDL_LIFECYCLE_MODE || 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Free disk space
|
||||
@@ -75,6 +97,7 @@ jobs:
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt-get update && sudo apt-get install -y terraform=1.9.*
|
||||
- name: Read CI VPC outputs
|
||||
if: ${{ env.ACDL_LIFECYCLE_MODE == 'full' }}
|
||||
working-directory: terraform/ci-vpc
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID }}
|
||||
@@ -106,11 +129,14 @@ jobs:
|
||||
l2-lifecycle:
|
||||
name: L2 lifecycle (${{ matrix.module }})
|
||||
needs: ci-vpc-apply
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
module: [static-assets, microservice]
|
||||
env:
|
||||
ACDL_LIFECYCLE_MODE: ${{ github.event.inputs.lifecycle_mode || vars.ACDL_LIFECYCLE_MODE || 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Free disk space
|
||||
@@ -129,6 +155,7 @@ jobs:
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt-get update && sudo apt-get install -y terraform=1.9.*
|
||||
- name: Read CI VPC outputs
|
||||
if: ${{ env.ACDL_LIFECYCLE_MODE == 'full' }}
|
||||
working-directory: terraform/ci-vpc
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID }}
|
||||
@@ -156,12 +183,12 @@ jobs:
|
||||
AWS_DEFAULT_REGION: us-east-1
|
||||
run: bash scripts/run_l2_lifecycle_destroy.sh ${{ matrix.module }} /tmp/ci-vpc-outputs.json
|
||||
|
||||
# Cleanup: destroy the CI VPC (always runs, even if lifecycle fails)
|
||||
# Cleanup: destroy the CI VPC (always runs in full mode, even if lifecycle fails)
|
||||
ci-vpc-destroy:
|
||||
name: CI VPC destroy
|
||||
needs: [lifecycle, l2-lifecycle]
|
||||
runs-on: ubuntu-latest
|
||||
if: always()
|
||||
if: ${{ always() && github.event.inputs.lifecycle_mode != 'plan' && vars.ACDL_LIFECYCLE_MODE != 'plan' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Terraform 1.9.*
|
||||
|
||||
@@ -11,6 +11,9 @@ runner-data/
|
||||
.env.secrets
|
||||
terraform/bootstrap/.bootstrap_state.json
|
||||
|
||||
# CIAgent runtime artifacts
|
||||
.ciagent/logs/
|
||||
|
||||
# Terraform — recursively ignore .terraform dirs, lock files, plans, and state
|
||||
**/.terraform/
|
||||
**/.terraform.lock.hcl
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
"""ACDL Terraform adapter — stateless assembler (v1.11 RESTART, P56a).
|
||||
|
||||
The adapter is a STATELESS ASSEMBLER. It owns no module content — no resource
|
||||
shape, no nested HCL blocks, no defaults, no type-specific logic. It reads
|
||||
the registry to find each L1 module's terraform/ dir, then emits a root
|
||||
main.tf that instantiates each resource as a `module "<rid>" { source = ... }`
|
||||
block with resolved inputs and wired refs.
|
||||
|
||||
Engine-specific knowledge (resource type, arg names, nested blocks, defaults)
|
||||
lives in the per-module terraform/ subdir (versions/variables/locals/main/
|
||||
outputs.tf), NOT in this file. interface.json stays engine-agnostic.
|
||||
A STATELESS ASSEMBLER. It owns no module content — no resource shape, no
|
||||
nested HCL blocks, no defaults, no type-specific logic. It reads the
|
||||
registry to find each L1 module's terraform/ dir, then emits a root
|
||||
main.tf that instantiates each resource as a `module "<rid>" { source }`
|
||||
block with resolved inputs and wired refs. Engine-specific knowledge
|
||||
lives in the per-module terraform/ subdir, NOT in this file.
|
||||
|
||||
CLI: adapter.py <instance.json> <out_dir>
|
||||
"""
|
||||
@@ -22,42 +19,39 @@ def _load_registry(repo_root):
|
||||
"""Load registry.json → {module_name: terraform_dir}."""
|
||||
with open(os.path.join(repo_root, "modules", "registry.json")) as fh:
|
||||
registry = json.load(fh)
|
||||
terraform_dirs = {}
|
||||
for name, versions in registry.items():
|
||||
latest = versions.get("1.0.0", {})
|
||||
if "terraform_dir" in latest:
|
||||
terraform_dirs[name] = latest["terraform_dir"]
|
||||
return terraform_dirs
|
||||
return {n: v.get("1.0.0", {}).get("terraform_dir")
|
||||
for n, v in registry.items()
|
||||
if v.get("1.0.0", {}).get("terraform_dir")}
|
||||
|
||||
|
||||
def _module_name(resource):
|
||||
"""Extract the module name from a resource's `module` field (e.g. s3@1.0.0 → s3)."""
|
||||
"""Extract the module name from a resource's `module` field (s3@1.0.0 → s3)."""
|
||||
return resource.get("module", "").split("@")[0]
|
||||
|
||||
|
||||
def _ref_expr(value, data_source_names=None):
|
||||
"""Translate a `ref:<rid>.<output>` string to a Terraform interpolation.
|
||||
|
||||
For module resources: `module.<rid>.<output>`.
|
||||
For data sources (platform-owned): `data.terraform_remote_state.platform.outputs.<output>`.
|
||||
Returns None if the value is not a ref."""
|
||||
def _ref_expr(value, data_source_names=None, id_remap=None):
|
||||
"""Translate `ref:<rid>.<output>` → `module.<rid>.<output>` (or
|
||||
`data.terraform_remote_state.platform.outputs.<output>` for data
|
||||
sources). Returns None if not a ref. id_remap rewrites expanded
|
||||
multi-resource L1 sub-ids (e.g. alb-targetgroup → alb). CAP-013."""
|
||||
if not isinstance(value, str) or not value.startswith("ref:"):
|
||||
return None
|
||||
body = value[len("ref:"):]
|
||||
rid, out_name = body.split(".", 1)
|
||||
rid, out_name = value[len("ref:"):].split(".", 1)
|
||||
if data_source_names and rid in data_source_names:
|
||||
return f"data.terraform_remote_state.platform.outputs.{out_name}"
|
||||
if id_remap:
|
||||
rid = id_remap.get(rid, rid)
|
||||
return f"module.{rid}.{out_name}"
|
||||
|
||||
|
||||
def _tf_value(value, data_source_names=None):
|
||||
def _tf_value(value, data_source_names=None, id_remap=None):
|
||||
"""Render a Python value as a Terraform expression fragment."""
|
||||
if isinstance(value, bool):
|
||||
return "true" if value else "false"
|
||||
if isinstance(value, (int, float)) and not isinstance(value, bool):
|
||||
return str(value)
|
||||
if isinstance(value, str):
|
||||
ref = _ref_expr(value, data_source_names)
|
||||
ref = _ref_expr(value, data_source_names, id_remap)
|
||||
if ref is not None:
|
||||
return ref
|
||||
stripped = value.lstrip()
|
||||
@@ -74,19 +68,16 @@ def _tf_value(value, data_source_names=None):
|
||||
raise ValueError(f"unsupported input value type {type(value).__name__}")
|
||||
|
||||
|
||||
def _emit_module_block(resource, terraform_dirs, repo_root, data_source_names=None):
|
||||
"""Emit a `module "<rid>" { source = ... ... }` block for one resource."""
|
||||
def _emit_module_block(resource, terraform_dirs, repo_root, data_source_names=None, id_remap=None):
|
||||
"""Emit a `module "<rid>" { source = ... ... }` block."""
|
||||
rid = resource["id"]
|
||||
name = _module_name(resource)
|
||||
tf_dir = terraform_dirs.get(name)
|
||||
tf_dir = terraform_dirs.get(_module_name(resource))
|
||||
if not tf_dir:
|
||||
raise ValueError(f"no terraform_dir in registry for module '{name}' (resource {rid})")
|
||||
source_path = os.path.join(repo_root, tf_dir)
|
||||
lines = [f'module "{rid}" {{', f' source = "{source_path}"']
|
||||
raise ValueError(f"no terraform_dir for module '{_module_name(resource)}' (resource {rid})")
|
||||
lines = [f'module "{rid}" {{', f' source = "{os.path.join(repo_root, tf_dir)}"']
|
||||
for in_name, value in resource.get("inputs", {}).items():
|
||||
if in_name == "region":
|
||||
continue
|
||||
lines.append(f" {in_name} = {_tf_value(value, data_source_names)}")
|
||||
if in_name != "region":
|
||||
lines.append(f" {in_name} = {_tf_value(value, data_source_names, id_remap)}")
|
||||
lines.append("}")
|
||||
return "\n".join(lines)
|
||||
|
||||
@@ -96,6 +87,16 @@ def _emit_root_output(out_name, rid, module_output_name):
|
||||
return f'output "{out_name}" {{\n value = module.{rid}.{module_output_name}\n}}'
|
||||
|
||||
|
||||
def _child_id(group_ids):
|
||||
"""Composition child id for resource ids sharing one terraform dir.
|
||||
Multi-resource L1s expand a child to `<childId>-<subType>` ids; the
|
||||
common-prefix (trailing `-` stripped) is the child id. Single-resource
|
||||
L1s: the id IS the child id."""
|
||||
if len(group_ids) == 1:
|
||||
return group_ids[0]
|
||||
return os.path.commonprefix([i + "-" for i in group_ids]).rstrip("-") or group_ids[0]
|
||||
|
||||
|
||||
def adapt(stack_instance, out_dir):
|
||||
"""Emit main.tf + terraform.tf + providers.tf to out_dir for the stack instance."""
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
@@ -106,15 +107,9 @@ def adapt(stack_instance, out_dir):
|
||||
resources = stack_instance.get("resources", [])
|
||||
stack_outputs = stack_instance.get("outputs", {})
|
||||
|
||||
# --- providers.tf: aws provider, region from the first resource's inputs.region ---
|
||||
region = "us-east-1"
|
||||
for r in resources:
|
||||
if "region" in r.get("inputs", {}):
|
||||
region = r["inputs"]["region"]
|
||||
break
|
||||
region = next((r["inputs"]["region"] for r in resources if "region" in r.get("inputs", {})), "us-east-1")
|
||||
providers_tf = f'provider "aws" {{\n region = "{region}"\n}}\n'
|
||||
|
||||
# --- terraform.tf: required_version + required_providers + S3 backend ---
|
||||
stack_name = stack.get("name", "spike")
|
||||
environment = stack.get("environment", "dev")
|
||||
terraform_tf = (
|
||||
@@ -134,12 +129,11 @@ def adapt(stack_instance, out_dir):
|
||||
'}\n'
|
||||
)
|
||||
|
||||
# --- data sources: emit terraform_remote_state for platform-owned resources ---
|
||||
data_source_names = stack_instance.get("data_sources", [])
|
||||
data_blocks = []
|
||||
parts = []
|
||||
if data_source_names:
|
||||
remote_state_key = os.environ.get("ACDL_REMOTE_STATE_KEY", "platform/terraform.tfstate")
|
||||
data_blocks.append(
|
||||
parts.append(
|
||||
'data "terraform_remote_state" "platform" {\n'
|
||||
' backend = "s3"\n'
|
||||
' config = {\n'
|
||||
@@ -150,32 +144,35 @@ def adapt(stack_instance, out_dir):
|
||||
'}\n'
|
||||
)
|
||||
|
||||
# --- main.tf: data blocks + module instantiations + root outputs ---
|
||||
parts = list(data_blocks)
|
||||
|
||||
# Deduplicate: multi-resource L1s (e.g. cloudfront) expand to multiple
|
||||
# stack resources sharing one terraform dir. Emit ONE module block per
|
||||
# dir, merging inputs. Use the first resource's id as the module name.
|
||||
seen = {} # terraform_dir → resource
|
||||
# Deduplicate multi-resource L1s (ecs-service, alb, ...) to ONE module
|
||||
# block per terraform dir, named by the composition child id (common
|
||||
# prefix), NOT the first sub-resource id. Stack outputs + cross-module
|
||||
# refs reference expanded sub-ids, rewritten via id_remap. CAP-013.
|
||||
groups = {} # terraform_dir → {"ids": [...], "inputs": {}, "module": ""}
|
||||
for r in resources:
|
||||
tf_dir = terraform_dirs.get(_module_name(r))
|
||||
if not tf_dir:
|
||||
raise ValueError(f"no terraform_dir in registry for module '{_module_name(r)}' (resource {r['id']})")
|
||||
if tf_dir in seen:
|
||||
for k, v in r.get("inputs", {}).items():
|
||||
if k != "region" and k not in seen[tf_dir].get("inputs", {}):
|
||||
seen[tf_dir].setdefault("inputs", {})[k] = v
|
||||
for k, v in r.get("outputs", {}).items():
|
||||
seen[tf_dir].setdefault("outputs", {})[k] = v
|
||||
else:
|
||||
seen[tf_dir] = r
|
||||
merged = list(seen.values()) if seen else resources
|
||||
parts.extend(_emit_module_block(r, terraform_dirs, repo_root, set(data_source_names)) for r in merged)
|
||||
raise ValueError(f"no terraform_dir for module '{_module_name(r)}' (resource {r['id']})")
|
||||
grp = groups.setdefault(tf_dir, {"ids": [], "inputs": {}, "module": r["module"]})
|
||||
grp["ids"].append(r["id"])
|
||||
for k, v in r.get("inputs", {}).items():
|
||||
if k != "region":
|
||||
grp["inputs"].setdefault(k, v)
|
||||
|
||||
id_remap = {}
|
||||
merged_resources = []
|
||||
for tf_dir, grp in groups.items():
|
||||
child_id = _child_id(grp["ids"])
|
||||
for sub_id in grp["ids"]:
|
||||
id_remap[sub_id] = child_id
|
||||
merged_resources.append({"id": child_id, "module": grp["module"], "inputs": grp["inputs"]})
|
||||
|
||||
parts.extend(_emit_module_block(r, terraform_dirs, repo_root, set(data_source_names), id_remap)
|
||||
for r in merged_resources)
|
||||
for out_name, out_spec in stack_outputs.items():
|
||||
if isinstance(out_spec, dict) and "from" in out_spec:
|
||||
rid = out_spec["from"]
|
||||
mod_out = out_spec.get("output", out_name)
|
||||
parts.append(_emit_root_output(out_name, rid, mod_out))
|
||||
rid = id_remap.get(out_spec["from"], out_spec["from"])
|
||||
parts.append(_emit_root_output(out_name, rid, out_spec.get("output", out_name)))
|
||||
main_tf = "\n\n".join(parts) + "\n"
|
||||
|
||||
with open(os.path.join(out_dir, "main.tf"), "w") as fh:
|
||||
@@ -192,6 +189,5 @@ if __name__ == "__main__":
|
||||
print("usage: adapter.py <instance.json> <out_dir>", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
with open(sys.argv[1], "r") as fh:
|
||||
stack = json.load(fh)
|
||||
adapt(stack, sys.argv[2])
|
||||
adapt(json.load(fh), sys.argv[2])
|
||||
print(f"adapter: emitted terraform to {sys.argv[2]}", file=sys.stderr)
|
||||
@@ -441,10 +441,15 @@ def _check_lifecycle_module_terraform(module: str) -> Tuple[Status, str]:
|
||||
tf_dir = ROOT / "modules" / "l1" / module / "terraform"
|
||||
if not tf_dir.is_dir():
|
||||
return "Broken", f"modules/l1/{module}/terraform/ does not exist"
|
||||
required = ["versions.tf", "variables.tf", "locals.tf", "main.tf", "outputs.tf"]
|
||||
required = ["versions.tf", "variables.tf", "main.tf", "outputs.tf"]
|
||||
missing = [f for f in required if not (tf_dir / f).is_file()]
|
||||
if missing:
|
||||
return "Broken", f"missing terraform files: {missing}"
|
||||
# locals.tf is only required when the module references local.* values
|
||||
# (CAP-017 fix, v1.12). Single-resource modules may legitimately omit it.
|
||||
tf_text = "".join((tf_dir / f).read_text() for f in ["variables.tf", "main.tf", "outputs.tf"] if (tf_dir / f).is_file())
|
||||
if "local." in tf_text and not (tf_dir / "locals.tf").is_file():
|
||||
return "Broken", "missing terraform files: ['locals.tf'] (referenced by module)"
|
||||
for ex in ["simple", "complex"]:
|
||||
contract = ROOT / "modules" / "l1" / module / "examples" / f"{ex}.yml"
|
||||
if not contract.is_file():
|
||||
@@ -482,11 +487,13 @@ def _check_cap_017_dynamodb() -> Tuple[Status, str]:
|
||||
|
||||
def _check_cap_018_lambda() -> Tuple[Status, str]:
|
||||
"""CAP-018: Lambda contract-ingestor. Evidence = local Lambda stub
|
||||
(CAP-011) + L1 lifecycle pipeline green for the platform terraform."""
|
||||
(CAP-011) + L1 lifecycle pipeline green for the platform terraform.
|
||||
The stub requires an outbox arg (CAP-018 fix, v1.12)."""
|
||||
rc, out, err = _run_subprocess([
|
||||
"python3", "-c",
|
||||
"from core.local_emulators import LocalLambdaStub; "
|
||||
"stub = LocalLambdaStub(); "
|
||||
"from core.local_emulators import LocalLambdaStub, FlatFileOutbox; "
|
||||
"import tempfile; "
|
||||
"stub = LocalLambdaStub(outbox=FlatFileOutbox(tempfile.mkdtemp(prefix='acdl_stub_'))); "
|
||||
"print('LocalLambdaStub instantiates OK')",
|
||||
])
|
||||
if rc != 0:
|
||||
|
||||
@@ -115,7 +115,7 @@ Distill the source of truth (Step 1) into presenter-ready cues, indexed by
|
||||
the Marp deck (Step 2) slide structure:
|
||||
|
||||
- **One section per Marp slide** — `## Slide N — Title`, matching the Marp
|
||||
deck's 10 main + 6 appendix slide structure exactly. The Marp deck
|
||||
deck's 10 main + Appendix TOC + appendix slide structure exactly. The Marp deck
|
||||
provides the indexing and context (what the audience sees); the source
|
||||
markdown provides the content (the speaker notes, the detail, the nuance).
|
||||
- **3-6 talking point bullets per slide** — punchy, actionable cues distilled
|
||||
@@ -145,37 +145,49 @@ and re-distill.
|
||||
docs/presentations/
|
||||
├── README.md ← this file
|
||||
├── how-the-platform-works.md ← Step 1: full source of truth
|
||||
├── how-the-platform-works-marp.md ← Step 2: Marp deck (10 main + 6 appendix)
|
||||
├── how-the-platform-works-marp.md ← Step 2: Marp deck (10 main + TOC + 8 appendix = 19)
|
||||
├── how-the-platform-works.html ← Step 3: rendered HTML (committed)
|
||||
├── how-the-platform-works-talking-points.md ← Step 4: presenter cues (16 sections)
|
||||
├── how-the-platform-works-talking-points.md ← Step 4: presenter cues (19 sections)
|
||||
├── the-developer-experience.md ← Step 1: full source of truth
|
||||
├── the-developer-experience-marp.md ← Step 2: Marp deck (10 main + 6 appendix)
|
||||
├── the-developer-experience-marp.md ← Step 2: Marp deck (10 main + TOC + 7 appendix = 18)
|
||||
├── the-developer-experience.html ← Step 3: rendered HTML (committed)
|
||||
├── the-developer-experience-talking-points.md ← Step 4: presenter cues (16 sections)
|
||||
├── the-developer-experience-talking-points.md ← Step 4: presenter cues (18 sections)
|
||||
└── assets/
|
||||
├── puppeteer-config.json ← no-sandbox config for mmdc
|
||||
├── mmd/ ← mermaid source files (Step 2 input)
|
||||
│ ├── sp-theme.json ← S&P Red/Black/White theme (mermaid-cli --configFile)
|
||||
│ ├── platform-works-01-contract-driven.mmd
|
||||
│ ├── platform-works-02-frictions.mmd
|
||||
│ ├── platform-works-02-end-to-end-flow.mmd
|
||||
│ ├── platform-works-03-north-star.mmd
|
||||
│ ├── platform-works-03-scope-boundary.mmd
|
||||
│ ├── platform-works-04-confidence-signal.mmd
|
||||
│ ├── platform-works-05-attestation-flow.mmd
|
||||
│ ├── platform-works-07-zero-trust.mmd
|
||||
│ ├── developer-experience-01b-scope-boundary.mmd
|
||||
│ ├── developer-experience-02-what-dev-does.mmd
|
||||
│ ├── developer-experience-03-no-cloning.mmd
|
||||
│ ├── developer-experience-04-promotion-journey.mmd
|
||||
│ ├── developer-experience-05-catalog.mmd
|
||||
│ ├── developer-experience-07-decommission.mmd
|
||||
│ ├── developer-experience-08-semver.mmd
|
||||
│ └── road-to-north-star.mmd
|
||||
└── png/ ← rendered PNGs (embedded in Marp)
|
||||
├── platform-works-01-contract-driven.png
|
||||
├── platform-works-02-frictions.png
|
||||
├── platform-works-02-end-to-end-flow.png
|
||||
├── platform-works-03-north-star.png
|
||||
├── platform-works-03-scope-boundary.png
|
||||
├── platform-works-04-confidence-signal.png
|
||||
├── platform-works-05-attestation-flow.png
|
||||
├── platform-works-07-zero-trust.png
|
||||
├── developer-experience-01b-scope-boundary.png
|
||||
├── developer-experience-02-what-dev-does.png
|
||||
├── developer-experience-03-no-cloning.png
|
||||
├── developer-experience-04-promotion-journey.png
|
||||
├── developer-experience-05-catalog.png
|
||||
├── developer-experience-07-decommission.png
|
||||
├── developer-experience-08-semver.png
|
||||
└── road-to-north-star.png
|
||||
```
|
||||
|
||||
@@ -183,12 +195,14 @@ docs/presentations/
|
||||
|
||||
### Appendix structure
|
||||
|
||||
Each Marp deck has **10 main slides + 6 appendix slides** (16 total). The
|
||||
Each Marp deck has **10 main slides + an Appendix TOC + appendix slides**. The
|
||||
main 10 are the presentation; the appendix is for deep dives and Q&A backup.
|
||||
The platform-works deck has 8 appendix slides (A1–A8); the developer-experience
|
||||
deck has 7 appendix slides (A1–A7). Both include an Appendix TOC slide.
|
||||
|
||||
- **Main slides** (1-10): the story arc, high-impact, minimal text,
|
||||
visual-heavy. These are what the audience sees during the talk.
|
||||
- **Appendix slides** (A1-A5 + TOC): detail-heavy slides moved out of the
|
||||
- **Appendix slides** (TOC + A1..An): detail-heavy slides moved out of the
|
||||
main 10 to preserve the narrative flow. The appendix starts with a TOC
|
||||
slide listing the contents, followed by detail slides and a glossary.
|
||||
- **The Road to the North Star** is a required appendix slide in both decks
|
||||
@@ -331,5 +345,5 @@ attachments to the Gitea release.
|
||||
|
||||
| Deck | Source of truth (Step 1) | Marp deck (Step 2) | Rendered HTML (Step 3) | Talking points (Step 4) | Slides | Audience |
|
||||
|---|---|---|---|---|---|---|
|
||||
| How the Platform Works | `how-the-platform-works.md` | `how-the-platform-works-marp.md` | `how-the-platform-works.html` | `how-the-platform-works-talking-points.md` | 10 main + 6 appendix | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
| The Developer Experience | `the-developer-experience.md` | `the-developer-experience-marp.md` | `the-developer-experience.html` | `the-developer-experience-talking-points.md` | 10 main + 6 appendix | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
| How the Platform Works | `how-the-platform-works.md` | `how-the-platform-works-marp.md` | `how-the-platform-works.html` | `how-the-platform-works-talking-points.md` | 10 main + TOC + 8 appendix (19) | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
| The Developer Experience | `the-developer-experience.md` | `the-developer-experience-marp.md` | `the-developer-experience.html` | `the-developer-experience-talking-points.md` | 10 main + TOC + 7 appendix (18) | CTO, Head of Cloud, Head of Infra, Head of DevOps |
|
||||
@@ -0,0 +1,25 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
subgraph PRIM ["Primitives"]
|
||||
direction TB
|
||||
P1["S3"]
|
||||
P2["VPC"]
|
||||
P3["ECS"]
|
||||
P4["IAM"]
|
||||
P5["ALB"]
|
||||
P6["ECR"]
|
||||
P7["CloudFront"]
|
||||
P8["WAF"]
|
||||
P9["RDS"]
|
||||
end
|
||||
subgraph MOD ["Modules — composed patterns"]
|
||||
direction TB
|
||||
M1["Static site\nCDN + WAF + S3"]
|
||||
M2["Microservice\nVPC + ECS + ALB + ECR"]
|
||||
end
|
||||
PRIM --> MOD
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class P1,P2,P3,P4,P5,P6,P7,P8,P9 supporting
|
||||
class M1,M2 accent
|
||||
@@ -0,0 +1,14 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
A["Validate CR\n(CMDB)"]
|
||||
B["Disable\nprevent_destroy"]
|
||||
C["SRE\napprove"]
|
||||
D["Zero counts\n+ destroy"]
|
||||
E["SRE\napprove"]
|
||||
F["Key enters\ngrace window"]
|
||||
A --> B --> C --> D --> E --> F
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class A,B,D,F supporting
|
||||
class C,E accent
|
||||
@@ -0,0 +1,28 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
subgraph FLOAT ["@v1.12 — floating MAJOR+MINOR"]
|
||||
direction LR
|
||||
F1["v1.12.0"]
|
||||
F2["v1.12.1"]
|
||||
F3["v1.12.2"]
|
||||
F1 --> F2 --> F3
|
||||
end
|
||||
subgraph PIN ["@v1.12.2 — pinned exact"]
|
||||
direction LR
|
||||
P1["v1.12.2"]
|
||||
P2["v1.12.2"]
|
||||
P3["v1.12.2"]
|
||||
P1 --> P2 --> P3
|
||||
end
|
||||
subgraph MAJ ["@v1 — float MAJOR only"]
|
||||
direction LR
|
||||
M1["v1.12.0"]
|
||||
M2["v1.13.0"]
|
||||
M3["v1.14.0"]
|
||||
M1 --> M2 --> M3
|
||||
end
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class F1,F2,F3,M1,M2,M3 accent
|
||||
class P1,P2,P3 supporting
|
||||
@@ -0,0 +1,19 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
subgraph ROW1 [" "]
|
||||
direction LR
|
||||
A["Cognitive load\nauthoring infra correctly"]
|
||||
B["Operational work\nmerged → running"]
|
||||
end
|
||||
subgraph ROW2 [" "]
|
||||
direction LR
|
||||
C["Red tape\ntickets, approvals, handoffs"]
|
||||
D["Scalability\nthroughput without headcount"]
|
||||
end
|
||||
A ~~~ B
|
||||
C ~~~ D
|
||||
A ~~~ C
|
||||
B ~~~ D
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
class A,B,C,D accent
|
||||
@@ -0,0 +1,23 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
subgraph TODAY ["Today"]
|
||||
direction TB
|
||||
A["Merged change"]
|
||||
B["Waits in queue"]
|
||||
C["Ticket + approvals"]
|
||||
D["Manual promotion"]
|
||||
A --> B --> C --> D
|
||||
end
|
||||
subgraph ACDL ["With ACDL"]
|
||||
direction TB
|
||||
E["Declare intent\n(one YAML contract)"]
|
||||
F["Platform delivers\nsafely, autonomously"]
|
||||
G["Traceable to\nhuman attestation"]
|
||||
E --> F --> G
|
||||
end
|
||||
TODAY -.before.-> ACDL
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class A,B,C,D supporting
|
||||
class E,F,G accent
|
||||
@@ -0,0 +1,12 @@
|
||||
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#1B1B1B", "primaryBorderColor": "#D6002A", "primaryTextColor": "#fff", "secondaryColor": "#fff", "secondaryBorderColor": "#D6002A", "secondaryTextColor": "#1B1B1B", "tertiaryColor": "#F0F0F0", "clusterBkg": "#F0F0F0", "lineColor": "#1B1B1B", "fontFamily": "\"Akkurat Pro\", \"Helvetica Neue\", \"Arial\", sans-serif"}}}%%
|
||||
|
||||
flowchart LR
|
||||
A["Consumer repo\n(no credentials)"]
|
||||
B["OIDC federation\nshort-lived token"]
|
||||
C["ABAC session policy\nrepo identity + tags"]
|
||||
D["Tagged resources\nonly"]
|
||||
A --> B --> C --> D
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class A,D supporting
|
||||
class B,C accent
|
||||
@@ -3,15 +3,16 @@
|
||||
flowchart LR
|
||||
A["v1.0\nDEMO\ncomplete"] --> B["v1.1–v1.8\nPLATFORM BUILD\ncomplete"]
|
||||
B --> C["v1.9\nPRESENTATIONS + PATCHES\ncomplete"]
|
||||
C --> D["v1.10\nNEXT\nHITL wiring\nall-runner OIDC\nregulatory ledger"]
|
||||
D --> E["v2.0\nFUTURE\ncompliance milestone\nself-service\ndynamic modules\nengine adapters"]
|
||||
E --> F["North Star\nREALIZED\nfull autonomy (lower)\nattested (higher)\ncitizen dev live\nevidence regulatory-grade"]
|
||||
C --> D["v1.10\nREGRESSION GATE\n+ verified reality\ncomplete"]
|
||||
D --> E["v1.11–v1.12\nLIFECYCLE TESTING\n+ presentation refine\n22/22 Verified\n+ torn down to zero-cost"]
|
||||
E --> F["v2.0\nFUTURE\ncompliance milestone\nself-service\ndynamic modules\nengine adapters"]
|
||||
F --> G["North Star\nREALIZED\nfull autonomy (lower)\nattested (higher)\ncitizen dev live\nevidence regulatory-grade"]
|
||||
A -.->|"stub-driven proof"| A
|
||||
B -.->|"IR + OIDC + ABAC +\nmodule catalog +\nencryption + decommission"| B
|
||||
C -.->|"10-slide decks +\ntalking points +\nS&P theme"| C
|
||||
D -.->|"proposed phasing\nnot formally planned"| D
|
||||
E -.->|"proposed phasing\nnot formally planned"| E
|
||||
D -.->|"regression gate (D-091)\nlocal emulating tier\nverified-reality rewrite"| D
|
||||
E -.->|"stateless adapter (918→~80 lines)\npipeline-driven lifecycle\nplan-only default (REQ-134)\ntorn down to zero-cost"| E
|
||||
F -.->|"proposed phasing\nnot formally planned"| F
|
||||
classDef accent fill:#1B1B1B,color:#fff,stroke:#D6002A,stroke-width:2px
|
||||
classDef supporting fill:#fff,color:#1B1B1B,stroke:#D6002A,stroke-width:1px
|
||||
class F accent
|
||||
|
||||
class G accent
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 39 KiB |
@@ -8,21 +8,20 @@ footer: "Internal"
|
||||
style: |
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 22px;
|
||||
font-size: 26px;
|
||||
color: #1B1B1B;
|
||||
}
|
||||
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||
h1 { color: #D6002A; font-size: 40px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 32px; margin-bottom: 0.2em; }
|
||||
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||
section.title h1 { color: #fff; }
|
||||
table { font-size: 18px; width: 100%; }
|
||||
table { font-size: 22px; width: 100%; }
|
||||
th { background: #F0F0F0; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 24px; }
|
||||
img { display: block; margin: 0 auto; max-height: 300px; }
|
||||
em.story { color: #6B7280; font-size: 16px; font-style: italic; }
|
||||
.badge {
|
||||
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||
font-size: 14px; font-weight: 600;
|
||||
font-size: 16px; font-weight: 600;
|
||||
}
|
||||
.testing { background: #DBEAFE; color: #1E3A5F; }
|
||||
.planned { background: #fef3c7; color: #78350f; }
|
||||
@@ -43,91 +42,73 @@ section.title h3 { color: #F0F0F0; font-weight: 400; font-size: 22px; margin-top
|
||||
|
||||
---
|
||||
|
||||
# The Problem & The North Star
|
||||
# Four frictions slow every team
|
||||
|
||||
<em class="story">Here's the problem we're solving and where we're going.</em>
|
||||

|
||||
|
||||
Four frictions slow every team:
|
||||
|
||||
- **Cognitive load** — authoring infrastructure correctly; the long tail of services inconsistent in security and observability
|
||||
- **Operational work** — promoting a change from "merged" to "running in production." Manual work that **scales with the system, not the change**
|
||||
- **Red tape** — tickets, approvals, and handoffs that scale with the organization. A merged change waits in a queue
|
||||
- **Scalability without increasing headcount** — throughput scales without linearly scaling platform engineers
|
||||
|
||||
> Consumers **declare intent**; the platform delivers **safe production deployment** — automatically, safely, with a complete audit trail.
|
||||
|
||||
- A merged change progresses **without a platform engineer joining a thread or approving a ticket**
|
||||
- A **non-technical consumer** ships by declaring intent — no workflow, no config file, no infrastructure module
|
||||
- Every production change is **traceable to a human attestation and an immutable evidence stream**
|
||||
- **Cognitive load** — services inconsistent in security and observability
|
||||
- **Operational work** — manual promotion scaling with the system
|
||||
- **Red tape** — tickets and handoffs scaling with the organization
|
||||
- **Scalability** — throughput without scaling platform engineers
|
||||
|
||||
---
|
||||
|
||||
# Where ACDL Sits in Your World
|
||||
# Declare intent; the platform delivers safe production
|
||||
|
||||
<em class="story">Now that we know the problem, here's where ACDL fits — and where it doesn't.</em>
|
||||

|
||||
|
||||
- A merged change progresses **without a ticket or thread**
|
||||
- A **non-technical consumer** ships by declaring intent
|
||||
- Every production change is **traceable to a human attestation**
|
||||
|
||||
---
|
||||
|
||||
# ACDL owns infrastructure, not your app
|
||||
|
||||

|
||||
|
||||
- **Upstream is anything** — your IDE, an agentic SDLC, or a citizen developer vibe coding on a laptop. ACDL doesn't care how the contract was produced.
|
||||
- **ACDL is infrastructure only** — it provisions and governs AWS resources. It does not build, test, or deploy your application code. That's upstream.
|
||||
- **Not a general-purpose AI** — autonomy is narrow, scoped to delivery, bounded by strict policy
|
||||
- **Not a permissive delivery highway** — no escape hatches to bypass the confidence framework
|
||||
- **Upstream is anything** — IDE, agentic SDLC, or vibe coding
|
||||
- **ACDL is infrastructure only** — provisions and governs AWS resources
|
||||
- **Not a general-purpose AI** — autonomy is narrow, policy-bounded
|
||||
- **Not a permissive highway** — no escape hatches
|
||||
|
||||
---
|
||||
|
||||
# The Contract-Driven Model
|
||||
|
||||
<em class="story">The contract is the boundary between upstream and ACDL. It's all a consumer writes.</em>
|
||||
|
||||
A single YAML contract — **module, environment, inputs**. The platform owns everything else.
|
||||
# One YAML file. The platform owns everything else.
|
||||
|
||||

|
||||
|
||||
- **Which module** — a catalog of pre-built, security-reviewed building blocks
|
||||
- **Which environment** — the platform raises the safety bar automatically as sensitivity rises
|
||||
- **Which inputs** — infrastructure values that vary per deployment (cpu, memory, port, desired_count)
|
||||
- The consumer provides **no AWS account, no VPC, no state backend** — the platform owns the blast radius
|
||||
- **Module** — pre-built, security-reviewed building blocks
|
||||
- **Environment** — `dev`, `qa`, `prod`, `dr`; bar rises with sensitivity
|
||||
- **Inputs** — cpu, memory, port, desired_count
|
||||
- Consumer provides **no AWS account, no VPC, no state backend**
|
||||
|
||||
---
|
||||
|
||||
# The End-to-End Flow
|
||||
|
||||
<em class="story">Once the contract is written, here's what the platform does with it — every time.</em>
|
||||
|
||||
Every deployment runs the same stages, in the same order, with the same checks — no team-specific pipelines, no tribal runbooks.
|
||||
# Same stages, same checks, every deployment
|
||||
|
||||

|
||||
|
||||
- **Security and policy checks run *before* any infrastructure is created**
|
||||
- **Every stage produces a record** that feeds the confidence signal and the evidence stream — there is no "unchecked" path
|
||||
- **Security and policy checks run *before* any infra is created**
|
||||
- **Every stage produces a record** — no "unchecked" path
|
||||
|
||||
---
|
||||
|
||||
# Zero-Trust by Default
|
||||
# No long-lived credentials. Blast radius contained.
|
||||
|
||||
<em class="story">Before any infrastructure is created, here's how access is scoped.</em>
|
||||

|
||||
|
||||
Consumer repositories hold **no long-lived cloud credentials.** Ever.
|
||||
|
||||
- **Authentication — OIDC federation.** Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. <span class="badge testing">Testing (GitHub Actions)</span> <span class="badge planned">Planned: all runners</span>
|
||||
- **Authorization — attribute-based (ABAC), not role-based.** Two attribute classes scope every action:
|
||||
- **Repository identity** — the role's trust policy binds to the exact consumer repo + branch
|
||||
- **Resource tags** — every resource is tagged `acdl:owner` + `acdl:contract`; the session policy grants access **only to matching tags**
|
||||
|
||||
**The effect:** a consumer can only touch the resources it created. Blast radius is contained. One consumer can never affect another.
|
||||
- **OIDC federation** — short-lived token per job, no stored credential <span class="badge testing">Testing (GitHub Actions)</span> <span class="badge planned">Planned: all runners</span>
|
||||
- **ABAC, not role-based** — repo identity + resource tags scope every action
|
||||
- **A consumer can only touch its own tagged resources.** One consumer can never affect another.
|
||||
|
||||
---
|
||||
|
||||
# Safety is Computed, Not Assumed
|
||||
# Safety is a measurable signal, not a black box
|
||||
|
||||
<em class="story">Now let's look at how the platform decides whether a deployment is safe.</em>
|
||||

|
||||
|
||||
Every delivery action produces a **measurable, explainable confidence signal** — a weighted sum of observable facts, not a black box. <span class="badge agentic">Agentic</span>
|
||||
|
||||

|
||||
|
||||
- **Six weighted inputs** — manually tuned, auditable. If a consumer asks "why 0.62?", the platform answers with a per-input breakdown
|
||||
- **Per-environment thresholds** that rise with sensitivity:
|
||||
- **Six weighted inputs** — manually tuned, auditable per-input breakdown <span class="badge agentic">Agentic</span>
|
||||
|
||||
| Environment | Threshold | Attester |
|
||||
|---|---|---|
|
||||
@@ -135,83 +116,32 @@ Every delivery action produces a **measurable, explainable confidence signal**
|
||||
| qa | ≥ 0.75 | QA <span class="badge planned">Planned</span> |
|
||||
| prod | ≥ 0.90 | SRE <span class="badge planned">Planned</span> |
|
||||
|
||||
- **A single critical finding hard-blocks** — critical findings are not averaged away
|
||||
- **A single critical finding hard-blocks** — not averaged away
|
||||
|
||||
---
|
||||
|
||||
# Security by Construction
|
||||
|
||||
<em class="story">Beyond the confidence signal, security defaults are on by construction — not by opt-in.</em>
|
||||
|
||||
Security defaults that **do not require a team to opt in.** Checks run on **every** deployment, normalized to a single schema. <span class="badge testing">Testing</span>
|
||||
|
||||
- **Policy checks** (Checkov, Wiz, Kyverno) — secrets in plaintext, public ingress, IAM wildcards, **required tagging standards** — all run *before* infra is created
|
||||
- **Encryption on every resource** — at-rest encryption on by default; per-stack customer-managed keys with 90-day rotation, **no shared keys across stacks**
|
||||
- **Deletion protection on by default** — `prevent_destroy` on unless explicitly disabled via a documented flag
|
||||
- **Safe decommission** — a 2-step pipeline with **two SRE attestation gates** and a **change-request validated against the CMDB**
|
||||
|
||||
---
|
||||
|
||||
# Accountability & Audit
|
||||
|
||||
<em class="story">Computed safety handles the gate. But humans still matter — here's how accountability works.</em>
|
||||
# Every change traceable to a human attestation
|
||||
|
||||

|
||||
|
||||
- **Dev is fully autonomous.** The confidence signal (≥ 0.50) is the only gate. <span class="badge testing">Testing</span> <span class="badge agentic">Agentic</span>
|
||||
- **qa, prod, dr require human attestation** — the approver reviews the contract, the planned Terraform changes, and the accumulated evidence <span class="badge planned">Planned</span>
|
||||
- **QA attests to infrastructure readiness, not application code** — the contract, the plan, and the evidence. Application code review is upstream
|
||||
- **Separation of duties** — the QA approver **cannot** be the prod approver. The platform **blocks on a match.** <span class="badge planned">Planned</span>
|
||||
- **Every deployment writes a hash-chained evidence event** — tampering breaks the chain. **RPO = 0** <span class="badge testing">Testing</span>
|
||||
- **Dev is fully autonomous** — confidence signal is the only gate <span class="badge testing">Testing</span> <span class="badge agentic">Agentic</span>
|
||||
- **qa, prod, dr require human attestation** — contract + plan + evidence <span class="badge planned">Planned</span>
|
||||
- **Separation of duties** — QA approver ≠ prod approver; platform **blocks on a match** <span class="badge planned">Planned</span>
|
||||
- **Hash-chained evidence event** — tampering breaks the chain. **RPO = 0** <span class="badge testing">Testing</span>
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# Testing vs. Planned
|
||||
# The vision realized
|
||||
|
||||
<em class="story">Let's be honest about what works today and what's on the roadmap.</em>
|
||||
|
||||
<style>
|
||||
section { font-size: 20px; }
|
||||
</style>
|
||||
|
||||
**11 capabilities testing today** (dev pilot-ready):
|
||||
|
||||
- Contract-driven deploys · Module catalog · Zero-trust OIDC + ABAC
|
||||
- Security + policy checks before infra creation · Confidence signal gating
|
||||
- Hash-chained evidence outbox (RPO = 0) · Encryption by default + per-stack CMKs
|
||||
- Deletion protection + safe decommission · Uptime monitoring
|
||||
- Platform-managed environments · Engine-agnostic core + VCS-agnostic ingestion
|
||||
|
||||
**9 planned** (production path):
|
||||
|
||||
- HITL wiring for qa/prod/dr · All-runner OIDC · Full regulatory ledger
|
||||
- Compliance milestone (GDPR, SOX, SOC2, DORA) · Environment self-service
|
||||
- Dynamic module creation <span class="badge agentic">Agentic</span> · Pattern recognition <span class="badge agentic">Agentic</span>
|
||||
- Additional engine adapters · Deeper observability bootstrap
|
||||
|
||||
**Verification Coverage** — 6 cloud capabilities are design-verified + locally emulated, deploy-unverified (IAM drift):
|
||||
DynamoDB contracts table · Lambda contract-ingestor · ECS service live · CloudFront prod stack · uptime-kuma · OIDC role
|
||||
|
||||
*Full inventory + phased roadmap in the appendix.*
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# The Vision Realized
|
||||
|
||||
<em class="story">Here's what success looks like when the North Star is reached.</em>
|
||||
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics (a simple contract, a one-line `uses:`); safety is in the gates the consumer cannot bypass.
|
||||
- **Security, observability, and compliance as platform defaults** — not per-team effort, not post-hoc remediation.
|
||||
- **Auditability as a byproduct, not a project.** Every production change is traceable to a human attestation and a tamper-evident evidence event.
|
||||
- **Blast radius contained by design.** Zero-trust OIDC + ABAC means a consumer can only touch its own tagged resources.
|
||||
- **Infrastructure as a utility, not a craft.** Teams consume infrastructure, they don't maintain it.
|
||||
- **A path to the citizen developer.** The same safety envelope that serves a senior engineer will serve a non-technical consumer. <span class="badge agentic">Agentic</span>
|
||||
- **Velocity without sacrificing safety** — speed in ergonomics, safety in unbypassable gates
|
||||
- **Security, observability, compliance as platform defaults** — not per-team effort
|
||||
- **Auditability as a byproduct, not a project** — every change traceable to a human attestation
|
||||
- **Blast radius contained by design** — OIDC + ABAC, only your own tagged resources
|
||||
- **Infrastructure as a utility, not a craft** — consume, don't maintain
|
||||
- **A path to the citizen developer** — same envelope, senior engineer or non-technical <span class="badge agentic">Agentic</span>
|
||||
|
||||
---
|
||||
|
||||
@@ -220,16 +150,16 @@ DynamoDB contracts table · Lambda contract-ingestor · ECS service live · Clou
|
||||
|
||||
# Appendix
|
||||
|
||||
<em class="story">For deep dives — these slides cover details omitted from the main 10.</em>
|
||||
|
||||
**Contents:**
|
||||
|
||||
1. Platform-Managed Environments (detail)
|
||||
2. Observability Built In (detail)
|
||||
3. The Road to the North Star (phased roadmap)
|
||||
4. Testing vs. Planned (full inventory)
|
||||
5. Glossary
|
||||
6. Operating Model & Cost
|
||||
3. Security by Construction (the full defaults inventory)
|
||||
4. The Road to the North Star (phased roadmap)
|
||||
5. Testing vs. Planned (full inventory)
|
||||
6. Glossary
|
||||
7. Operating Model & Cost (real AWS spend + pre-mortem)
|
||||
8. Verified by Construction (the v1.11 architecture)
|
||||
|
||||
---
|
||||
|
||||
@@ -244,7 +174,7 @@ A named environment is a platform-owned bundle of:
|
||||
- A state backend (S3 + DynamoDB for state + locking)
|
||||
- An IAM role surfaced via ABAC, scoped to the consumer's identity and resource tags
|
||||
|
||||
The consumer selects an environment **by name** in their contract. The platform resolves the name to the underlying resources at run time. **The consumer never sees raw credentials.**
|
||||
The consumer selects an environment **by name** in their contract. The platform resolves it at run time. **The consumer never sees raw credentials.**
|
||||
|
||||
**Friendly onboarding:** the first run detects no environment and emits a guided prompt (not an opaque failure). <span class="badge testing">Testing</span> <span class="badge planned">Self-service: planned</span>
|
||||
|
||||
@@ -254,18 +184,29 @@ The consumer selects an environment **by name** in their contract. The platform
|
||||
|
||||
Monitoring is **a platform default, not a per-team project.** <span class="badge testing">Testing</span>
|
||||
|
||||
- **Uptime monitoring deployed automatically with every stack** — a dedicated monitoring instance is provisioned after any module deploy, in a separate state, with a feature flag to disable
|
||||
- **Uptime monitoring deployed automatically with every stack** — separate state, feature flag to disable
|
||||
- **Monitored endpoints passed from the deployment's own outputs** — no manual endpoint registration
|
||||
- **Alert channels:** Microsoft Teams webhook, email, SMS, and GitHub issues
|
||||
- **The uptime URL is published to the developer** via a PR comment — they don't hunt for it
|
||||
- **Roadmap:** deeper observability bootstrap (dashboards, runbooks, on-call bindings) as first-class contract fields <span class="badge planned">Planned</span>
|
||||
- **The uptime URL is published to the developer** via a PR comment
|
||||
- **Roadmap:** deeper observability bootstrap (dashboards, runbooks, on-call bindings) <span class="badge planned">Planned</span>
|
||||
|
||||
---
|
||||
|
||||
# A3 — Security by Construction
|
||||
|
||||
Security defaults that **do not require a team to opt in.** Checks run on **every** deployment, normalized to a single schema. <span class="badge testing">Testing</span>
|
||||
|
||||
- **Policy checks** (Checkov, Wiz, Kyverno) — secrets, public ingress, IAM wildcards, **required tagging** — all run *before* infra is created
|
||||
- **Encryption on every resource** — at-rest on by default; per-stack CMKs with 90-day rotation, **no shared keys across stacks**
|
||||
- **Deletion protection on by default** — `prevent_destroy` on unless explicitly disabled via a documented flag
|
||||
- **Safe decommission** — a 2-step pipeline with **two SRE attestation gates** and a **change-request validated against the CMDB**
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# A3 — The Road to the North Star
|
||||
# A4 — The Road to the North Star
|
||||
|
||||
*Proposed phasing — not formally planned.*
|
||||
|
||||
@@ -276,20 +217,22 @@ Monitoring is **a platform default, not a per-team project.** <span class="badge
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# A4 — Testing vs. Planned (Full Inventory)
|
||||
# A5 — Testing vs. Planned (Full Inventory)
|
||||
|
||||
<style>
|
||||
section { font-size: 15px; }
|
||||
td { font-size: 14px; vertical-align: top; }
|
||||
section { font-size: 18px; }
|
||||
td { font-size: 16px; vertical-align: top; }
|
||||
ul { margin: 0; padding-left: 1.2em; }
|
||||
li { margin-bottom: 2px; }
|
||||
</style>
|
||||
|
||||
**22/22 Verified** — the v1.11 lifecycle pipeline ran apply→modify→destroy against live AWS for every L1 + L2 module, then tore down to zero-cost (D-096). The v1.10 "6 deploy-unverified (IAM drift)" status is closed (CAP-013 fixed in P67).
|
||||
|
||||
<table style="width: 100%; border: none;">
|
||||
<tr>
|
||||
<td style="width: 52%; border: none; padding-right: 12px;">
|
||||
|
||||
**Testing** (works internally, dev pilot-ready)
|
||||
**Testing** (22/22 Verified — works internally, dev pilot-ready)
|
||||
|
||||
- Contract-driven deploys with a versioned reusable workflow
|
||||
- Module catalog (primitives + modules) with validated examples
|
||||
@@ -324,7 +267,7 @@ li { margin-bottom: 2px; }
|
||||
|
||||
---
|
||||
|
||||
# A5 — Glossary
|
||||
# A6 — Glossary
|
||||
|
||||
| Term | Meaning |
|
||||
|---|---|
|
||||
@@ -340,13 +283,43 @@ li { margin-bottom: 2px; }
|
||||
|
||||
---
|
||||
|
||||
# A6 — Operating Model & Cost
|
||||
# A7 — Operating Model & Cost
|
||||
|
||||
ACDL runs at **zero cloud cost** for day-to-day development.
|
||||
<style>
|
||||
section { font-size: 20px; }
|
||||
table { font-size: 18px; }
|
||||
</style>
|
||||
|
||||
- **Local emulators are the primary tier** — the full pipeline (contract → resolver → adapter → local ECS → flat-file outbox → local Lambda) runs in-process, no AWS credentials, no Checkov, no DynamoDB. <span class="badge testing">Testing</span>
|
||||
- **Live-AWS is a one-off spike per milestone** — `terraform init/validate/plan` against the real account verifies the adapter emits valid Terraform. No BAU cloud spend.
|
||||
- **No running infrastructure between milestones** — state is in S3 (one bucket), the outbox is in DynamoDB (one table), both are query-only between spikes.
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). No ECS, no CloudFront, no Lambda running persistently.
|
||||
ACDL runs at **zero cloud cost** for day-to-day development. AWS spend was measured via Cost Explorer (`COST.md`, 2026-07-28):
|
||||
|
||||
**The operating model:** local-first development, milestone-scoped verification, zero BAU cloud spend.
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total spend (8 days) | **$0.001883** |
|
||||
| Daily average | $0.000235 |
|
||||
| Projected monthly | ~$0.007 |
|
||||
| Peak day | 2026-07-27 ($0.000867) |
|
||||
|
||||
- **S3 dominates** (98.8%, terraform state bucket) — no compute ran because v1.0→v1.10 was plan-only for IAM-gated capabilities
|
||||
- **Local emulators are the primary tier** — the full pipeline runs in-process, no AWS credentials <span class="badge testing">Testing</span>
|
||||
- **Live-AWS verification is milestone-scoped, then torn down.** The pipeline now **defaults to plan-only** on every PR; `ACDL_LIFECYCLE_MODE=full` overrides to apply→destroy for milestone verification (REQ-134, v1.12).
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). Any spike > $1/day is an anomaly.
|
||||
|
||||
**Pre-mortem (`PRE_MORTEM.md`):** the v1.10 decay incident (diff-scoped VERIFY missed 7 adapter defects) is the root pattern: *a claim outruns the verification that backs it.* Four forward failure modes + structural mitigations (regression-tested IAM baseline, mandatory teardown, verified-only deck claims, honest scope).
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# A8 — Verified by Construction
|
||||
|
||||
<style>
|
||||
section { font-size: 20px; }
|
||||
</style>
|
||||
|
||||
Two architectural pillars make "Verified" a structural property, not a claim:
|
||||
|
||||
- **The stateless adapter (918 → ~80 lines).** The Terraform adapter was a 918-line monolith with 3 constant tables and 39 type-specific branches. It is now a ~80-line **stateless assembler**: it owns no module content — no resource shape, no nested HCL blocks, no defaults. Each L1 module ships a real `terraform/` module dir owning its shape, nested blocks, and defaults. The adapter reads the registry and emits `module "x" { source = ... }` blocks. A new module is a new terraform dir, not a code change. *(The v1.12 P67 fix closed a dedup defect for multi-resource L1s — ecs-service, alb; CAP-013 now Verified.)*
|
||||
- **Pipeline-driven lifecycle testing.** A `modules-lifecycle` pipeline matrix-runs each L1 and L2 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS. **The "test" = the pipeline cell going green.** Defaults to **plan-only** on every PR (fast, no AWS mutation, no cost); `ACDL_LIFECYCLE_MODE=full` overrides to the real apply→destroy for milestone verification (REQ-134, v1.12). The regression gate (D-091) re-runs all 22 capabilities at milestone completion — **22/22 Verified** as of v1.12.
|
||||
|
||||
The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently. The ~80-line stateless adapter + the milestone regression gate are the structural fix.
|
||||
@@ -1,6 +1,6 @@
|
||||
# How The Platform Works — Talking Points
|
||||
|
||||
> **Companion to:** `how-the-platform-works-marp.md` (10 main + 6 appendix = 16 slides)
|
||||
> **Companion to:** `how-the-platform-works-marp.md` (10 main + Appendix TOC + 8 appendix = 19 slides)
|
||||
> **Content source:** `how-the-platform-works.md` (full source of truth with speaker notes)
|
||||
> **Purpose:** Presenter-ready cues — 3-6 talking points per slide + the one key takeaway the audience should remember.
|
||||
> **Audience:** Senior Leadership — CTO, Head of Cloud, Head of Infrastructure, Head of DevOps
|
||||
@@ -10,204 +10,227 @@
|
||||
## Slide 1 — Title
|
||||
|
||||
**Talking points:**
|
||||
- Brief introduction — this deck explains *how* the platform works internally, not what the developer experience is (that's the companion deck)
|
||||
- Brief introduction — this deck explains *how* the platform works internally, not the developer experience (that's the companion deck)
|
||||
- Set the frame: the platform is not a CI/CD tool — it's the organizational lever for shipping safely at the pace the business demands
|
||||
- The deck has 10 main slides plus a 6-slide appendix for deep-dive questions
|
||||
- Every "Testing" claim is Verified — 22/22 capabilities via the v1.11 lifecycle pipeline (see A8)
|
||||
|
||||
**Key takeaway:** This is a platform that computes safety, doesn't assume it.
|
||||
**Key takeaway:** The platform is the organizational lever for safe, fast shipping.
|
||||
|
||||
---
|
||||
|
||||
## Slide 2 — The Problem & The North Star
|
||||
## Slide 2 — Four frictions slow every team
|
||||
|
||||
**Talking points:**
|
||||
- Open with the cost of the status quo — every team running its own pipeline, its own Terraform, its own review checklist is paying a tax that doesn't differentiate the business
|
||||
- Walk through the 4 frictions quickly: cognitive load, operational work, red tape, scalability. Don't dwell — the North Star is the resolution
|
||||
- Land the North Star quote: "declare intent → safe production deployment" — this is the entire value proposition in one sentence
|
||||
- Open with the cost of the status quo — every team running its own pipeline, Terraform, and review checklist pays a tax that doesn't differentiate the business
|
||||
- The four frictions are categorically parallel: cognitive load, operational work, red tape, scalability
|
||||
- The platform absorbs all four — that is the value proposition in one sentence
|
||||
- Don't dwell here; this is the setup for the before/after contrast on the next slide
|
||||
|
||||
**Key takeaway:** Four frictions slow every team. The platform absorbs all four.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Declare intent; the platform delivers safe production
|
||||
|
||||
**Talking points:**
|
||||
- Land the before/after contrast: today's queue vs. ACDL's autonomous flow
|
||||
- The litmus test: if a platform engineer still has to touch a ticket for a dev→qa promotion, we haven't delivered the vision
|
||||
- Note: the 2 anti-goals ("not a general-purpose AI" and "not a permissive delivery highway") have moved to slide 3 — they belong with the scope boundary, not the North Star
|
||||
- The North Star is one sentence: "declare intent → safe production deployment"
|
||||
- A non-technical consumer ships by declaring intent — no workflow, no config file, no module
|
||||
|
||||
**Key takeaway:** The platform absorbs all four frictions. Declare intent, not execute operations.
|
||||
**Key takeaway:** Declare intent; the platform delivers safe production — autonomously, with a complete audit trail.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Where ACDL Sits in Your World
|
||||
## Slide 4 — ACDL owns infrastructure, not your app
|
||||
|
||||
**Talking points:**
|
||||
- This is the new scope-boundary slide — it tells leadership where ACDL fits and, just as importantly, where it doesn't
|
||||
- Upstream is anything — your IDE, an agentic SDLC, or a citizen developer vibe coding on a laptop. ACDL doesn't care how the contract was produced
|
||||
- ACDL is infrastructure only — it provisions and governs AWS resources. It does not build, test, or deploy your application code. That's upstream
|
||||
- Land the 2 anti-goals: "not a general-purpose AI" (autonomy is narrow, scoped to delivery, bounded by strict policy) and "not a permissive delivery highway" (no escape hatches to bypass the confidence framework)
|
||||
- The sovereign boundary means the platform team owns delivery and infrastructure, not the upstream development process
|
||||
- The platform is deliberately scoped — it is not trying to be everything
|
||||
- The sovereign boundary: the platform team owns delivery and infrastructure, not the upstream development process
|
||||
- The anti-goals are as important as the goals — they tell leadership what not to expect
|
||||
- Upstream is anything: IDE, agentic SDLC, or vibe coding — ACDL doesn't care how the contract was produced
|
||||
|
||||
**Key takeaway:** ACDL is the delivery and infrastructure boundary. Upstream is anything; ACDL is infra only.
|
||||
**Key takeaway:** ACDL is infrastructure only. App build/test/deploy is upstream.
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — The Contract-Driven Model
|
||||
## Slide 5 — One YAML file. The platform owns everything else.
|
||||
|
||||
**Talking points:**
|
||||
- Emphasize the asymmetry — the consumer's surface is intentionally tiny (module + environment + inputs), the platform's surface is large and opinionated
|
||||
- Note: the contract examples now show **infrastructure inputs** (cpu, memory, desired_count, port) — not a container image. The image is upstream; the platform governs infrastructure
|
||||
- The contract is the API — it's deliberately small so it can be reviewed, validated, and audited
|
||||
- The consumer does not write infrastructure modules, workflow logic, or adapter code — they declare intent; the platform reconciles, provisions, and progresses
|
||||
- Land the "no AWS account, no VPC, no state backend" point — the platform owns the blast radius. Consumers can't drift into misconfigured state or over-permissioned roles because they never touch them
|
||||
- Hold this slide — emphasize the asymmetry. The consumer's surface is intentionally tiny; the platform's surface is large and opinionated
|
||||
- The contract names three things: module, environment, inputs — that's the entire consumer-facing interface to production
|
||||
- The contract shows infrastructure inputs (cpu, memory, desired_count, port) — not a container image. The image is upstream; the platform governs infrastructure
|
||||
- The consumer provides no AWS account, no VPC, no state backend — the platform owns the blast radius
|
||||
|
||||
**Key takeaway:** A single YAML contract. The platform owns everything else — including the blast radius.
|
||||
**Key takeaway:** One YAML file. The platform owns everything else.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — The End-to-End Flow
|
||||
## Slide 6 — Same stages, same checks, every deployment
|
||||
|
||||
**Talking points:**
|
||||
- Walk the flow left to right once — don't dwell on internals. The point is that the flow is fixed, opinionated, and identical for every consumer
|
||||
- Land beat 1: security and policy checks run *before* any infrastructure is created — not after the fact, not as a post-deployment audit
|
||||
- Land beat 2: every stage produces a record that feeds the confidence signal and the evidence stream. There is no "unchecked" path
|
||||
- Tease the confidence signal (slide 7) — this is where "safety is computed" lands
|
||||
- Walk left to right once — don't dwell on internals; the point is the flow is fixed, opinionated, and identical for every consumer
|
||||
- The two leadership-relevant beats: (1) checks before creation, (2) every stage is evidenced
|
||||
- No team-specific pipelines, no tribal runbooks — the flow is the contract
|
||||
- The confidence signal (Slide 8) is where the "safety is computed" story lands
|
||||
|
||||
**Key takeaway:** The same pipeline, every time. Checks before creation, evidence at every stage.
|
||||
**Key takeaway:** Same stages, same checks, every deployment. No "unchecked" path.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — Zero-Trust by Default
|
||||
## Slide 7 — No long-lived credentials. Blast radius contained.
|
||||
|
||||
**Talking points:**
|
||||
- This is the slide for the Head of Cloud/Security — the key phrase is "blast radius contained to the consumer's own stack"
|
||||
- Contrast with the common failure mode: shared CI roles that can touch any account resource. The platform's ABAC model scopes every action to the consumer's own tagged resources
|
||||
- OIDC means no long-lived credentials in consumer repos — each job mints a short-lived token. Be honest: this is testing on GitHub Actions runners today; all-runner coverage is planned
|
||||
- The static-key override exists for edge cases but is rotated daily on platform runners — it is never the default
|
||||
- Contrast with the common failure mode of shared CI roles that can touch any account resource
|
||||
- OIDC federation: short-lived token per job, no credential stored in the consumer repo or runner secret
|
||||
- ABAC, not role-based: repo identity + resource tags scope every action — a consumer can only touch its own tagged resources
|
||||
- The static-key override exists for edge cases but is rotated daily on platform runners; it is never the default
|
||||
|
||||
**Key takeaway:** A consumer can only touch the resources it created. One consumer can never affect another.
|
||||
**Key takeaway:** No long-lived credentials. A consumer can only touch its own tagged resources.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Safety is Computed, Not Assumed
|
||||
## Slide 8 — Safety is a measurable signal, not a black box
|
||||
|
||||
**Talking points:**
|
||||
- This is the bet that separates this platform from "yet another CI/CD tool" — reliance on operator instinct or tenure is not a substitute for a computed, auditable signal
|
||||
- The new confidence signal diagram makes the six inputs and the per-input breakdown visible — walk it briefly so the audience sees the signal is *not* a black box
|
||||
- The weights are **manually tuned**, the inputs are **observable**, and the breakdown is **auditable** — if a consumer asks "why 0.62?", the platform answers with a per-input breakdown. This is the "auditable, not magic" point
|
||||
- Walk the threshold table: dev ≥ 0.50 (autonomous, Testing) → qa ≥ 0.75 (QA, Planned) → prod ≥ 0.90 (SRE, Planned). The bar rises automatically with sensitivity
|
||||
- A single critical policy finding hard-blocks the deployment — critical findings are not averaged away. This is non-negotiable
|
||||
- The thresholds are tunable by Infra & Ops + SRE jointly, and any override is itself a confidence-event in the audit stream
|
||||
- This is the bet that separates this platform from "yet another CI/CD tool" — reliance on operator instinct or tenure is not a substitute
|
||||
- The signal is auditable; the thresholds are tunable by Infra & Ops + SRE jointly, and any override is itself a confidence-event in the audit stream
|
||||
- Six weighted inputs: policy, validation, freshness, provenance, history, NFRs — manually tuned, auditable per-input breakdown
|
||||
- If a consumer asks "why 0.62?", the platform answers with a per-input breakdown — not a black box
|
||||
- A single critical finding hard-blocks — critical findings are not averaged away
|
||||
|
||||
**Key takeaway:** Safety is a measurable, explainable signal — manually tuned, observable inputs, auditable breakdown. A single critical finding blocks everything.
|
||||
**Key takeaway:** Safety is a measurable, explainable signal — not a black box.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — Security by Construction
|
||||
## Slide 9 — Every change traceable to a human attestation
|
||||
|
||||
**Talking points:**
|
||||
- The phrase to land is "secure by default, not secure by effort" — teams don't opt in to security, it's on by construction
|
||||
- Policy checks (Checkov, Wiz, Kyverno) are normalized to a single schema — we can add a new security tool without changing the confidence model or the evidence stream
|
||||
- Tagging standards are enforced, not advisory — a missing `acdl:owner` tag fails the check, it doesn't warn
|
||||
- Encryption is on every resource with per-stack customer-managed keys — no shared keys across stacks, 90-day rotation
|
||||
- The decommission flow is the counter-argument to "deletion protection makes cleanup impossible" — it's a deliberate, gated, two-SRE-approval path with CMDB validation, not a lock with no key
|
||||
- The "lower environments autonomous, higher environments attested" tenet resolves the classic "move fast vs. be safe" false dichotomy
|
||||
- Be honest: the separation-of-duties *mechanism* is designed and the dev path is wired; qa/prod/dr wiring is on the roadmap
|
||||
- The audit trail is a byproduct of deployment, not a project — every production change is traceable to a human attestation
|
||||
- The full regulatory ledger (S3 Object Lock, JWS signatures, daily checkpoints) is planned; what ships today is the outbox + hash chain that makes every event tamper-evident and queryable
|
||||
- RPO = 0 — the evidence write is synchronous; a deployment is not acknowledged until the evidence event is durably recorded
|
||||
|
||||
**Key takeaway:** Encryption, deletion protection, policy checks — on by default. Decommission is gated, not impossible.
|
||||
**Key takeaway:** Every change is traceable to a human attestation and a tamper-evident evidence event.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Accountability & Audit
|
||||
|
||||
**Talking points:**
|
||||
- The "lower environments autonomous, higher environments attested" tenet is the resolution to the classic "move fast vs. be safe" false dichotomy
|
||||
- The new attestation flow diagram shows the human-in-the-loop path — dev autonomous → qa/prod/dr human attestation → evidence event. Walk it briefly
|
||||
- Land the QA clarification: **QA attests to infrastructure readiness — the contract, the planned Terraform changes, and the accumulated evidence. QA does not review application code (that's upstream).** This is the scope-boundary point reiterated
|
||||
- Badge reclassification to be clear about: separation of duties = **Planned** (not "design tested"); dev autonomous = **Testing**; qa/prod/dr attestation = **Planned**
|
||||
- The audit trail is a byproduct of deployment, not a project — every deployment writes a hash-chained evidence event synchronously (RPO = 0)
|
||||
- Be honest about the ledger: the outbox + hash chain is testing today; the full regulatory ledger (S3 Object Lock, JWS signatures, daily checkpoints) is planned
|
||||
|
||||
**Key takeaway:** Dev is autonomous. Higher environments are attested. QA attests to infra readiness, not app code. Every change is evidenced.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — The Vision Realized
|
||||
## Slide 10 — The vision realized
|
||||
|
||||
**Talking points:**
|
||||
- Close on the strategic frame — the platform is not "a CI/CD tool," it's the organizational lever for shipping safely at the pace the business demands
|
||||
- Velocity without sacrificing safety: speed is in the ergonomics (a simple contract, a one-line `uses:`), safety is in the gates the consumer cannot bypass
|
||||
- Security, observability, and compliance as platform defaults — not per-team effort, not post-hoc remediation
|
||||
- Auditability as a byproduct, not a project — every production change traceable to a human attestation and a tamper-evident evidence event
|
||||
- Infrastructure as a utility, not a craft — teams consume, they don't maintain. The platform compounds value over time by learning from recurring patterns
|
||||
- The path to the citizen developer — the same safety envelope that serves a senior engineer will serve a non-technical consumer. Expanding who can ship safely without lowering the bar
|
||||
- Velocity without sacrificing safety: speed is in the ergonomics, safety is in the unbypassable gates
|
||||
- Security, observability, compliance as platform defaults — not per-team effort, not post-hoc remediation
|
||||
- A path to the citizen developer: the same safety envelope serves a senior engineer and a non-technical consumer
|
||||
- Invite questions; the companion deck ("The Developer Experience") covers who uses the platform and how fast/safe they ship
|
||||
|
||||
**Key takeaway:** The investment is in the abstraction, not the tool. Ship safely at the pace the business demands, with the security and audit posture the regulators require.
|
||||
**Key takeaway:** Ship safely at the pace the business demands, with the security and audit posture the regulators require.
|
||||
|
||||
---
|
||||
|
||||
## Appendix TOC — Deep Dives
|
||||
## Appendix TOC — Appendix
|
||||
|
||||
**Talking points:**
|
||||
- These slides are for follow-up questions — don't walk them in the main 15-minute talk
|
||||
- Pull them up when an audience member wants detail on a specific topic: environments, observability, roadmap, full inventory, or glossary terms
|
||||
- The appendix exists so the main deck stays tight while still having answers ready
|
||||
- These are deep-dive slides for follow-up questions — don't walk them in the main 15-minute talk
|
||||
- Pull them up when an audience member wants detail on a specific topic
|
||||
- The appendix is indexed to match the Marp deck's A1-A8 structure
|
||||
|
||||
**Key takeaway:** The appendix is the backup — detail on demand, not on the critical path.
|
||||
**Key takeaway:** Deep dives available — pull the relevant appendix slide when asked.
|
||||
|
||||
---
|
||||
|
||||
## A1 — Platform-Managed Environments
|
||||
|
||||
**Talking points:**
|
||||
- A consumer provides no AWS account, no VPC, no subnet, no state backend, no runner key — the platform owns the entire blast radius
|
||||
- A named environment is a platform-owned bundle: an AWS account (or scoped partition), a network, a state backend, and an IAM role surfaced via ABAC
|
||||
- The consumer selects an environment by name (`environment: dev`) and the platform resolves it at run time — the consumer never sees raw credentials
|
||||
- Friendly onboarding is testing today: the first run detects no environment and emits a guided prompt, not an opaque failure. Self-service provisioning is planned
|
||||
- For the Head of Cloud: this is the governance story — the platform team owns accounts, network design, and state hygiene; consumers can't drift because they never touch them
|
||||
- For the Head of Cloud: this is the governance story — the platform team owns the accounts, the network design, the state hygiene
|
||||
- Consumers can't drift into misconfigured state backends or over-permissioned roles because they never touch them
|
||||
- The onboarding prompt matters — first impressions of a platform are made when it fails for the first time
|
||||
- Self-service environment provisioning is planned
|
||||
|
||||
**Key takeaway:** Environments are platform-owned bundles. Consumers pick a name; the platform owns the rest.
|
||||
**Key takeaway:** The consumer never sees raw credentials. The platform owns the blast radius.
|
||||
|
||||
---
|
||||
|
||||
## A2 — Observability Built In
|
||||
|
||||
**Talking points:**
|
||||
- Monitoring is a platform default, not a per-team project — you don't deploy a service and *then* remember to set up monitoring
|
||||
- Uptime monitoring (Uptime-kuma on ECS Fargate) is provisioned automatically after any module deploy, in a separate state, with a feature flag to disable
|
||||
- Monitored endpoints come from the deployment's own outputs — no manual endpoint registration. The platform constructs the synthetic monitoring contract from what was just deployed
|
||||
- Alert channels: Microsoft Teams webhook, email, SMS, and GitHub issues — all testing today
|
||||
- The uptime URL is published to the developer via a PR comment so they don't hunt for it
|
||||
- Roadmap: deeper observability bootstrap (dashboards, runbooks, on-call bindings) as first-class contract fields for prod/dr — planned
|
||||
- The Head of DevOps cares about this — "you don't deploy a service and *then* remember to set up monitoring; the platform does it as part of the deploy"
|
||||
- Uptime monitoring deployed automatically with every stack — separate state, feature flag to disable
|
||||
- The feature flag means teams with existing monitoring (e.g. Datadog) can opt out cleanly
|
||||
- Deeper observability bootstrap (dashboards, runbooks, on-call bindings) is on the roadmap
|
||||
|
||||
**Key takeaway:** Monitoring ships with the deploy, not after it. The feature flag lets teams with existing monitoring opt out cleanly.
|
||||
**Key takeaway:** Monitoring is a platform default, not a per-team project.
|
||||
|
||||
---
|
||||
|
||||
## A3 — The Road to the North Star
|
||||
## A3 — Security by Construction
|
||||
|
||||
**Talking points:**
|
||||
- Be explicit up front: this is **proposed phasing, not formally planned** — the phases are sequenced by dependency, not by calendar
|
||||
- Phase 1 — Testing baseline (current): contract-driven deploys, zero-trust OIDC + ABAC, confidence signal, hash-chained evidence, encryption by default, safe decommission, uptime monitoring, platform-managed environments
|
||||
- Phase 2 — Production readiness: HITL wiring for qa/prod/dr, all-runner OIDC, full regulatory ledger, environment self-service
|
||||
- Phase 3 — Compliance & expansion: compliance milestone (GDPR, SOX, SOC2, DORA), additional engine adapters (OpenTofu, Pulumi, Kubernetes CRDs), deeper observability bootstrap
|
||||
- Phase 4 — Agentic frontier: dynamic module creation from a contract (citizen-developer flow), pattern recognition that compounds value over time
|
||||
- Each phase's items are gated on the prior phase's maturity — invite questions on any phase boundary
|
||||
- The phrase to land is "secure by default, not secure by effort"
|
||||
- The selling point is *normalization* — we can add a new security tool without changing the confidence model or the evidence stream
|
||||
- For the Head of Security: tagging standards are enforced, not advisory — a missing `acdl:owner` tag fails the check, not a warning
|
||||
- The decommission flow is the counter-argument to "deletion protection makes cleanup impossible" — it's a deliberate, gated, two-approval path
|
||||
|
||||
**Key takeaway:** A dependency-sequenced path from testing baseline to agentic frontier — proposed, not formally committed.
|
||||
**Key takeaway:** Secure by default, not secure by effort. Checks run before infra is created.
|
||||
|
||||
---
|
||||
|
||||
## A4 — Testing vs. Planned (Full Inventory)
|
||||
## A4 — The Road to the North Star
|
||||
|
||||
**Talking points:**
|
||||
- Close on honesty — the platform delivers real, verifiable value today, and the roadmap is concrete, not aspirational hand-waving
|
||||
- Walk the Testing column (11 capabilities) quickly — from contract-driven deploys to encryption by default to uptime monitoring. These work internally and are dev pilot-ready
|
||||
- Walk the Planned column (9 capabilities) — be clear about what's not yet done: HITL wiring, full regulatory ledger, compliance milestone, environment self-service, dynamic module creation, additional engine adapters, deeper observability
|
||||
- Two agentic items are flagged: dynamic module creation and pattern recognition — both involve AI agents or autonomous decision-making
|
||||
- Invite questions on any "planned" item — each has a defined milestone and a clear reason it isn't shipped yet (usually an upstream dependency, not an engineering gap)
|
||||
- Be clear with leadership: this is a proposed phasing, not a formally committed plan
|
||||
- The phases are sequenced by dependency, not by calendar — each phase's items are gated on the prior phase's maturity
|
||||
- Phase 1 is now fully Verified (22/22) and torn down to zero-cost — it is no longer aspirational
|
||||
- Invite questions on any phase boundary
|
||||
|
||||
**Key takeaway:** Proposed phasing, not formally planned. Phase 1 is Verified; Phase 4 is the North Star.
|
||||
|
||||
---
|
||||
|
||||
## A5 — Testing vs. Planned (Full Inventory)
|
||||
|
||||
**Talking points:**
|
||||
- Close on honesty — the platform delivers real, verifiable value today: 22/22 auto-verifiable capabilities Verified via the v1.11 lifecycle pipeline
|
||||
- The roadmap is concrete, not aspirational hand-waving — 9 planned items, each with a defined milestone and a clear reason it isn't shipped yet (usually an upstream dependency, not an engineering gap)
|
||||
- Emphasize: 0 consumer adoption today — "Testing" means it works internally and is dev pilot-ready, not that it's released
|
||||
- The lifecycle pipeline defaults to plan-only on every PR; `ACDL_LIFECYCLE_MODE=full` overrides for milestone verification
|
||||
|
||||
**Key takeaway:** 11 capabilities testing today. 9 planned items on a concrete roadmap. Zero consumer adoption — yet.
|
||||
**Key takeaway:** 22/22 Verified today. 9 planned, each with a clear milestone and reason.
|
||||
|
||||
---
|
||||
|
||||
## A5 — Glossary
|
||||
## A6 — Glossary
|
||||
|
||||
**Talking points:**
|
||||
- This is a reference slide — don't read it aloud, point to it as a takeaway reference for term definitions
|
||||
- The terms most likely to come up in questions: OIDC (short-lived tokens), ABAC (tag-scoped access), CMK (per-stack encryption keys), RPO = 0 (synchronous evidence write)
|
||||
- HITL is the human-attestation term for qa/prod/dr; NFR is the non-functional-requirements input to the confidence signal
|
||||
- IR (Intermediate Representation) is the engine-agnostic stack definition between the contract and Terraform — the abstraction that makes the platform portable
|
||||
- Use this slide as a reference when the audience asks for term definitions
|
||||
- Don't read it aloud — point to it as a takeaway reference
|
||||
- All acronyms used in the deck are defined here
|
||||
|
||||
**Key takeaway:** A shared vocabulary — keep it as a reference for follow-up questions.
|
||||
**Key takeaway:** Reference slide — don't read aloud.
|
||||
|
||||
---
|
||||
|
||||
## A7 — Operating Model & Cost
|
||||
|
||||
**Talking points:**
|
||||
- The headline for the Head of Cloud / Finance: less than one cent over 8 days of active development; zero BAU cloud spend
|
||||
- The lifecycle pipeline defaults to plan-only so the PR-time cost is zero
|
||||
- The pre-mortem is the credibility slide — we already asked "how does this fail?" and the mitigations are structural
|
||||
- The v1.10 decay incident is disclosed honestly, not hidden — that disclosure IS the mitigation
|
||||
|
||||
**Key takeaway:** Zero BAU cloud cost. Pre-mortemed failure modes with structural mitigations.
|
||||
|
||||
---
|
||||
|
||||
## A8 — Verified by Construction
|
||||
|
||||
**Talking points:**
|
||||
- This is the deep-dive slide for the Head of Engineering / Architecture — the two pillars answer "how do you keep the decks honest?"
|
||||
- The adapter is simple enough to reason about (a stateless assembler); the lifecycle pipeline is the automated verification that backs every "Testing" claim
|
||||
- The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently because the VERIFY gate was diff-scoped
|
||||
- The ~80-line stateless adapter + the milestone regression gate are the structural fix
|
||||
- The plan-only default (v1.12) means verification runs on every PR at zero cost, with the full apply→destroy gated behind a CI variable override
|
||||
|
||||
**Key takeaway:** "Verified" is a structural property, not a claim — the stateless adapter + lifecycle pipeline make it so.
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
> **Subtitle:** Agentic Cloud Delivery Platform
|
||||
> **Audience:** Senior Leadership, CTO, Head of Cloud, Head of Infrastructure, Head of DevOps
|
||||
> **Length:** ~15 minutes · 10 main + 6 appendix = 16 slides
|
||||
> **Length:** ~15 minutes · 10 main + Appendix TOC + 8 appendix = 19 slides
|
||||
> **Purpose:** Sell the platform's value to tech leadership — zero-trust, security, observability, auditability, and the shift from "operators guess" to "the platform computes safety."
|
||||
> **Maturity framing:** "Testing" = works internally, dev pilot-ready. "Planned" = on the roadmap, not yet implemented. "Agentic" = involves AI agents or autonomous decision-making.
|
||||
> **Re-verification (2026-07-27):** Every "Testing" claim in this deck was re-verified in v1.10 Phase 54 (D-093). The headline E2E (contract → resolver → adapter → terraform init/validate/plan) passes against the live AWS account; the local emulating tier (Phase 53) runs the full E2E with no cloud credentials. 16/16 auto-verifiable capabilities Verified; 6 IAM-gated cloud resources are escalated (require an admin principal the spike-runner lacks). See `.ciagent/CAPABILITY_INVENTORY.md`.
|
||||
> **Re-verification (2026-07-29):** Every "Testing" claim in this deck was re-verified in v1.10 Phase 54 (D-093) and again in v1.11 via the pipeline-driven lifecycle tests (P59–P62). The headline E2E (contract → resolver → adapter → terraform init/validate/plan) passes against the live AWS account; the local emulating tier (Phase 53) runs the full E2E with no cloud credentials. **22/22 auto-verifiable capabilities Verified** (CAP-013 fixed in v1.12 P67 — the adapter's multi-resource L1 dedup defect is closed; CAP-017/018 probe bugs fixed). The v1.11 lifecycle pipeline ran apply→modify→destroy against live AWS and was then torn down to zero-cost (D-096). See `.ciagent/CAPABILITY_INVENTORY.md` and `.ciagent/PRE_MORTEM.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -19,76 +19,130 @@
|
||||
|
||||
---
|
||||
|
||||
## Slide 2 — The Problem & The North Star
|
||||
## Slide 2 — Four frictions slow every team
|
||||
|
||||
Here's the problem we're solving and where we're going.
|
||||
Most teams can write code; far fewer get the infrastructure right. Delivery scales with the **coordination surface around it**, not the engineering inside it.
|
||||
|
||||
Software delivery scales with the **coordination surface around it**, not the engineering inside it. Most teams can write code; far fewer get the infrastructure right.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph ROW1 [" "]
|
||||
direction LR
|
||||
A["Cognitive load\nauthoring infra correctly"]
|
||||
B["Operational work\nmerged → running"]
|
||||
end
|
||||
subgraph ROW2 [" "]
|
||||
direction LR
|
||||
C["Red tape\ntickets, approvals, handoffs"]
|
||||
D["Scalability\nthroughput without headcount"]
|
||||
end
|
||||
A ~~~ B
|
||||
C ~~~ D
|
||||
A ~~~ C
|
||||
B ~~~ D
|
||||
```
|
||||
|
||||
Four frictions slow every team:
|
||||
- **Cognitive load** — the long tail of services, inconsistent in security and observability.
|
||||
- **Operational work** — manual promotion that scales with the system, not the change.
|
||||
- **Red tape** — tickets and handoffs that scale with the organization.
|
||||
- **Scalability** — throughput without linearly scaling platform engineers.
|
||||
|
||||
- **Cognitive load** — authoring infrastructure correctly; the long tail of services inconsistent in security and observability.
|
||||
- **Operational work** — promoting a change from "merged" to "running in production." Manual work that **scales with the system, not the change.**
|
||||
- **Red tape** — tickets, approvals, and handoffs that scale with the organization. A merged change waits in a queue.
|
||||
- **Scalability without increasing headcount** — throughput scales without linearly scaling platform engineers.
|
||||
|
||||
> Consumers **declare intent**; the platform delivers **safe production deployment** — automatically, safely, with a complete audit trail.
|
||||
|
||||
- A merged change progresses **without a platform engineer joining a thread or approving a ticket.**
|
||||
- A **non-technical consumer** ships by declaring intent — no workflow, no config file, no infrastructure module.
|
||||
- Every production change is **traceable to a human attestation and an immutable evidence stream.**
|
||||
|
||||
> **Speaker notes:** Open with the cost of the status quo. Every team that stands up its own pipeline, its own Terraform, its own review checklist is paying a tax that doesn't differentiate the business. The platform absorbs all four frictions — that is the value proposition in one sentence. Land the North Star quote: "declare intent → safe production deployment." The litmus test: if a platform engineer still has to touch a ticket for a dev→qa promotion, we haven't delivered the vision.
|
||||
> **Speaker notes:** Open with the cost of the status quo. Every team that stands up its own pipeline, its own Terraform, its own review checklist is paying a tax that doesn't differentiate the business. The platform absorbs all four frictions — that is the value proposition in one sentence.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — Where ACDL Sits in Your World
|
||||
## Slide 3 — Declare intent; the platform delivers safe production
|
||||
|
||||
Now that we know the problem, here's where ACDL fits — and where it doesn't.
|
||||
Consumers **declare intent**; the platform delivers **safe production deployment** — automatically, safely, with a complete audit trail.
|
||||
|
||||
Now that we know the problem, here's where ACDL fits — and where it doesn't.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph TODAY ["Today"]
|
||||
direction TB
|
||||
A["Merged change"]
|
||||
B["Waits in queue"]
|
||||
C["Ticket + approvals"]
|
||||
D["Manual promotion"]
|
||||
A --> B --> C --> D
|
||||
end
|
||||
subgraph ACDL ["With ACDL"]
|
||||
direction TB
|
||||
E["Declare intent\n(one YAML contract)"]
|
||||
F["Platform delivers\nsafely, autonomously"]
|
||||
G["Traceable to\nhuman attestation"]
|
||||
E --> F --> G
|
||||
end
|
||||
TODAY -.before.-> ACDL
|
||||
```
|
||||
|
||||
- **Upstream is anything** — your IDE, an agentic SDLC, or a citizen developer vibe coding on a laptop. ACDL doesn't care how the contract was produced.
|
||||
- **ACDL is infrastructure only** — it provisions and governs AWS resources. It does not build, test, or deploy your application code. That's upstream.
|
||||
- **Not a general-purpose AI** — autonomy is narrow, scoped to delivery, bounded by strict policy envelopes.
|
||||
- **Not a permissive delivery highway** — no escape hatches to bypass the confidence framework or human attestation requirements.
|
||||
- A merged change progresses **without a platform engineer joining a thread.**
|
||||
- A **non-technical consumer** ships by declaring intent — no workflow, no config file, no module.
|
||||
- Every production change is **traceable to a human attestation** and an immutable evidence stream.
|
||||
|
||||
> **Speaker notes:** This slide gives leadership the framing they need. The platform is deliberately scoped — it is not trying to be everything. The sovereign boundary means the platform team owns delivery and infrastructure, not the upstream development process. The anti-goals are as important as the goals: they tell leadership what not to expect.
|
||||
> **Speaker notes:** Land the before/after contrast: today's queue vs. ACDL's autonomous flow. The litmus test: if a platform engineer still has to touch a ticket for a dev→qa promotion, we haven't delivered the vision. The North Star is "declare intent → safe production deployment."
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — The Contract-Driven Model
|
||||
## Slide 4 — ACDL owns infrastructure, not your app
|
||||
|
||||
The platform is deliberately scoped — it is not trying to be everything.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph UP ["Upstream — anything"]
|
||||
direction TB
|
||||
A["IDE / IDE + AI\n(dev writes contract)"]
|
||||
B["Agentic SDLC\n(agent writes contract)"]
|
||||
C["Citizen dev\n(vibe codes → AI agent\n→ contract)"]
|
||||
end
|
||||
subgraph ACDL ["ACDL — infrastructure only"]
|
||||
D["Contract\nvalidated"]
|
||||
E["Resolve → Plan\nSecurity + Policy checks\nConfidence signal"]
|
||||
F["Provision\nAWS resources"]
|
||||
G["Evidence\nhash-chained"]
|
||||
end
|
||||
subgraph DOWN ["Downstream"]
|
||||
H["AWS resources\nrunning"]
|
||||
I["Consumer pipeline\ndeploys image"]
|
||||
end
|
||||
A --> D
|
||||
B --> D
|
||||
C --> D
|
||||
D --> E
|
||||
E --> F
|
||||
E --> G
|
||||
F --> H
|
||||
H --> I
|
||||
```
|
||||
|
||||
- **Upstream is anything** — IDE, agentic SDLC, or vibe coding. ACDL doesn't care how the contract was produced.
|
||||
- **ACDL is infrastructure only** — it provisions and governs AWS resources. App build/test/deploy is upstream.
|
||||
- **Not a general-purpose AI** — autonomy is narrow, scoped to delivery, bounded by strict policy.
|
||||
- **Not a permissive highway** — no escape hatches to bypass the confidence framework.
|
||||
|
||||
> **Speaker notes:** The sovereign boundary means the platform team owns delivery and infrastructure, not the upstream development process. The anti-goals are as important as the goals: they tell leadership what not to expect.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — One YAML file. The platform owns everything else.
|
||||
|
||||
The contract is the boundary between upstream and ACDL. It's all a consumer writes.
|
||||
|
||||
The contract is the boundary between upstream and ACDL. It's all a consumer writes.
|
||||
|
||||
A single YAML contract — **module, environment, inputs**. The platform owns everything else.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Consumer<br/>writes a contract"] --> B["Platform resolves,<br/>compiles, checks,<br/>deploys, records"]
|
||||
B --> C["Resources running in AWS<br/>+ tamper-evident evidence"]
|
||||
```
|
||||
|
||||
The contract names three things:
|
||||
|
||||
- **Which module** — a catalog of pre-built, security-reviewed building blocks (a static site, a microservice, a database, and more).
|
||||
- **Which environment** — `dev`, `qa`, `prod`, or `dr`. The platform raises the safety bar automatically as the environment gets more sensitive.
|
||||
- **Which module** — a catalog of pre-built, security-reviewed building blocks.
|
||||
- **Which environment** — `dev`, `qa`, `prod`, or `dr`. The bar rises automatically with sensitivity.
|
||||
- **Which inputs** — infrastructure values that vary per deployment (cpu, memory, port, desired_count).
|
||||
- The consumer provides **no AWS account, no VPC, no state backend** — the platform owns the blast radius.
|
||||
|
||||
The consumer does **not** write infrastructure modules, workflow logic, or adapter code. They declare intent; the platform reconciles, provisions, and progresses.
|
||||
|
||||
> **Speaker notes:** Emphasize the asymmetry. The consumer's surface is intentionally tiny — a contract that fits on one screen. The platform's surface is large and opinionated. That asymmetry is what makes "declare intent, not execute operations" concrete. Note that the contract examples now show infrastructure inputs (cpu, memory, desired_count, port) — not a container image. The image is upstream; the platform governs infrastructure.
|
||||
> **Speaker notes:** Emphasize the asymmetry. The consumer's surface is intentionally tiny — a contract that fits on one screen. The platform's surface is large and opinionated. The contract examples show infrastructure inputs (cpu, memory, desired_count, port) — not a container image. The image is upstream; the platform governs infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — The End-to-End Flow
|
||||
|
||||
Once the contract is written, here's what the platform does with it — every time.
|
||||
|
||||
Once the contract is written, here's what the platform does with it — every time.
|
||||
## Slide 6 — Same stages, same checks, every deployment
|
||||
|
||||
Every deployment runs the same stages, in the same order, with the same checks — no team-specific pipelines, no tribal runbooks.
|
||||
|
||||
@@ -104,117 +158,104 @@ flowchart TD
|
||||
H --> I["Infrastructure apply<br/>(dev only — higher envs hold for attestation)"]
|
||||
```
|
||||
|
||||
Two properties matter to leadership:
|
||||
- **Security and policy checks run *before* any infrastructure is created** — not as a post-deployment audit.
|
||||
- **Every stage produces a record** that feeds the confidence signal and the evidence stream. No "unchecked" path.
|
||||
|
||||
- **Security and policy checks run *before* any infrastructure is created** — not after the fact, not as a post-deployment audit.
|
||||
- **Every stage produces a record** that feeds the confidence signal and the evidence stream. There is no "unchecked" path.
|
||||
|
||||
> **Speaker notes:** Walk left to right once. Don't dwell on internals — the point is that the flow is fixed, opinionated, and identical for every consumer. The two leadership-relevant beats are (1) checks before creation, (2) every stage is evidenced. The confidence signal (Slide 7) is where the "safety is computed" story lands.
|
||||
> **Speaker notes:** Walk left to right once. Don't dwell on internals — the point is that the flow is fixed, opinionated, and identical for every consumer. The two leadership-relevant beats: (1) checks before creation, (2) every stage is evidenced. The confidence signal (Slide 8) is where the "safety is computed" story lands.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — Zero-Trust by Default
|
||||
|
||||
Before any infrastructure is created, here's how access is scoped.
|
||||
|
||||
Before any infrastructure is created, here's how access is scoped.
|
||||
## Slide 7 — No long-lived credentials. Blast radius contained.
|
||||
|
||||
Consumer repositories hold **no long-lived cloud credentials.** Ever.
|
||||
|
||||
- **Authentication is OIDC federation** between the platform runners and the cloud provider. Each job mints a short-lived token; no credential is stored in the consumer repo or in a runner secret. *(Testing on GitHub Actions runners; planned for all platform runners.)*
|
||||
- **Authorization is attribute-based (ABAC), not role-based.** Two attribute classes scope every action:
|
||||
- **Repository identity** — the role's trust policy binds to the exact consumer repo + branch that invoked the workflow.
|
||||
- **Resource-creation attributes** — every resource is tagged with `acdl:owner=<consumer-repo>` and `acdl:contract=<contract-id>`. The session policy grants view/update/delete **only on resources whose tags match the calling repo.**
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Consumer repo\n(no credentials)"]
|
||||
B["OIDC federation\nshort-lived token"]
|
||||
C["ABAC session policy\nrepo identity + tags"]
|
||||
D["Tagged resources\nonly"]
|
||||
A --> B --> C --> D
|
||||
```
|
||||
|
||||
**The effect:** a consumer's pipeline can only touch the resources it created. Blast radius is contained to that consumer's own stack instances. One consumer can never touch another's resources, and the consumer cannot escape its own scope.
|
||||
- **Authentication — OIDC federation.** Each job mints a short-lived token; no credential stored in the consumer repo or runner secret. <span class="badge testing">Testing (GitHub Actions)</span> <span class="badge planned">Planned: all runners</span>
|
||||
- **Authorization — attribute-based (ABAC), not role-based.** Two attribute classes scope every action:
|
||||
- **Repository identity** — trust policy binds to the exact consumer repo + branch.
|
||||
- **Resource tags** — every resource tagged `acdl:owner` + `acdl:contract`; session policy grants access **only to matching tags.**
|
||||
- **The effect:** a consumer can only touch the resources it created. One consumer can never affect another.
|
||||
|
||||
> **Speaker notes:** This is the slide for the Head of Cloud/Security. The key phrase is "blast radius contained to the consumer's own stack." Contrast with the common failure mode of shared CI roles that can touch any account resource. The static-key override exists for edge cases but is rotated daily on platform runners; it is never the default.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Safety is Computed, Not Assumed
|
||||
## Slide 8 — Safety is a measurable signal, not a black box
|
||||
|
||||
Now let's look at how the platform decides whether a deployment is safe.
|
||||
Every delivery action produces a **measurable, explainable confidence signal** — a weighted sum of observable facts, not a black box. <span class="badge agentic">Agentic</span>
|
||||
|
||||
Now let's look at how the platform decides whether a deployment is safe.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P["Policy"] --> S["Score"]
|
||||
V["Validation"] --> S
|
||||
F["Freshness"] --> S
|
||||
Pr["Provenance"] --> S
|
||||
H["History"] --> S
|
||||
N["NFRs"] --> S
|
||||
S --> B["Band + threshold"]
|
||||
```
|
||||
|
||||
Every delivery action produces a **measurable, explainable confidence signal** — a weighted sum of observable facts, not a black box. *(Agentic.)*
|
||||
|
||||
- **Six weighted inputs** — policy conformance, validation, freshness, source provenance, history, and non-functional requirements (NFRs). The weights are **manually tuned**, the inputs are **observable**, and the breakdown is **auditable** — if a consumer asks "why 0.62?", the platform answers with a per-input breakdown.
|
||||
- **Six weighted inputs** — policy, validation, freshness, provenance, history, NFRs. Manually tuned, auditable. If a consumer asks "why 0.62?", the platform answers with a per-input breakdown.
|
||||
- **Per-environment thresholds** that rise with sensitivity:
|
||||
|
||||
| Environment | Threshold | Who must attest |
|
||||
| Environment | Threshold | Attester |
|
||||
|---|---|---|
|
||||
| dev | ≥ 0.50 | No one — fully autonomous *(Testing)* |
|
||||
| qa | ≥ 0.75 | QA *(Planned)* |
|
||||
| prod | ≥ 0.90 | SRE *(Planned)* |
|
||||
| dr | ≥ 0.95 | SRE + a disaster-recovery drill reference *(Planned)* |
|
||||
| dev | ≥ 0.50 | No one — autonomous <span class="badge testing">Testing</span> |
|
||||
| qa | ≥ 0.75 | QA <span class="badge planned">Planned</span> |
|
||||
| prod | ≥ 0.90 | SRE <span class="badge planned">Planned</span> |
|
||||
|
||||
- **A single critical policy finding hard-blocks the deployment**, regardless of every other input. Critical findings are not averaged away.
|
||||
- **When the platform halts, it gives a measured reason** — a policy violation, an insufficient signal, a missing attestation — never an opaque, manual-debugging exercise.
|
||||
- **A single critical finding hard-blocks** — critical findings are not averaged away.
|
||||
|
||||
> **Speaker notes:** This is the bet that separates this platform from "yet another CI/CD tool." Reliance on operator instinct or tenure is not a substitute. The signal is auditable; the thresholds are tunable by Infra & Ops + SRE jointly, and any override is itself a confidence-event in the audit stream. Leadership cares about this because it makes promotion decisions *reviewable*. The new confidence signal diagram makes the six inputs and the per-input breakdown visible — emphasize that the weights are manually tuned and the breakdown is auditable, not a black box.
|
||||
> **Speaker notes:** This is the bet that separates this platform from "yet another CI/CD tool." Reliance on operator instinct or tenure is not a substitute. The signal is auditable; the thresholds are tunable by Infra & Ops + SRE jointly, and any override is itself a confidence-event in the audit stream. Leadership cares because it makes promotion decisions *reviewable*.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — Security by Construction
|
||||
## Slide 9 — Every change traceable to a human attestation
|
||||
|
||||
Beyond the confidence signal, security defaults are on by construction — not by opt-in.
|
||||
Computed safety handles the gate. Humans still matter — here's how accountability works.
|
||||
|
||||
Beyond the confidence signal, security defaults are on by construction — not by opt-in.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph DEV ["dev — autonomous"]
|
||||
D1["Confidence ≥ 0.50\n→ apply"]
|
||||
end
|
||||
subgraph GATED ["qa / prod / dr — gated"]
|
||||
G1["Confidence ≥ threshold"]
|
||||
G2["Human attestation\nreviews contract\n+ plan + evidence"]
|
||||
G3["Separation of duties\nQA ≠ prod approver"]
|
||||
G1 --> G2 --> G3
|
||||
end
|
||||
DEV --> OUT["Hash-chained\nevidence event\n(RPO = 0)"]
|
||||
GATED --> OUT
|
||||
```
|
||||
|
||||
Security defaults that **do not require a team to opt in.** Checks run on **every** deployment, normalized to a single schema regardless of which engine produced them. *(Testing.)*
|
||||
- **Dev is fully autonomous.** The confidence signal (≥ 0.50) is the only gate. <span class="badge testing">Testing</span> <span class="badge agentic">Agentic</span>
|
||||
- **qa, prod, dr require human attestation** — the approver reviews contract, planned Terraform, and accumulated evidence. <span class="badge planned">Planned</span>
|
||||
- **Separation of duties is enforced** — the QA approver **cannot** be the prod approver. The platform **blocks on a match.** <span class="badge planned">Planned</span>
|
||||
- **Every deployment writes a hash-chained evidence event** — tampering breaks the chain. **RPO = 0.** <span class="badge testing">Testing</span>
|
||||
|
||||
- **Infrastructure-as-code policy** (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS key references, **required tagging standards** (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`). All run *before* infra is created.
|
||||
- **Cloud security posture** (Wiz adapter) — translates cloud security findings into the same normalized record. *(Adapter testing; activates when a Wiz tenant is configured.)*
|
||||
- **Kubernetes-native policy** (Kyverno adapter) — ready for the GitOps reconciler roadmap item. *(Adapter testing; inactive for Terraform-only stacks.)*
|
||||
- **Encryption on every resource** — at-rest encryption is on by default for every primitive (S3, RDS, ECR, ECS, and more). *(Testing.)*
|
||||
- **Per-stack customer-managed keys (CMKs)** — one key per deployment, 90-day rotation at creation, **no shared keys across stacks.** *(Testing.)*
|
||||
- **Managed-key fallback with a loud warning** — standalone primitives fall back to cloud-managed keys only when no CMK is provided, and the platform warns explicitly. *(Testing.)*
|
||||
- **Deletion protection on by default** — every resource has `prevent_destroy` on unless a consumer explicitly disables it via a documented feature flag. *(Testing.)*
|
||||
- **Safe decommission** — a 2-step pipeline (disable protection → zero counts → destroy) with **two SRE human-attestation gates** and a **change-request validated against the platform CMDB** before any destructive action. *(Testing.)* Encryption keys enter a grace window (default 30 days) so encrypted data remains recoverable during decommission.
|
||||
|
||||
> **Speaker notes:** The phrase to land is "secure by default, not secure by effort." The selling point is *normalization* — we can add a new security tool without changing the confidence model or the evidence stream. For the Head of Security: tagging standards are enforced, not advisory — a missing `acdl:owner` tag fails the check, not a warning. The decommission flow is the counter-argument to "deletion protection makes cleanup impossible" — it's a deliberate, gated, two-approval path, not a lock with no key.
|
||||
> **Speaker notes:** The "lower environments autonomous, higher environments attested" tenet is the resolution to the classic "move fast vs. be safe" false dichotomy. Be honest: the separation-of-duties *mechanism* is designed and the dev path is wired; qa/prod/dr wiring is on the roadmap. The audit trail is a byproduct of deployment, not a project. The full regulatory ledger (S3 Object Lock, JWS signatures, daily checkpoints) is planned; what ships today is the outbox + hash chain that makes every event tamper-evident and queryable.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Accountability & Audit
|
||||
## Slide 10 — The vision realized
|
||||
|
||||
Computed safety handles the gate. But humans still matter — here's how accountability works.
|
||||
|
||||
Computed safety handles the gate. But humans still matter — here's how accountability works.
|
||||
|
||||
- **Dev is fully autonomous.** The confidence signal (≥ 0.50) is the only gate. Queue-based handoffs are eliminated from lower environments. *(Testing, Agentic.)*
|
||||
- **qa, prod, and dr require deliberate human attestation** — not rubber stamps, but policy-mandated acts of accountability via protected deployment approvals. The approver reviews the contract, the planned Terraform changes, and the accumulated evidence. *(Planned.)*
|
||||
- **QA attests to infrastructure readiness — the contract, the planned Terraform changes, and the accumulated evidence. QA does not review application code (that's upstream).**
|
||||
- **Separation of duties is enforced** *(Planned)* — the person who approved the qa promotion **cannot** be the person who approves the prod promotion. The platform reads both identities from the outbox and **blocks** on a match, emitting a `SEPARATION_OF_DUTIES_VIOLATION` and routing a halt artifact to SRE on-call.
|
||||
- **Timeout discipline** — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit. Rejection extends the audit chain; it does not tear it up.
|
||||
|
||||
Version control is a **coordination tool, not an evidentiary fortress.** True compliance requires an immutable, externally-stored ledger.
|
||||
|
||||
- **Every deployment writes a hash-chained evidence event** — each event links to the previous via a cryptographic hash. Tampering breaks the chain. *(Testing — the DynamoDB outbox.)*
|
||||
- **Tiered storage design:** cold, tamper-proof source of truth (S3 Object Lock, compliance mode, 7-year retention) + a hot query index for fast lookup. *(Outbox tested; S3 Object Lock + JWS detached signatures are planned regulatory-ledger build-out.)*
|
||||
- **RPO = 0** — the evidence write is synchronous; a deployment is not acknowledged until the evidence event is durably recorded.
|
||||
- **Every production change is traceable to a human attestation** — the QA and prod approver identities are the only durable record outside the VCS's audit log, stored in the outbox keyed by contract.
|
||||
|
||||
> **Speaker notes:** The "lower environments autonomous, higher environments attested" tenet is the resolution to the classic "move fast vs. be safe" false dichotomy. Be honest: the separation-of-duties *mechanism* (CODEOWNERS routing, identity-distinctness check, the 8-concern attestation matrix) is designed and the dev path is wired; the qa/prod/dr wiring is on the roadmap. The new attestation flow diagram makes the human-in-the-loop path visible. Note the QA clarification: QA attests to infrastructure readiness — the contract, the plan, and the evidence — not application code. The audit trail is a byproduct of deployment, not a project. Note honestly that the full regulatory ledger (S3 Object Lock, JWS signatures, daily checkpoints) is planned; what ships today is the outbox + hash chain that makes every event tamper-evident and queryable. Badge reclassification: separation of duties = Planned (not "design tested"), dev autonomous = Testing, qa/prod/dr attestation = Planned.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — The Vision Realized
|
||||
|
||||
Here's what success looks like when the North Star is reached.
|
||||
|
||||
Here's what success looks like when the North Star is reached.
|
||||
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics (a simple contract, a one-line `uses:`); safety is in the gates the consumer cannot bypass.
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics; safety is in the gates the consumer cannot bypass.
|
||||
- **Security, observability, and compliance as platform defaults** — not per-team effort, not post-hoc remediation.
|
||||
- **Auditability as a byproduct, not a project.** Every production change is traceable to a human attestation and a tamper-evident evidence event.
|
||||
- **Blast radius contained by design.** Zero-trust OIDC + ABAC means a consumer can only touch its own tagged resources.
|
||||
- **Infrastructure as a utility, not a craft.** Teams consume infrastructure, they don't maintain it.
|
||||
- **A path to the citizen developer.** The same safety envelope that serves a senior engineer will serve a non-technical consumer. *(Agentic.)*
|
||||
- **A path to the citizen developer.** The same safety envelope serves a senior engineer and a non-technical consumer. <span class="badge agentic">Agentic</span>
|
||||
|
||||
> **Speaker notes:** Close on the strategic frame. The platform is not "a CI/CD tool," it's the organizational lever for shipping safely at the pace the business demands. The investment is in the abstraction, not the tool. Ship safely at the pace the business demands, with the security and audit posture the regulators require.
|
||||
> **Speaker notes:** Close on the strategic frame. The platform is not "a CI/CD tool" — it's the organizational lever for shipping safely at the pace the business demands, with the security and audit posture the regulators require. The investment is in the abstraction, not the tool.
|
||||
|
||||
---
|
||||
|
||||
@@ -226,9 +267,12 @@ For deep dives — these slides cover details omitted from the main 10.
|
||||
|
||||
1. Platform-Managed Environments (detail)
|
||||
2. Observability Built In (detail)
|
||||
3. The Road to the North Star (phased roadmap)
|
||||
4. Testing vs. Planned (full inventory)
|
||||
5. Glossary
|
||||
3. Security by Construction (the full defaults inventory)
|
||||
4. The Road to the North Star (phased roadmap)
|
||||
5. Testing vs. Planned (full inventory)
|
||||
6. Glossary
|
||||
7. Operating Model & Cost (real AWS spend + pre-mortem)
|
||||
8. Verified by Construction (the v1.11 architecture)
|
||||
|
||||
> **Speaker notes:** These are deep-dive slides for follow-up questions. Don't walk them in the main 15-minute talk — pull them up when an audience member wants detail on a specific topic.
|
||||
|
||||
@@ -236,8 +280,6 @@ For deep dives — these slides cover details omitted from the main 10.
|
||||
|
||||
## A1 — Platform-Managed Environments
|
||||
|
||||
For deep dives — these slides cover details omitted from the main 10.
|
||||
|
||||
A consumer provides **no AWS account, no VPC, no subnet, no state backend, no runner key.** The platform owns the blast radius.
|
||||
|
||||
A named environment is a platform-owned bundle of:
|
||||
@@ -269,24 +311,43 @@ Monitoring is **a platform default, not a per-team project.** *(Testing.)*
|
||||
|
||||
---
|
||||
|
||||
## A3 — The Road to the North Star
|
||||
## A3 — Security by Construction
|
||||
|
||||
Security defaults that **do not require a team to opt in.** Checks run on **every** deployment, normalized to a single schema regardless of which engine produced them. *(Testing.)*
|
||||
|
||||
- **Infrastructure-as-code policy** (Checkov) — secrets in plaintext, public ingress, IAM wildcards, KMS key references, **required tagging standards** (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`). All run *before* infra is created.
|
||||
- **Cloud security posture** (Wiz adapter) — translates cloud security findings into the same normalized record. *(Adapter testing; activates when a Wiz tenant is configured.)*
|
||||
- **Kubernetes-native policy** (Kyverno adapter) — ready for the GitOps reconciler roadmap item. *(Adapter testing; inactive for Terraform-only stacks.)*
|
||||
- **Encryption on every resource** — at-rest encryption is on by default for every primitive (S3, RDS, ECR, ECS, and more). *(Testing.)*
|
||||
- **Per-stack customer-managed keys (CMKs)** — one key per deployment, 90-day rotation at creation, **no shared keys across stacks.** *(Testing.)*
|
||||
- **Managed-key fallback with a loud warning** — standalone primitives fall back to cloud-managed keys only when no CMK is provided, and the platform warns explicitly. *(Testing.)*
|
||||
- **Deletion protection on by default** — every resource has `prevent_destroy` on unless a consumer explicitly disables it via a documented feature flag. *(Testing.)*
|
||||
- **Safe decommission** — a 2-step pipeline (disable protection → zero counts → destroy) with **two SRE human-attestation gates** and a **change-request validated against the platform CMDB** before any destructive action. *(Testing.)* Encryption keys enter a grace window (default 30 days) so encrypted data remains recoverable during decommission.
|
||||
|
||||
> **Speaker notes:** The phrase to land is "secure by default, not secure by effort." The selling point is *normalization* — we can add a new security tool without changing the confidence model or the evidence stream. For the Head of Security: tagging standards are enforced, not advisory — a missing `acdl:owner` tag fails the check, not a warning. The decommission flow is the counter-argument to "deletion protection makes cleanup impossible" — it's a deliberate, gated, two-approval path, not a lock with no key.
|
||||
|
||||
---
|
||||
|
||||
## A4 — The Road to the North Star
|
||||
|
||||
*Proposed phasing — not formally planned.*
|
||||
|
||||
A phased roadmap from the current Testing baseline to the full North Star:
|
||||
|
||||
- **Phase 1 — Testing baseline (current):** contract-driven deploys, zero-trust OIDC + ABAC on GitHub Actions, confidence signal gating, hash-chained evidence, encryption by default, deletion protection + safe decommission, uptime monitoring, platform-managed environments.
|
||||
- **Phase 1 — Testing baseline (current, v1.12):** contract-driven deploys, zero-trust OIDC + ABAC on GitHub Actions, confidence signal gating, hash-chained evidence, encryption by default, deletion protection + safe decommission, uptime monitoring, platform-managed environments. **22/22 capabilities Verified** via the v1.11 lifecycle pipeline (apply→modify→destroy against live AWS, then torn down to zero-cost). The stateless adapter + lifecycle pipeline are the structural verification (see A8).
|
||||
- **Phase 2 — Production readiness:** HITL wiring for qa/prod/dr, all-runner OIDC, full regulatory ledger (S3 Object Lock + JWS signatures + daily checkpoints), environment self-service.
|
||||
- **Phase 3 — Compliance & expansion:** compliance milestone (GDPR, SOX, SOC2, DORA extension points), additional engine adapters (OpenTofu, Pulumi, Kubernetes CRDs), deeper observability bootstrap.
|
||||
- **Phase 4 — Agentic frontier:** dynamic module creation from a contract (the agentic citizen-developer composition mechanism), pattern recognition that compounds value over time.
|
||||
|
||||
> **Speaker notes:** Be clear with leadership: this is a proposed phasing, not a formally committed plan. The phases are sequenced by dependency, not by calendar — each phase's items are gated on the prior phase's maturity. Invite questions on any phase boundary.
|
||||
> **Speaker notes:** Be clear with leadership: this is a proposed phasing, not a formally committed plan. The phases are sequenced by dependency, not by calendar — each phase's items are gated on the prior phase's maturity. Phase 1 is now fully Verified (22/22) and torn down to zero-cost — it is no longer aspirational. Invite questions on any phase boundary.
|
||||
|
||||
---
|
||||
|
||||
## A4 — Testing vs. Planned (Full Inventory)
|
||||
## A5 — Testing vs. Planned (Full Inventory)
|
||||
|
||||
**Testing** (works internally, dev pilot-ready) — 11 capabilities:
|
||||
> **Verification status (v1.12, 2026-07-29):** 22/22 auto-verifiable capabilities **Verified** — the v1.11 lifecycle pipeline ran apply→modify→destroy against live AWS for every L1 + L2 module, then tore down to zero-cost (D-096). The v1.10 "6 deploy-unverified (IAM drift)" status is closed (CAP-013 fixed in P67). See `CAPABILITY_INVENTORY.md`.
|
||||
|
||||
**Testing** (works internally, dev pilot-ready — 22/22 Verified via lifecycle pipeline + regression gate):
|
||||
|
||||
- Contract-driven deploys with a versioned reusable workflow.
|
||||
- Module catalog (primitives + modules) with validated examples.
|
||||
@@ -312,11 +373,11 @@ A phased roadmap from the current Testing baseline to the full North Star:
|
||||
- Additional engine adapters (OpenTofu, Pulumi, Kubernetes CRDs).
|
||||
- Deeper observability bootstrap (dashboards, runbooks, on-call bindings).
|
||||
|
||||
> **Speaker notes:** Close on honesty. The platform delivers real, verifiable value today — 11 capabilities that work internally. The roadmap is concrete, not aspirational hand-waving — 9 planned items, each with a defined milestone and a clear reason it isn't shipped yet (usually an upstream dependency, not an engineering gap). Emphasize: 0 consumer adoption today — "Testing" means it works internally and is dev pilot-ready, not that it's released.
|
||||
> **Speaker notes:** Close on honesty. The platform delivers real, verifiable value today — 22/22 auto-verifiable capabilities are Verified via the v1.11 lifecycle pipeline (apply→modify→destroy against live AWS) + the D-091 regression gate. The roadmap is concrete, not aspirational hand-waving — 9 planned items, each with a defined milestone and a clear reason it isn't shipped yet (usually an upstream dependency, not an engineering gap). Emphasize: 0 consumer adoption today — "Testing" means it works internally and is dev pilot-ready, not that it's released. The lifecycle pipeline defaults to **plan-only** on every PR (fast, no AWS mutation, no cost); a CI variable (`ACDL_LIFECYCLE_MODE=full`) overrides to the real apply→destroy for milestone verification (REQ-134, v1.12).
|
||||
|
||||
---
|
||||
|
||||
## A5 — Glossary
|
||||
## A6 — Glossary
|
||||
|
||||
| Term | Meaning |
|
||||
|---|---|
|
||||
@@ -330,4 +391,37 @@ A phased roadmap from the current Testing baseline to the full North Star:
|
||||
| **NFR** | Non-Functional Requirement — encryption, tagging, observability standards |
|
||||
| **IR** | Intermediate Representation — the engine-agnostic stack definition between contract and Terraform |
|
||||
|
||||
> **Speaker notes:** Use this slide as a reference when the audience asks for term definitions. Don't read it aloud — point to it as a takeaway reference.
|
||||
> **Speaker notes:** Use this slide as a reference when the audience asks for term definitions. Don't read it aloud — point to it as a takeaway reference.
|
||||
|
||||
---
|
||||
|
||||
## A7 — Operating Model & Cost (real AWS spend + pre-mortem)
|
||||
|
||||
ACDL runs at **zero cloud cost** for day-to-day development. The v1.0→v1.10 AWS spend was measured directly via Cost Explorer (`COST.md`, 2026-07-28):
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total spend (8 days) | **$0.001883** |
|
||||
| Daily average | $0.000235 |
|
||||
| Projected monthly | ~$0.007 |
|
||||
| Peak day | 2026-07-27 ($0.000867 — v1.10 regression + verify run) |
|
||||
|
||||
- **S3 dominates** (98.8%, terraform state bucket) — no compute (ECS/Lambda) ran because v1.0→v1.10 was plan-only for IAM-gated capabilities.
|
||||
- **Local emulators are the primary tier** — the full pipeline runs in-process, no AWS credentials, no Checkov, no DynamoDB. *(Testing.)*
|
||||
- **Live-AWS verification is milestone-scoped, then torn down.** The v1.11 lifecycle pipeline ran apply→modify→destroy for every module, then tore down to zero-cost steady state (D-096 — teardown mandatory before milestone COMPLETE; no merge to main until `terraform show` confirms no resources). The lifecycle pipeline now **defaults to plan-only** on every PR (fast, no AWS mutation, no cost); a CI variable (`ACDL_LIFECYCLE_MODE=full`) overrides to the real apply→destroy for milestone verification (REQ-134, v1.12).
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). Any cost spike > $1/day is an anomaly.
|
||||
|
||||
**Pre-mortem (`PRE_MORTEM.md`):** the project's failure modes were pre-mortemed before the leadership pitch. The v1.10 decay incident (diff-scoped VERIFY missed 7 adapter defects across 8 NFR-patch phases — decks advertised capability that wasn't reproducible) is the root pattern: *a claim outruns the verification that backs it.* Four forward failure modes + structural mitigations: (FM-1) IAM-drift recurrence → IAM policy baseline is regression-tested; (FM-2) cost spike from un-torn-down stacks → D-096 mandatory teardown; (FM-3) deck overstates capability → verified-only claims + decks unfrozen only after re-verification; (FM-4) pilot contract gap → honest scope (microservice + static-assets today; the L2 pattern is extensible). All mitigations are structural, not procedural.
|
||||
|
||||
> **Speaker notes:** This is the slide for the Head of Cloud / Finance. The headline: less than one cent over 8 days of active development; zero BAU cloud spend; the lifecycle pipeline defaults to plan-only so the PR-time cost is zero. The pre-mortem is the credibility slide — we have already asked "how does this fail?" and the mitigations are structural (regression-tested baselines, mandatory teardown, verified-only deck claims). The v1.10 decay incident is disclosed honestly, not hidden — that disclosure IS the mitigation.
|
||||
|
||||
---
|
||||
|
||||
## A8 — Verified by Construction (the v1.11 architecture)
|
||||
|
||||
v1.11 rebuilt the platform on two architectural pillars that make "Verified" a structural property, not a claim:
|
||||
|
||||
- **The stateless adapter (REQ-123, 918 → ~80 lines).** The Terraform adapter was a 918-line monolith with 3 constant tables and 39 type-specific branches. It is now a ~80-line **stateless assembler**: it owns no module content — no resource shape, no nested HCL blocks, no defaults, no type-specific logic. Each L1 module ships a real `terraform/` module dir owning its resource shape, nested blocks, and defaults (centralized in `locals.tf`). The adapter reads the registry and emits `module "x" { source = ... }` blocks. No type-specific logic in the adapter means a new module is a new terraform dir, not a code change. *(The v1.12 P67 fix closed a dedup defect where multi-resource L1s — ecs-service, alb — produced invalid Terraform; CAP-013 now Verified.)*
|
||||
- **Pipeline-driven lifecycle testing (REQ-127/128).** A `modules-lifecycle` pipeline matrix-runs each L1 and L2 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS. No per-module Python. **The "test" = the pipeline cell going green.** Defaults to **plan-only** on every PR (fast, no AWS mutation, no cost); `ACDL_LIFECYCLE_MODE=full` runs the real apply→destroy for milestone verification (REQ-134, v1.12). The regression gate (D-091) re-runs all 22 capabilities at milestone completion — 22/22 Verified as of v1.12.
|
||||
|
||||
> **Speaker notes:** This is the deep-dive slide for the Head of Engineering / Architecture. The two pillars are the answer to "how do you keep the decks honest?" The adapter is simple enough to reason about (a stateless assembler), and the lifecycle pipeline is the automated verification that backs every "Testing" claim. The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently because the VERIFY gate was diff-scoped. The ~80-line stateless adapter + the milestone regression gate are the structural fix. The plan-only default (v1.12) means this verification runs on every PR at zero cost, with the full apply→destroy gated behind a CI variable override.
|
||||
@@ -8,23 +8,22 @@ footer: "Internal"
|
||||
style: |
|
||||
section {
|
||||
font-family: "Akkurat Pro", "Helvetica Neue", "Arial", sans-serif;
|
||||
font-size: 22px;
|
||||
font-size: 26px;
|
||||
color: #1B1B1B;
|
||||
}
|
||||
h1 { color: #D6002A; font-size: 34px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 26px; margin-bottom: 0.2em; }
|
||||
h1 { color: #D6002A; font-size: 40px; margin-bottom: 0.3em; }
|
||||
h2 { color: #D6002A; font-size: 32px; margin-bottom: 0.2em; }
|
||||
section.title { background: #1B1B1B; color: #fff; border-top: 8px solid #D6002A; }
|
||||
section.title h1 { color: #fff; }
|
||||
table { font-size: 18px; width: 100%; }
|
||||
table { font-size: 22px; width: 100%; }
|
||||
th { background: #F0F0F0; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 20px; }
|
||||
pre { font-size: 14px; line-height: 1.3; }
|
||||
code { font-size: 14px; }
|
||||
blockquote { border-left: 4px solid #D6002A; color: #2E2E2E; font-size: 24px; }
|
||||
pre { font-size: 16px; line-height: 1.3; }
|
||||
code { font-size: 16px; }
|
||||
img { display: block; margin: 0 auto; max-height: 280px; }
|
||||
em.story { color: #6B7280; font-size: 16px; font-style: italic; }
|
||||
.badge {
|
||||
display: inline-block; padding: 2px 8px; border-radius: 4px;
|
||||
font-size: 14px; font-weight: 600;
|
||||
font-size: 16px; font-weight: 600;
|
||||
}
|
||||
.testing { background: #DBEAFE; color: #1E3A5F; }
|
||||
.planned { background: #fef3c7; color: #78350f; }
|
||||
@@ -45,24 +44,18 @@ section.title h3 { color: #F0F0F0; font-weight: 400; font-size: 22px; margin-top
|
||||
|
||||
---
|
||||
|
||||
# Where Agentic Cloud Delivery (ACDL) Sits in Your World
|
||||
|
||||
<em class="story">Here's who uses the platform and where the boundary is.</em>
|
||||
# Two consumer paths, one safety envelope
|
||||
|
||||

|
||||
|
||||
- **Technical developer** — owns app code + a contract + a thin CI definition
|
||||
- **Citizen developer** — declares intent in plain language; an AI agent produces a contract that passes the **same** safety envelope <span class="badge agentic">Agentic</span>
|
||||
- **Upstream is anything** — your IDE, an agentic SDLC, or vibe coding on a laptop. ACDL doesn't care how the contract was produced
|
||||
- **ACDL is infrastructure only** — it provisions and governs AWS resources. Application deployment is upstream
|
||||
- **Citizen developer** — declares intent; an AI agent produces a contract that passes the **same** safety envelope <span class="badge agentic">Agentic</span>
|
||||
- **Upstream is anything** — IDE, agentic SDLC, or vibe coding. ACDL doesn't care how the contract was produced
|
||||
- **ACDL is infrastructure only** — provisions and governs AWS resources. Application deployment is upstream
|
||||
|
||||
---
|
||||
|
||||
# The Contract — The Entire Consumer Surface
|
||||
|
||||
<em class="story">Now let's look at what a consumer actually writes — it's tiny.</em>
|
||||
|
||||
Three things. That is the entire consumer-side surface.
|
||||
# Three things. The entire consumer surface.
|
||||
|
||||
<img src="assets/png/developer-experience-02-what-dev-does.png" style="float: right; width: 38%; margin-left: 20px; margin-bottom: 10px;" />
|
||||
|
||||
@@ -84,42 +77,84 @@ infrastructure:
|
||||
```
|
||||
|
||||
- **3. A one-line CI definition** — a thin `uses:` wrapper pointing at a versioned platform workflow
|
||||
- The developer does **not**: write infrastructure modules, clone the platform repo, hold cloud credentials, or maintain a state backend
|
||||
- The developer does **not**: write modules, clone the platform repo, hold cloud credentials, or maintain a state backend
|
||||
|
||||
---
|
||||
|
||||
# The Developer Feedback Loop
|
||||
# See what the platform does, in real time
|
||||
|
||||
<em class="story">Once you push, here's what you see — in real time, in your own logs.</em>
|
||||
|
||||
Developers see **what the platform is doing**, in real time. <span class="badge testing">Testing</span>
|
||||
|
||||
- **Streamed output by default** — the infrastructure plan, policy-check results, and each check record flow to stdout
|
||||
- **PR comments after every successful pipeline stage** — a developer always knows where they stand without refreshing a dashboard
|
||||
- **Clear, explainable halt reasons** — a policy violation, an insufficient confidence signal, or a missing attestation. **Never an opaque debugging exercise.**
|
||||
- **Connection strings posted as PR comments** — human-readable, no hunting
|
||||
- **Runtime secrets in encrypted Parameter Store** — KMS-encrypted, namespaced, **no raw secrets in logs**
|
||||
- **Errors become GitHub issues, automatically** — a failed deploy opens an issue on the platform repo
|
||||
- **Streamed output by default** — the plan, policy results, and each check record flow to stdout
|
||||
- **PR comments after every successful pipeline stage** — always know where you stand
|
||||
- **Clear, explainable halt reasons** — a policy violation, an insufficient signal, or a missing attestation. **Never opaque.**
|
||||
- **Connection strings posted as PR comments** — human-readable, no hunting. Runtime secrets go to encrypted Parameter Store, never to logs
|
||||
- **Errors become GitHub issues, automatically** — a failed deploy opens an issue on the platform repo <span class="badge testing">Testing</span>
|
||||
|
||||
---
|
||||
|
||||
# Versioned, Predictable Releases
|
||||
# Pick from pre-built, security-reviewed blocks
|
||||
|
||||
<em class="story">You control when you absorb platform improvements — no surprise upgrades.</em>
|
||||

|
||||
|
||||
Consumers control **when** they absorb platform improvements. <span class="badge testing">Testing</span>
|
||||
- **Primitives** — single-purpose resources (S3, VPC, ECS, IAM, ALB, ECR, CloudFront, WAF, RDS)
|
||||
- **Modules** — composed patterns (static site with CDN + WAF; microservice with VPC + ECS + ALB + ECR)
|
||||
- **Validated examples per module** — `simple.yaml` + `complex.yaml`, validated against the contract schema in CI
|
||||
- **Auto-promotion of patterns** — after 3 observed usages <span class="badge planned">Planned</span> <span class="badge agentic">Agentic</span>
|
||||
|
||||
- **Floating MAJOR + MINOR tags** (e.g. `@v1.10`) — a consumer automatically receives patch updates within the line
|
||||
---
|
||||
|
||||
# The bar rises automatically with sensitivity
|
||||
|
||||

|
||||
|
||||
| Environment | What the platform adds | Maturity |
|
||||
|---|---|---|
|
||||
| dev | Confidence ≥ 0.50, fully autonomous | <span class="badge testing">Testing</span> |
|
||||
| qa | QA human attestation + confidence ≥ 0.75 | <span class="badge planned">Planned</span> |
|
||||
| prod | SRE human attestation + confidence ≥ 0.90 | <span class="badge planned">Planned</span> |
|
||||
| dr | SRE human attestation + confidence ≥ 0.95 + DR drill | <span class="badge planned">Planned</span> |
|
||||
|
||||
- **No staging environment** — dev is the only autonomous environment
|
||||
- **Separation of duties** — the QA approver cannot be the prod approver
|
||||
|
||||
---
|
||||
|
||||
# Tearing down is as gated as deploying
|
||||
|
||||

|
||||
|
||||
<style>
|
||||
section { font-size: 22px; }
|
||||
pre { font-size: 13px; line-height: 1.2; }
|
||||
code { font-size: 13px; }
|
||||
</style>
|
||||
|
||||
```yaml
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.12
|
||||
with:
|
||||
contract: .acdl/contract.yml
|
||||
mode: decommission
|
||||
changeRequestId: "CHG0678912"
|
||||
```
|
||||
|
||||
- **Validate the change request** — platform queries the CMDB; CR must be `approved` and match the consumer repo
|
||||
- **Two SRE human-attestation gates** — disable protection → SRE approves → zero counts + destroy → second SRE approves
|
||||
- **Per-stack encryption key enters a grace window** (default 30 days) so encrypted data remains recoverable <span class="badge testing">Testing</span>
|
||||
|
||||
---
|
||||
|
||||
# You control when you absorb improvements
|
||||
|
||||

|
||||
|
||||
- **Floating MAJOR + MINOR tags** (e.g. `@v1.12`) — automatically receive patch updates within the line
|
||||
- **Semantic versioning with a clear contract:** interface → MAJOR, behavior → MINOR, lifecycle → PATCH
|
||||
- **A consumer can pin to an exact version** for maximum stability, or float on MAJOR only (`@v1`) to absorb new features on their own cadence
|
||||
- **Pin to an exact version** for stability, or float on MAJOR only (`@v1`) to absorb new features on your own cadence
|
||||
- **Unversioned references (`@main`, bare) are discouraged** — the versioned tag is the only immutability lever
|
||||
- **Automated release job** computes the next semver on merge to main, creates the tag, and updates the floating tags
|
||||
- **Automated release job** computes the next semver on merge to main, creates the tag, and updates floating tags <span class="badge testing">Testing</span>
|
||||
|
||||
---
|
||||
|
||||
# Friendly Onboarding
|
||||
|
||||
<em class="story">First impressions matter — the platform fails gracefully, not opaquely.</em>
|
||||
# Fails gracefully, not opaquely
|
||||
|
||||
First impressions of a platform are made **when it fails for the first time.** The platform fails gracefully. <span class="badge testing">Testing</span>
|
||||
|
||||
@@ -136,111 +171,18 @@ The pipeline then **exits without attempting a deployment** — no partial state
|
||||
|
||||
---
|
||||
|
||||
# Safe Promotion Path
|
||||
|
||||
<em class="story">Promotion is a workflow choice, not a contract edit — and the bar rises automatically.</em>
|
||||
|
||||
The contract is environment-agnostic. The platform raises the bar automatically.
|
||||
|
||||

|
||||
|
||||
<table style="width: 100%; border: none;">
|
||||
<tr>
|
||||
<td style="width: 50%; vertical-align: top; border: none; padding-right: 12px;">
|
||||
|
||||
**Approach A — One contract, one job per environment.** Environment passed by each job.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
dev:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract.yml, environment: dev }
|
||||
qa:
|
||||
needs: dev
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract.yml, environment: qa }
|
||||
```
|
||||
|
||||
</td>
|
||||
<td style="width: 50%; vertical-align: top; border: none; padding-left: 12px;">
|
||||
|
||||
**Approach B — Environment-specific contracts.** When inputs differ per environment.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
dev:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract-dev.yaml }
|
||||
qa:
|
||||
needs: dev
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract-qa.yaml }
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<style>
|
||||
section { font-size: 16px; }
|
||||
pre { font-size: 10px; line-height: 1.2; }
|
||||
code { font-size: 10px; }
|
||||
td { font-size: 14px; }
|
||||
</style>
|
||||
|
||||
---
|
||||
|
||||
# Safe Decommission
|
||||
|
||||
<em class="story">Tearing down is as deliberate as deploying — and just as gated.</em>
|
||||
|
||||
Tearing down a stack is **as deliberate as deploying one.** <span class="badge testing">Testing</span>
|
||||
|
||||
```yaml
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with:
|
||||
contract: .acdl/contract.yml
|
||||
mode: decommission
|
||||
changeRequestId: "CHG0678912"
|
||||
```
|
||||
|
||||
A 2-step pipeline with **two SRE human-attestation gates**:
|
||||
|
||||
1. **Validate the change request** — the platform queries the CMDB; the CR must be `approved` and match the consumer repo
|
||||
2. **Disable deletion protection** → **SRE approves** → **Zero all counts + destroy** → **a second SRE approves**
|
||||
|
||||
The per-stack encryption key enters a **grace window** (default 30 days) so encrypted data remains recoverable.
|
||||
|
||||
---
|
||||
|
||||
# Self-Service Module Catalog
|
||||
|
||||
<em class="story">You don't author infrastructure — you pick from pre-built, security-reviewed building blocks.</em>
|
||||
|
||||
Developers pick from **pre-built, security-reviewed building blocks.** <span class="badge testing">Testing</span>
|
||||
|
||||
- **Primitives** — single-purpose resources (S3, VPC, ECS, IAM, load balancer, container registry, CloudFront, WAF, RDS), each with documented inputs/outputs, usage, compliance extension points, and versioning
|
||||
- **Modules** — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + load balancer + registry)
|
||||
- **Validated examples per module** — `simple.yaml` + `complex.yaml` + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently
|
||||
- **Auto-promotion of patterns** — auto-promoted to the catalog after 3 observed usages <span class="badge planned">Planned</span> <span class="badge agentic">Agentic</span>
|
||||
- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, DORA controls will wire in <span class="badge planned">Planned</span>
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# The Desired Outcomes
|
||||
# The desired outcomes
|
||||
|
||||
<em class="story">Here's what this delivers to the organization.</em>
|
||||
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics (a simple contract, a one-line `uses:`); safety is in the gates the consumer cannot bypass.
|
||||
- **Security, observability, and compliance as platform defaults** — not per-team effort, not post-hoc remediation.
|
||||
- **Auditability as a byproduct, not a project.** Every production change is traceable to a human attestation and a tamper-evident evidence event.
|
||||
- **Blast radius contained by design.** Zero-trust OIDC + ABAC means a consumer can only touch its own tagged resources.
|
||||
- **The bottleneck moves off the platform team's ticket queue.** A merged change progresses through lower environments without a platform engineer joining a thread.
|
||||
- **Infrastructure as a utility, not a craft.** Teams consume infrastructure, they don't maintain it — and the platform compounds value over time by learning from recurring patterns.
|
||||
- **A path to the citizen developer.** The same safety envelope that serves a senior engineer will serve a non-technical consumer. <span class="badge agentic">Agentic</span>
|
||||
- **Velocity without sacrificing safety** — speed in ergonomics, safety in unbypassable gates
|
||||
- **Security, observability, compliance as platform defaults** — not per-team effort, not post-hoc remediation
|
||||
- **Auditability as a byproduct, not a project** — every change traceable to a human attestation and a tamper-evident evidence event
|
||||
- **Blast radius contained by design** — OIDC + ABAC, only your own tagged resources
|
||||
- **The bottleneck moves off the platform team's ticket queue** — a merged change progresses without a platform engineer joining a thread
|
||||
- **Infrastructure as a utility, not a craft** — consume, don't maintain
|
||||
- **A path to the citizen developer** — same envelope, senior engineer or non-technical <span class="badge agentic">Agentic</span>
|
||||
|
||||
---
|
||||
|
||||
@@ -249,8 +191,6 @@ Developers pick from **pre-built, security-reviewed building blocks.** <span cla
|
||||
|
||||
# Appendix
|
||||
|
||||
<em class="story">For deep dives — these slides cover details omitted from the main 10.</em>
|
||||
|
||||
**Contents:**
|
||||
|
||||
1. The Citizen Developer Experience (full)
|
||||
@@ -259,6 +199,7 @@ Developers pick from **pre-built, security-reviewed building blocks.** <span cla
|
||||
4. The Road to the North Star (phased roadmap)
|
||||
5. Glossary
|
||||
6. Operating Model & Cost
|
||||
7. Verified by Construction
|
||||
|
||||
---
|
||||
|
||||
@@ -327,20 +268,45 @@ The entire CI pipeline runs **from the shell**, not just in CI. <span class="bad
|
||||
| **HITL** | Human-in-the-Loop — deliberate human attestation required for qa/prod/dr environments |
|
||||
| **VCS** | Version Control System — the git hosting platform (GitHub, Gitea, GitLab) |
|
||||
| **NFR** | Non-Functional Requirement — encryption, tagging, observability standards |
|
||||
| **IR** | Intermediate Representation — the engine-agnostic stack definition between contract and Terraform |
|
||||
|
||||
---
|
||||
|
||||
# A6 — Operating Model & Cost
|
||||
|
||||
ACDL runs at **zero cloud cost** for day-to-day development.
|
||||
<style>
|
||||
section { font-size: 20px; }
|
||||
table { font-size: 18px; }
|
||||
</style>
|
||||
|
||||
- **Local emulators are the primary tier** — the full pipeline runs in-process, no AWS credentials, no Checkov, no DynamoDB. <span class="badge testing">Testing</span>
|
||||
- **Live-AWS is a one-off spike per milestone** — `terraform init/validate/plan` verifies the adapter. No BAU cloud spend.
|
||||
- **No running infrastructure between milestones** — state in S3 (one bucket), outbox in DynamoDB (one table), both query-only.
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents).
|
||||
ACDL runs at **zero cloud cost** for day-to-day development. AWS spend was measured via Cost Explorer (`COST.md`, 2026-07-28):
|
||||
|
||||
**Verification Coverage** — 6 cloud capabilities are design-verified + locally emulated, deploy-unverified (IAM drift):
|
||||
DynamoDB contracts table · Lambda contract-ingestor · ECS service live · CloudFront prod stack · uptime-kuma · OIDC role
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total spend (8 days) | **$0.001883** |
|
||||
| Daily average | $0.000235 |
|
||||
| Projected monthly | ~$0.007 |
|
||||
| Peak day | 2026-07-27 ($0.000867) |
|
||||
|
||||
**The operating model:** local-first development, milestone-scoped verification, zero BAU cloud spend.
|
||||
- **Local emulators are the primary tier** — the full pipeline runs in-process, no AWS credentials <span class="badge testing">Testing</span>
|
||||
- **Live-AWS verification is milestone-scoped, then torn down.** The pipeline now **defaults to plan-only** on every PR; `ACDL_LIFECYCLE_MODE=full` overrides to apply→destroy for milestone verification (REQ-134, v1.12).
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). No running infrastructure between milestones.
|
||||
|
||||
**Pre-mortem (`PRE_MORTEM.md`):** the v1.10 decay incident (diff-scoped VERIFY missed 7 adapter defects) is the root pattern: *a claim outruns the verification that backs it.* Four forward failure modes + structural mitigations (regression-tested IAM baseline, mandatory teardown, verified-only deck claims, honest scope).
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: title -->
|
||||
<!-- _paginate: false -->
|
||||
|
||||
# A7 — Verified by Construction
|
||||
|
||||
<style>
|
||||
section { font-size: 20px; }
|
||||
</style>
|
||||
|
||||
Two architectural pillars make "Verified" a structural property, not a claim:
|
||||
|
||||
- **The stateless adapter (918 → ~80 lines).** The Terraform adapter was a 918-line monolith with 3 constant tables and 39 type-specific branches. It is now a ~80-line **stateless assembler**: it owns no module content — no resource shape, no nested HCL blocks, no defaults. Each L1 module ships a real `terraform/` module dir owning its shape, nested blocks, and defaults. The adapter reads the registry and emits `module "x" { source = ... }` blocks. A new module is a new terraform dir, not a code change. *(The v1.12 P67 fix closed a dedup defect for multi-resource L1s — ecs-service, alb; CAP-013 now Verified.)*
|
||||
- **Pipeline-driven lifecycle testing.** A `modules-lifecycle` pipeline matrix-runs each L1 and L2 module's contracts through apply→modify→destroy against live AWS. **The "test" = the pipeline cell going green.** Defaults to **plan-only** on every PR (fast, no AWS mutation, no cost); `ACDL_LIFECYCLE_MODE=full` overrides to the real apply→destroy for milestone verification (REQ-134, v1.12). The regression gate (D-091) re-runs all 22 capabilities at milestone completion — **22/22 Verified** as of v1.12.
|
||||
|
||||
The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently. The ~80-line stateless adapter + the milestone regression gate are the structural fix.
|
||||
@@ -1,6 +1,6 @@
|
||||
# The Developer Experience — Talking Points
|
||||
|
||||
> **Companion to:** `the-developer-experience-marp.md` (10 main + 6 appendix = 16 slides)
|
||||
> **Companion to:** `the-developer-experience-marp.md` (10 main + Appendix TOC + 7 appendix = 18 slides)
|
||||
> **Content source:** `the-developer-experience.md` (full source of truth with speaker notes)
|
||||
> **Purpose:** Presenter-ready cues — 3-6 talking points per slide + the one key takeaway the audience should remember.
|
||||
> **Audience:** Senior Leadership — CTO, Head of Cloud, Head of Infrastructure, Head of DevOps
|
||||
@@ -12,12 +12,13 @@
|
||||
**Talking points:**
|
||||
- Brief introduction — this deck covers *who uses the platform and how fast/safe they ship*, not the internal mechanics (that's the companion deck)
|
||||
- Set the frame: velocity without sacrificing safety, and security/observability/compliance as platform defaults rather than per-team effort
|
||||
- v1.12 re-verification: every "Testing" claim in this deck is now Verified — 22/22 capabilities via the v1.11 lifecycle pipeline (see A7)
|
||||
|
||||
**Key takeaway:** The consumer surface is intentionally tiny. The platform's surface is large and opinionated.
|
||||
|
||||
---
|
||||
|
||||
## Slide 2 — Where ACDL Sits in Your World
|
||||
## Slide 2 — Two consumer paths, one safety envelope
|
||||
|
||||
**Talking points:**
|
||||
- This is the scope-boundary slide — here's who uses the platform, and here's where ACDL's responsibility starts and stops
|
||||
@@ -30,12 +31,12 @@
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — The Contract — The Entire Consumer Surface
|
||||
## Slide 3 — Three things. The entire consumer surface.
|
||||
|
||||
**Talking points:**
|
||||
- Hold this slide — the audience should sit with how small the consumer surface is. Three things: app code, a contract, a one-line CI definition
|
||||
- The contract is a single YAML file: module, environment, inputs. That's the entire consumer-facing interface to production
|
||||
- The contract example now shows **infrastructure inputs** (cpu, memory, desired_count, port) — not an `image:` field. The consumer declares capacity and shape; the platform resolves the rest
|
||||
- The contract example shows **infrastructure inputs** (cpu, memory, desired_count, port) — not an `image:` field. The consumer declares capacity and shape; the platform resolves the rest
|
||||
- Walk the "does not" list quickly — no infrastructure modules, no platform repo cloning, no cloud credentials, no state backends. Every item is a category of toil the platform removes
|
||||
- For the Head of DevOps: this is the lever for throughput — the bottleneck moves off the platform team's ticket queue
|
||||
|
||||
@@ -43,7 +44,7 @@
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — The Developer Feedback Loop
|
||||
## Slide 4 — See what the platform does, in real time
|
||||
|
||||
**Talking points:**
|
||||
- This directly answers "but developers hate platforms that hide what they're doing" — the platform is opinionated about *what* runs, not *opaque* about *that* it runs
|
||||
@@ -57,159 +58,184 @@
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — Versioned, Predictable Releases
|
||||
|
||||
**Talking points:**
|
||||
- This is the "no surprise upgrades" story — consumers aren't forced to chase the platform, and the platform isn't forced to support N forks of every workflow
|
||||
- Floating MAJOR + MINOR tags (e.g. `@v1.6`) — a consumer automatically receives patch updates within the line. Pin to exact version for stability, or float on MAJOR only for new features
|
||||
- Semantic versioning with a clear contract: interface → MAJOR, behavior → MINOR, lifecycle → PATCH
|
||||
- Unversioned references (`@main`, bare) are discouraged — the versioned tag is the only immutability lever a consumer has
|
||||
- The automated release job computes the next semver on merge to main, creates the tag, and updates the floating tags — no manual release process
|
||||
|
||||
**Key takeaway:** Consumers control when they absorb platform improvements. No surprise upgrades.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — Friendly Onboarding
|
||||
|
||||
**Talking points:**
|
||||
- This looks like a small thing; it's actually a cultural one — the platform's posture is "help me get started," not "you should have known"
|
||||
- First impressions of a platform are made when it fails for the first time. The platform fails gracefully with a guided prompt, not an opaque error
|
||||
- The prompt tells the consumer: what's missing, what the platform will provision, the expected turnaround, and how to request an environment
|
||||
- The pipeline exits without attempting a deployment — no partial state, no confusing errors
|
||||
- Be honest: the citizen developer onboarding path is planned, not yet shipped
|
||||
|
||||
**Key takeaway:** The platform fails gracefully. First impressions drive adoption — platforms that fail opaquely get routed around.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Safe Promotion Path
|
||||
|
||||
**Talking points:**
|
||||
- Promotion is a workflow choice, not a contract mutation — this matters because it means a promotion can be reviewed as a *diff in the workflow*, not as a rewritten contract
|
||||
- The new promotion journey diagram shows the rising bar: dev (autonomous) → qa (QA attests) → prod (SRE attests) → dr (SRE attests + DR drill)
|
||||
- Approach A (one contract, environment passed by the job) keeps the single source of truth — the contract never changes
|
||||
- Approach B (environment-specific contracts) lets teams whose inputs genuinely vary keep that variation explicit and reviewable
|
||||
- The rising bar is annotated with maturity: **dev = Testing** (works internally, pilot-ready); **qa/prod/dr = Planned** (on the roadmap). Be honest about that split
|
||||
- Separation of duties is enforced — the QA approver cannot be the prod approver. No staging environment — the design deliberately removes the "staging is basically prod but not really" anti-pattern
|
||||
|
||||
**Key takeaway:** Change the environment field, not the contract. The platform raises the bar automatically. The consumer can't bypass the gates.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — Safe Decommission
|
||||
|
||||
**Talking points:**
|
||||
- The counter-argument to "deletion protection makes cleanup impossible" — decommission is a first-class, gated, two-approval flow, not a lock with no key
|
||||
- The change request must be `approved` in the CMDB and match the consumer repo — no CR, no decommission
|
||||
- Two SRE human-attestation gates: one to disable deletion protection, a second to zero counts and destroy
|
||||
- The per-stack encryption key enters a 30-day grace window so encrypted data remains recoverable — the key is permanently deleted only after the window expires
|
||||
- For the Head of Infrastructure: the CMDB validation means decommission is auditable, not just possible
|
||||
|
||||
**Key takeaway:** Tearing down is as gated as deploying. Two SRE approvals, CMDB-validated change request, 30-day key grace window.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Self-Service Module Catalog
|
||||
## Slide 5 — Pick from pre-built, security-reviewed blocks
|
||||
|
||||
**Talking points:**
|
||||
- The catalog is what makes "declare intent" practical — you can only declare a module that exists
|
||||
- Primitives are single-purpose resources (S3, VPC, ECS, IAM, ALB, ECR, CloudFront, WAF, RDS) — each with documented inputs/outputs, usage, compliance extension points, and versioning
|
||||
- Modules are composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + ALB + registry) — one well-reviewed module serves every consumer
|
||||
- Validated examples per module — `simple.yaml` + `complex.yaml` + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently
|
||||
- For leadership: the catalog is the leverage — a fix to a module serves every consumer on the next run. This is the compounding asset
|
||||
- Auto-promotion of patterns (after 3 observed usages) and compliance extension points (GDPR, SOX, SOC2, DORA) are planned
|
||||
- For leadership: the catalog is the leverage. One well-reviewed module serves every consumer; a fix to the module serves every consumer on the next run. This is the compounding asset
|
||||
- Primitives are single-purpose resources (S3, VPC, ECS, IAM, ALB, ECR, CloudFront, WAF, RDS) — each with documented inputs/outputs and versioning
|
||||
- Modules are composed patterns — a static site with CDN + WAF; a microservice with VPC + ECS + ALB + ECR
|
||||
- Validated examples per module (`simple.yaml` + `complex.yaml`) are validated against the contract schema in CI — examples cannot drift from the schema silently
|
||||
- Auto-promotion of patterns (after 3 observed usages) and compliance extension points (GDPR, SOX, SOC2, DORA) are on the roadmap
|
||||
|
||||
**Key takeaway:** The catalog is the compounding asset. One well-reviewed module serves every consumer. A fix serves everyone on the next run.
|
||||
**Key takeaway:** You don't author infrastructure — you pick from pre-built, security-reviewed building blocks. The catalog is the compounding asset.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — The Desired Outcomes
|
||||
## Slide 6 — The bar rises automatically with sensitivity
|
||||
|
||||
**Talking points:**
|
||||
- Close on the strategic frame — the platform is not "a CI/CD tool," it's the organizational lever for shipping safely at the pace the business demands
|
||||
- Velocity without sacrificing safety: speed is in the ergonomics (a simple contract, a one-line `uses:`), safety is in the gates the consumer cannot bypass
|
||||
- Security, observability, and compliance as platform defaults — not per-team effort, not post-hoc remediation. Encryption, deletion protection, uptime monitoring, policy checks, and evidence are on by construction
|
||||
- Promotion is a workflow choice, not a contract edit — a promotion can be reviewed as a *diff in the workflow*, not as a rewritten contract
|
||||
- The DX win: the contract stays stable across environments; the safety win: the platform raises the threshold and attestation bar automatically based on the target environment
|
||||
- The consumer can't bypass the gates — they pick *which* environment to target, and the platform applies the right bar
|
||||
- No staging environment — the design deliberately removes the "staging is basically prod but not really" anti-pattern. Dev is the only autonomous environment
|
||||
- Separation of duties is enforced — the QA approver cannot be the prod approver
|
||||
- Be honest about maturity: dev is tested and pilot-ready; qa/prod/dr wiring is planned
|
||||
|
||||
**Key takeaway:** The bar rises automatically with sensitivity. The consumer picks the environment; the platform applies the right gate.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Tearing down is as gated as deploying
|
||||
|
||||
**Talking points:**
|
||||
- The counter-argument to "deletion protection makes cleanup impossible" is this slide. Decommission is a first-class, gated, two-approval flow — not a lock with no key, and not an ungated `terraform destroy`
|
||||
- The CMDB validation means decommission is auditable, not just possible — the platform queries the CMDB and asserts the CR is `approved` and matches the consumer repo
|
||||
- Two SRE human-attestation gates: disable protection → SRE approves → zero all counts + destroy → a second SRE approves
|
||||
- The per-stack encryption key enters a grace window (default 30 days) so encrypted data remains recoverable during decommission
|
||||
- For the Head of Infrastructure: this is what makes deletion protection safe to ship by default — cleanup is a deliberate, gated path, not an impossible one
|
||||
|
||||
**Key takeaway:** Tearing down is as deliberate as deploying — two SRE attestation gates + CMDB-validated change request.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — You control when you absorb improvements
|
||||
|
||||
**Talking points:**
|
||||
- This is the "no surprise upgrades" story. Leadership hears two things: (1) consumers aren't forced to chase the platform, (2) the platform isn't forced to support N forks of every workflow
|
||||
- Floating MAJOR + MINOR tags (e.g. `@v1.12`) — a consumer automatically receives patch updates within the line
|
||||
- Semantic versioning with a clear contract: interface → MAJOR, behavior → MINOR, lifecycle → PATCH
|
||||
- A consumer can pin to an exact version for maximum stability, or float on MAJOR only (`@v1`) to absorb new features on their own cadence
|
||||
- Unversioned references (`@main`, bare) are discouraged — the versioned tag is the only immutability lever a consumer has
|
||||
- The automated release job computes the next semver on merge to main, creates the tag, and updates the floating tags
|
||||
|
||||
**Key takeaway:** You control when you absorb platform improvements — no surprise upgrades, no forced forks.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Fails gracefully, not opaquely
|
||||
|
||||
**Talking points:**
|
||||
- This looks like a small thing; it's actually a cultural one. The platform's posture is "help me get started," not "you should have known"
|
||||
- For the Head of DevOps: this is what drives adoption. Platforms that fail opaquely on first run get routed around
|
||||
- When no environment is bound, the platform emits a user-friendly onboarding prompt — not an opaque failure
|
||||
- The prompt tells the consumer: no environment bound, what the platform will provision, expected turnaround, how to request an environment
|
||||
- The pipeline then exits without attempting a deployment — no partial state, no confusing errors
|
||||
- The citizen developer onboarding path is planned
|
||||
|
||||
**Key takeaway:** The platform fails gracefully, not opaquely — first impressions are made when it fails for the first time.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — The desired outcomes
|
||||
|
||||
**Talking points:**
|
||||
- Close on the strategic frame. The platform is not "a CI/CD tool" — it is the organizational lever for shipping safely at the pace the business demands, with the security and audit posture the regulators require
|
||||
- Velocity without sacrificing safety: speed is in the ergonomics (a simple contract, a one-line `uses:`); safety is in the gates the consumer cannot bypass
|
||||
- Security, observability, and compliance as platform defaults — not per-team effort, not post-hoc remediation
|
||||
- Auditability as a byproduct, not a project — every production change is traceable to a human attestation and a tamper-evident evidence event
|
||||
- The bottleneck moves off the platform team's ticket queue — a merged change progresses through lower environments without a platform engineer joining a thread
|
||||
- Infrastructure as a utility, not a craft — teams consume, they don't maintain. The platform compounds value over time by learning from recurring patterns
|
||||
- The path to the citizen developer — the same safety envelope that serves a senior engineer will serve a non-technical consumer. Expanding who can ship safely without lowering the bar
|
||||
- A path to the citizen developer: the same safety envelope serves a senior engineer and a non-technical consumer
|
||||
- Invite questions; the companion deck ("How the Platform Works") covers the internal mechanics in more depth
|
||||
|
||||
**Key takeaway:** Velocity without sacrificing safety. Security and auditability as byproducts. The bottleneck moves off the platform team's queue.
|
||||
**Key takeaway:** Ship safely at the pace the business demands, with the security and audit posture the regulators require.
|
||||
|
||||
---
|
||||
|
||||
## Appendix — Contents
|
||||
## Appendix TOC — Appendix
|
||||
|
||||
**Talking points:**
|
||||
- These are backup slides for Q&A — don't walk through them in the main talk unless time permits
|
||||
- Use A1 when asked about the citizen developer detail; A2 for the no-cloning mechanism; A3 for local reproducibility; A4 for the roadmap; A5 for term definitions
|
||||
- These are backup slides for Q&A. Use them when the audience asks for the detail behind a main-slide claim
|
||||
- Don't walk through them in the main talk unless time permits
|
||||
- The appendix is indexed to match the Marp deck's A1-A7 structure
|
||||
|
||||
**Key takeaway:** The appendix is the deep-dive drawer. Pull a slide when the audience asks for the detail behind a main-slide claim.
|
||||
**Key takeaway:** Backup slides for Q&A — pull the relevant appendix slide when asked.
|
||||
|
||||
---
|
||||
|
||||
## A1 — The Citizen Developer Experience
|
||||
|
||||
**Talking points:**
|
||||
- The framing is **vibe coding on a laptop** — the consumer describes what they want in plain language; an AI agent turns that into a contract the platform treats identically to a senior engineer's
|
||||
- The consumer opens an issue (e.g. "a web API for the pricing service"); an AI agent maps the intent to a contract referencing a module from the reviewed skill catalog
|
||||
- The contract enters the same pipeline and must clear the same confidence gate — no weaker mode
|
||||
- Guardrails: skills are versioned, signed, and reviewed for sensitive data before release (Infra & Ops owns the review); agents are stateless — all state lives in the platform; the platform trusts and always verifies
|
||||
- The agent's trace and submission confidence are captured in the contract (`profile: agentic`), so a reviewer can see how the contract was produced
|
||||
- Be honest about maturity: the mechanism is designed and stub-proven; the full skill catalog and real agent runtime are planned
|
||||
- Be honest about maturity: the *mechanism* (agent → contract → same pipeline) is designed and the stub was proven in the v1.0 demo; the full skill catalog and real agent runtime are planned
|
||||
- The "vibe coding on a laptop" framing is intentional — it meets the citizen developer where they already are, but every submission still passes the same safety envelope
|
||||
- The design point matters to leadership now: we are building for a world where more of the org can ship safely, not where more of the org has to become a platform engineer
|
||||
- Guardrails: skills are versioned, signed, reviewed for sensitive data; agents are stateless; the platform trusts and always verifies
|
||||
- The agent's trace and submission confidence are captured in the contract (`profile: agentic`) for review
|
||||
|
||||
**Key takeaway:** Vibe coding on a laptop — but every submission passes the same safety envelope. The agent produces the contract; the platform verifies it.
|
||||
**Key takeaway:** A non-technical consumer ships by declaring intent — same pipeline, same safety envelope, no weaker checks.
|
||||
|
||||
---
|
||||
|
||||
## A2 — No Platform Code, No Cloning
|
||||
|
||||
**Talking points:**
|
||||
- The consumer's CI definition is a thin wrapper — one `uses:` line pointing at a versioned tag. That's the only coupling
|
||||
- The runner checks out the consumer repo, then checks out the platform repo into the workspace. The platform installs its own runtime dependencies — the consumer installs nothing
|
||||
- The consumer never clones the platform repo, never invokes platform scripts locally (optional `--check-only` validation is available but not required)
|
||||
- When the platform ships a fix, every consumer on a floating MAJOR.MINOR tag gets it on their next run — no per-repo upgrade project
|
||||
- For the Head of Cloud: there is no "platform code in every consumer repo" problem. The version-pinned `uses:` line is the only coupling, and it updates itself within the line
|
||||
- The Head of Cloud cares about this: there is no "platform code in every consumer repo" problem
|
||||
- The version-pinned `uses:` line is the *only* coupling, and it's a coupling that updates itself within the line
|
||||
- The runner checks out the consumer repo, then checks out the platform repo into the workspace — the consumer never clones the platform repo
|
||||
- The platform installs its own runtime dependencies — the consumer installs nothing
|
||||
- When the platform ships a fix, every consumer on a floating tag gets it on their next run — no per-repo upgrade project
|
||||
|
||||
**Key takeaway:** One `uses:` line is the only coupling. The platform fetches itself at run time. No per-repo upgrade projects.
|
||||
**Key takeaway:** The consumer never touches platform internals. The versioned `uses:` line is the only coupling.
|
||||
|
||||
---
|
||||
|
||||
## A3 — Local Reproducibility
|
||||
|
||||
**Talking points:**
|
||||
- The entire CI pipeline runs from the shell, not just in CI — no "works on my machine, fails in CI" gap
|
||||
- This is the "no surprises before you push" story. A consumer can validate their contract offline, run the plan offline, and only push when they're confident
|
||||
- `scripts/run_ci.sh` mirrors the CI pipeline locally — the same three stages (lint → test → check-only) in sequence
|
||||
- `scripts/run_platform.sh --check-only` runs the platform offline — no AWS, no policy engine, no outbox required. Validates a contract end-to-end before pushing
|
||||
- `--plan-only` runs through the infrastructure plan without applying
|
||||
- The CI and deploy pipelines are defined by declarative contracts (YAML instances validated against JSON Schemas) — a single source of truth that both workflows implement
|
||||
- `scripts/run_platform.sh --check-only` runs the platform offline — no AWS, no policy engine, no outbox required
|
||||
- The same declarative contract drives both the local tooling and CI — there's no "works on my machine, fails in CI" gap
|
||||
|
||||
**Key takeaway:** Validate offline, plan offline, push when confident. The same declarative contract drives local tooling and CI.
|
||||
**Key takeaway:** The entire CI pipeline runs from the shell — no surprises before you push.
|
||||
|
||||
---
|
||||
|
||||
## A4 — The Road to the North Star
|
||||
|
||||
**Talking points:**
|
||||
- Call this out explicitly: **proposed phasing, not formally planned** — don't let the audience read it as a commitment
|
||||
- Phase 1 is what's tested today — core platform (contract, catalog, evidence)
|
||||
- Phase 2 is the next milestone — safe promotion wiring for qa/prod/dr
|
||||
- Phase 3 introduces the agentic surface — skill catalog + agents
|
||||
- Phase 4 is the north star — citizen developer GA on the same safety envelope
|
||||
- Use this slide only when an audience member asks "how do you get from here to there"
|
||||
- This is a proposed phasing, not a formally committed plan — call that out explicitly
|
||||
- Phase 1 is what's tested and Verified today (22/22 capabilities, torn down to zero-cost)
|
||||
- Phase 2 is the next milestone (qa/prod/dr wiring)
|
||||
- Phase 3 introduces the agentic surface (skill catalog + agents)
|
||||
- Phase 4 is the north star: citizen developer GA on the same safety envelope
|
||||
- Use this only when an audience member asks "how do you get from here to there"
|
||||
|
||||
**Key takeaway:** A proposed path from the tested core to the citizen developer north star — proposed phasing, not formally planned.
|
||||
**Key takeaway:** Proposed phasing — Phase 1 Verified, Phase 4 is the North Star (citizen developer GA).
|
||||
|
||||
---
|
||||
|
||||
## A5 — Glossary
|
||||
|
||||
**Talking points:**
|
||||
- Keep this slide in your back pocket for the audience member who asks "what does ABAC actually mean?" — don't read it aloud
|
||||
- OIDC = short-lived federation tokens, no long-lived credentials; ABAC = access scoped by resource tags + repo identity, not roles
|
||||
- CMK = per-stack encryption key, 90-day rotation; CMDB = validates change requests for decommission
|
||||
- RPO = 0 means evidence written synchronously, no data loss; HITL = deliberate human attestation for qa/prod/dr
|
||||
- VCS = the git hosting platform (GitHub, Gitea, GitLab); NFR = encryption, tagging, observability standards
|
||||
- Keep this slide in your back pocket for the audience member who asks "what does ABAC actually mean?"
|
||||
- Don't read it aloud
|
||||
- All acronyms used in the deck are defined here
|
||||
|
||||
**Key takeaway:** The deck uses real security and ops vocabulary. The glossary is the cheat sheet for the audience member who wants the definitions.
|
||||
**Key takeaway:** Reference slide — don't read aloud.
|
||||
|
||||
---
|
||||
|
||||
## A6 — Operating Model & Cost
|
||||
|
||||
**Talking points:**
|
||||
- The headline for the Head of Cloud / Finance: less than one cent over 8 days of active development; zero BAU cloud spend
|
||||
- The lifecycle pipeline defaults to plan-only so the PR-time cost is zero; `ACDL_LIFECYCLE_MODE=full` overrides for milestone verification
|
||||
- The pre-mortem is the credibility slide — we already asked "how does this fail?" and the mitigations are structural
|
||||
- The v1.10 decay incident is disclosed honestly, not hidden — that disclosure IS the mitigation
|
||||
- Cost drivers are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). No running infrastructure between milestones
|
||||
|
||||
**Key takeaway:** Zero BAU cloud cost. Pre-mortemed failure modes with structural mitigations.
|
||||
|
||||
---
|
||||
|
||||
## A7 — Verified by Construction
|
||||
|
||||
**Talking points:**
|
||||
- This is the deep-dive slide for the Head of Engineering / Architecture — the two pillars answer "how do you keep the decks honest?"
|
||||
- The adapter is simple enough to reason about (a stateless assembler); the lifecycle pipeline is the automated verification that backs every "Testing" claim
|
||||
- The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently because the VERIFY gate was diff-scoped
|
||||
- The ~80-line stateless adapter + the milestone regression gate are the structural fix
|
||||
- The plan-only default (v1.12) means verification runs on every PR at zero cost, with the full apply→destroy gated behind a CI variable override
|
||||
|
||||
**Key takeaway:** "Verified" is a structural property, not a claim — the stateless adapter + lifecycle pipeline make it so.
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
> **Subtitle:** Agentic Cloud Delivery Platform
|
||||
> **Audience:** Senior Leadership, CTO, Head of Cloud, Head of Infrastructure, Head of DevOps
|
||||
> **Length:** ~15 minutes · 10 main + 6 appendix = 16 slides
|
||||
> **Length:** ~15 minutes · 10 main + Appendix TOC + 7 appendix = 18 slides
|
||||
> **Purpose:** Sell the developer experience and the citizen developer experience to tech leadership — velocity without sacrificing safety, and security/observability/compliance as platform defaults rather than per-team effort.
|
||||
> **Maturity framing:** "Testing" = works internally, dev pilot-ready. "Planned" = on the roadmap. "Agentic" = involves AI agents or autonomous decision-making.
|
||||
> **Re-verification (2026-07-27):** Every "Testing" claim in this deck was re-verified in v1.10 Phase 54 (D-093). The headline E2E (contract → resolver → adapter → terraform init/validate/plan) passes against the live AWS account; the local emulating tier (Phase 53) runs the full E2E with no cloud credentials. 16/16 auto-verifiable capabilities Verified; 6 IAM-gated cloud resources are escalated (require an admin principal the spike-runner lacks). See `.ciagent/CAPABILITY_INVENTORY.md`.
|
||||
> **Re-verification (2026-07-29):** Every "Testing" claim in this deck was re-verified in v1.10 Phase 54 (D-093) and again in v1.11 via the pipeline-driven lifecycle tests (P59–P62). The headline E2E (contract → resolver → adapter → terraform init/validate/plan) passes against the live AWS account; the local emulating tier (Phase 53) runs the full E2E with no cloud credentials. **22/22 auto-verifiable capabilities Verified** (CAP-013 fixed in v1.12 P67 — the adapter's multi-resource L1 dedup defect is closed). The v1.11 lifecycle pipeline ran apply→modify→destroy against live AWS and was then torn down to zero-cost (D-096). See `.ciagent/CAPABILITY_INVENTORY.md` and `.ciagent/PRE_MORTEM.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -17,14 +17,10 @@ The consumer surface is intentionally tiny. The platform's surface is large and
|
||||
|
||||
---
|
||||
|
||||
## Slide 2 — Where Agentic Cloud Delivery (ACDL) Sits in Your World
|
||||
|
||||
Here's who uses the platform and where the boundary is.
|
||||
## Slide 2 — Two consumer paths, one safety envelope
|
||||
|
||||
The platform serves **two kinds of consumer** through two coordinated paths — but both converge on the **same contract, the same policy envelope, and the same evidence stream.**
|
||||
|
||||
**Agentic Cloud Delivery (ACDL)** sits between upstream (anything that produces a contract) and downstream (AWS resources running + the consumer's image pipeline).
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph UP ["Upstream — anything"]
|
||||
@@ -49,27 +45,19 @@ flowchart LR
|
||||
F --> G
|
||||
```
|
||||
|
||||
- **Technical developer** — owns app code + a contract + a thin CI definition. Uses the full module catalog and inputs.
|
||||
- **Citizen developer** — declares intent in plain language; an AI agent produces a contract that passes the **same** safety envelope as a senior engineer's. <span class="badge agentic">Agentic</span>
|
||||
- **Upstream is anything** — your IDE, an agentic SDLC, or vibe coding on a laptop. ACDL doesn't care how the contract was produced.
|
||||
- **Technical developer** — owns app code + a contract + a thin CI definition.
|
||||
- **Citizen developer** — declares intent in plain language; an AI agent produces a contract that passes the **same** safety envelope. <span class="badge agentic">Agentic</span>
|
||||
- **Upstream is anything** — IDE, agentic SDLC, or vibe coding. ACDL doesn't care how the contract was produced.
|
||||
- **ACDL is infrastructure only** — it provisions and governs AWS resources. Application deployment is upstream.
|
||||
|
||||
The platform is **opinionated in what it accepts, regardless of who is declaring.** There is no "citizen developer mode" with weaker checks.
|
||||
|
||||
> **Speaker notes:** This is the thesis of the deck. The two surfaces are *parallel*, not a progression — a citizen developer doesn't "graduate" to the developer surface. Both produce a contract; both get the same treatment. The scope boundary matters: anything upstream of the contract is out of ACDL's concern — ACDL is the infrastructure layer that takes a contract and governs the AWS resources. The leadership takeaway: we expand who can ship safely without lowering the bar.
|
||||
> **Speaker notes:** This is the thesis of the deck. The two surfaces are *parallel*, not a progression — a citizen developer doesn't "graduate" to the developer surface. Both produce a contract; both get the same treatment. The scope boundary matters: anything upstream of the contract is out of ACDL's concern. The leadership takeaway: we expand who can ship safely without lowering the bar.
|
||||
|
||||
---
|
||||
|
||||
## Slide 3 — The Contract — The Entire Consumer Surface
|
||||
|
||||
Now let's look at what a consumer actually writes — it's tiny.
|
||||
## Slide 3 — Three things. The entire consumer surface.
|
||||
|
||||
Three things. That is the entire consumer-side surface.
|
||||
|
||||
1. **App code** — the consumer's service, at the top level of the repo
|
||||
2. **A contract** — a single YAML file: id, name, environment, infrastructure
|
||||
3. **A one-line CI definition** — a thin `uses:` wrapper pointing at a versioned platform workflow
|
||||
|
||||
```yaml
|
||||
id: msvc
|
||||
name: microservice
|
||||
@@ -84,53 +72,166 @@ infrastructure:
|
||||
port: 8080
|
||||
```
|
||||
|
||||
The developer does **not**:
|
||||
1. **App code** — the consumer's service, at the top level of the repo
|
||||
2. **A contract** — a single YAML file: id, name, environment, infrastructure
|
||||
3. **A one-line CI definition** — a thin `uses:` wrapper pointing at a versioned platform workflow
|
||||
|
||||
- Write infrastructure modules.
|
||||
- Author workflow YAML beyond the one-line `uses:` wrapper.
|
||||
- Clone the platform repo.
|
||||
- Hold cloud credentials.
|
||||
- Maintain a state backend, a VPC, or a runner.
|
||||
The developer does **not**: write infrastructure modules, clone the platform repo, hold cloud credentials, or maintain a state backend.
|
||||
|
||||
> **Speaker notes:** Hold this slide. The audience should sit with how small the consumer surface is. Every item in the "does not" list is a category of toil the platform removes. The contract is the API — deliberately tiny so that it can be reviewed, validated, and audited. For the Head of DevOps: this is the lever for throughput — the bottleneck moves off the platform team's ticket queue.
|
||||
|
||||
---
|
||||
|
||||
## Slide 4 — The Developer Feedback Loop
|
||||
|
||||
Once you push, here's what you see — in real time, in your own logs.
|
||||
## Slide 4 — See what the platform does, in real time
|
||||
|
||||
Developers see **what the platform is doing**, in real time. <span class="badge testing">Testing</span>
|
||||
|
||||
- **Streamed output by default** — the infrastructure plan, policy-check results, and each check record flow to stdout.
|
||||
- **PR comments after every successful pipeline stage** — a developer always knows where they stand without refreshing a dashboard.
|
||||
- **Streamed output by default** — the plan, policy-check results, and each check record flow to stdout.
|
||||
- **PR comments after every successful pipeline stage** — a developer always knows where they stand.
|
||||
- **Clear, explainable halt reasons** — a policy violation, an insufficient confidence signal, or a missing attestation. **Never an opaque debugging exercise.**
|
||||
- **Connection strings posted as PR comments** — human-readable, no hunting. Runtime secrets go to encrypted Parameter Store (KMS-encrypted, namespaced), never to logs.
|
||||
- **Errors become GitHub issues, automatically** — a failed deploy opens an issue on the platform repo. The consumer's only grant is the onboarding-granted Lambda-invoke permission — no separate `issues: write` scope on the consumer side.
|
||||
- **Errors become GitHub issues, automatically** — a failed deploy opens an issue on the platform repo.
|
||||
|
||||
> **Speaker notes:** This directly answers "but developers hate platforms that hide what they're doing." The platform is opinionated about *what* runs, not *opaque* about *that* it runs. The PR-comment-after-each-stage pattern is a small thing that compounds into trust. The "errors become issues" point is a DX win that also helps the platform team — every consumer failure is a tracked, queryable artifact, not a lost log line. The Head of DevOps should hear: the platform closes the feedback loop, it doesn't just push a green/red status.
|
||||
> **Speaker notes:** This directly answers "but developers hate platforms that hide what they're doing." The platform is opinionated about *what* runs, not *opaque* about *that* it runs. The PR-comment-after-each-stage pattern is a small thing that compounds into trust. The "errors become issues" point is a DX win that also helps the platform team — every consumer failure is a tracked, queryable artifact, not a lost log line.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5 — Versioned, Predictable Releases
|
||||
## Slide 5 — Pick from pre-built, security-reviewed blocks
|
||||
|
||||
You control when you absorb platform improvements — no surprise upgrades.
|
||||
Developers pick from **pre-built, security-reviewed building blocks.** <span class="badge testing">Testing</span>
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph PRIM ["Primitives"]
|
||||
direction TB
|
||||
P1["S3"]
|
||||
P2["VPC"]
|
||||
P3["ECS"]
|
||||
P4["IAM"]
|
||||
P5["ALB"]
|
||||
P6["ECR"]
|
||||
P7["CloudFront"]
|
||||
P8["WAF"]
|
||||
P9["RDS"]
|
||||
end
|
||||
subgraph MOD ["Modules — composed patterns"]
|
||||
direction TB
|
||||
M1["Static site\nCDN + WAF + S3"]
|
||||
M2["Microservice\nVPC + ECS + ALB + ECR"]
|
||||
end
|
||||
PRIM --> MOD
|
||||
```
|
||||
|
||||
- **Primitives** — single-purpose resources (S3, VPC, ECS, IAM, ALB, ECR, CloudFront, WAF, RDS), each with documented inputs/outputs and versioning.
|
||||
- **Modules** — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + ALB + ECR).
|
||||
- **Validated examples per module** — `simple.yaml` + `complex.yaml`, validated against the contract schema in CI. Examples cannot drift from the schema silently.
|
||||
- **Auto-promotion of patterns** — auto-promoted to the catalog after 3 observed usages. <span class="badge planned">Planned</span> <span class="badge agentic">Agentic</span>
|
||||
- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, DORA controls will wire in. <span class="badge planned">Planned</span>
|
||||
|
||||
> **Speaker notes:** The catalog is what makes "declare intent" practical — you can only declare a module that exists. For leadership: the catalog is the leverage. One well-reviewed module serves every consumer; a fix to the module serves every consumer on the next run. This is the compounding asset.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — The bar rises automatically with sensitivity
|
||||
|
||||
The contract is environment-agnostic. The platform raises the bar automatically.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
DEV["dev<br/>autonomous"] -->|raise the bar| QA["qa<br/>QA attests"]
|
||||
QA -->|raise the bar| PROD["prod<br/>SRE attests"]
|
||||
PROD -->|raise the bar| DR["dr<br/>SRE attests + DR drill"]
|
||||
```
|
||||
|
||||
| Environment | What the platform adds | Maturity |
|
||||
|---|---|---|
|
||||
| dev | Confidence ≥ 0.50, fully autonomous | <span class="badge testing">Testing</span> |
|
||||
| qa | QA human attestation + confidence ≥ 0.75 | <span class="badge planned">Planned</span> |
|
||||
| prod | SRE human attestation + confidence ≥ 0.90 | <span class="badge planned">Planned</span> |
|
||||
| dr | SRE human attestation + confidence ≥ 0.95 + DR drill reference | <span class="badge planned">Planned</span> |
|
||||
|
||||
- **No staging environment** — the design deliberately removes the "staging is basically prod but not really" anti-pattern.
|
||||
- **Separation of duties is enforced** — the QA approver cannot be the prod approver.
|
||||
- **Timeout discipline** — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit.
|
||||
|
||||
> **Speaker notes:** Promotion is a workflow choice, not a contract mutation — this matters because it means a promotion can be reviewed as a *diff in the workflow*, not as a rewritten contract. The DX win: the contract stays stable across environments; the safety win: the platform raises the threshold and attestation bar automatically based on the target environment. The consumer can't bypass the gates — they pick *which* environment to target, and the platform applies the right bar. Be honest about maturity: dev is tested and pilot-ready; qa/prod/dr wiring is planned.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Tearing down is as gated as deploying
|
||||
|
||||
Tearing down a stack is **as deliberate as deploying one.** <span class="badge testing">Testing</span>
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["Validate CR\n(CMDB)"]
|
||||
B["Disable\nprevent_destroy"]
|
||||
C["SRE\napprove"]
|
||||
D["Zero counts\n+ destroy"]
|
||||
E["SRE\napprove"]
|
||||
F["Key enters\ngrace window"]
|
||||
A --> B --> C --> D --> E --> F
|
||||
```
|
||||
|
||||
```yaml
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.12
|
||||
with:
|
||||
contract: .acdl/contract.yml
|
||||
mode: decommission
|
||||
changeRequestId: "CHG0678912"
|
||||
```
|
||||
|
||||
A 2-step pipeline with **two SRE human-attestation gates**:
|
||||
|
||||
1. **Validate the change request** — the platform queries the CMDB and asserts the CR is `approved` and matches the consumer repo. No CR, no decommission.
|
||||
2. **Disable deletion protection** → **SRE approves** → **Zero all counts + destroy** → **a second SRE approves.**
|
||||
|
||||
The per-stack encryption key enters a **grace window** (default 30 days) so encrypted data remains recoverable.
|
||||
|
||||
> **Speaker notes:** The counter-argument to "deletion protection makes cleanup impossible" is this slide. Decommission is a first-class, gated, two-approval flow — not a lock with no key, and not an ungated `terraform destroy`. For the Head of Infrastructure: the CMDB validation means decommission is auditable, not just possible.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — You control when you absorb improvements
|
||||
|
||||
Consumers control **when** they absorb platform improvements. <span class="badge testing">Testing</span>
|
||||
|
||||
- **Floating MAJOR + MINOR tags** (e.g. `@v1.10`) — a consumer automatically receives patch updates within the line.
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph FLOAT ["@v1.12 — floating MAJOR+MINOR"]
|
||||
direction LR
|
||||
F1["v1.12.0"]
|
||||
F2["v1.12.1"]
|
||||
F3["v1.12.2"]
|
||||
F1 --> F2 --> F3
|
||||
end
|
||||
subgraph PIN ["@v1.12.2 — pinned exact"]
|
||||
direction LR
|
||||
P1["v1.12.2"]
|
||||
P2["v1.12.2"]
|
||||
P3["v1.12.2"]
|
||||
P1 --> P2 --> P3
|
||||
end
|
||||
subgraph MAJ ["@v1 — float MAJOR only"]
|
||||
direction LR
|
||||
M1["v1.12.0"]
|
||||
M2["v1.13.0"]
|
||||
M3["v1.14.0"]
|
||||
M1 --> M2 --> M3
|
||||
end
|
||||
```
|
||||
|
||||
- **Floating MAJOR + MINOR tags** (e.g. `@v1.12`) — automatically receive patch updates within the line.
|
||||
- **Semantic versioning with a clear contract:** interface → MAJOR, behavior → MINOR, lifecycle → PATCH.
|
||||
- **A consumer can pin to an exact version** for maximum stability, or float on MAJOR only (`@v1`) to absorb new features on their own cadence.
|
||||
- **Unversioned references (`@main`, bare) are discouraged** — the versioned tag is the only immutability lever a consumer has.
|
||||
- **Pin to an exact version** for maximum stability, or float on MAJOR only (`@v1`) to absorb new features on your own cadence.
|
||||
- **Unversioned references (`@main`, bare) are discouraged** — the versioned tag is the only immutability lever.
|
||||
- **Automated release job** computes the next semver on merge to main, creates the tag, and updates the floating tags.
|
||||
|
||||
> **Speaker notes:** This is the "no surprise upgrades" story. Leadership hears two things: (1) consumers aren't forced to chase the platform, (2) the platform isn't forced to support N forks of every workflow. The versioning discipline is what makes both true.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6 — Friendly Onboarding
|
||||
|
||||
First impressions matter — the platform fails gracefully, not opaquely.
|
||||
## Slide 9 — Fails gracefully, not opaquely
|
||||
|
||||
First impressions of a platform are made **when it fails for the first time.** The platform fails gracefully. <span class="badge testing">Testing</span>
|
||||
|
||||
@@ -149,114 +250,15 @@ The pipeline then **exits without attempting a deployment** — no partial state
|
||||
|
||||
---
|
||||
|
||||
## Slide 7 — Safe Promotion Path
|
||||
## Slide 10 — The desired outcomes
|
||||
|
||||
Promotion is a workflow choice, not a contract edit — and the bar rises automatically.
|
||||
|
||||
The contract is environment-agnostic. The platform raises the bar automatically.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
DEV["dev<br/>autonomous"] -->|raise the bar| QA["qa<br/>QA attests"]
|
||||
QA -->|raise the bar| PROD["prod<br/>SRE attests"]
|
||||
PROD -->|raise the bar| DR["dr<br/>SRE attests + DR drill"]
|
||||
```
|
||||
|
||||
**Approach A — One contract, one job per environment.** A single contract is referenced by multiple jobs; the environment is passed by each job and interpolated at runtime. The contract itself never changes.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
dev:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract.yml, environment: dev }
|
||||
qa:
|
||||
needs: dev
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract.yml, environment: qa }
|
||||
```
|
||||
|
||||
**Approach B — Environment-specific contracts.** When inputs genuinely differ per environment, each job points at its own contract file. The pipeline, policy, and confidence model stay identical.
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
dev:
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract-dev.yaml }
|
||||
qa:
|
||||
needs: dev
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with: { contract: .acdl/contract-qa.yaml }
|
||||
```
|
||||
|
||||
Whichever approach a team picks, the platform applies the same rising bar:
|
||||
|
||||
| Environment | What the platform adds | Maturity |
|
||||
|---|---|---|
|
||||
| dev | Confidence ≥ 0.50, fully autonomous | <span class="badge testing">Testing</span> |
|
||||
| qa | QA human attestation + confidence ≥ 0.75 | <span class="badge planned">Planned</span> |
|
||||
| prod | SRE human attestation + confidence ≥ 0.90 | <span class="badge planned">Planned</span> |
|
||||
| dr | SRE human attestation + confidence ≥ 0.95 + a disaster-recovery drill reference | <span class="badge planned">Planned</span> |
|
||||
|
||||
- **No staging environment** — the design deliberately removes the "staging is basically prod but not really" anti-pattern. Dev is the only autonomous environment.
|
||||
- **Separation of duties is enforced** — the QA approver cannot be the prod approver.
|
||||
- **Timeout discipline** — 1 business day = warn + escalate; 2 business days = auto-freeze + re-submit.
|
||||
|
||||
> **Speaker notes:** Promotion is a workflow choice, not a contract mutation — this matters because it means a promotion can be reviewed as a *diff in the workflow*, not as a rewritten contract. Approach A keeps the single source of truth; Approach B lets teams whose inputs genuinely vary keep that variation explicit and reviewable. For leadership: the DX win is that the contract stays stable across environments; the safety win is that the platform raises the threshold and attestation bar automatically based on the target environment the job declares. The consumer can't bypass the gates — they pick *which* environment to target, and the platform applies the right bar. Be honest about maturity: dev is tested and pilot-ready; qa/prod/dr wiring is planned.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8 — Safe Decommission
|
||||
|
||||
Tearing down is as deliberate as deploying — and just as gated.
|
||||
|
||||
Tearing down a stack is **as deliberate as deploying one.** <span class="badge testing">Testing</span>
|
||||
|
||||
```yaml
|
||||
uses: acdl/.github/workflows/deploy.yml@v1.10
|
||||
with:
|
||||
contract: .acdl/contract.yml
|
||||
mode: decommission
|
||||
changeRequestId: "CHG0678912"
|
||||
```
|
||||
|
||||
A 2-step pipeline with **two SRE human-attestation gates**:
|
||||
|
||||
1. **Validate the change request** — the platform queries the CMDB and asserts the CR is `approved` and matches the consumer repo. No CR, no decommission.
|
||||
2. **Disable deletion protection** → **SRE approves** → **Zero all counts + destroy** → **a second SRE approves.**
|
||||
|
||||
The per-stack encryption key enters a **grace window** (default 30 days) so encrypted data remains recoverable. The key is permanently deleted only after the window expires.
|
||||
|
||||
> **Speaker notes:** The counter-argument to "deletion protection makes cleanup impossible" is this slide. Decommission is a first-class, gated, two-approval flow — not a lock with no key, and not an ungated `terraform destroy`. For the Head of Infrastructure: the CMDB validation means decommission is auditable, not just possible.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9 — Self-Service Module Catalog
|
||||
|
||||
You don't author infrastructure — you pick from pre-built, security-reviewed building blocks.
|
||||
|
||||
Developers pick from **pre-built, security-reviewed building blocks.** <span class="badge testing">Testing</span>
|
||||
|
||||
- **Primitives** — single-purpose resources (S3, VPC, ECS, IAM, load balancer, container registry, CloudFront, WAF, RDS). Each has documented inputs/outputs, usage, compliance extension points, and versioning.
|
||||
- **Modules** — composed patterns (a static site with CDN + WAF; a microservice with VPC + ECS + load balancer + registry).
|
||||
- **Validated examples per module** — `simple.yaml` + `complex.yaml` + variation files, validated against the contract schema in CI. Examples cannot drift from the schema silently.
|
||||
- **Auto-promotion of patterns** — auto-promoted to the catalog after 3 observed usages. <span class="badge planned">Planned</span> <span class="badge agentic">Agentic</span>
|
||||
- **Compliance extension points** — each module lists where GDPR, SOX, SOC2, DORA controls will wire in. <span class="badge planned">Planned</span>
|
||||
|
||||
> **Speaker notes:** The catalog is what makes "declare intent" practical — you can only declare a module that exists. For leadership: the catalog is the leverage. One well-reviewed module serves every consumer; a fix to the module serves every consumer on the next run. This is the compounding asset.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10 — The Desired Outcomes
|
||||
|
||||
Here's what this delivers to the organization.
|
||||
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics (a simple contract, a one-line `uses:`); safety is in the gates the consumer cannot bypass.
|
||||
- **Security, observability, and compliance as platform defaults** — not per-team effort, not post-hoc remediation. Encryption, deletion protection, uptime monitoring, policy checks, and evidence are on by construction.
|
||||
- **Auditability as a byproduct, not a project.** Every production change is traceable to a human attestation and a tamper-evident evidence event — captured during the deploy, not reconstructed for the audit.
|
||||
- **Blast radius contained by design.** Zero-trust OIDC + ABAC means a consumer can only touch its own tagged resources. One consumer can never affect another.
|
||||
- **The bottleneck moves off the platform team's ticket queue.** A merged change progresses through lower environments without a platform engineer joining a thread. The platform team invests in the platform, not in per-deployment hand-holding.
|
||||
- **Infrastructure as a utility, not a craft.** Teams consume infrastructure, they don't maintain it — and the platform compounds value over time by learning from recurring patterns.
|
||||
- **A path to the citizen developer.** The same safety envelope that serves a senior engineer will serve a non-technical consumer. <span class="badge agentic">Agentic</span>
|
||||
- **Velocity without sacrificing safety.** Speed is in the ergonomics; safety is in the gates the consumer cannot bypass.
|
||||
- **Security, observability, and compliance as platform defaults** — not per-team effort, not post-hoc remediation.
|
||||
- **Auditability as a byproduct, not a project.** Every production change is traceable to a human attestation and a tamper-evident evidence event.
|
||||
- **Blast radius contained by design.** Zero-trust OIDC + ABAC means a consumer can only touch its own tagged resources.
|
||||
- **The bottleneck moves off the platform team's ticket queue.** A merged change progresses through lower environments without a platform engineer joining a thread.
|
||||
- **Infrastructure as a utility, not a craft.** Teams consume infrastructure, they don't maintain it.
|
||||
- **A path to the citizen developer.** The same safety envelope serves a senior engineer and a non-technical consumer. <span class="badge agentic">Agentic</span>
|
||||
|
||||
> **Speaker notes:** Close on the strategic frame. The platform is not "a CI/CD tool" — it is the organizational lever for shipping safely at the pace the business demands, with the security and audit posture the regulators require. Invite questions; the companion deck ("How the Platform Works") covers the internal mechanics in more depth.
|
||||
|
||||
@@ -271,6 +273,8 @@ For deep dives — these slides cover details omitted from the main 10.
|
||||
3. **A3 — Local Reproducibility** (detail)
|
||||
4. **A4 — The Road to the North Star** (phased roadmap)
|
||||
5. **A5 — Glossary**
|
||||
6. **A6 — Operating Model & Cost** (real AWS spend + pre-mortem)
|
||||
7. **A7 — Verified by Construction** (the v1.11 architecture)
|
||||
|
||||
> **Speaker notes:** These are backup slides for Q&A. Use them when the audience asks for the detail behind a main-slide claim. Don't walk through them in the main talk unless time permits.
|
||||
|
||||
@@ -339,12 +343,12 @@ The entire CI pipeline runs **from the shell**, not just in CI. <span class="bad
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P1["Phase 1<br/>Core platform<br/>(contract, catalog, evidence)"] --> P2["Phase 2<br/>Safe promotion<br/>qa/prod/dr wiring"]
|
||||
P1["Phase 1<br/>Core platform<br/>(22/22 Verified)"] --> P2["Phase 2<br/>Safe promotion<br/>qa/prod/dr wiring"]
|
||||
P2 --> P3["Phase 3<br/>Agentic surface<br/>(skill catalog + agents)"]
|
||||
P3 --> P4["Phase 4<br/>North star<br/>citizen developer GA"]
|
||||
```
|
||||
|
||||
> **Speaker notes:** This is a proposed phasing, not a formally committed plan — call that out explicitly. Phase 1 is what's tested today. Phase 2 is the next milestone (qa/prod/dr wiring). Phase 3 introduces the agentic surface. Phase 4 is the north star: citizen developer GA on the same safety envelope. Use this only when an audience member asks "how do you get from here to there."
|
||||
> **Speaker notes:** This is a proposed phasing, not a formally committed plan — call that out explicitly. Phase 1 is what's tested and Verified today (22/22 capabilities, torn down to zero-cost). Phase 2 is the next milestone (qa/prod/dr wiring). Phase 3 introduces the agentic surface. Phase 4 is the north star: citizen developer GA on the same safety envelope. Use this only when an audience member asks "how do you get from here to there."
|
||||
|
||||
---
|
||||
|
||||
@@ -361,4 +365,36 @@ flowchart LR
|
||||
| **VCS** | Version Control System — the git hosting platform (GitHub, Gitea, GitLab) |
|
||||
| **NFR** | Non-Functional Requirement — encryption, tagging, observability standards |
|
||||
|
||||
> **Speaker notes:** Keep this slide in your back pocket for the audience member who asks "what does ABAC actually mean?" Don't read it aloud.
|
||||
> **Speaker notes:** Keep this slide in your back pocket for the audience member who asks "what does ABAC actually mean?" Don't read it aloud.
|
||||
|
||||
---
|
||||
|
||||
## A6 — Operating Model & Cost
|
||||
|
||||
ACDL runs at **zero cloud cost** for day-to-day development. The v1.0→v1.10 AWS spend was measured directly via Cost Explorer (`COST.md`, 2026-07-28):
|
||||
|
||||
| Metric | Value |
|
||||
|--------|-------|
|
||||
| Total spend (8 days) | **$0.001883** |
|
||||
| Daily average | $0.000235 |
|
||||
| Projected monthly | ~$0.007 |
|
||||
| Peak day | 2026-07-27 ($0.000867 — v1.10 regression + verify run) |
|
||||
|
||||
- **Local emulators are the primary tier** — the full pipeline runs in-process, no AWS credentials, no Checkov, no DynamoDB. <span class="badge testing">Testing</span>
|
||||
- **Live-AWS verification is milestone-scoped, then torn down.** The v1.11 lifecycle pipeline ran apply→modify→destroy for every module, then tore down to zero-cost steady state (D-096 — teardown mandatory before milestone COMPLETE). The lifecycle pipeline now **defaults to plan-only** on every PR (fast, no AWS mutation, no cost); a CI variable (`ACDL_LIFECYCLE_MODE=full`) overrides to the real apply→destroy for milestone verification (REQ-134, v1.12).
|
||||
- **Cost drivers** are spike-scoped: Terraform plan reads (free), S3 state storage (cents), DynamoDB outbox (cents). No running infrastructure between milestones.
|
||||
|
||||
**Pre-mortem (`PRE_MORTEM.md`):** the project's failure modes were pre-mortemed before the leadership pitch. The v1.10 decay incident (diff-scoped VERIFY missed 7 adapter defects — decks advertised capability that wasn't reproducible) is the root pattern: *a claim outruns the verification that backs it.* Four forward failure modes + structural mitigations (regression-tested IAM baseline, mandatory teardown, verified-only deck claims, honest scope).
|
||||
|
||||
> **Speaker notes:** The headline for the Head of Cloud / Finance: less than one cent over 8 days of active development; zero BAU cloud spend; the lifecycle pipeline defaults to plan-only so the PR-time cost is zero. The pre-mortem is the credibility slide — we already asked "how does this fail?" and the mitigations are structural.
|
||||
|
||||
---
|
||||
|
||||
## A7 — Verified by Construction (the v1.11 architecture)
|
||||
|
||||
v1.11 rebuilt the platform on two architectural pillars that make "Verified" a structural property, not a claim:
|
||||
|
||||
- **The stateless adapter (918 → ~80 lines).** The Terraform adapter was a 918-line monolith with 3 constant tables and 39 type-specific branches. It is now a ~80-line **stateless assembler**: it owns no module content. Each L1 module ships a real `terraform/` module dir owning its resource shape, nested blocks, and defaults. A new module is a new terraform dir, not a code change. *(The v1.12 P67 fix closed a dedup defect for multi-resource L1s — ecs-service, alb; CAP-013 now Verified.)*
|
||||
- **Pipeline-driven lifecycle testing.** A `modules-lifecycle` pipeline matrix-runs each L1 and L2 module's contracts through apply→modify→destroy against live AWS. **The "test" = the pipeline cell going green.** Defaults to **plan-only** on every PR (fast, no AWS mutation, no cost); `ACDL_LIFECYCLE_MODE=full` runs the real apply→destroy for milestone verification (REQ-134, v1.12). The regression gate (D-091) re-runs all 22 capabilities at milestone completion — 22/22 Verified as of v1.12.
|
||||
|
||||
> **Speaker notes:** This is the deep-dive slide for the Head of Engineering / Architecture. The two pillars answer "how do you keep the decks honest?" The adapter is simple enough to reason about (a stateless assembler); the lifecycle pipeline is the automated verification that backs every "Testing" claim. The v1.10 lesson is the negative space: a 918-line adapter with type-specific branches decayed silently. The ~80-line stateless adapter + the milestone regression gate are the structural fix. The plan-only default (v1.12) means verification runs on every PR at zero cost, with the full apply→destroy gated behind a CI variable override.
|
||||
@@ -11,18 +11,34 @@ name: acdl-modules-lifecycle
|
||||
# VPC-dependent L1s (alb, ecs-service, rds, uptime) reference the platform
|
||||
# VPC applied by a prerequisite job. Non-VPC L1s run independent.
|
||||
#
|
||||
# Lifecycle mode (REQ-134, v1.12): `default_mode: plan` — the lifecycle
|
||||
# scripts run `run_platform.sh --plan-only` (fast, no AWS mutation, no
|
||||
# AWS credentials, no cost) on every PR. Set the ACDL_LIFECYCLE_MODE CI
|
||||
# variable (workflow_dispatch input `lifecycle_mode`) to `full` for the
|
||||
# real apply→modify→destroy against live AWS. The CI VPC apply/destroy
|
||||
# jobs are skipped in plan mode (nothing is applied).
|
||||
#
|
||||
# Both Gitea (.gitea/workflows/modules-lifecycle.yml) and GitHub
|
||||
# (.github/workflows/modules-lifecycle.yml) implement this contract
|
||||
# byte-identically.
|
||||
|
||||
triggers:
|
||||
pull_request: [main]
|
||||
workflow_dispatch: []
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
- name: lifecycle_mode
|
||||
description: "Lifecycle mode: 'plan' (default, fast) or 'full' (real apply→destroy)"
|
||||
default: plan
|
||||
|
||||
runner: ubuntu-latest
|
||||
python_version: "3.12"
|
||||
terraform_version: "1.9.*"
|
||||
|
||||
# Default lifecycle mode: "plan" (plan-only, fast, no AWS mutation) or "full"
|
||||
# (real apply→modify→destroy against live AWS). Overridable via the
|
||||
# ACDL_LIFECYCLE_MODE CI variable / workflow_dispatch input.
|
||||
default_mode: plan
|
||||
|
||||
stages:
|
||||
- name: platform-vpc-apply
|
||||
command: cd terraform/platform && terraform init -input=false && terraform apply -auto-approve -lock=false
|
||||
|
||||
@@ -20,9 +20,26 @@
|
||||
"description": "Branches that trigger the pipeline on PR."
|
||||
},
|
||||
"workflow_dispatch": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Allows manual dispatch (empty array = no params)."
|
||||
"description": "Manual dispatch — either an empty array (no params) or an object with an 'inputs' array of {name, description, default} objects (REQ-134).",
|
||||
"oneOf": [
|
||||
{"type": "array", "items": {"type": "string"}},
|
||||
{"type": "object",
|
||||
"properties": {
|
||||
"inputs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"description": {"type": "string"},
|
||||
"default": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -38,6 +55,11 @@
|
||||
"type": "string",
|
||||
"description": "Terraform version constraint (e.g. '1.9.*')."
|
||||
},
|
||||
"default_mode": {
|
||||
"type": "string",
|
||||
"enum": ["plan", "full"],
|
||||
"description": "Default lifecycle mode (REQ-134, v1.12): 'plan' = plan-only (fast, no AWS mutation, no credentials, no cost); 'full' = real apply→modify→destroy against live AWS. Overridable via the ACDL_LIFECYCLE_MODE CI variable / workflow_dispatch input."
|
||||
},
|
||||
"stages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
|
||||
@@ -5,12 +5,24 @@
|
||||
#
|
||||
# Wraps run_platform.sh for L2 composition modules in the modules-lifecycle
|
||||
# pipeline. Sets ACDL_REMOTE_STATE_KEY to point to the CI VPC state.
|
||||
#
|
||||
# Lifecycle mode (REQ-134): ACDL_LIFECYCLE_MODE default "plan" = no-op
|
||||
# (plan mode never applies resources, so there is nothing to destroy).
|
||||
# Set to "full" for the real `--destroy` against live AWS.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
MODULE="$1"
|
||||
|
||||
# Lifecycle mode: "plan" (default) skips destroy; "full" runs the real destroy.
|
||||
LIFECYCLE_MODE="${ACDL_LIFECYCLE_MODE:-plan}"
|
||||
|
||||
if [ "$LIFECYCLE_MODE" != "full" ]; then
|
||||
echo "lifecycle mode=$LIFECYCLE_MODE — nothing to destroy (plan-only run), exiting 0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONTRACT="modules/l2/${MODULE}/examples/complex.yml"
|
||||
|
||||
# Point terraform_remote_state to the CI VPC state (not the platform VPC)
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
# pipeline. Sets ACDL_REMOTE_STATE_KEY to point to the CI VPC state so the
|
||||
# microservice composition's terraform_remote_state data source reads from
|
||||
# the short-lived CI VPC (not the long-lived platform VPC).
|
||||
#
|
||||
# Lifecycle mode (REQ-134): ACDL_LIFECYCLE_MODE default "plan" runs
|
||||
# `run_platform.sh --plan-only` (fast, no AWS mutation). Set to "full" for
|
||||
# the real `--apply` against live AWS.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
@@ -14,10 +18,17 @@ cd "$ROOT"
|
||||
MODULE="$1"
|
||||
EXAMPLE="$2" # simple or complex
|
||||
|
||||
# Lifecycle mode: "plan" (default, fast) or "full" (real apply against AWS).
|
||||
LIFECYCLE_MODE="${ACDL_LIFECYCLE_MODE:-plan}"
|
||||
|
||||
CONTRACT="modules/l2/${MODULE}/examples/${EXAMPLE}.yml"
|
||||
|
||||
# Point terraform_remote_state to the CI VPC state (not the platform VPC)
|
||||
export ACDL_REMOTE_STATE_KEY="spike/ci-vpc/terraform.tfstate"
|
||||
|
||||
# Run the platform lifecycle command
|
||||
bash scripts/run_platform.sh --apply "$CONTRACT"
|
||||
# Run the platform lifecycle command (plan-only by default; full = apply).
|
||||
if [ "$LIFECYCLE_MODE" = "full" ]; then
|
||||
bash scripts/run_platform.sh --apply "$CONTRACT"
|
||||
else
|
||||
bash scripts/run_platform.sh --plan-only "$CONTRACT"
|
||||
fi
|
||||
@@ -5,6 +5,11 @@
|
||||
#
|
||||
# For VPC-dependent modules, injects CI VPC outputs into the complex contract
|
||||
# before destroy (so terraform can find the resources in the right VPC).
|
||||
#
|
||||
# Lifecycle mode (REQ-134): ACDL_LIFECYCLE_MODE default "plan" = no-op
|
||||
# (plan mode never applies resources, so there is nothing to destroy; the
|
||||
# script exits 0 so the pipeline matrix cell stays green). Set to "full"
|
||||
# for the real `--destroy` against live AWS.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
@@ -12,6 +17,15 @@ cd "$ROOT"
|
||||
MODULE="$1"
|
||||
CI_VPC_OUTPUTS="${2:-}"
|
||||
|
||||
# Lifecycle mode: "plan" (default) skips destroy (nothing was applied);
|
||||
# "full" runs the real terraform destroy.
|
||||
LIFECYCLE_MODE="${ACDL_LIFECYCLE_MODE:-plan}"
|
||||
|
||||
if [ "$LIFECYCLE_MODE" != "full" ]; then
|
||||
echo "lifecycle mode=$LIFECYCLE_MODE — nothing to destroy (plan-only run), exiting 0"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CONTRACT="modules/l1/${MODULE}/examples/complex.yml"
|
||||
|
||||
VPC_DEPENDENT="alb ecs-service rds uptime"
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
#
|
||||
# The CI VPC is short-lived (created/destroyed by the pipeline), separate
|
||||
# from the long-lived platform VPC.
|
||||
#
|
||||
# Lifecycle mode (REQ-134): the ACDL_LIFECYCLE_MODE env var selects the
|
||||
# tier. Default "plan" runs `run_platform.sh --plan-only` (fast, no AWS
|
||||
# mutation, validates the contract->resolver->adapter->plan chain for
|
||||
# every module). Set to "full" to run the real `--apply` (terraform apply
|
||||
# against live AWS). The CI variable is passed via the workflow input
|
||||
# `lifecycle_mode`.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
@@ -17,13 +24,17 @@ MODULE="$1"
|
||||
EXAMPLE="$2" # simple or complex
|
||||
CI_VPC_OUTPUTS="${3:-}"
|
||||
|
||||
# Lifecycle mode: "plan" (default, fast) or "full" (real apply against AWS).
|
||||
LIFECYCLE_MODE="${ACDL_LIFECYCLE_MODE:-plan}"
|
||||
|
||||
CONTRACT="modules/l1/${MODULE}/examples/${EXAMPLE}.yml"
|
||||
|
||||
# VPC-dependent modules that need CI VPC outputs injected
|
||||
VPC_DEPENDENT="alb ecs-service rds uptime"
|
||||
|
||||
# If the module is VPC-dependent and we have CI VPC outputs, inject them
|
||||
if echo "$VPC_DEPENDENT" | grep -qw "$MODULE" && [ -n "$CI_VPC_OUTPUTS" ] && [ -f "$CI_VPC_OUTPUTS" ]; then
|
||||
# (only meaningful in full mode; plan mode ignores VPC outputs)
|
||||
if [ "$LIFECYCLE_MODE" = "full" ] && echo "$VPC_DEPENDENT" | grep -qw "$MODULE" && [ -n "$CI_VPC_OUTPUTS" ] && [ -f "$CI_VPC_OUTPUTS" ]; then
|
||||
# Generate a temporary contract with CI VPC outputs injected
|
||||
TMP_CONTRACT="/tmp/acdl-lifecycle-${MODULE}-${EXAMPLE}.yml"
|
||||
python3 -c "
|
||||
@@ -70,5 +81,9 @@ print('$TMP_CONTRACT')
|
||||
CONTRACT="$TMP_CONTRACT"
|
||||
fi
|
||||
|
||||
# Run the platform lifecycle command
|
||||
bash scripts/run_platform.sh --apply "$CONTRACT"
|
||||
# Run the platform lifecycle command (plan-only by default; full = apply).
|
||||
if [ "$LIFECYCLE_MODE" = "full" ]; then
|
||||
bash scripts/run_platform.sh --apply "$CONTRACT"
|
||||
else
|
||||
bash scripts/run_platform.sh --plan-only "$CONTRACT"
|
||||
fi
|
||||
@@ -9,7 +9,7 @@ import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from adapters.terraform.adapter import adapt, _tf_value, _ref_expr, _module_name
|
||||
from adapters.terraform.adapter import adapt, _tf_value, _ref_expr, _module_name, _child_id
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
|
||||
@@ -241,4 +241,93 @@ class TestAdapterEmitsValidTerraform:
|
||||
["terraform", "validate"],
|
||||
cwd=str(tmp_path), capture_output=True, text=True
|
||||
)
|
||||
assert result.returncode == 0, f"terraform validate failed: {result.stderr}"
|
||||
assert result.returncode == 0, f"terraform validate failed: {result.stderr}"
|
||||
|
||||
|
||||
class TestAdapterDedupMultiResourceL1:
|
||||
"""CAP-013 (v1.12, REQ-129): multi-resource L1s (ecs-service, alb) with
|
||||
stack outputs + cross-module refs must dedup to ONE module block named by
|
||||
the composition child id, with all expanded sub-ids rewritten. This is the
|
||||
regression test that locks in the fix — a future refactor that re-breaks
|
||||
the dedup must turn this red."""
|
||||
|
||||
def test_microservice_dedup_names_modules_by_child_id(self, tmp_path):
|
||||
import sys
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from core.contract_resolver import resolve
|
||||
stack = resolve(str(ROOT / "contracts/microservice.yml"))
|
||||
adapt(stack, str(tmp_path))
|
||||
main_tf = (tmp_path / "main.tf").read_text()
|
||||
# The merged modules are named by the child id (alb, service), not the
|
||||
# expanded sub-ids (alb-loadbalancer, service-service, ...).
|
||||
assert 'module "alb" {' in main_tf
|
||||
assert 'module "service" {' in main_tf
|
||||
# Expanded sub-ids must NOT appear as module names.
|
||||
assert 'module "alb-loadbalancer"' not in main_tf
|
||||
assert 'module "alb-targetgroup"' not in main_tf
|
||||
assert 'module "alb-listener"' not in main_tf
|
||||
assert 'module "service-task-definition"' not in main_tf
|
||||
assert 'module "service-service"' not in main_tf
|
||||
|
||||
def test_microservice_dedup_rewrites_stack_outputs(self, tmp_path):
|
||||
"""Stack outputs reference the expanded sub-ids; after dedup they
|
||||
must resolve to the child-id module name."""
|
||||
import sys
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from core.contract_resolver import resolve
|
||||
stack = resolve(str(ROOT / "contracts/microservice.yml"))
|
||||
adapt(stack, str(tmp_path))
|
||||
main_tf = (tmp_path / "main.tf").read_text()
|
||||
# service_arn output references service-service -> module.service
|
||||
assert 'output "service_arn" {\n value = module.service.service_arn' in main_tf
|
||||
# lb_arn output references alb-loadbalancer -> module.alb
|
||||
assert 'output "lb_arn" {\n value = module.alb.lb_arn' in main_tf
|
||||
|
||||
def test_microservice_dedup_rewrites_cross_module_refs(self, tmp_path):
|
||||
"""A ref: input that targets an expanded sub-id (e.g.
|
||||
ref:alb-targetgroup.target_group_arn) must be rewritten to the
|
||||
child-id module (module.alb.target_group_arn)."""
|
||||
import sys
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from core.contract_resolver import resolve
|
||||
stack = resolve(str(ROOT / "contracts/microservice.yml"))
|
||||
adapt(stack, str(tmp_path))
|
||||
main_tf = (tmp_path / "main.tf").read_text()
|
||||
assert "lb_target_group_arn = module.alb.target_group_arn" in main_tf
|
||||
# The un-rewritten expanded form must NOT appear.
|
||||
assert "module.alb-targetgroup" not in main_tf
|
||||
assert "module.service-service" not in main_tf
|
||||
|
||||
def test_microservice_emits_valid_terraform(self, tmp_path):
|
||||
"""CAP-013 end-to-end: the microservice (multi-resource L1s) main.tf
|
||||
passes terraform init + validate. This is the real regression — the
|
||||
v1.11 dedup produced 'No module call name' here."""
|
||||
import sys
|
||||
sys.path.insert(0, str(ROOT))
|
||||
from core.contract_resolver import resolve
|
||||
stack = resolve(str(ROOT / "contracts/microservice.yml"))
|
||||
adapt(stack, str(tmp_path))
|
||||
result = subprocess.run(
|
||||
["terraform", "init", "-backend=false", "-input=false"],
|
||||
cwd=str(tmp_path), capture_output=True, text=True
|
||||
)
|
||||
assert result.returncode == 0, f"terraform init failed: {result.stderr}"
|
||||
result = subprocess.run(
|
||||
["terraform", "validate"],
|
||||
cwd=str(tmp_path), capture_output=True, text=True
|
||||
)
|
||||
assert result.returncode == 0, f"terraform validate failed (CAP-013 regression): {result.stderr}"
|
||||
|
||||
|
||||
class TestChildIdHelper:
|
||||
"""Unit tests for _child_id (the common-prefix heuristic)."""
|
||||
|
||||
def test_single_resource_returns_id_verbatim(self):
|
||||
assert _child_id(["cluster"]) == "cluster"
|
||||
assert _child_id(["kms-key"]) == "kms-key"
|
||||
|
||||
def test_multi_resource_returns_common_prefix(self):
|
||||
# ecs-service expands to service-task-definition + service-service
|
||||
assert _child_id(["service-task-definition", "service-service"]) == "service"
|
||||
# alb expands to alb-loadbalancer + alb-targetgroup + alb-listener
|
||||
assert _child_id(["alb-loadbalancer", "alb-targetgroup", "alb-listener"]) == "alb"
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Tests for the lifecycle test scripts' plan-only/full mode flag (REQ-134).
|
||||
|
||||
The lifecycle scripts (run_lifecycle_test.sh, run_lifecycle_destroy.sh,
|
||||
run_l2_lifecycle_test.sh, run_l2_lifecycle_destroy.sh) wrap run_platform.sh.
|
||||
REQ-134 (v1.12) adds the ACDL_LIFECYCLE_MODE env var: default "plan" runs
|
||||
`run_platform.sh --plan-only` (fast, no AWS mutation); "full" runs the real
|
||||
`--apply`/`--destroy` against live AWS.
|
||||
|
||||
These tests verify the dispatch logic offline by inspecting script content
|
||||
(running the scripts end-to-end requires AWS credentials in full mode).
|
||||
"""
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = __import__("pathlib").Path(__file__).resolve().parent.parent
|
||||
|
||||
SCRIPTS = [
|
||||
"scripts/run_lifecycle_test.sh",
|
||||
"scripts/run_lifecycle_destroy.sh",
|
||||
"scripts/run_l2_lifecycle_test.sh",
|
||||
"scripts/run_l2_lifecycle_destroy.sh",
|
||||
]
|
||||
|
||||
|
||||
def _read(path):
|
||||
return (ROOT / path).read_text()
|
||||
|
||||
|
||||
class TestLifecycleModeFlag:
|
||||
"""REQ-134: the lifecycle scripts dispatch to plan-only by default."""
|
||||
|
||||
@pytest.mark.parametrize("script", SCRIPTS)
|
||||
def test_script_reads_acdl_lifecycle_mode(self, script):
|
||||
"""Every lifecycle script reads ACDL_LIFECYCLE_MODE with a 'plan' default."""
|
||||
src = _read(script)
|
||||
# The default must be 'plan' (the speed-up default). The scripts use
|
||||
# an intermediate LIFECYCLE_MODE var sourced from ACDL_LIFECYCLE_MODE.
|
||||
assert "${ACDL_LIFECYCLE_MODE:-plan}" in src, \
|
||||
f"{script} must read ACDL_LIFECYCLE_MODE defaulting to 'plan'"
|
||||
assert "LIFECYCLE_MODE=" in src, \
|
||||
f"{script} must assign LIFECYCLE_MODE from the env var"
|
||||
|
||||
@pytest.mark.parametrize("script", [
|
||||
"scripts/run_lifecycle_test.sh",
|
||||
"scripts/run_l2_lifecycle_test.sh",
|
||||
])
|
||||
def test_apply_scripts_dispatch_to_plan_only_by_default(self, script):
|
||||
"""Apply/modify scripts run --plan-only when mode != full."""
|
||||
src = _read(script)
|
||||
assert "--plan-only" in src, f"{script} must support --plan-only (plan mode)"
|
||||
assert "--apply" in src, f"{script} must support --apply (full mode)"
|
||||
# The dispatch must branch on LIFECYCLE_MODE
|
||||
assert "LIFECYCLE_MODE" in src and "full" in src, \
|
||||
f"{script} must branch on LIFECYCLE_MODE == 'full'"
|
||||
|
||||
@pytest.mark.parametrize("script", [
|
||||
"scripts/run_lifecycle_destroy.sh",
|
||||
"scripts/run_l2_lifecycle_destroy.sh",
|
||||
])
|
||||
def test_destroy_scripts_noop_in_plan_mode(self, script):
|
||||
"""Destroy scripts are a no-op (exit 0) in plan mode — nothing was applied."""
|
||||
src = _read(script)
|
||||
# The destroy script must check the mode and exit 0 in plan mode.
|
||||
assert "nothing to destroy" in src, \
|
||||
f"{script} must no-op (with a message) in plan mode"
|
||||
assert "--destroy" in src, f"{script} must still support --destroy in full mode"
|
||||
assert "LIFECYCLE_MODE" in src, f"{script} must read LIFECYCLE_MODE"
|
||||
|
||||
def test_apply_script_plan_mode_uses_plan_only(self):
|
||||
"""In plan mode, run_lifecycle_test.sh dispatches to --plan-only."""
|
||||
src = _read("scripts/run_lifecycle_test.sh")
|
||||
# The if/else: full -> --apply, else -> --plan-only
|
||||
assert re.search(r'if.*LIFECYCLE_MODE.*=.*"full".*;.*then', src)
|
||||
assert re.search(r'else\s+bash scripts/run_platform\.sh --plan-only', src, re.DOTALL)
|
||||
|
||||
def test_apply_script_full_mode_uses_apply(self):
|
||||
"""In full mode, run_lifecycle_test.sh dispatches to --apply."""
|
||||
src = _read("scripts/run_lifecycle_test.sh")
|
||||
assert re.search(r'LIFECYCLE_MODE.*=.*"full".*bash scripts/run_platform\.sh --apply', src, re.DOTALL)
|
||||
|
||||
def test_destroy_script_plan_mode_exits_zero(self):
|
||||
"""In plan mode, the L1 destroy script exits 0 without calling run_platform."""
|
||||
src = _read("scripts/run_lifecycle_destroy.sh")
|
||||
assert re.search(r'LIFECYCLE_MODE.*!=.*"full".*exiting 0', src, re.DOTALL)
|
||||
|
||||
def test_l2_apply_script_dispatches_correctly(self):
|
||||
"""The L2 apply script dispatches to plan-only by default, apply in full."""
|
||||
src = _read("scripts/run_l2_lifecycle_test.sh")
|
||||
assert "--plan-only" in src and "--apply" in src
|
||||
assert re.search(r'if.*LIFECYCLE_MODE.*=.*"full"', src)
|
||||
|
||||
def test_l2_destroy_script_noop_in_plan_mode(self):
|
||||
"""The L2 destroy script is a no-op in plan mode."""
|
||||
src = _read("scripts/run_l2_lifecycle_destroy.sh")
|
||||
assert "nothing to destroy" in src
|
||||
assert re.search(r'LIFECYCLE_MODE.*!=.*"full".*exiting 0', src, re.DOTALL)
|
||||
|
||||
def test_vpc_injection_gated_on_full_mode(self):
|
||||
"""VPC output injection is gated on full mode (plan mode skips it)."""
|
||||
src = _read("scripts/run_lifecycle_test.sh")
|
||||
# The VPC injection block must be gated on LIFECYCLE_MODE == full.
|
||||
assert re.search(r'LIFECYCLE_MODE.*=.*"full".*&&.*echo.*VPC_DEPENDENT', src, re.DOTALL) or \
|
||||
re.search(r'\[ "\$LIFECYCLE_MODE" = "full" \] && echo.*VPC_DEPENDENT', src, re.DOTALL)
|
||||
@@ -581,10 +581,14 @@ class TestModulesLifecyclePipeline:
|
||||
assert any("Modify" in n for n in step_names), "Missing modify step"
|
||||
assert any("Destroy" in n for n in step_names), "Missing destroy step"
|
||||
|
||||
def test_platform_vpc_destroy_always_runs(self):
|
||||
def test_platform_vpc_destroy_runs_in_full_mode(self):
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
destroy_job = wf["jobs"]["ci-vpc-destroy"]
|
||||
assert destroy_job.get("if") == "always()", "ci-vpc-destroy must always run (cleanup)"
|
||||
# ci-vpc-destroy must always run in full mode (cleanup), but is
|
||||
# skipped in plan mode (REQ-134: nothing is applied).
|
||||
cond = destroy_job.get("if", "")
|
||||
assert "always()" in cond, "ci-vpc-destroy must run in full mode even if lifecycle fails"
|
||||
assert "plan" in cond, "ci-vpc-destroy must be skipped in plan mode (REQ-134)"
|
||||
|
||||
def test_l2_lifecycle_job_exists(self):
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
@@ -613,4 +617,67 @@ class TestModulesLifecyclePipeline:
|
||||
|
||||
def test_contract_matrix_lists_l2_modules(self):
|
||||
contract = _load_yaml("pipelines/modules-lifecycle.yml")
|
||||
assert set(contract["matrix"]["l2_modules"]) == {"static-assets", "microservice"}
|
||||
assert set(contract["matrix"]["l2_modules"]) == {"static-assets", "microservice"}
|
||||
|
||||
# --- REQ-134: lifecycle mode flag (plan-only default, full override) ---
|
||||
|
||||
def test_contract_declares_plan_as_default_mode(self):
|
||||
"""The pipeline contract declares default_mode: plan (REQ-134)."""
|
||||
contract = _load_yaml("pipelines/modules-lifecycle.yml")
|
||||
assert contract.get("default_mode") == "plan", \
|
||||
"default_mode must be 'plan' (fast, no AWS mutation, the default on every PR)"
|
||||
|
||||
def test_schema_accepts_default_mode_field(self):
|
||||
"""The schema accepts the default_mode field with plan/full enum."""
|
||||
schema = json.load(open(ROOT / "schemas/modules-lifecycle-pipeline.schema.json"))
|
||||
props = schema["properties"]
|
||||
assert "default_mode" in props
|
||||
assert set(props["default_mode"]["enum"]) == {"plan", "full"}
|
||||
|
||||
def test_workflow_has_lifecycle_mode_dispatch_input(self):
|
||||
"""workflow_dispatch exposes a lifecycle_mode input defaulting to plan."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
wd = wf["on"]["workflow_dispatch"]
|
||||
assert isinstance(wd, dict), "workflow_dispatch must declare inputs"
|
||||
inputs = wd.get("inputs", {})
|
||||
assert "lifecycle_mode" in inputs
|
||||
assert inputs["lifecycle_mode"].get("default") == "plan"
|
||||
assert inputs["lifecycle_mode"].get("type") == "choice"
|
||||
assert set(inputs["lifecycle_mode"].get("options", [])) == {"plan", "full"}
|
||||
|
||||
def test_lifecycle_job_passes_mode_env_to_steps(self):
|
||||
"""The lifecycle job sets ACDL_LIFECYCLE_MODE env so scripts dispatch
|
||||
to plan-only by default, full on override."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
env = wf["jobs"]["lifecycle"].get("env", {})
|
||||
assert "ACDL_LIFECYCLE_MODE" in env
|
||||
# The expression must resolve to 'plan' when no input/var is set.
|
||||
assert "plan" in env["ACDL_LIFECYCLE_MODE"]
|
||||
|
||||
def test_l2_lifecycle_job_passes_mode_env_to_steps(self):
|
||||
"""The L2 lifecycle job also sets ACDL_LIFECYCLE_MODE env."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
env = wf["jobs"]["l2-lifecycle"].get("env", {})
|
||||
assert "ACDL_LIFECYCLE_MODE" in env
|
||||
assert "plan" in env["ACDL_LIFECYCLE_MODE"]
|
||||
|
||||
def test_ci_vpc_apply_skipped_in_plan_mode(self):
|
||||
"""The CI VPC apply job is skipped in plan mode (nothing is applied)."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
cond = wf["jobs"]["ci-vpc-apply"].get("if", "")
|
||||
assert "plan" in cond, "ci-vpc-apply must be skipped in plan mode (REQ-134)"
|
||||
|
||||
def test_lifecycle_job_runs_even_if_vpc_apply_skipped(self):
|
||||
"""The lifecycle job uses `if: always()` so it still runs (plan-only)
|
||||
even when ci-vpc-apply is skipped in plan mode."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
assert wf["jobs"]["lifecycle"].get("if") == "always()"
|
||||
assert wf["jobs"]["l2-lifecycle"].get("if") == "always()"
|
||||
|
||||
def test_read_ci_vpc_outputs_skipped_in_plan_mode(self):
|
||||
"""The 'Read CI VPC outputs' step is skipped in plan mode (no VPC)."""
|
||||
wf = _load_workflow(".gitea/workflows/modules-lifecycle.yml")
|
||||
steps = wf["jobs"]["lifecycle"]["steps"]
|
||||
read_step = next(s for s in steps if s.get("name") == "Read CI VPC outputs")
|
||||
cond = read_step.get("if", "")
|
||||
assert "full" in cond, "Read CI VPC outputs step must be skipped in plan mode (REQ-134)"
|
||||