ACDL — Requirements
v1
Category: Repos & Org
- REQ-01: All demo code lives under the
continuous-intelligence Gitea org at https://git.cloudinit.dev.
- REQ-09: Three repos exist:
acdl (platform + stubs + reusable workflows), acdl-contracts (developer surface), acdl-evidence (Pages audit timeline).
Category: L1 Modules
- REQ-02: 8 L1 module folders exist under
acdl/modules/l1/: l1-eks-fargate, l1-iam-role, l1-lambda, l1-api-gateway, l1-eventbridge, l1-sqs, l1-s3, l1-cloudwatch.
- REQ-03: Each L1 module has a
manifest.yaml (declaring inputs) and a mock_apply.sh that echoes success, sleeps 1s, and exits 0.
Category: L2 Modules
- REQ-04: 4 L2 modules exist under
acdl/modules/l2/: l2-invoice-service, l2-commodity-price-feed, l2-energy-analytics-api, l2-regulatory-reporting, each composing the specified L1s.
- REQ-05: L2 modules compose L1 primitives into deployable shapes with a maximum depth of 5.
Category: Core Scripts
- REQ-06:
mock_executor.sh reads an L2 composition, invokes each L1 mock_apply.sh, and writes state.json.
- REQ-07:
policy_checker.py reads contract.yaml and fails with POLICY_VIOLATION:PUBLIC_INGRESS on public-ingress: true; otherwise passes.
- REQ-08:
confidence_signal.py returns a base score of 0.90 and drops to 0.40 (with reason code) when policy fails; gate threshold is ≥ 0.50.
Category: Evidence Stream
- REQ-11:
evidence_writer.py appends events to audit.json and links each event to the previous via a SHA-256 hash chain (prev_hash + own hash).
- REQ-13:
acdl-evidence is Pages-enabled and serves audit.json plus index.html.
Category: Pipeline
- REQ-10: The reusable pipeline runs Dev (autonomous), pauses at QA (manual approval), pauses at Prod (manual approval), then finalizes by committing
audit.json to acdl-evidence.
- REQ-12: Opening an Issue in
acdl-contracts runs l3b_agent_stub.py, commits a generated contract.yaml to a new branch, closes the Issue, and triggers the main pipeline.
Category: Demo Acts
- REQ-14:
index.html uses vanilla JS to fetch audit.json from the Pages URL and render events as a timeline.
- REQ-15: All four demo acts (Friction, Developer Self-Service, Citizen Developer, Safety Net) reproduce deterministically in a dry run.
v2
(None — v1 covers the complete demo.)
v1.1 (Prior milestone — architecture finalization + v1 spike, complete)
Category: Architecture Finalization
- REQ-16: Architecture reaches v1.0 — all 11 open decisions in
docs/architecture.md §13 are resolved and recorded in PROJECT.md (W1.A, W1.B, W2.A, W3.D, W3.E, BA.A–F, OpenTofu timing).
- REQ-17: Target Stack IR is defined as a JSON Schema under
schemas/ir.schema.json; engine-agnostic (resources, relationships, composition max-depth-5, policy hooks).
- REQ-18:
PolicyCheckResult normalized schema is defined under schemas/policy_check_result.schema.json; a Checkov adapter translates Checkov JSON to this schema.
- REQ-19: Six-input confidence signal is specified under
platform/confidence_signal.py with per-env thresholds (dev 0.50 / qa 0.75 / prod 0.90 / dr 0.95) and severity→penalty mapping (critical=hard override, high=-0.2, medium=-0.05, low=-0.01, info=0.0).
- REQ-20: Tiered audit ledger design is authored: S3 Object Lock (compliance mode, 7-yr) + DynamoDB outbox (RPO=0, JWS detached signatures,
prev_event_hash chain, daily checkpoints).
- REQ-21: Full 8-concern HITL matrix + separation-of-duties design is authored (CODEOWNERS routing + DynamoDB identity-distinctness check; pre-execution gate model; 1d warn / 2d freeze timeout).
- REQ-22: Contract schema (JSON Schema draft 2020-12) is defined under
schemas/contract.schema.json with per-env mandatory/optional inputs (W3.E) and profile: agentic marker for L3B fields.
Category: AWS OIDC Bootstrap
- REQ-23: AWS auth bootstrap + state backend for the spike: an S3 state bucket + DynamoDB lock/outbox table + an IAM user with a minimal scoped policy (S3 + DynamoDB + plan-only). The temporary long-lived key is used once (waiver D-034) then rotated via
scripts/rotate_spike_key.sh after each spike run (D-039). Real OIDC federation is deferred to v1.2 — Gitea Actions does not support id-token: write (RESEARCH TARGET 1, conf 0.95), blocked on go-gitea/gitea#36988.
Category: v1 Spike — IR, L1, Adapter
- REQ-24: One real L1 module
l1-s3 exists under modules-ir/l1/l1-s3/ with an IR-typed interface (typed inputs/outputs/NFRs) registered in the L1 registry.
- REQ-25: One real L2 thin-composition
l2-static-assets exists under modules-ir/l2/l2-static-assets/ referencing l1-s3 only (depth 1, within max-depth-5).
- REQ-26: The Terraform adapter (
adapters/terraform/) compiles the IR-typed L1 interface to Terraform variable/output blocks and the L2 thin-composition tree to a Terraform root module; it emits a real terraform plan against AWS via OIDC; state is stored in S3 + DynamoDB.
Category: v1 Spike — End-to-End
- REQ-27: One end-to-end contract submission (
contracts/spike.yaml for l2-static-assets) flows through: contract schema validation → contract→IR resolution → terraform plan (real AWS) → Checkov PolicyCheckResult → confidence signal → evidence event written to the DynamoDB outbox.
- REQ-28: Spike verification (
scripts/verify_phase10.sh) proves the IR-shaped commitments hold: the adapter is the only engine-specific code; no polyglot mess; the L1 content, contract YML, and thin-composition tree are engine-agnostic.
Out of Scope (v1.1)
| Feature |
Reason |
| Full HITL matrix wiring (qa/prod/dr) |
Spike is dev-only (terraform plan); HITL wiring is v1.2. |
| Kyverno + OPA policy engines |
Spike uses Checkov only; Kyverno/OPA are v1.2. |
| MCP skill catalog + real L3B agent |
L3B spike = a single stub contract submission; the 5-skill catalog is v1.2. |
| GitOps reconciler (ArgoCD/Flux) |
v1.2. |
| Multi-region state / outbox |
Single-region in v1 (§9, §12.3). |
| Prod/dr environments |
v1.2. |
Terraform apply (real provisioning) |
Spike runs plan only; apply is gated by HITL in v1.2. |
v1.2 (Prior milestone — platform hardening + first real consumer deployment, complete, tag v1.3.0)
Category: Documentation & Simplification
- REQ-29:
README.md is fully rewritten to reflect the v1.1-complete platform: the actual spike flow (contract → IR → terraform plan → Checkov → confidence signal → outbox), how to run it (scripts/run_platform.sh), the real repo layout (acdl_platform/, schemas/, adapters/, terraform/, modules-ir/, contracts/, demo/), and the v1.2 objective. No stale "v1.1 (active)" framing.
- REQ-30: NFR hardening of the v1.1 spike: (a)
terraform/bootstrap/spike_runner_policy.json audited to least-privilege (S3 + DynamoDB + ECS + ECR + ELB + IAM plan-only, no wildcards beyond the documented exceptions); (b) create_state_backend.py and create_iam_user.py are idempotent (re-running exits 0 without duplicating resources); (c) run_spike_plan.sh + run_spike_e2e.sh consolidated into a single scripts/run_platform.sh with proper exit codes and error handling; (d) P1-1 carried forward from the v1.1 audit — the two AWS access key IDs in .ciagent/VERIFY.md Phase 09 narrative are redacted to placeholders; (e) any remaining stale platform/ paths in .ciagent/ are corrected to acdl_platform/.
Category: L1 Catalog Expansion (ECS Fargate)
- REQ-31: Six new IR-typed L1 modules exist under
modules-ir/l1/ and are registered in modules-ir/registry.json: l1-vpc (VPC + subnets + route tables), l1-ecs-cluster (ECS Fargate cluster), l1-ecs-service (ECS service + task definition), l1-iam-role (task execution + task role), l1-alb (application load balancer + listener + target group), l1-ecr (ECR repository). Each has an interface.json valid against schemas/ir.schema.json and produces a valid terraform plan fragment via the Terraform adapter. The adapter TYPE_MAP is expanded to cover all six IR resource types.
Category: L2 Composition & Contract Schema
- REQ-32:
l2-microservice thin-composition exists under modules-ir/l2/l2-microservice/ referencing the six ECS L1s (depth ≤ 5, within max-depth-5). schemas/contract.schema.json is extended with microservice inputs (image: string, port: integer, env: map, healthcheck: object) and validates a contracts/microservice.yaml submission. Contract→IR resolution (acdl_platform/contract_resolver.py) yields a complete target stack for l2-microservice.
Category: Real Provisioning
- REQ-33: The platform runs
terraform apply (not just plan) for the dev environment, autonomous per §10 (confidence ≥ 0.50, no HITL). The apply creates real AWS resources (VPC, ECS cluster, ECR repo, ALB, ECS service) and the result is captured in the evidence stream. apply for qa/prod/dr remains HITL-gated and out of scope for v1.2.
Category: Consumer Repo
- REQ-34: A new Gitea repo
acdl-consumer-microservice exists under the continuous-intelligence org, containing: a basic HTTP microservice (e.g., a tiny Python/Go server returning 200), a Dockerfile, an ECR push step, and a contracts/microservice.yaml submission for l2-microservice (dev environment).
Category: End-to-End Verification
- REQ-35: One end-to-end flow: consumer commit to
acdl-consumer-microservice → pipeline triggered → contract→IR resolution → terraform plan → terraform apply (dev) → a live ECS Fargate service serving HTTP 200 on its ALB → evidence event written to the DynamoDB outbox → the event renders on the acdl-evidence timeline. scripts/verify_phase16.sh proves the full flow green.
v1.3 (Prior — module documentation + thin-composition removal, complete)
Category: Thin-Composition Removal
- REQ-36: The L2 thin-composition layer is removed completely:
composition.json files, acdl_platform/contract_resolver.py, schemas/contract.schema.json, contracts/spike.yaml, contracts/microservice.yaml, and L2 entries in modules-ir/registry.json are deleted. The L2 directories are kept as placeholders with READMEs. The downstream pipeline (adapter → checkov → confidence → outbox) is patched to load a pre-existing IR instance instead of resolving a contract.
- REQ-37: A
modules-ir/README-TEMPLATE.md exists that works for both L1 and L2 modules, written in plain language (no jargon), with sections for Overview, Resources, Inputs, Outputs, Usage, Compliance extension points, and Versioning.
- REQ-38: Every module has a
README.md: the 7 L1 modules have full READMEs with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning sections derived from their interface.json; the 2 L2 modules have placeholder READMEs noting the composition is under redesign. A modules-ir/README.md catalog index lists all modules with one-line descriptions and links.
Category: Testing
- REQ-39: A pytest test suite exists under
tests/ covering the platform components offline (no AWS, no Checkov, no DynamoDB): the Terraform adapter (adapters/terraform/adapter.py), the confidence signal (acdl_platform/confidence_signal.py), the Checkov adapter (adapters/terraform/policy/checkov_adapter.py), and the outbox writer (acdl_platform/outbox_writer.py). The suite validates the IR schema, registry, spike_instance, and adapter output structure. pyproject.toml + requirements-test.txt pin test dependencies (pytest, jsonschema, pyyaml, boto3-stubs or moto for outbox mocking).
Category: Shell Reproducibility
- REQ-40:
scripts/run_platform.sh has a --check-only mode that runs offline: loads the pre-existing IR instance, runs the adapter to emit Terraform, validates the JSON structure — without AWS credentials, Checkov, or DynamoDB. The existing --plan-only and full modes continue to require AWS. The --check-only mode is what CI pipelines run.
Category: CI/CD Pipelines
-
REQ-41: Identical CI/CD pipelines exist for both Gitea Actions (.gitea/workflows/ci.yml, dev environment) and GitHub Actions (.github/workflows/ci.yml, production). Both run the same three stages: (1) lint — py_compile all Python files, (2) test — pytest, (3) check-only — bash scripts/run_platform.sh --check-only. Both trigger on push to main + pull request. Both use ubuntu-latest. Identical outcomes — the only difference is the runner environment.
-
REQ-42: pyproject.toml exists at the repo root with pytest configuration (testpaths, markers) and the project metadata. requirements-test.txt pins test-only dependencies separate from runtime dependencies.
v1.4 (Active — central pipeline contract + shell reproducibility + streaming)
Category: Central Pipeline Contract
- REQ-43: A central pipeline contract exists as
schemas/pipeline.schema.json (JSON Schema draft 2020-12) + pipelines/ci.yaml (YAML instance). The contract declares the pipeline name, triggers (push/PR branches), runner, Python version, and stages (name + command + required + install + description). Both .gitea/workflows/ci.yml (Gitea Actions, dev) and .github/workflows/ci.yml (GitHub Actions, production) implement the same stages, commands, triggers, and runner as declared in the contract. A test (tests/test_pipeline_contract.py) validates the contract against the schema and asserts both workflows conform (same jobs, same commands, same triggers, same runner, byte-identical).
Category: Shell Reproducibility
- REQ-44:
scripts/run_ci.sh reproduces the CI pipeline locally — runs the same 3 stages (lint, test, check-only) in sequence with proper exit codes, failing on first error. The script exits 0 with "CI PIPELINE OK" on success. A --quiet flag suppresses per-stage banners. The script mirrors the central pipeline contract (pipelines/ci.yaml) so the shell and CI environments produce identical outcomes.
Category: Pipeline Streaming
- REQ-45:
scripts/run_platform.sh streams output by default: terraform init/validate/plan output is piped to stdout via tee (visible to the user and logged), Checkov results are printed in human-readable form, and PolicyCheckResult records are displayed with severity, rule ID, and pass/fail status per record. The --check-only mode streams the emitted Terraform file content. A --quiet flag suppresses streaming (output to log files only) for backwards compatibility. Both gitea and github workflows are byte-identical (identical outcomes — the only difference is the forge runtime).
v1.5 (Prior — consumer happy path + zero-trust docs + reusable deploy workflow, complete)
Category: Consumer Happy Path Documentation
- REQ-46:
README.md is rewritten so the consumer model is unambiguous: this repo is the platform source; a consumer never clones it. A consumer repo contains only app code + contract.yaml referencing the central pipeline + contract. The platform-flow diagram is a mermaid flowchart TD (replacing the ASCII art). "L3A"/"L3B" nomenclature is removed from README (single-surface model). "spike" nomenclature is removed from prose (code paths in bash blocks are kept verbatim).
- REQ-47:
docs/CONSUMER_GUIDE.md (all-caps) replaces docs/consumer-guide-static-assets.md. It is generic across all L2 modules (static-assets as the worked example), uses mermaid diagrams (model + pipeline flow), documents versioned uses: references (floating MAJOR+MINOR tags — bare/@main discouraged), scopes prerequisites to consumer-repo bootstrap only (no Terraform/Checkov/boto3/runner-key — those are platform-repo concerns), and documents that the pipeline fetches the ACDL repo at run time via a reusable workflow (consumers never invoke scripts/run_platform.sh locally for the happy path).
- REQ-48:
README.md Credentials section is rewritten to express the zero-trust target model: consumer repos use OIDC federation (no long-lived keys) with attribute-based authorization (ABAC) — IAM roles + session policies scoped by repository identity and resource-creation tags so a consumer can only view/update resources it created (blast-radius containment). A documented override allows a static key in GitHub Secrets (consumer repo) or .env.secrets (local testing), rotated by a platform-managed scheduled pipeline on a daily cadence; when .env.secrets is used locally, rotating out of band is the consumer's responsibility.
Category: Reusable Deploy Workflow
- REQ-49: A reusable deploy workflow exists as byte-identical
.gitea/workflows/deploy.yml (Gitea, dev) and .github/workflows/deploy.yml (GitHub, production), implementing the central deployment pipeline contract (pipelines/deploy.yaml validated against schemas/deploy-pipeline.schema.json). It is invoked by consumer repos via uses: acdl/.gitea/workflows/deploy.yml@vMAJOR.MINOR (versioned tag). The workflow checks out the consumer repo, checks out the ACDL platform repo into the runner workspace, installs runtime deps (Python, Terraform, Checkov), and invokes scripts/run_platform.sh against the consumer's contract path (passed as a workflow input). OIDC is the default auth (permissions: id-token: write); a static-key override reads from repository secrets.
- REQ-50:
contracts/static-assets.yaml uses a versioned uses: reference (@v1.4, MAJOR+MINOR) — not bare @v1 or @main — as the canonical example the consumer guide points at.
- REQ-51:
tests/test_pipeline_contract.py is extended to validate the new deploy workflows: both files exist, are byte-identical, and conform to schemas/deploy-pipeline.schema.json (stages present, names match pipelines/deploy.yaml stage names). The existing CI-workflow conformance tests continue to pass unchanged.
v1.6 (Active — consumer-facing docs restructure + terminology normalization + environments concept)
Category: Internal-surface scrub
- REQ-52: No consumer-facing documentation (README.md, docs/, modules//README.md, contracts/**) references
.ciagent/ — it is local CIAgent metadata, never visible to platform engineers or consumers. The README repository-layout table has no .ciagent/ row. No .gitea/ references appear in consumer-facing docs (consumers use GitHub only); the README repository-layout table has no .gitea/workflows/ row.
- REQ-53:
acdl_platform/ is renamed to core/ across the directory, all imports in tests/scripts/pipelines/workflows, and all doc references. (platform/ was the original target but shadows Python's stdlib platform module — core/ was chosen to stay importable.) grep -R "acdl_platform" . (excluding .ciagent/, demo/, .git/) returns 0 hits. The test suite passes after the rename.
Category: Docs site restructure
- REQ-54:
docs/ is restructured into a Jekyll-style GitHub Pages site: docs/_config.yml, docs/index.md (landing), docs/modules/ (catalog + per-module Pages-friendly copies), docs/contracts/index.md, docs/pipeline/index.md + docs/pipeline/versioning.md, docs/environments/index.md, docs/consumer-guide.md, docs/architecture.md (consolidated from architecture.md + architecture-v1.0.md, current-architecture only), docs/vision.md. No .ciagent/ links anywhere in docs/. Consumer-facing content (modules, contracts, pipeline, versioning) lives in Pages.
Category: Terminology normalization
- REQ-55: Consumer-facing docs drop the "L2" nomenclature — L2 modules are referred to as "modules". "L1" label is dropped in consumer-facing docs — L1 primitives are referred to as "primitives". The "composition" terminology is changed to "pattern" for modules in prose (the on-disk
composition.json files and code references are unchanged this phase). A roadmap entry records that "composition" will later describe the thin orchestration where consumers dynamically create a module directly from the contract file (future implementation, not implemented now).
- REQ-56: The term "forge" is replaced in consumer-facing docs with "platform runners" / "platform-managed" as appropriate. The term "forge" remains only in internal architecture docs.
Category: README rewrite
- REQ-57: README.md repository-roles section is restated to match reality: a consumer repo contains (a) its application code, (b) one or more contracts (
.acdl/contract.yaml), and (c) one or more CI definitions (a thin .github/workflows/deploy.yml that uses: the central reusable workflow, pointing at the appropriate environment + contract). The platform repo (this one) owns modules/adapters/schemas/pipelines/scripts/workflows. A consumer never clones the platform repo.
- REQ-58: README.md Status section is replaced with a Features list (referenceable by consumers and platform engineers) and a Roadmap subsection listing only planned future features (no internal CIAgent status, no version-by-version changelog).
- REQ-59: README.md "How the platform works" mermaid diagram is revised so all node text is visible (no overflow): labels are split with
<br/>, boxes widened as needed. A security-checks stage is added before the policy-checks stage. Specific tools (Checkov, Terraform) are not named — they are "security checks (adapter)", "policy checks (adapter)", "infrastructure plan". An "infrastructure apply" stage is added at the appropriate level (dev only, after confidence).
- REQ-60: README.md Credentials & zero-trust section removes the "go-gitea/gitea#36988 blocked" mention and the "waivers D-039/D-047" language (not consumer/platform-engineer facing). It states: default OIDC + ABAC; alternative is a static AWS key (GitHub Secrets for platform-runner runs, or
.env.secrets locally) with the expectation of daily rotation (platform-managed for runner runs) or out-of-band rotation (consumer-managed for local .env.secrets).
Category: Environments concept + onboarding
- REQ-61: The concept of platform-managed environments is introduced: consumers are not required to provide an AWS account, VPC, subnet, S3 state bucket, or runner key.
docs/environments/index.md documents that a named environment is a platform-owned AWS account + network + state backend + IAM role surfaced to the consumer via ABAC, selected by name in the contract. The old README environments table (dev/qa/prod/dr) is removed completely. A minimal onboarding scaffold exists: platform/environments/ with a sample dev.json + README, platform/environment_check.py, a wire-in at the top of scripts/run_platform.sh, a friendly first-run onboarding message when no environment is defined for the repo, and tests/test_environment_check.py covering the missing-env and present-env cases.
v1.7 (Active — production platform + contract ingestion + pipeline maturation)
Category: Rename + production-ready stack
- REQ-62:
static-assets is renamed to static-assets everywhere (D-048 — including .ciagent/ historical narrative: verbatim phase descriptions, REQ-25/27/50 text, D-036, RESEARCH.md). grep -R "static-assets[^s]" . (excluding .git/) returns 0 hits. The module dir modules/l2/static-assets/ → modules/l2/static-assets/; contracts/static-assets.yaml → contracts/static-assets.yaml; the registry key is renamed; all scripts, tests, docs, and .ciagent/ files use static-assets. The reconstruction test is updated to expect static-assets throughout.
- REQ-63: Two new primitives exist:
cloudfront (distribution + OAC, stack types aws:cloudfront:distribution + aws:cloudfront:originaccesscontrol) and waf (WAFv2 web ACL, stack type aws:wafv2:webacl), each with an interface.json valid against schemas/stack.schema.json and a full README (Resources/Inputs/Outputs/Usage/Compliance/Versioning). Both are registered in modules/registry.json. The Terraform adapter TYPE_MAP/INPUT_MAP/OUTPUT_MAP covers the new stack types.
- REQ-64: The
static-assets module is augmented to a production-ready stack referencing s3 + cloudfront + waf (depth 1, D-049). composition.json wires the s3 bucket regional domain name to the CloudFront origin, and the WAF web ACL ARN to the CloudFront distribution. schemas/contract.schema.json is extended for the new module inputs (price_class, viewer_protocol_policy, waf_enabled, default_ttl, max_ttl). The uses:/ref: tag advances from @v1.4 to @v1.6 (D-056/D-057); floating git tags v1.6 + v1 are created pointing at v1.6.0.
Category: Tagging standards + security adapters
- REQ-65: A required-tag set is defined in
schemas/tagging-standard.json (acdl:owner, acdl:contract, acdl:environment, acdl:cost-center). A Checkov custom YAML rule at adapters/terraform/policy/custom_rules/acdl_tagging.yaml fails (severity medium) when required tags are missing on taggable resources. checkov_adapter.py removes the _emit_tag_naming_skipped() placeholder (D-043 closure) and maps ACDL_TAG_NAMING as a real rule. scripts/run_platform.sh Step 5 passes --external-checks-dir to load the custom rule.
- REQ-66: A Wiz adapter stub exists at
adapters/wiz/wiz_adapter.py translating Wiz API issues → PolicyCheckResult records (engine: "wiz", D-052). It degrades gracefully when unconfigured (emits a single SKIPPED WIZ_NOT_CONFIGURED record). tests/test_wiz_adapter.py passes offline with a fixture response. The pipeline invokes it optionally (Step 5b) when WIZ_API_TOKEN is set.
- REQ-67: A Kyverno K8s-native adapter exists at
adapters/kyverno/kyverno_adapter.py translating Kyverno PolicyReport results → PolicyCheckResult records (engine: "kyverno", D-053). Sample policies exist at adapters/kyverno/policies/ (disallow-privileged, require-labels, require-image-digests). tests/test_kyverno_adapter.py passes offline. The adapter is inactive for Terraform-only stacks (the platform emits Terraform, not K8s manifests); it is ready for the GitOps reconciler roadmap item. schemas/policy_check_result.schema.json engine enum includes checkov | kyverno | opa | wiz.
Category: Platform Lambda + contract ingestion
- REQ-68: A platform Lambda (
core/lambda/contract_ingestor.py) is invoked via a Function URL (IAM auth) and accepts { consumerRepo, contractId, contract, environment, action }. It writes contracts to a DynamoDB table acdl-contracts (PK consumerRepo, SK contractId#submittedAt, SSE via a customer-managed CMK, point-in-time recovery) (D-051). terraform/platform/main.tf defines the table, Lambda, Function URL, KMS key, Secrets Manager secret (acdl/github-token), and Lambda execution role. terraform/platform/consumer_invoke_policy.json grants the consumer's deploy role lambda:InvokeFunctionUrl on the Lambda ARN, scoped via ABAC (cross-account). Onboarding grants the Lambda-invoke permission; docs/environments/index.md documents this. tests/test_contract_ingestor.py passes offline (moto-mocked DynamoDB).
- REQ-69:
scripts/run_platform.sh has a publish-outputs step (after apply) that writes deploy outputs to SSM Parameter Store as SecureString (KMS-encrypted, namespaced /acdl/{env}/{contractId}/{output_name}) for runtime-injectable values, and a comment-outputs step that posts a structured GitHub PR comment / job summary with human-readable connection strings (D-050). core/output_publisher.py implements the SSM write + GitHub comment formatting. tests/test_output_publisher.py passes offline (moto + mocked GitHub API). pipelines/deploy.yaml + both deploy workflow YAMLs declare the new stages (byte-identical).
- REQ-70: The Lambda
report_error action (core/lambda/contract_ingestor.py) creates a GitHub issue on the platform repo (acdl/acdl) via the GitHub API using a token from Secrets Manager (D-055). Idempotent (comments on an existing open issue rather than duplicating). .github/workflows/deploy.yml + .gitea/workflows/deploy.yml (byte-identical) have an if: failure() error-report step invoking the Lambda via aws lambda invoke-function-url (SigV4-signed). Gitea is excluded (only the CIAgent uses it; platform engineers and consumers use GitHub).
- REQ-71:
.github/workflows/deploy.yml + .gitea/workflows/deploy.yml (byte-identical) post a PR comment after every successful pipeline stage (validate-contract, resolve-stack, plan, checkov, confidence, apply, publish-outputs) via scripts/post_stage_comment.sh (uses GITHUB_TOKEN + gh api; no-op when not in a PR context). The comment includes the stage name, status (pass), and key metrics (plan counts, confidence score, outputs published).
Category: Platform pipelines + release automation
- REQ-72: Three platform pipelines exist: (1)
.github/workflows/platform-test.yml (PR, stages: lint, unit-test, integration-test — runs run_platform.sh --check-only for every sample contract, schema-validation — validates all schemas/*.json + modules/**/interface.json + modules/**/composition.json + modules/<name>/examples/*.yaml against their schemas); (2) .github/workflows/primitives-plan.yml (PR, plan-only for all L1 primitives via matrix, scripts/run_primitive_plan.sh); (3) .github/workflows/patterns-plan.yml (PR, plan-only for all L2 modules via matrix, scripts/run_pattern_plan.sh).
- REQ-73:
.github/workflows/release.yml runs on merge to main, computes the next semver (PATCH per phase, MINOR on milestone COMPLETE), creates the MAJOR.MINOR.PATCH tag, force-moves the MAJOR.MINOR + MAJOR floating tags, and creates a GitHub release with an auto-generated body (D-057). tests/test_release_logic.py passes (unit test the semver computation + tag-update logic with a mocked git describe).
Category: Remove legacy consumer-repos + module examples + RDS primitive
- REQ-74: The legacy consumer-repos directory is deleted entirely (a v1.2 artifact removed in v1.7; references in
.ciagent/ historical narrative are rewritten per D-048). A recursive grep for the legacy directory name (excluding .git/) returns 0 hits.
- REQ-75: A new RDS primitive (
modules/l1/rds/) with an engine input (enum: postgres, mysql, etc.) demonstrates multi-engine variation (D-059). Every module (primitives + patterns) has a modules/<name>/examples/ directory with simple.yaml + complex.yaml (+ variation files) validated against schemas/contract.schema.json in the platform-test pipeline schema-validation stage (D-058). Each module's README.md ## Examples section references + excerpts the validated files. docs/modules/index.md + docs/consumer-guide.md + docs/contracts/index.md are updated with the new module names + examples.
v1.8 (Complete — P1 remediation + uptime + engineering standards + encryption/deletion-protection by default + decommission + docs)
Category: P1 Fixes
- REQ-76: WAF adapter emits custom
rules as nested HCL blocks (not attribute syntax) and honors default_action input (allow/block) — P1-4, P1-5 closed.
- REQ-77: L2 composition
outputs[] array is resolved by contract_resolver.py into stack.outputs; the adapter emits corresponding output blocks — P1-7 closed.
- REQ-78: SSM publisher fails loud when
ACDL_KMS_KEY_ID is unset (no silent AWS-managed-key fallback); ACDL_ALLOW_DEFAULT_KMS=1 escape hatch for local testing — P1-3 closed.
- REQ-79:
consumer_invoke_policy is rendered via Terraform with the caller's live account ID (no 000000000000 placeholder) — P1-6 closed.
- REQ-80:
run_platform.sh emits adapter output to a per-run temp dir, not committed terraform/spike/*.tf; the committed files are removed — P1-8 closed.
- REQ-81:
contract_ingestor.py reads GITHUB_API_BASE env for forge-agnostic API URLs (GitHub + Gitea) — P1-9 closed.
- REQ-82: Deploy workflow static-key override is wired to
configure-aws-credentials inputs (access-key/secret-key), not inert env vars — S1 closed.
Category: Encryption by Default
- REQ-83: A per-stack CMK primitive (
kms-key) exists with 90-day rotation enabled at creation; one key per L2 deployment; no shared keys across stacks.
- REQ-84: All primitives have encryption by default (
encryption_enabled NFR, default true) + optional kms_key_arn input. CMK is prioritized; managed KMS is the fallback when no CMK is provided.
- REQ-85: L2 modules wire a per-stack CMK child + connect its
kms_key_arn output to each child's kms_key_arn input.
Category: Deletion Protection by Default
- REQ-86:
deletion_protection NFR (boolean, default true) on every L1 primitive; the adapter emits prevent_destroy lifecycle meta-arg when true.
- REQ-87: L2 modules expose a
features.deletion_protection flag (default true); consumers can disable via contract inputs.deletion_protection: false.
Category: Uptime Monitoring
- REQ-88: An uptime-kuma L1 primitive exists (ECS Fargate) with:
feature_flag_enabled (boolean, default true), monitored_endpoints (array of HTTP/DNS/TCP checks), static_checks (pre-defined health checks), alert_channels (Teams webhook, email, SMS, GitHub issues).
- REQ-89: Uptime is deployed by default after any L2 module deploy (separate terraform state, separate terraform run); L2 module outputs (endpoints) are passed to the uptime deployment as
monitored_endpoints. The uptime URL is published to the consumer via PR comment.
- REQ-90: The
feature_flag_enabled input (set from consumer contract inputs.uptime_enabled, default true) disables the uptime deployment entirely (no resources emitted).
- REQ-91: A
deploy-uptime pipeline stage is declared in pipelines/deploy.yaml + both deploy workflow YAMLs (byte-identical).
Category: Decommission + CMDB
- REQ-92: A decommission mode on the deploy pipeline (
mode: decommission) implements a 2-step pipeline: (1) plan/apply to disable deletion protection with an HITL SRE gate, (2) plan/apply with all counts set to 0 with a second HITL SRE gate. Uses the existing deploy pipeline with different behavior.
- REQ-93: A DynamoDB
acdl-change-requests table serves as the CMDB. The decommission alias accepts a changeRequestId input validated via a validate_change_request Lambda action (CR status must be approved).
- REQ-94: The decommission flow is documented in
docs/CONSUMER_GUIDE.md (how to request a CR, trigger decommission, HITL gates, what happens).
Category: Engineering Standards
- REQ-95:
modules/STANDARDS.md exists with comprehensive L1 + L2 authoring + code review standards (scanned from current modules): required files, interface schema, input/output/NFR conventions, encryption + deletion protection as mandatory NFRs, naming, adapter extension pattern, code review checklist.
- REQ-96:
modules/README.md catalog index includes all primitives (rds + uptime + kms-key added); modules/README-TEMPLATE.md updated with ## NFRs section.
Category: Path Documentation
- REQ-97:
schemas/README.md documents how to write a schema, wire it into the platform, test it in CI, where to write tests, dependencies, and the existing schema catalog.
- REQ-98:
pipelines/README.md documents how to write a pipeline contract, wire it into workflows, test it, dependencies, and the existing pipeline catalog.
- REQ-99:
adapters/README.md documents how to write an adapter, wire it into the platform, test it, dependencies, and the existing adapter catalog.
Out of Scope (v1.2)
| REQ |
Original criterion |
Clarified criterion (effective) |
Decision |
| REQ-09 |
Three repos exist |
Three repos exist (acdl, acdl-contracts, acdl-evidence) under continuous-intelligence; new repos use default_branch: "main", auto_init: true |
D-015 |
| REQ-10 |
"Pages returns 200 with placeholder index.html" on acdl-evidence |
Gitea has no Pages; substitute: an HTTP GET against the raw file URL https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html returns 200 with the placeholder HTML body |
D-012, D-016 |
| REQ-10 |
"qa and prod environments exist on acdl-contracts" |
Gitea has no environments API and ignores environment: blocks; substitute: the reusable workflow defines qa-gate and prod-gate jobs gated by workflow_dispatch approval inputs (D-004 fallback); a qa and prod branch may be created on acdl-contracts as a visible stand-in for environments |
D-013 |
Out of Scope (v1.0 demo — retained for history)
| Feature |
Reason |
| Real cloud provisioning (AWS/GCP/Azure) |
Demo explicitly stubs all infrastructure; no cloud access available. |
| Real LLM inference / external AI APIs |
Spec forbids external AI; L3B is a keyword parser. |
| Production-grade infrastructure |
Demo target is a 30-minute executive show, not a production system. |
| Adversarial tamper-proofing of evidence |
Hash chain is demonstrative; not cryptographically secure against a determined attacker. |
| Multi-tenant isolation |
Out of demo scope. |
v1.9 (complete — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation, tag v1.9.0)
Category: Design Doc Refresh
- REQ-100:
core/hitl_matrix_design.md is up to date: the "dev-only spike" framing is replaced with the v1.9 wired-gates reality (qa/prod/dr workflow_dispatch approval gates + CODEOWNERS routing + outbox-based SoD); the 8-concern attestation matrix is marked implemented (offline-testable subset) with operator-supplied concerns noted; the spike-scope note is updated. No stale "v1.2 wires the gates" language remains.
- REQ-101:
core/audit_ledger_design.md is up to date: the hash-chain + DynamoDB-outbox path is marked shipped + production (since v1.8); the S3 Object Lock + JWS + async worker + DLQ + daily checkpoints build-out is clearly labeled "Deferred to a future milestone" (D-083); the RPO/RTO table reflects the v1.9 state.
Category: P1-1 Remediation
- REQ-102: The adapter (
adapters/terraform/adapter.py) contains no resource-type-specific hardcoded defaults for ECS/ALB/VPC resources — desired_count, launch_type, target_type, load_balancer_type, family, and Name tag values are read from L1 interface.json inputs (with defaults declared in the interface). The adapter is a thin translator. An L1 with an overridden desired_count: 3 emits desired_count = 3; the default emits desired_count = 1 via the interface default, not an adapter hardcode (P1-1 closed).
Category: Contract Interpolation
- REQ-103: The contract resolver (
core/contract_resolver.py) expands ${env.<field>} and ${contract.<field>} tokens in contract string values (including dotted paths like ${env.state_backend.bucket}) after schema validation and before IR resolution. The env context is the loaded core/environments/<contract.environment>.json; the contract context is the contract dict. Unresolved tokens raise ValueError (fail loud). Sample contracts use naming patterns that include region, account id, and environment (e.g. acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}).
- REQ-104: An environment JSON schema
schemas/environment.schema.json (draft 2020-12) defines the environment file shape (name, account_id, region, state_backend, network, runner_role_arn, autonomy, confidence_threshold). core/environments/dev.json validates against it. qa.json, prod.json, dr.json placeholder bindings exist (autonomy attested, thresholds 0.75/0.90/0.95).
Category: Per-Environment CI Jobs
- REQ-105: Per-environment contract files exist for each sample module (
contracts/static-assets.{dev,qa,prod,dr}.yaml and contracts/microservice.{dev,qa,prod,dr}.yaml), each setting environment: to its own name and using interpolation for env-specific values. The existing contracts/static-assets.yaml + contracts/microservice.yaml remain as the dev default for backwards compatibility.
- REQ-106: The reusable deploy workflow (
.github/workflows/deploy.yml + .gitea/workflows/deploy.yml, byte-identical) declares an environment workflow_call input (enum dev/qa/prod/dr, default empty). When non-empty, scripts/run_platform.sh --environment <name> overrides the contract's environment field at load time (before interpolation). A consumer repo's caller workflow has one job per environment, each pointing at its respective contract (or the same contract + the env input). Promotion = running the matching job; no environment: field editing. docs/CONSUMER_GUIDE.md documents the per-env caller workflow pattern.
Category: Stub Implementation
- REQ-107:
core/separation_of_duties.py route_halt_artifact is a real implementation: publishes to an SNS topic acdl-sod-halt (ARN from ACDL_SOD_HALT_TOPIC_ARN); when unset, falls back to a structured stderr emission + a SEPARATION_OF_DUTIES_VIOLATION event write to the DynamoDB outbox via outbox_writer.write_event. No silent print-only stub. The SNS topic is defined in terraform/platform/main.tf.
- REQ-108: HITL qa/prod/dr pre-execution attestation gates are wired via
core/hitl_gates.py (attest(contract_id, env, approver, evidence)). The gate records the approver (gitea.actor / github.actor) to the outbox (approver_qa / approver_prod / approver_dr attributes per audit_ledger_design.md), runs the separation-of-duties check on prod, and returns (ok, reason). scripts/run_platform.sh calls hitl_gates.attest before apply for qa/prod/dr (dev skips). The workflow's workflow_dispatch approval input is the trigger.
- REQ-109: The full 8-concern attestation matrix from
hitl_matrix_design.md §10.4 is implemented in core/attestation_matrix.py. Offline-testable concerns (contract NFRs, schema validity, policy pass) run for real; operator-supplied concerns (k6 load test, DR drill, FinOps forecast) accept an uploaded signed evidence artifact validated for freshness + schema, failing loud if missing/expired for prod/dr. hitl_gates.attest invokes the matrix for the target env and blocks on any failing concern.
- REQ-110: The Wiz adapter (
adapters/wiz/wiz_adapter.py) is a real API client: a WizClient queries the Wiz GraphQL API (WIZ_API_TOKEN + WIZ_API_URL) and translates issues → PolicyCheckResult records. It degrades gracefully (existing WIZ_NOT_CONFIGURED SKIPPED record) when env unset. Offline tests use a recorded GraphQL fixture.
- REQ-111: The Kyverno adapter (
adapters/kyverno/kyverno_adapter.py) translator is fleshed out: full PolicyReport → PolicyCheckResult mapping with severity + skip handling. It remains inactive for Terraform-only stacks (guard preserved); a --kube-version stub is added for future GitOps. Sample policies already exist.
v1.10 (active — pipeline regression fix + capability re-verification + verified-reality rewrite, tag v1.10.0)
Category: Pipeline Regression Fix
- REQ-112: The CIAgent VERIFY stage supports a
regression mode that re-runs capability checks (not just diff checks), triggered at minimum on milestone completion. The regression run executes the local-emulator tier (REQ-113) for every capability marked Verified in prior milestones; any capability that fails the regression run blocks milestone completion. Regression results are recorded in ---ci--- blocks as regression: { capability: <id>, status: Verified|Decayed|Broken }. Existing diff-scoped VERIFY behavior is preserved for non-regression invocations. A regression run against the current codebase surfaces at least one Decayed/Broken capability (proving the gate catches decay, not just passes). tests/test_verify_regression_mode.py passes.
Category: Local Emulating Adapters
- REQ-113: Local emulating adapters exist so the platform is fully locally testable without cloud credentials: (a) a flat-file DynamoDB outbox adapter that writes evidence events to flat files in a temp folder with a valid hash chain, same write/read interface as the live DynamoDB outbox adapter; (b) a local ECS Fargate emulator that records the service definition and returns a synthetic HTTP 200 from a local shell process, same interface as the live ECS adapter; (c) a local S3 state backend (flat-file tfstate in a temp folder); (d) a local Lambda stub that invokes the handler in-process with no AWS Lambda call. The headline E2E (contract submission → service live → evidence event) runs end-to-end against the local tier with no cloud credentials.
tests/test_local_emulating_adapters.py passes. run_platform.sh --local (or equivalent) runs the full pipeline locally.
Category: Capability Re-Verification Sweep
- REQ-114: Every capability advertised in v1.1→v1.8 PROJECT/ROADMAP is enumerated in
.ciagent/CAPABILITY_INVENTORY.md with a unique ID per capability (v1.0 demo excluded as archived/superseded). Each capability is re-verified: the headline E2E (contract → ECS Fargate → evidence event) runs both live-AWS and local-emulator tiers, both must pass; all other capabilities run the local tier via emulating adapters (REQ-113). Each capability is tagged Verified / Decayed / Broken in CAPABILITY_INVENTORY.md. Every Decayed/Broken capability is fixed in-sweep (D-090: no cap) until Verified, with per-capability commits verify(P54): <id> — <status> and fix(P54): <id> — <summary>. All v1.1→v1.8 advertised capabilities end Verified. The regression run (REQ-112) is clean against the re-verified state.
Category: Verified-Reality Rewrite
- REQ-115: PROJECT.md, ROADMAP.md, and both leadership decks are rewritten to match
CAPABILITY_INVENTORY.md exactly. PROJECT.md gains a "Capability Status (Re-Verified 2026-07-27)" section listing every v1.1→v1.8 capability with its Verified tag and the tier(s) tested, plus a decay disclosure: capabilities marked complete in v1.1–v1.8 ran at the time of tagging; as of 2026-07-27 they were not reproducible and were re-verified in v1.10. ROADMAP.md v1.9.x entries note deck-freeze and superseded-by-reverification status. Both leadership decks reflect the re-verified status; any claim that cannot be demonstrated live is removed. HTML is re-rendered; PPTX is uploaded to the v1.10.0 release. Decks are unfrozen only after this lands. ci-doc-verifier confirms no stale capability claims remain. v1.10.0 is tagged; the Gitea release is published.
Out of Scope (v1.9)
| Feature |
Reason |
| S3 Object Lock + JWS + async worker + DLQ + daily checkpoints (audit ledger build-out) |
Requires non-offline-testable AWS infra (Object Lock bucket, KMS signing key, SQS DLQ, Lambda worker). Deferred to a future milestone (D-083). The hash-chain + DynamoDB-outbox path remains the v1.9 production audit record. |
| Live k6/Gatling load test execution, live DR drill, live FinOps forecast |
Operator-supplied evidence artifacts (signed blobs) are accepted + validated; the platform does not run these inline. |
| Self-service environment provisioning |
Adding an environment remains a platform-team action (per core/environments/README.md). v1.9 adds the env files + schema, not self-service provisioning. |
Traceability
v1.0 (prior — demo)
| Requirement |
Phase |
Status |
| REQ-01 |
1 |
complete (v1.0.1) |
| REQ-02 |
2 |
complete (v1.0.2) |
| REQ-03 |
2 |
complete (v1.0.2) |
| REQ-04 |
3 |
complete (v1.0.3) |
| REQ-05 |
3 |
complete (v1.0.3) |
| REQ-06 |
3 |
complete (v1.0.3) |
| REQ-07 |
3 |
complete (v1.0.3) |
| REQ-08 |
3 |
complete (v1.0.3) |
| REQ-09 |
1 |
complete (v1.0.1) |
| REQ-10 |
4 |
complete (v1.0.4) |
| REQ-11 |
3 |
complete (v1.0.3) |
| REQ-12 |
4 |
complete (v1.0.4) |
| REQ-13 |
5 |
complete (v1.0.5) |
| REQ-14 |
5 |
complete (v1.0.5) |
| REQ-15 |
5 |
complete (v1.0.5) |
v1.1 (prior — architecture finalization + v1 spike, complete)
| Requirement |
Phase |
Status |
| REQ-16 |
07 |
complete (v1.1.2) |
| REQ-17 |
07 |
complete (v1.1.2) |
| REQ-18 |
07 |
complete (v1.1.2) |
| REQ-19 |
07 |
complete (v1.1.2) |
| REQ-20 |
07 |
complete (v1.1.2) |
| REQ-21 |
07 |
complete (v1.1.2) |
| REQ-22 |
07 |
complete (v1.1.2) |
| REQ-23 |
08 |
complete (v1.1.3) |
| REQ-24 |
09 |
complete (v1.1.4) |
| REQ-25 |
10 |
complete (v1.1.5) |
| REQ-26 |
09 |
complete (v1.1.4) |
| REQ-27 |
10 |
complete (v1.1.5) |
| REQ-28 |
10 |
complete (v1.1.5) |
v1.2 (prior — platform hardening + first real consumer deployment, complete)
| Requirement |
Phase |
Status |
| REQ-29 |
11 |
complete (v1.2.1) |
| REQ-30 |
12 |
complete (v1.2.2) |
| REQ-31 |
13 |
complete (v1.2.3) |
| REQ-32 |
14 |
complete (v1.2.4) |
| REQ-33 |
15 |
partial (v1.2.5, IAM-blocked) |
| REQ-34 |
15 |
complete (v1.2.5) |
| REQ-35 |
16 |
partial (v1.2.6, IAM-blocked) |
v1.3 (prior — module documentation + thin-composition removal, complete)
| Requirement |
Phase |
Status |
| REQ-36 |
17 |
complete (v1.3.1) |
| REQ-37 |
17 |
complete (v1.3.1) |
| REQ-38 |
17 |
complete (v1.3.1) |
| REQ-39 |
18 |
complete (v1.3.2) |
| REQ-40 |
18 |
complete (v1.3.2) |
| REQ-41 |
18 |
complete (v1.3.2) |
| REQ-42 |
18 |
complete (v1.3.2) |
v1.4 (prior — central pipeline contract + shell reproducibility + streaming)
| Requirement |
Phase |
Status |
| REQ-43 |
19 |
complete (v1.4.1) |
| REQ-44 |
19 |
complete (v1.4.1) |
| REQ-45 |
19 |
complete (v1.4.1) |
v1.5 (prior — consumer happy path + zero-trust docs + reusable deploy workflow, complete)
| Requirement |
Phase |
Status |
| REQ-46 |
20 |
complete (v1.5.0) |
| REQ-47 |
20 |
complete (v1.5.0) |
| REQ-48 |
20 |
complete (v1.5.0) |
| REQ-49 |
20 |
complete (v1.5.0) |
| REQ-50 |
20 |
complete (v1.5.0) |
| REQ-51 |
20 |
complete (v1.5.0) |
v1.6 (complete — consumer-facing docs restructure + terminology normalization + environments concept, tag v1.6.0)
| Requirement |
Phase |
Status |
| REQ-52 |
21 |
complete (v1.6.0) |
| REQ-53 |
21 |
complete (v1.6.0) |
| REQ-54 |
21 |
complete (v1.6.0) |
| REQ-55 |
21 |
complete (v1.6.0) |
| REQ-56 |
21 |
complete (v1.6.0) |
| REQ-57 |
21 |
complete (v1.6.0) |
| REQ-58 |
21 |
complete (v1.6.0) |
| REQ-59 |
21 |
complete (v1.6.0) |
| REQ-60 |
21 |
complete (v1.6.0) |
| REQ-61 |
21 |
complete (v1.6.0) |
v1.7 (complete — production platform + contract ingestion + pipeline maturation, tag v1.7.0)
| Requirement |
Phase |
Status |
| REQ-62 |
22 |
complete (v1.7.0) |
| REQ-63 |
22 |
complete (v1.7.0) |
| REQ-64 |
22 |
complete (v1.7.0) |
| REQ-65 |
23 |
complete (v1.7.0) |
| REQ-66 |
23 |
complete (v1.7.0) |
| REQ-67 |
23 |
complete (v1.7.0) |
| REQ-68 |
24 |
complete (v1.7.0) |
| REQ-69 |
25 |
complete (v1.7.0) |
| REQ-70 |
25 |
complete (v1.7.0) |
| REQ-71 |
25 |
complete (v1.7.0) |
| REQ-72 |
26 |
complete (v1.7.0) |
| REQ-73 |
26 |
complete (v1.7.0) |
| REQ-74 |
27 |
complete (v1.7.0) |
| REQ-75 |
27 |
complete (v1.7.0) |
v1.8 (complete — P1 remediation + uptime + standards + encryption/deletion-protection by default + decommission + docs, tag v1.8.0)
| Requirement |
Phase |
Status |
| REQ-76 |
28 |
complete (v1.8.0) |
| REQ-77 |
28 |
complete (v1.8.0) |
| REQ-78 |
29 |
complete (v1.8.0) |
| REQ-79 |
29 |
complete (v1.8.0) |
| REQ-80 |
30 |
complete (v1.8.0) |
| REQ-81 |
30 |
complete (v1.8.0) |
| REQ-82 |
30 |
complete (v1.8.0) |
| REQ-83 |
31 |
complete (v1.8.0) |
| REQ-84 |
31 |
complete (v1.8.0) |
| REQ-85 |
31 |
complete (v1.8.0) |
| REQ-86 |
32 |
complete (v1.8.0) |
| REQ-87 |
32 |
complete (v1.8.0) |
| REQ-88 |
33 |
complete (v1.8.0) |
| REQ-89 |
33 |
complete (v1.8.0) |
| REQ-90 |
33 |
complete (v1.8.0) |
| REQ-91 |
33 |
complete (v1.8.0) |
| REQ-92 |
34 |
complete (v1.8.0) |
| REQ-93 |
34 |
complete (v1.8.0) |
| REQ-94 |
34 |
complete (v1.8.0) |
| REQ-95 |
35 |
complete (v1.8.0) |
| REQ-96 |
35 |
complete (v1.8.0) |
| REQ-97 |
36 |
complete (v1.8.0) |
| REQ-98 |
36 |
complete (v1.8.0) |
| REQ-99 |
36 |
complete (v1.8.0) |
v1.9 (complete — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation, tag v1.9.0)
| Requirement |
Phase |
Status |
| REQ-100 |
39 |
complete (v1.9.0) |
| REQ-101 |
39 |
complete (v1.9.0) |
| REQ-102 |
39 |
complete (v1.9.0) |
| REQ-103 |
40 |
complete (v1.9.0) |
| REQ-104 |
40 |
complete (v1.9.0) |
| REQ-105 |
41 |
complete (v1.9.0) |
| REQ-106 |
41 |
complete (v1.9.0) |
| REQ-107 |
42 |
complete (v1.9.0) |
| REQ-108 |
42 |
complete (v1.9.0) |
| REQ-109 |
42 |
complete (v1.9.0) |
| REQ-110 |
42 |
complete (v1.9.0) |
| REQ-111 |
42 |
complete (v1.9.0) |
v1.10 (active — pipeline regression fix + capability re-verification + verified-reality rewrite, tag v1.10.0)
| Requirement |
Phase |
Status |
| REQ-112 |
52 |
complete (v1.9.9) |
| REQ-113 |
53 |
complete (v1.9.10) |
| REQ-114 |
54 |
complete (v1.9.11) |
| REQ-115 |
55 |
complete (v1.9.12) |
v1.11 (active — RESTART: stateless adapter + pipeline-driven module lifecycle testing, tag v1.11.0)
The v1.11 milestone closes G-005 (CAP-017..022 deploy-unverified) and G-008
(no cost docs) via a corrected architecture. The first v1.11 attempt is
abandoned (branches phase/56-iam-re-bootstrap + phase/57-live-deploy-microservice);
the restart branches off v1.10.2.
Category: Stateless Adapter
- REQ-123 — The terraform adapter (
adapters/terraform/adapter.py) is rewritten from a 918-line monolith (3 constant tables TYPE_MAP/INPUT_MAP/OUTPUT_MAP + 39 type-specific branches) to a ~80-line stateless assembler. Each L1 module ships a real terraform/ module dir owning its resource shape, nested blocks, and defaults. The adapter reads the registry and emits module "x" { source = ... } blocks. No type-specific logic in the adapter. (Phase P56a)
Category: Per-Module Terraform
- REQ-124 — All 12 L1 modules have a
terraform/ subdir (versions.tf/variables.tf/locals.tf/main.tf/outputs.tf) with defaults centralized in locals.tf (heavy interpolation of vars against sensible defaults). interface.json stays engine-agnostic. The registry has a terraform_dir field per entry. (Phase P56b)
Category: Shell Lifecycle Modes
- REQ-125 —
scripts/run_platform.sh gains --apply and --destroy modes; the shell owns all terraform lifecycle. Python never runs terraform. scripts/verify_deploy_microservice.py is deleted. (Phase P57)
Category: Single Platform VPC + Deterministic State
- REQ-126 —
terraform/platform/main.tf owns ONE VPC; the microservice composition references it via data source (no inline VPC). State keys are deterministic and env-aware (spike/{id}/{env}/terraform.tfstate), stable across apply/modify/destroy. (Phase P58)
Category: L1 Lifecycle Pipeline
- REQ-127 — 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. The "test" = the pipeline cell going green. (Phases P59–P60)
Category: L2 Lifecycle Pipeline
- REQ-128 — The lifecycle pipeline extends to L2 modules (static-assets, microservice). L2 = composition only (no L2 terraform files); the composition is deterministic (same contract → same stack → same state key). (Phases P61–P62)
Category: Operating Model + G-005/G-008 Closure
- REQ-116 — CAP-017..022 marked Verified in CAPABILITY_INVENTORY + PROJECT + decks with "Verified live-aws via lifecycle pipeline; torn down to zero-cost" note. (Phase P65)
- REQ-118 — Both leadership decks rewritten to reflect verified-then-torn-down status; no stale "deploy-unverified" claims. (Phase P65)
- REQ-119 —
.ciagent/COST.md documents the v1.0→v1.10 AWS spend window (Cost Explorer query). (Phase P63)
- REQ-120 —
.ciagent/PRE_MORTEM.md documents the v1.10 decay root cause + forward pre-mortem. (Phase P64)
- REQ-121 — CAP-017..022 added to the regression registry (evidence = lifecycle pipeline green). (Phase P63)
- REQ-122 — All deployed stacks torn down via
--decommission (D-070 two-step, CR CHG0680001); zero live ACDL resources remain. (Phase P64)
v1.11 Traceability
| Requirement |
Phase |
Status |
| REQ-123 |
P56a |
complete |
| REQ-124 |
P56b |
complete |
| REQ-125 |
P57 |
complete |
| REQ-126 |
P58 |
complete |
| REQ-127 |
P59, P60 |
complete |
| REQ-128 |
P61, P62 |
complete |
| REQ-116 |
P65 |
complete |
| REQ-118 |
P65 |
complete |
| REQ-119 |
P63 |
complete |
| REQ-120 |
P64 |
complete |
| REQ-121 |
P63 |
complete |
| REQ-122 |
P64 |
complete |
Out of Scope (v1.11)
- OIDC act_runner adoption (pending go-gitea/gitea#36988).
- Per-phase regression (G-007: milestone-level regression gate is correct).
- Audit ledger build-out (D-083).
- 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).
Milestone v1.14 — NFR Refinement (REQ-135..REQ-154)
Objective: Bug fixes, security posture improvements, stub/missing-
functionality identification + implementation, and documentation + NFR
refinement across the entire codebase. No new features. NFR milestone
— the final phase's patch IS the deliverable.
The v1.11 multi-persona review left 5 P1 + 4 P2 findings open; the
codebase has 6+ swallowed-error sites, 15+ hardcoded account-ID
references, 7 untested scripts, an offline-proxy regression gate,
ARCHITECTURE.md with no v1.11–v1.13 addendum, and consumer-facing docs
referencing stale @v1.6–@v1.9 workflow tags. v1.14 clears all of it
in a 20-phase sweep.
Requirements
- REQ-135 — The adapter dedup loop raises
ValueError for
unregistered-module resources instead of silently dropping them (P1-1).
(Phase P1)
- REQ-136 — The static-assets L2 composition wires
default_ttl/
max_ttl/price_class/viewer_protocol_policy and makes WAF
conditional via waf_enabled, so complex.yml is a real modify (P1-2).
(Phase P2)
- REQ-137 — The L2 lifecycle scripts' usage strings no longer
advertise the vestigial
[ci-vpc-outputs.json] arg, or document the
remote-state design (P1-3). (Phase P3)
- REQ-138 — The regression gate's CAP-017..022 checks run
terraform validate (not just file-existence + resolver); the
offline-proxy caveat is documented honestly (P1-5). (Phase P4)
- REQ-139 — Unit tests for adapter dedup merge behavior +
ACDL_REMOTE_STATE_KEY override exist and pass (P2-2). (Phase P5)
- REQ-140 — The ALB target group
name_prefix derives from var.name
(P2-1). (Phase P6)
- REQ-141 — 6 over-broad
except ...: pass sites narrowed to specific
exceptions; errors logged with context. (Phase P7)
- REQ-142 — The hardcoded account ID
581513795199 is externalized to
ACDL_AWS_ACCOUNT_ID env / data.aws_caller_identity across 15+ sites.
(Phase P8)
- REQ-143 — 6
Resource: "*" IAM statements scoped to acdl-* ARNs;
regression test asserts the scoping. (Phase P9)
- REQ-144 — The contract ingestor validates
contractId/environment/
error; ABAC reliance documented; spoofing-resistance test passes.
(Phase P10)
- REQ-145 —
contract.schema.json + environment.schema.json reject
undocumented fields (additionalProperties: false); format validation
for bucket/ARN/CIDR. (Phase P11)
- REQ-146 —
.gitignore has a credential-pattern catch-all;
test_no_secrets_tracked.py passes. (Phase P12)
- REQ-147 — The Kyverno
--kube-version flag is either implemented or
removed with a documented deferral rationale. (Phase P13)
- REQ-148 — Orphan bytecode + dead config cleaned (orphan
.pyc,
stale coverage source, stale version, dead JS allowlist). (Phase P14)
- REQ-149 — 7 untested scripts have unit test coverage (≥1 test each).
(Phase P15)
- REQ-150 — Gitea workflow parity resolved;
rotate_spike_key.sh +
sync_to_gl.sh have set -euo pipefail. (Phase P16)
- REQ-151 —
config.json persona block + branching strategy +
ollama-cloud backend aligned with PERSONAS.md + actual runtime.
(Phase P17)
- REQ-152 —
modules/STANDARDS.md internally consistent; no stale
TYPE_MAP reference. (Phase P18)
- REQ-153 — ARCHITECTURE.md has v1.11–v1.14 addenda; stale
@v1.6–1.9
→ @v1.13; GRILL G-005/G-008 resolved; COST.md window covers v1.11–v1.14;
D-083 deferral recorded. (Phase P19)
- REQ-154 — Platform VPC CIDR is a variable; subnet count is
data-driven;
0.0.0.0/0 ingress documented. (Phase P20)
v1.14 Traceability
| Requirement |
Phase |
Status |
| REQ-135 |
P1 |
pending |
| REQ-136 |
P2 |
pending |
| REQ-137 |
P3 |
pending |
| REQ-138 |
P4 |
pending |
| REQ-139 |
P5 |
pending |
| REQ-140 |
P6 |
pending |
| REQ-141 |
P7 |
pending |
| REQ-142 |
P8 |
pending |
| REQ-143 |
P9 |
pending |
| REQ-144 |
P10 |
pending |
| REQ-145 |
P11 |
pending |
| REQ-146 |
P12 |
pending |
| REQ-147 |
P13 |
pending |
| REQ-148 |
P14 |
pending |
| REQ-149 |
P15 |
pending |
| REQ-150 |
P16 |
pending |
| REQ-151 |
P17 |
pending |
| REQ-152 |
P18 |
pending |
| REQ-153 |
P19 |
pending |
| REQ-154 |
P20 |
pending |
Out of Scope (v1.14)
- New features (feat phases). v1.14 is NFR-only.
- D-083 audit ledger build-out (S3 Object Lock + JWS + SQS DLQ + async
worker) — remains deferred; documented explicitly in ARCHITECTURE.md.
- Real OIDC federation (blocked on go-gitea/gitea#36988).
- Per-phase regression hardening (G-007, unchanged).
- Boto3 post-deploy verification probes (deferred to a future QA
milestone).