---ci--- project: acdl phase: 0 milestone: v1.8 status: clarify ---/ci--- 12 decisions resolved (D-061..D-072) at full autonomy: - D-061: Fold all 3 new requirements into v1.8 (feature milestone) - D-062: P1-3 SSM fail loud + escape hatch - D-063: P1-6 Terraform-rendered invoke policy - D-064: P1-8 Remove committed spike .tf files - D-065: S1 Single conditional AWS credentials step - D-066: Uptime on ECS Fargate - D-067: Uptime as deploy-uptime pipeline stage, separate state - D-068: CMDB = DynamoDB acdl-change-requests table - D-069: Per-stack CMK (one key per L2 deployment) - D-070: Decommission as mode on existing deploy pipeline, HITL SRE gates - D-071: uses: ref bump @v1.6 -> @v1.8 at COMPLETE - D-072: Managed KMS fallback for standalone L1s with warning
46 KiB
ACDL — Agentic Cloud Delivery Platform
Vision / Core Value
Consumers declare intent; the platform delivers safe production deployment through an agentic stack. The platform absorbs two frictions: the cognitive load of getting the infrastructure right, and the operational work of getting the change to production safely.
Source of truth for why: docs/vision.md.
Source of truth for how: docs/architecture.md + .ciagent/ARCHITECTURE.md.
Where the two conflict, the vision wins.
North Star
A merged change progresses through lower environments end-to-end without a platform engineer joining a thread, approving a ticket, or manually triggering a stage gate. A non-technical consumer ships a production deployment by declaring intent — without authoring a workflow, a configuration file, or a Terraform module. Every production change is traceable to a human attestation and an immutable evidence stream.
Core Tenets (from docs/vision.md)
- Operations are Declared, Not Executed. Consumers define what they need; the platform reconciles, provisions, and progresses.
- The Delivery Lifecycle is a Sovereign Boundary. The platform governs infra and delivery; it does not penetrate upstream product/SDLC. Integration is only through validated, published contracts.
- Lower Environments are Autonomous; Higher Environments are Attested. Dev = zero-touch agentic. QA/prod/dr = deliberate human attestation, not rubber stamps.
- Safety is Computed, Not Assumed. Every action produces a measurable, explainable confidence signal. The signal is the platform's certified answer to "is this safe to proceed?"
- Infrastructure is Consumed, Not Maintained. Compute is abstract, containerized, or serverless. No node/OS/bare-metal lifecycle.
- Two Consumer Surfaces, One Platform. Technical developers (L3A) and non-technical consumers (L3B) converge on the same contract schema, the same policy envelope, and the same evidence stream.
Domain Boundaries
- In scope: environment progression; cloud resource lifecycle; operational security and observability NFRs; policy enforcement; immutable audit lineage; confidence frameworks; two consumer surfaces (developer + agentic).
- Out of scope: application business logic; IDE workflows; product backlog / sprint planning; compute requiring node-level or OS-level management.
- Interface: upstream systems integrate through a strict contract boundary. The platform validates, enriches with operational standards, and reconciles the target state.
Objective for Milestone v1.1 (prior — complete, tag v1.2.0)
Finalize the architecture to v1.0 (resolve all 11 open design decisions in
docs/architecture.md §13) and prove the locked commitments with one
end-to-end v1 implementation spike:
- One L1 module (
l1-s3) — substrate-agnostic, IR-typed interface. - One L2 thin-composition (
l2-static-assets) — references the L1. - Terraform adapter — compiles the IR to a real
terraform planagainst AWS via OIDC (no long-lived credentials, per §12.5). - One contract submission → contract→IR resolution →
terraform plan→ PolicyCheckResult (Checkov) → confidence signal → evidence event to the DynamoDB outbox.
The spike validates the architecture's claim that the IR-shaped commitments
do not require a polyglot mess (docs/architecture.md §14, step 2).
Status: COMPLETE — all 5 phases shipped (v1.1.1..v1.1.5) + verified; review
READY TO SHIP (0 P0); audit CLEAN; milestone tag v1.2.0; Gitea release
id 202 published. D-034 closed (root key deactivated by user).
Milestone v1.1 Phases (prior — complete)
| Phase | Name | Goal |
|---|---|---|
| 06 | archive-demo-and-reorient | Move the v1.0 demo (modules/, scripts/, evidence-ui/, contracts/, demo workflows) to demo/; establish the new repo layout (platform/, schemas/, adapters/, terraform/, modules-ir/); rewrite README. |
| 07 | architecture-v1-finalization | Resolve the 11 open decisions → architecture v1.0. Author IR JSON Schema, PolicyCheckResult schema, contract schema, confidence-signal spec, HITL matrix, outbox/ledger design under schemas/ + platform/. |
| 08 | aws-oidc-bootstrap | One-shot use of a temporary long-lived key (waiver D-034) to create an IAM role + OIDC trust policy for the act_runner, an S3 state bucket, and a DynamoDB lock table. Rotate the key. Verify the runner assumes the role via OIDC with no long-lived secret. |
| 09 | v1-spike-ir-and-l1-and-adapter | Target Stack IR; one real L1 (l1-s3) with IR-typed interface; L1 registry; Terraform adapter (IR → Terraform var/output + terraform plan) running against AWS via OIDC. |
| 10 | v1-spike-l2-and-contract-e2e | One L2 thin-composition (l2-static-assets) referencing l1-s3; contract schema + contract→IR resolution; one end-to-end contract submission → terraform plan → Checkov → confidence signal → evidence event to outbox. Verify the IR commitments hold. |
Milestone COMPLETE gate: review → ship v1.2.0 (feature milestone, next
minor per ship.md) → audit. DONE.
Objective for Milestone v1.2 (prior — complete)
Platform hardening + first real consumer deployment. The v1.1 spike proved
the IR commitments hold on a single dev-only terraform plan for one S3
bucket. v1.2 takes the spike to a real, simpler, better-documented platform
that actually delivers a microservice to AWS ECS Fargate end-to-end.
Five scope axes (user-directed, 2026-07-21):
- Re-evaluate the current state. Confirm go-gitea/gitea#36988 (OIDC for Gitea Actions) is still unmerged (re-checked 2026-07-21: open, last updated 2026-05-27). Extend the D-039 per-run-rotated-key waiver for v1.2; real OIDC is deferred to v1.3+ (D-047).
- NFR improvements on the existing spike. Least-privilege IAM audit, idempotent bootstrap, proper exit codes / error handling, rotation hygiene, P1-1 / P1-B redaction carried forward from the v1.1 audit.
- Streamline / simplify the current setup. Consolidate the
run_spike_*.shscripts into onescripts/run_platform.sh; remove dead code and stale paths; one command runs the whole pipeline. - README.md fully up to date on how the platform works. The current README still says "v1.1 (active)" — it must reflect v1.1 complete, the actual spike flow, how to run it, the real repo layout, and the v1.2 objective.
- Bootstrap a consumer repo with a basic microservice deployed to ECS
end-to-end. New Gitea repo
acdl-consumer-microservice(orgcontinuous-intelligence) holding a tiny HTTP container + Dockerfile; new IR-typed L1s (l1-vpc,l1-ecs-cluster,l1-ecs-service,l1-iam-role,l1-alb,l1-ecr); newl2-microservicethin-composition; one contract submission →terraform apply(dev, autonomous) → a live ECS Fargate service serving HTTP 200 → evidence event to the DynamoDB outbox → acdl-evidence timeline.
The milestone proves the platform delivers real value (a running microservice), not just a plan.
Milestone v1.2 Phases
| Phase | Name | Goal |
|---|---|---|
| 11 | v1.2-research-and-readme | Re-eval #36988 (confirm open → extend D-039 as D-047). Audit the v1.1 spike for NFR gaps (least-privilege, idempotency, error handling, rotation hygiene) + simplification opportunities. Rewrite README.md to reflect v1.1 complete + how the platform actually works (spike flow, how to run, repo layout, v1.2 objective). Output: RESEARCH.md v1.2 addendum; updated README. |
| 12 | nfr-harden-and-simplify | Apply Phase 11 findings: tighten spike_runner_policy.json (least-privilege audit); make terraform/bootstrap/create_*.py idempotent; consolidate run_spike_*.sh → one scripts/run_platform.sh; proper exit codes / error handling; redact P1-1 AWS key IDs in VERIFY.md; fix any remaining stale platform/ paths. Spike still runs e2e after the refactor. |
| 13 | l1-catalog-for-ecs | Author IR-typed L1s for an ECS Fargate microservice: l1-vpc, l1-ecs-cluster, l1-ecs-service, l1-iam-role (task + exec role), l1-alb, l1-ecr. Register all in modules-ir/registry.json. Expand the Terraform adapter TYPE_MAP. Each L1 produces a valid terraform plan fragment. |
| 14 | l2-microservice-and-contract-schema | Author l2-microservice thin-composition (references the ECS L1s, depth ≤ 5). Extend schemas/contract.schema.json for microservice inputs (image, port, env, healthcheck). Verify contract→IR resolution yields a complete target stack. |
| 15 | consumer-repo-and-terraform-apply | Create consumer repo acdl-consumer-microservice (Gitea org) with a basic microservice (tiny HTTP container + Dockerfile + ECR push). Lift the platform from plan → apply (dev, autonomous per §10). Submit contracts/microservice.yaml → pipeline → IR → plan → apply → a real ECS Fargate service running. |
| 16 | v1.2-capstone-e2e | End-to-end verification: consumer commit → pipeline → ECS service live serving HTTP 200 → evidence event to the DynamoDB outbox → acdl-evidence timeline renders it. Verify NFR improvements hold, the setup is simpler (one run_platform.sh), and the README is accurate. |
Milestone COMPLETE gate: review → ship v1.3.0 (feature milestone, next
minor per ship.md — v1.1 shipped v1.2.0) → audit.
Objective for Milestone v1.4 (active)
Central pipeline contract + shell reproducibility + output streaming. The v1.3 milestone (Phases 17–18) created identical CI/CD pipelines for Gitea and GitHub but they were duplicated copies with no single source of truth. v1.4 makes the pipeline a declarative contract, enables full shell reproducibility, and streams terraform/checkov output so users can see what the platform is doing.
Three scope axes:
- Central pipeline contract. A JSON Schema
(
schemas/pipeline.schema.json) + YAML instance (pipelines/ci.yaml) declares the pipeline stages, commands, triggers, and runner. Both.gitea/workflows/ci.yml(Gitea Actions, dev) and.github/workflows/ci.yml(GitHub Actions, production) implement the contract. A test validates conformance. - Shell reproducibility.
scripts/run_ci.shmirrors the CI pipeline locally — runs the same 3 stages (lint, test, check-only) in sequence. The pipeline is fully reproducible from the shell, not just in CI. - Output streaming.
scripts/run_platform.shstreams terraform init/validate/plan output, Checkov compliance results, and PolicyCheckResult records to stdout by default, so the user sees what is happening. A--quietflag suppresses streaming for log-only mode.
Milestone v1.4 Phases
| Phase | Name | Goal |
|---|---|---|
| 19 | central-pipeline-contract-and-shell-reproducibility | Create the central pipeline contract (JSON Schema + YAML instance). Create scripts/run_ci.sh for shell reproducibility. Update run_platform.sh to stream terraform/checkov output. Update both workflow YAMLs with contract references (staying byte-identical). Add tests for contract validation, workflow conformance, and streaming. |
Milestone COMPLETE gate: review → ship v1.4.1 (feature milestone, next
minor per ship.md — v1.3 shipped v1.3.2) → audit.
Objective for Milestone v1.7 (complete)
Production platform + contract ingestion + pipeline maturation. The v1.6 milestone left the platform documented and environments-aware; v1.7 took it to a production-grade platform. 12 user-directed scope axes (2026-07-22):
- Rename
static-assets→static-assets(D-048 — including.ciagent/historical narrative, overriding the v1.6 preservation precedent). The reconstruction test is updated to expectstatic-assets. - Augment
static-assetsto a production-ready stack by authoring a newcloudfrontprimitive + awafprimitive (D-049: S3 + CloudFront OAC + WAF; Route53/ACM are domain-dependent and deferred to documented extension points). - DX-friendly deploy outputs (D-050): SSM Parameter Store (KMS-encrypted
SecureString) for runtime-injectable values + GitHub PR comment / job summary for human-readable connection strings. No raw secrets in logs. - Central deploy pipeline error reporting via the platform Lambda
report_erroraction (D-055): the Lambda creates a GitHub issue on the platform repo. The consumer's onboarding-granted Lambda-invoke permission is the only grant needed — uniform pathway, no separate GitHubissues: writeon the consumer side. Gitea is excluded (only the CIAgent uses it). - PR comments after every successful stage so developers always know where they stand.
- Three platform pipelines: (1) platform-test (PR, unit + integration + schema-validation); (2) primitives-plan (PR, plan-only for all L1 primitives); (3) patterns-plan (PR, plan-only for all L2 modules).
- Release job on merge to
main: computes MAJOR.MINOR.PATCH semver, creates the tag, then updates (force-moves) or creates the MAJOR.MINOR + MAJOR floating tags (D-057). Consumers on@v1or@v1.6receive updates depending on their pinned version. - Platform Lambda for one-way consumer→platform communication
(contracts). Onboarding grants the consumer repo's environment the right
to trigger the Lambda (cross-account IAM). The Lambda ingests contracts
and stores them in a DynamoDB table
acdl-contracts(D-051) for historical reference, impact analysis, CMDB-style application-state queries, and pattern detection. The IAM policy reflects cross-account invocation. - Tagging standards in policy/compliance checks (D-054): a required-tag
set (
acdl:owner,acdl:contract,acdl:environment,acdl:cost-center) enforced by a Checkov custom YAML rule. Closes the D-043 deferral (the SKIPPEDACDL_TAG_NAMINGplaceholder becomes a real check). - Wiz adapter for security checks (D-052): a stub + schema path that
translates Wiz API issues →
PolicyCheckResultrecords, degrading gracefully when unconfigured. Matches the Checkov adapter pattern. - Kyverno adapter for compliance/security checks (D-053): a
K8s-native policy adapter that translates Kyverno
PolicyReportresults →PolicyCheckResultrecords. Ready but inactive for Terraform-only stacks (the platform emits Terraform, not K8s manifests); it activates when the GitOps reconciler (roadmap) emits K8s manifests. - Remove the legacy consumer-repos directory and add validated per-module examples
(D-058:
modules/<name>/examples/withsimple.yaml+complex.yamlvalidated in CI) + a new RDS primitive demonstrating multi-engine variation (D-059).
Milestone v1.7 Phases
| Phase | Name | Goal |
|---|---|---|
| 22 | rename-and-production-static-assets-stack | Rename static-assets → static-assets everywhere (D-048). Author cloudfront + waf primitives. Augment static-assets to S3 + CloudFront (OAC) + WAF (D-049). Expand adapter. Bump uses: to @v1.6; create floating v1.6 + v1 tags (D-057). |
| 23 | tagging-standards-and-security-adapters | Required-tag set + Checkov custom rule (D-054, D-043 closure). Wiz adapter stub (D-052). Kyverno K8s-native adapter (D-053). Schema engine enum updated. |
| 24 | platform-lambda-and-contract-ingestion | Platform Lambda + DynamoDB acdl-contracts table (D-051) + cross-account IAM + onboarding grant. |
| 25 | deploy-pipeline-dx-outputs-and-error-reporting | SSM SecureString + PR comment outputs (D-050). Lambda report_error → GitHub issue (D-055). Stage comments after each successful stage. |
| 26 | platform-pipelines-and-release-automation | 3 platform pipelines (platform-test, primitives-plan, patterns-plan). Release job with semver + MAJOR.MINOR/MAJOR tag updates (D-057). |
| 27 | remove-legacy-consumer-repos-and-module-documentation-examples | Delete the legacy consumer-repos directory. RDS primitive (D-059). Validated per-module examples (D-058). Docs updates. |
Milestone COMPLETE gate: review → ship v1.7.0 (feature milestone, next
minor per ship.md — v1.6 shipped v1.6.0) → audit.
Objective for Milestone v1.8 (active)
P1 remediation + uptime monitoring + engineering standards + encryption and deletion-protection by default + decommission alias + documentation. The v1.7 milestone shipped production platform + contract ingestion but left 8 P1 issues flagged for post-hoc review. v1.8 clears all of them AND delivers three user-directed feature/NFR tracks (2026-07-22):
Track 1 — P1 Remediation (Phases 28–30): Clear all 8 pending P1 issues from v1.5/v1.6/v1.7 verify reviews:
- P1-3: SSM uses AWS-managed key silently → fail loud without CMK config
- P1-4: WAF custom rules emit invalid HCL (attribute vs block syntax)
- P1-5: WAF default_action input silently ignored
- P1-6: consumer_invoke_policy.json has placeholder account ID
- P1-7: L2 composition outputs section not implemented in resolver
- P1-8: terraform/spike/*.tf overwritten by run_platform.sh (state contamination)
- P1-9: GitHub API URLs hardcoded in contract_ingestor.py (Gitea fails silently)
- S1: Deploy workflow static-key override not wired (passes ACDL_AWS_* env vars to configure-aws-credentials which reads AWS_*/its own inputs)
Track 2 — Encryption + Deletion Protection by Default (Phases 31–32): All primitives encrypted by default (CMK priority + SSE, managed KMS fallback). Per-stack CMK (one key per L2 deployment, 90-day rotation, no shared keys). Deletion protection on by default for every primitive. L2 modules expose a feature flag to turn off deletion protection. A decommission alias uses a 2-step pipeline (disable deletion protection → zero counts → destroy) with HITL SRE gates and CMDB-validated change request ID.
Track 3 — Uptime + Standards + Docs (Phases 33–36): A new uptime-kuma primitive (ECS Fargate) deployed by default after any L2 module deploy (separate terraform state), with a feature flag to disable. Monitored endpoints passed from L2 outputs. Alert channels (Teams/email/SMS/GitHub issues). The uptime URL published to consumers via PR comments. Engineering standards for L1 + L2 module authoring (scanned from current modules, stored in modules/). READMEs for schemas/, adapters/, pipelines/ paths documenting how to write, wire, and test each.
Milestone v1.8 Phases
| Phase | Name | Goal |
|---|---|---|
| 28 | adapter-waf-and-resolver-outputs | Fix WAF HCL emission (nested rules blocks + default_action input) + implement L2 composition outputs in resolver + adapter output blocks. P1-4, P1-5, P1-7. |
| 29 | ssm-kms-and-invoke-policy | SSM publisher fails loud without CMK (escape hatch for local) + Terraform-rendered consumer_invoke_policy (no placeholder account ID). P1-3, P1-6. |
| 30 | run-platform-isolation-and-api-portability | Adapter output to per-run temp dir (remove committed spike .tf) + forge-agnostic API URLs + deploy.yml static-key override wired. P1-8, P1-9, S1. |
| 31 | encryption-by-default-and-per-stack-cmk | KMS-key primitive + per-stack CMK wired in L2 modules + encryption NFRs on all primitives + managed KMS fallback. |
| 32 | deletion-protection-by-default-and-l2-feature-flag | Deletion protection NFR on all primitives (default true) + L2 feature flag + contract schema update. |
| 33 | uptime-kuma-primitive | Uptime L1 primitive (ECS Fargate, feature flag, monitored endpoints, alert channels) + deploy-uptime pipeline stage (separate state) + URL published via PR comment. |
| 34 | decommission-alias-and-cmdb-validation | Decommission mode on deploy pipeline (2-step: disable deletion protection → zero counts, HITL SRE gates) + DynamoDB CMDB validation + consumer guide docs. |
| 35 | module-engineering-standards | modules/STANDARDS.md (L1+L2 authoring + review standards scanned from current modules) + catalog index fix + template update + automated standards test. |
| 36 | schemas-adapters-pipelines-readmes | schemas/README.md + pipelines/README.md + adapters/README.md (how to write, wire, test, dependencies). |
| 37 | verify | 4-layer verification of all v1.8 phases. |
| 38 | review-audit-complete | Multi-persona review + audit + milestone completion (tag v1.8.0). |
Milestone COMPLETE gate: review → ship v1.8.0 (feature milestone, next
minor per run.md — v1.7 shipped v1.7.0) → audit.
Requirements
v1.0 (Prior milestone — the demo)
Status: complete. Tag v1.1.0. All REQ-01..15 satisfied by the stub-driven
executive demo. See REQUIREMENTS.md §v1 and the prior decisions table
appendix below. The demo is archived to demo/ in Phase 06.
v1.1 (Prior milestone — architecture finalization + v1 spike, complete)
New requirements REQ-16..REQ-28 — see REQUIREMENTS.md §v1.1. Summary:
- REQ-16: Architecture finalized to v1.0 (11 open decisions resolved).
- REQ-17: Target Stack IR defined as JSON Schema; substrate-agnostic.
- REQ-18: PolicyCheckResult normalized schema defined; Checkov adapter.
- REQ-19: Six-input confidence signal specified with per-env thresholds (dev 0.50 / qa 0.75 / prod 0.90 / dr 0.95) and severity→penalty mapping.
- REQ-20: Tiered audit ledger design (S3 Object Lock 7-yr + DynamoDB
outbox, RPO=0, JWS detached signatures,
prev_event_hashchain). - REQ-21: Full 8-concern HITL matrix + separation-of-duties design (CODEOWNERS + DynamoDB identity-distinctness).
- REQ-22: Contract schema (JSON Schema draft 2020-12) with per-env
mandatory/optional inputs and
profile: agenticmarker for L3B. - REQ-23: AWS OIDC bootstrap (IAM role + trust policy for act_runner); the long-lived key is used once then rotated (waiver D-034).
- REQ-24: One real L1 module (
l1-s3) with an IR-typed interface. - REQ-25: One real L2 thin-composition (
l2-static-assets) referencingl1-s3. - REQ-26: Terraform adapter compiles the IR to a real
terraform planagainst AWS via OIDC; state in S3 + DynamoDB. - REQ-27: One end-to-end contract submission → contract→IR resolution →
terraform plan→ Checkov → confidence signal → evidence event to outbox. - REQ-28: Spike verification proves the IR-shaped commitments hold (no polyglot mess; the adapter is the only substrate-specific code).
v1.2 (Prior milestone — platform hardening + first real consumer deployment, complete)
New requirements REQ-29..REQ-35 — see REQUIREMENTS.md §v1.2. Summary:
- REQ-29: README.md fully documents the v1.1-complete platform: spike flow, how to run, repo layout, v1.2 objective.
- REQ-30: NFR hardening — least-privilege IAM audit, idempotent
bootstrap, consolidated
run_platform.sh, error handling, P1-1/P1-B redaction. - REQ-31: L1 catalog expanded for ECS — 6 new IR-typed L1s
(
l1-vpc,l1-ecs-cluster,l1-ecs-service,l1-iam-role,l1-alb,l1-ecr) registered and adapter-compiled. - REQ-32:
l2-microservicethin-composition + contract schema extended for microservice inputs (image, port, env, healthcheck). - REQ-33:
terraform apply(dev, autonomous) — real provisioning, not justplan. - REQ-34: Consumer repo
acdl-consumer-microservicewith a basic microservice (ECR image, Dockerfile, contract). - REQ-35: End-to-end verification — consumer commit → live ECS service (HTTP 200) → evidence event → timeline.
v1.4 (Prior milestone — central pipeline contract + shell reproducibility + streaming)
New requirements REQ-43..REQ-45 — see REQUIREMENTS.md §v1.4. Summary:
- REQ-43: Central pipeline contract —
schemas/pipeline.schema.json+pipelines/ci.yaml. Both Gitea and GitHub workflows implement the contract; a test validates conformance. - REQ-44:
scripts/run_ci.shmirrors the CI pipeline locally (lint → test → check-only), exiting 0 with "CI PIPELINE OK". - REQ-45:
scripts/run_platform.shstreams terraform/checkov output by default (with--quietfor log-only mode). Both workflows byte-identical.
Constraints
- Forge: Gitea at
https://git.cloudinit.dev, orgcontinuous-intelligence. - CI runtime: act_runner / Gitea Actions (reuses GitHub Actions workflow YAML).
- Cloud: AWS via OIDC federation. Long-lived credentials are forbidden (§12.5). The v1.1 spike uses a temporary long-lived key once to bootstrap OIDC (waiver D-034), then rotates it.
- Substrate: Terraform adapter in v1 (the only adapter). L1/L2 are substrate-agnostic in shape; the adapter is the only substrate-specific code.
- State: S3 (state files) + DynamoDB (locking), single-region in v1.
- Environments: dev (autonomous) → qa (QA HITL) → prod (SRE HITL) → dr (SRE HITL). Staging does not exist (Path A locked).
- Compute: abstract / containerized / serverless. No VMs, bare metal, OS lifecycle.
- Autonomy: Full. Escalation hooks: deploy, delete_data, merge_to_main.
Anti-Goals (from docs/vision.md §7)
- Not an upstream development platform (no product backlogs, IDE, code authorship).
- Not a general-purpose AI (autonomy is narrow, bounded by policy envelopes).
- Not a legacy infrastructure bridge (no VMs/bare metal/OS).
- Not a permissive delivery highway (no escape hatches past confidence or HITL).
- Not a mutable audit log (VCS history ≠ regulatory evidence).
Context
- The
acdlrepo exists at the org root.acdl-contractsandacdl-evidenceexist from the v1.0 demo and continue as the developer surface and the audit-timeline host respectively. docs/vision.mdanddocs/architecture.md(v0.2) are the upstream vision/architecture sources, pulled fromorigin/mainat the start of v1.1.- The v1.0 demo (tag
v1.1.0) is the reference of intent — it proved the shape (L1/L2/contract/confidence/evidence/HITL) on stubs. v1.1 replaces the stubs with the real platform substrate.
Key Decisions (v1.1)
Carries forward the still-valid v1.0 decisions (see appendix). New v1.1 decisions:
| ID | Decision | Rationale | Outcome |
|---|---|---|---|
| D-034 | Temporary long-lived AWS key (waiver) used once in Phase 08 to bootstrap the state backend + IAM user; rotated/deactivated immediately after | §12.5 forbids long-lived creds; the bootstrap needed one aws iam call before the spike user + rotated key could take over |
Spike achieves real terraform plan against AWS without violating the locked target after bootstrap. CLOSED 2026-07-21: root key AKIA…ROOT-DEACTIVATED deactivated by the user in the AWS IAM console (verified — InvalidClientTokenId); the spike uses the rotated acdl-spike-runner key per D-039. Key ID redacted in v1.2 Phase 12 (P1-1). |
| D-035 | Milestone version = v1.1 (feature), ship tag v1.2.0 |
Real platform is a breaking reframing of the demo, but treated as the next incremental milestone per user choice; ship.md: feature milestone → next minor | Tag v1.2.0 on milestone COMPLETE |
| D-036 | Spike picks l1-s3 + l2-static-assets |
Simplest real AWS resource (no IAM/network deps); smallest real terraform plan; proves the IR + adapter end-to-end |
Spike scope fixed |
| D-037 | Demo archived to demo/ (not deleted) |
Preserves the working v1.0 demo as intent reference; new platform layout under platform/, schemas/, adapters/, terraform/, modules-ir/ |
No churn on demo code; clean separation |
| D-038 | Open decisions resolved in "accept recommendations + decide rest" mode | User-locked mode: accept architecture's stated recommendations (W1.A, W1.B, W2.A, BA.A); lead-developer decides the remaining 8 (W3.D, W3.E, BA.B, BA.C, BA.D, BA.E, BA.F, OpenTofu timing) with rationale | Architecture reaches v1.0 in Phase 07 |
| D-039 | Spike-only waiver: per-run-rotated long-lived AWS key. OIDC federation deferred to v1.2, blocked on go-gitea/gitea#36988. | RESEARCH TARGET 1 verdict (conf 0.95): Gitea Actions does NOT support id-token: write / OIDC token issuance as of Gitea 1.27.x / gitea-runner v2.1.0. GitHub's OIDC pattern is not portable. The waiver satisfies §12.5's intent (no persistent long-lived key) for the spike: the key is rotated after each run by scripts/rotate_spike_key.sh. v1.2 implements real OIDC when the Gitea PR merges. |
Spike achieves real terraform plan against AWS without a persistently long-lived key; real OIDC is a v1.2 deliverable |
| D-040 | The 6 confidence-signal inputs are: policy (0.30), validation (0.25), freshness (0.10), source (0.15), history (0.10), nfrs (0.10). Weights frozen for v1, tuned in v1.2 alongside thresholds (BA.B). | Architecture §8 locks "six canonical inputs" but does not enumerate them; RESEARCH TARGET 6 chose the platform-computable subset present in every environment (incl. dev). | Confidence signal (Phase 10) has a concrete input enumeration |
| D-041 | Spike audit ledger = v1.0 hash chain + DynamoDB outbox + acdl-evidence mirror. S3 Object Lock (compliance mode, 7-yr) + JWS (platform KMS key, quarterly rotation) + daily checkpoints are v1.2 build-out, authored as design in Phase 07. |
REQ-20 is "design authored," not "implemented." The spike proves the outbox write path; the regulatory ledger is v1.2. | Spike scope stays bounded; REQ-20 satisfied by the Phase 07 design doc |
| D-042 | HITL approver identity in Gitea = gitea.actor of the workflow_dispatch run that sets approve_qa=true/approve_prod=true/approve_dr=true. Separation-of-duties reads approver_qa from the DynamoDB outbox and compares to the prod-dispatch gitea.actor. |
Gitea has no Environments API (re-confirmed in RESEARCH); gitea.actor is the only approval-identity signal. |
SoD design (Phase 07) is concrete for the Gitea forge |
| D-043 | Tag/naming compliance deferred for the spike: the Checkov adapter emits a single SKIPPED PolicyCheckResult (ruleId: ACDL_TAG_NAMING, severity: info) so the confidence policy input is non-empty. Custom Checkov YAML rule lands in v1.2. |
Checkov has no built-in tag-presence check; a custom rule in the spike is scope creep. | Spike's policy input is non-empty without a custom-rule dependency |
| D-044 | DynamoDB outbox = PAY_PER_REQUEST; PK contractId, SK eventType#eventTs, TTL expire_at = now + 365d. No separate async worker/DLQ in the spike (RTO = workflow re-run); v1.2 outbox worker + DLQ is a Phase 07 design artifact. |
On-demand is zero-cost-at-idle for the spike's single dev submission. | Spike outbox is minimal; v1.2 worker design authored in Phase 07 |
| D-045 | Runner tooling: runs-on: ubuntu-latest; install terraform via HashiCorp apt repo (pin 1.9.*), checkov via pip (pin >=3.2,<4, --break-system-packages). Neither is pre-installed on the default runner image. |
RESEARCH TARGET 2; pinning avoids mid-spike version drift. | Phase 09/10 workflows have a concrete setup step |
| D-046 | act_runner → gitea-runner rename: Phase 07 updates docs to use the current name gitea-runner (renamed 2026-04 in gitea/runner#850). |
RESEARCH TARGET 1 + R-4: naming drift between v1.0 docs and the current runner. | Docs reflect the current binary name |
| D-047 | v1.2 carries forward the D-039 per-run-rotated-key waiver. Real OIDC federation remains deferred to v1.3+, blocked on go-gitea/gitea#36988 (re-checked 2026-07-21: still open, last updated 2026-05-27, not merged). | §12.5 forbids long-lived creds; the Gitea Actions OIDC provider is still not merged. The waiver continues to satisfy §12.5's intent (no persistently long-lived key) for v1.2: scripts/rotate_spike_key.sh rotates the key, and Phase 12 tightens the IAM scoping + rotation hygiene. |
v1.2 achieves terraform apply against AWS without a persistently long-lived key; real OIDC is a v1.3+ deliverable. |
Key Decisions (v1.8)
Resolved at the CLARIFY stage (full autonomy — all within locked constraints or user-directed scope). New v1.8 decisions:
| ID | Decision | Rationale | Outcome |
|---|---|---|---|
| D-061 | Fold all 3 new requirements into v1.8 alongside P1 fixes. | User chose single milestone. v1.8 becomes a feature milestone (ship tag v1.8.0, minor bump). | 11 phases (28–38) in one milestone. |
| D-062 | P1-3: SSM publisher fails loud (RuntimeError) when ACDL_KMS_KEY_ID unset. ACDL_ALLOW_DEFAULT_KMS=1 escape hatch for local testing. |
User chose fail loud. Silent AWS-managed-key use is the security gap; callers must set the env. | Phase 29 implements fail-loud + escape hatch. |
| D-063 | P1-6: consumer_invoke_policy.json rendered via Terraform data.aws_caller_identity + templatestring at apply time. |
User chose Terraform-rendered. No committed account ID; no stale placeholder. | Phase 29 converts JSON to TF-rendered template. |
| D-064 | P1-8: Remove committed terraform/spike/*.tf entirely; adapter emits to per-run temp dir. |
User chose remove. Cleaner; no stale fixtures. | Phase 30 removes files + changes run_platform.sh target. |
| D-065 | S1: Single conditional configure-aws-credentials step (OIDC when no static key, access-key/secret-key inputs when static key present). |
User chose single conditional step. Cleaner workflow YAML. | Phase 30 restructures the deploy workflow step. |
| D-066 | Uptime deployment target: ECS Fargate (reuse existing ecs-cluster + ecs-service + alb primitives). | User chose ECS Fargate. Most consistent with current platform; ALB gives a stable URL. | Phase 33 authors uptime primitive on ECS Fargate. |
| D-067 | Uptime trigger: new deploy-uptime pipeline stage after publish-outputs. Separate terraform state (S3 key prefix uptime/). |
User chose pipeline stage. Most integrated with existing flow. | Phase 33 adds the pipeline stage + separate state. |
| D-068 | CMDB = DynamoDB acdl-change-requests table (PK changeRequestId, SK submittedAt). |
User chose DynamoDB. Consistent with existing platform Lambda + DynamoDB pattern. | Phase 34 adds the table + validate_change_request Lambda action. |
| D-069 | Encryption key granularity: per-stack CMK (one key per L2 deployment, tagged with acdl:owner + acdl:environment). | User chose per-stack. No shared keys across stacks; 90-day rotation at creation. | Phase 31 authors kms-key primitive + L2 wiring. |
| D-070 | Decommission: new mode on the existing deploy pipeline (mode: decommission). 2-step with HITL SRE gates. |
User chose existing pipeline with different behavior. Plan/apply to disable deletion protection (HITL SRE gate) → plan/apply with counts=0 (second HITL SRE gate). Documented in consumer guide. | Phase 34 adds decommission mode + HITL gates. |
| D-071 | uses:/ref: bump from @v1.6 to @v1.8 at milestone COMPLETE. |
Consumer-facing version tracks the last released MAJOR.MINOR. | Phase 38 bumps references + creates floating v1.8 + v1 tags. |
| D-072 | Managed KMS fallback for standalone L1 deployments (no L2 CMK): adapter uses alias/aws/<service> with a stderr warning. kms_key_arn input is optional everywhere; encryption_enabled NFR defaults to true. |
Requirement says "prioritize CMKs, fallback to managed KMS". Standalone L1s don't have a per-stack CMK. | Phase 31 implements fallback + warning. |
Key Decisions (v1.7)
Resolved at the CLARIFY stage (full autonomy — all within locked constraints or user-directed scope). New v1.7 decisions:
| ID | Decision | Rationale | Outcome |
|---|---|---|---|
| D-048 | Rename static-assets → static-assets: rewrite all occurrences including verbatim historical phase descriptions in .ciagent/ (ROADMAP, REQUIREMENTS, RESEARCH, decision tables), overriding the v1.6 audit precedent that preserved some historical references. |
User chose full rewrite. Maximally consistent; the reconstruction test is updated to expect static-assets throughout. |
Phase 22 rewrites every static-assets string to static-assets; no preserved historical tokens remain. |
| D-049 | Production static-assets stack = S3 + CloudFront (OAC) + WAF. | Self-contained, domain-free production edge. Route53/ACM are domain-dependent (consumer-supplied) and deferred to documented extension points / a complex example. | Phase 22 authors cloudfront + waf primitives and augments the module. |
| D-050 | Deploy outputs: SSM Parameter Store (SecureString, KMS-encrypted, namespaced /acdl/{env}/{contractId}/{output_name}) for runtime-injectable values + GitHub PR comment / job summary for human-readable connection strings. |
Two canonical mechanisms: SSM for resources that read at runtime; PR comment for developers. No raw secrets in logs. | Phase 25 implements core/output_publisher.py + two new pipeline stages. |
| D-051 | Contract ingestion storage = DynamoDB table acdl-contracts (PK consumerRepo, SK contractId#submittedAt, SSE via customer-managed CMK, point-in-time recovery). |
Enables historical queries, impact analysis, CMDB-style application-state queries, and pattern detection via DynamoDB queries. S3 flat-file mirror deferred (DynamoDB is sufficient for v1.7). | Phase 24 defines the table + Lambda. |
| D-052 | Wiz adapter = stub + schema path (no live Wiz tenant in CI). | Matches the Checkov adapter pattern; typed interface, offline-testable, degrades gracefully when unconfigured (emits WIZ_NOT_CONFIGURED SKIPPED record). |
Phase 23 authors adapters/wiz/wiz_adapter.py. |
| D-053 | Kyverno adapter = K8s-native policy adapter translating PolicyReport results → PolicyCheckResult. Ready but inactive for Terraform-only stacks. |
The platform emits Terraform, not K8s manifests. The adapter activates when the GitOps reconciler (roadmap) emits K8s manifests. Sample policies included as documentation. | Phase 23 authors adapters/kyverno/kyverno_adapter.py + sample policies. |
| D-054 | Tagging standard = required-tag set (acdl:owner, acdl:contract, acdl:environment, acdl:cost-center) enforced by a Checkov custom YAML rule. |
Closes the D-043 deferral (the SKIPPED ACDL_TAG_NAMING placeholder becomes a real check). Naming-convention regex deferred (brittle across AWS resource types). |
Phase 23 authors schemas/tagging-standard.json + adapters/terraform/policy/custom_rules/acdl_tagging.yaml. |
| D-055 | Error reporting = the platform Lambda report_error action creates a GitHub issue on the platform repo (acdl/acdl). Uniform communication pathway via the Lambda; the consumer's onboarding-granted Lambda-invoke permission is the only grant needed. No separate GitHub issues: write on the consumer side. Gitea is excluded (only the CIAgent uses it; platform engineers and consumers use GitHub). |
Unifies requirements 4 + 8 around one mechanism. The Lambda holds a GitHub token (Secrets Manager) scoped to the platform repo. Idempotent (comments on existing open issue rather than duplicating). | Phase 24 prepares the action; Phase 25 implements it + wires the if: failure() workflow step. |
| D-056 | Ship v1.7.0; bump uses:/ref: from @v1.4 to @v1.6. |
Consumer-facing version tracks the last released MAJOR.MINOR. Consumers on @v1.4 stay on v1.4 behavior until they bump. |
Phase 22 bumps the references. |
| D-057 | The uses:/ref: bump + floating v1.6/v1 tag creation happen in Phase 22 (pointing at v1.6.0), so the reference never points at a non-existent tag. The release job (Phase 26) owns ongoing tag updates. |
Sequencing: if Phase 22 bumps uses: to @v1.6 but the tag doesn't exist, the reference is temporarily broken. Creating the tag early (pointing at the last release) fixes this. |
Phase 22 creates the floating tags; Phase 26's release job maintains them. |
| D-058 | Module examples = separate validated files in modules/<name>/examples/ (simple.yaml + complex.yaml + variation files), validated against schemas/contract.schema.json in the platform-test pipeline schema-validation stage. Each module's README ## Examples section references + excerpts them. |
Examples cannot drift from the schema silently. | Phase 27 authors the example files; Phase 26's platform-test pipeline validates them. |
| D-059 | Add an RDS primitive (modules/l1/rds/) with an engine input (enum: postgres, mysql, etc.) + a multi-engine example demonstrating the variation pattern. |
Concrete demonstration of the multi-engine variation the requirement calls out. Adds one primitive + examples. | Phase 27 authors the primitive + adapter expansion + examples. |
| D-060 | (Consolidated into D-058.) | — | — |
Open-decision resolutions (Phase 07 deliverable — recorded here for traceability)
| ID | Question | Resolution |
|---|---|---|
| W1.A | AI-refinement trigger | Accept recommendation. Joint condition: N ≥ 50 consecutive changes with zero rollbacks AND no L1/L2 incident in last 6 months AND Infra & Ops unilateral override. |
| W1.B | Multi-stack edge case rule | Accept recommendation. Permitted only for (a) DR-region mirror, (b) time-boxed experimental stack with TTL ≤ 30d, (c) explicit Infra & Ops approval with multiStack.justification. |
| W2.A | Tag mutability for prod | Accept recommendation (Path B). Tag for dev/qa, SHA for prod. Platform CLI resolves tag→SHA for prod-bound workflows. Justified by the "Audit truth lives outside the repository" bet. |
| BA.A | Initial L3B skill catalog | Accept recommendation. 5 skills: web API, worker, scheduled job, static asset, basic observability bootstrap. Addition criteria: (a) reviewable for sensitive data, (b) expressible as a single contract submission, (c) documented use case. |
| W3.D | L1/L2 standard versioning | Decided. Semver: interface → MAJOR, behavior → MINOR, lifecycle → PATCH (same as the v1.0 demo D-rule, lifted to the real platform). Pin model: L2 contracts pin L1 by name@semver; the resolver picks the highest compatible. Evolution: MAJOR bumps require a new registry entry (immutable publication); old entry enters a 12-month deprecation window. |
| W3.E | Schema mandatory vs optional inputs | Decided. Per-env mandatory table: dev requires stack + environment; qa adds validation.e2eSuite + validation.loadTest; prod adds runbook + dashboard + oncall; dr adds drDrillRef. inputs map is always optional. profile: agentic fields (naturalLanguageIntent, confidenceAtSubmission, agentTrace) optional everywhere. |
| BA.B | Confidence threshold tuning | Decided. Starting thresholds frozen for v1. Tuning begins in v1.2: track FP/FN per environment quarterly; override authority = Infra & Ops + SRE joint sign-off; any override is itself a confidence-event in the audit stream. |
| BA.C | On-call / operational ownership | Decided. Platform on-call = Infra & Ops rotation. Escalation: L3A/L3B halt → platform on-call pager (Sev2); consumer-visible outage → consumer on-call (Sev1) with platform on-call support. Consumer on-call relationship is contractual, defined at onboarding (BA.E). |
| BA.D | Cost / capacity governance | Decided. Cloud cost owner = Infra & Ops FinOps. Per-contract consumption reported monthly. Runaway spend: hard halt at 120% of contract-declared budget envelope via the confidence signal (cost is one of the 6 inputs); override = FinOps + SRE joint sign-off. |
| BA.E | Consumer onboarding | Decided. Two paths: developer (L3A) — getting-started walks through contract schema + central pipeline template; citizen developer (L3B) — onboarding grants a scoped agent + skill catalog, no workflow authoring. Both end in a sandbox dev submission that must pass the confidence gate before the consumer is promoted. |
| BA.F | Cross-platform evolution | Decided. The contract schema, IR, PolicyCheckResult, confidence signal, and audit stream are portable (substrate- and forge-agnostic). Forge-specific code: workflow YAML, OIDC trust, CODEOWNERS, Environments. A second forge (e.g., GitLab) requires a forge adapter + a workflow-template translator; no change to L1/L2/IR/confidence/audit. |
| Q1.3 | OpenTofu timing | Decided (deferred). Not in v1 or v1.1. The substrate abstraction (§12) makes OpenTofu a future adapter, not an architecture change. Revisit when an OpenTofu adapter is requested; no version committed. |
Appendix — Prior milestone (v1.0 demo) decisions
The v1.0 demo (tag v1.1.0) carried decisions D-001..D-033. They governed
the stub-driven executive demo and remain valid for the archived demo
under demo/. They are superseded by the v1.1 decisions above for the
real platform. Full text preserved in git history at tag v1.1.0.
Operational parameters (CLARIFY auto-resolution, full autonomy)
Resolved at the CLARIFY stage to unblock planning. None require user sign-off (autonomy = full; all within locked constraints).
| Parameter | Value | Rationale |
|---|---|---|
| AWS region | us-east-1 |
Default; matches v1.0 demo references; single-region in v1 (§12.3) |
| Terraform state bucket | acdl-tfstate-<account-id>-us-east-1 |
Namespaced by account id to avoid collision; region-suffixed |
| Terraform lock table | acdl-tflock |
DynamoDB; single-region v1 |
| OIDC IAM role | acdl-act-runner-role |
Assumed by the act_runner via web-identity |
| OIDC trust subject | repo:continuous-intelligence/acdl:ref:refs/heads/main (+ phase branches) |
Least-privilege; refined in Phase 08 |
Spike L1 (l1-s3) inputs |
bucket_name: string, region: string |
Minimal S3 interface per §2 |
Spike L2 (l2-static-assets) |
thin-composition referencing l1-s3 only; depth 1 |
Smallest real plan per D-036 |
| Spike contract | contracts/spike.yaml: stack: l2-static-assets, environment: dev, inputs: { bucket_name: acdl-spike-bucket, region: us-east-1 } |
One end-to-end submission (REQ-27) |
Spike terraform command |
plan only |
apply is out of scope (Out of Scope table); HITL-gated in v1.2 |
| Checkov ruleset (spike) | the 4 L2 checks (secrets-in-plaintext, public ingress, IAM wildcard, KMS key reference) + tag/naming | §3 + §12.4; Kyverno/OPA deferred |
| v1.0 tags preserved | v1.0.1..v1.0.5, v1.1.0 retained |
Immutability; demo archive does not rewrite history |
| Next ship tag | v1.3.0 |
Feature milestone → next minor per ship.md (v1.1 shipped v1.2.0; v1.2 ships v1.3.0) |
Items deferred to RESEARCH (not clarifications)
- Gitea/act_runner OIDC support — does act_runner emit an OIDC
id-token? Determines whether real-AWS plan is achievable in this environment or whether a spike-only waiver is needed. Highest-priority research target. - Terraform + Checkov availability on the runner image — install in the workflow if missing.
actions/configure-aws-credentialsaction on act_runner — if unavailable, fall back toaws sts assume-role-with-web-identityfrom a step.