# Nova — The New Dawn of DevSecOps

> **Rebrand complete (milestone v1.15 — Nova, tag v1.15.4).** The
> project was rebranded from **ACDL** / "Agentic Cloud Delivery
> Platform" → **Nova** / "The New Dawn of DevSecOps — security as a
> seamless enabler of fast deployments." The new tagline is added
> alongside the existing "North Star" / "consumers declare intent"
> framing. See `.ciagent/REQUIREMENTS.md` §v1.15 and
> `.ciagent/ROADMAP.md` §v1.15.

## 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`)

1. **Operations are Declared, Not Executed.** Consumers define what they
   need; the platform reconciles, provisions, and progresses.
2. **The Delivery Lifecycle is a Sovereign Boundary.** The platform
   governs infra and delivery; it does not reach into upstream product/SDLC.
   Integration is only through validated, published contracts.
3. **Lower Environments are Autonomous; Higher Environments are Attested.**
   Dev = zero-touch agentic. QA/prod/dr = deliberate human attestation, not
   rubber stamps.
4. **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?"
5. **Infrastructure is Consumed, Not Maintained.** Compute is abstract,
   containerized, or serverless. No node/OS/bare-metal lifecycle.
6. **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.

## Scope: Nova is Downstream of PDLC

> **Promoted from Core Tenet #2 + Anti-Goal #1 (v1.18, REQ-216).** This
> is the unmissable scope statement — the PDLC is upstream, Nova is
> downstream.

The **Product Development Lifecycle (PDLC)** — product backlog, code
authorship, IDE workflows, sprint planning, application business logic —
is **upstream** of Nova. Nova never reaches into the PDLC. Nova's domain is
**infrastructure + delivery only**: environment progression, cloud
resource lifecycle, operational security/observability NFRs, policy
enforcement, immutable audit lineage, and the two consumer surfaces
(technical developer + agentic).

Integration between the PDLC and Nova is **only** through the validated,
published contract boundary (`schemas/contract.schema.json` +
`schemas/submission-readiness.schema.json`). The citizen developer's AI
coding agent, an upstream agentic SDLC platform, or any upstream
development platform may all produce submissions — the source does not
matter because all are subject to the same compliance standards (the
submission-readiness gate, D-133). Nova validates, enriches with
operational standards, and reconciles the target state. Nova never
authors application code, manages product backlogs, or provides IDE
workflows.

```
PDLC (upstream)                         Nova (downstream)
─────────────────                       ─────────────────
product backlog                         contract ingestion
code authorship (AI agent / IDE / SDLC) → submission-readiness gate
sprint planning                         → policy enforcement
application business logic              → cloud resource lifecycle
                                        → environment progression (dev→qa→prod→dr)
                                        → immutable audit + attestation
```

## RACI Matrix

> **Source of truth (v1.18, REQ-215, D-139).** Three roles clarify who
> owns what across the Nova delivery lifecycle. The matrix is the
> authoritative version; `docs/raci.md` is the citizen-developer-facing
> copy.

### Roles

- **Citizen Developer (CD)** — the consumer (technical developer L3A or
  non-technical L3B). Responsible for all **Functional Requirements (FRs)**
  and **User Acceptance Testing (UAT)**. The FRs + UAT are produced via
  the citizen developer's AI coding agent, an upstream agentic SDLC, or
  an upstream development platform — **the source does not matter as all
  are subject to the same compliance standards** (the submission-readiness
  gate, D-133).
- **Platform** — Nova. Responsible for all **Non-Functional Requirements
  (NFRs)**, **Infrastructure** (cloud resource lifecycle, state, IAM),
  **QA** (the platform-side quality checks: policy, confidence, schema),
  and **Production deployments to cloud** (the apply path, the pipeline,
  the release).
- **Release Management (RM)** — **co-owned**. QA + SRE attestations are
  required by the actual release. The attestations are performed
  agentically (the platform runs the checks), but the release is
  **overseen and triggered by the Citizen Developer** — the human
  attestation at the stage gate (D-042, hitl_gates.py). The platform
  performs; the citizen developer authorizes.

### Matrix

| Work Category | Citizen Developer | Platform | Release Management |
|---|---|---|---|
| **Functional Requirements (FRs)** | **R/A** | C | I |
| **User Acceptance Testing (UAT)** | **R/A** | C | I |
| **Non-Functional Requirements (NFRs)** | I | **R/A** | C |
| **Infrastructure (cloud, state, IAM)** | I | **R/A** | C |
| **QA (policy, confidence, schema checks)** | C | **R/A** | I |
| **Production deployment to cloud** | I | **R/A** | C |
| **Release attestation (QA + SRE sign-off)** | **A** | R | **R** |

**Key: R** = Responsible (does the work) · **A** = Accountable (owns the
outcome, sign-off) · **C** = Consulted · **I** = Informed.

**Compliance-standard equivalence note:** the citizen developer's FRs +
UAT may originate from any upstream source — an AI coding agent, an
agentic SDLC platform, or a traditional development platform. All are
subject to the same compliance standards: the submission-readiness gate
(`schemas/submission-readiness.schema.json`), the contract schema, the
policy envelope, and the immutable audit stream. The platform does not
differentiate by upstream source; it validates the submission, not the
author.

**Co-ownership of Release Management:** the release is co-owned. The
platform performs the QA + SRE attestations agentically (confidence signal,
policy checks, separation-of-duties). The citizen developer oversees and
triggers the actual release — the human attestation at the stage gate is
the citizen developer's authorization, recorded with approver identity
(D-042). The platform runs the checks; the citizen developer authorizes
the promotion. This is the "autonomy in operations, human at stage gates"
model from the NORTH_STAR.

## Capability Status (Re-Verified 2026-07-27)

> Source of truth: `.ciagent/CAPABILITY_INVENTORY.md` (Phase 54, D-093).
> Tier: **local** = runs via emulating adapters (no AWS); **live-aws** =
> runs against the live AWS account (581513795199).

**Decay disclosure.** Capabilities marked complete in v1.1–v1.8 ran
successfully at the time of tagging. As of 2026-07-27 they were **not
reproducible** — the v1.7/v1.8 platform simplification introduced 7
adapter defects that prevented `terraform init/validate/plan` from
succeeding against live AWS, and the decks (v1.9.1–v1.9.8) presented
the capability as current without disclosing the decay. The v1.10
milestone (Phases 52–55) re-verified every advertised capability and
fixed all 7 defects in-sweep (D-090: no cap). The headline E2E now
passes at both tiers.

**Auto-verified capabilities (16/16 Verified):**

| ID | Capability | Tier | Status |
|----|-----------|------|--------|
| CAP-001..CAP-012 | contract schema, resolver, adapter, interpolation, confidence, outbox, pytest, run_ci, local E2E (microservice + static-assets) | local | Verified |
| CAP-013 | terraform init+validate+plan live AWS (microservice) | live-aws | Verified |
| CAP-014 | terraform init+validate+plan live AWS (static-assets: CloudFront+WAF+S3) | live-aws | Verified |
| CAP-015 | DynamoDB outbox table exists + describable | live-aws | Verified |
| CAP-016 | S3 state bucket exists + readable | live-aws | Verified |

**IAM-gated cloud resources (6, escalated — not auto-verifiable):**
CAP-017..CAP-022 (DynamoDB contracts table, Lambda contract-ingestor,
ECS service live, CloudFront production stack, uptime-kuma, OIDC
role). The `acdl-spike-runner` IAM user lacks the permissions to
verify these (chicken-and-egg: it cannot fix its own IAM). The
terraform plan path (CAP-013, CAP-014) proves the code would deploy
them; the local emulators (Phase 53) prove the runtime behavior.
Re-bootstrap of the OIDC role + IAM re-grant requires an admin
principal — escalated, not silently skipped. See
`CAPABILITY_INVENTORY.md` §"Cloud capabilities NOT re-verified".

**Regression gate.** `bash scripts/run_regression.sh` re-runs all 16
auto-verifiable capabilities and fails closed on any non-Verified
result. The gate runs at milestone completion (D-091).

## 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`) — engine-agnostic, IR-typed interface.
- **One L2 thin-composition** (`l2-static-assets`) — references the L1.
- **Terraform adapter** — compiles the IR to a real `terraform plan`
  against 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):

1. **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).
2. **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.
3. **Streamline / simplify the current setup.** Consolidate the
   `run_spike_*.sh` scripts into one `scripts/run_platform.sh`; remove
   dead code and stale paths; one command runs the whole pipeline.
4. **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.
5. **Bootstrap a consumer repo with a basic microservice deployed to ECS
   end-to-end.** New Gitea repo `acdl-consumer-microservice` (org
   `continuous-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`); new `l2-microservice`
   thin-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:

1. **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.
2. **Shell reproducibility.** `scripts/run_ci.sh` mirrors 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.
3. **Output streaming.** `scripts/run_platform.sh` streams terraform
   init/validate/plan output, Checkov compliance results, and
   PolicyCheckResult records to stdout by default, so the user sees what
   is happening. A `--quiet` flag 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):

1. **Rename `static-assets` → `static-assets`** (D-048 — including
   `.ciagent/` historical narrative, overriding the v1.6 preservation
   precedent). The reconstruction test is updated to expect `static-assets`.
2. **Augment `static-assets` to a production-ready stack** by authoring a
   new `cloudfront` primitive + a `waf` primitive (D-049: S3 + CloudFront
   OAC + WAF; Route53/ACM are domain-dependent and deferred to documented
   extension points).
3. **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.
4. **Central deploy pipeline error reporting** via the platform Lambda
   `report_error` action (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 GitHub
   `issues: write` on the consumer side. Gitea is excluded (only the CIAgent
   uses it).
5. **PR comments after every successful stage** so developers always know
   where they stand.
6. **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).
7. **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 `@v1` or `@v1.6` receive updates
   depending on their pinned version.
8. **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.
9. **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
   SKIPPED `ACDL_TAG_NAMING` placeholder becomes a real check).
10. **Wiz adapter** for security checks (D-052): a stub + schema path that
    translates Wiz API issues → `PolicyCheckResult` records, degrading
    gracefully when unconfigured. Matches the Checkov adapter pattern.
11. **Kyverno adapter** for compliance/security checks (D-053): a
    K8s-native policy adapter that translates Kyverno `PolicyReport` results
    → `PolicyCheckResult` records. Ready but inactive for Terraform-only
    stacks (the platform emits Terraform, not K8s manifests); it activates
    when the GitOps reconciler (roadmap) emits K8s manifests.
12. **Remove the legacy consumer-repos directory** and add validated per-module examples
    (D-058: `modules/<name>/examples/` with `simple.yaml` + `complex.yaml`
    validated 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.

## Objective for Milestone v1.9 (complete, tag `v1.9.0`)

Production-grade progression: contract interpolation, per-environment
promotion without field editing, stub implementation, and P1-1
remediation. The v1.8 milestone shipped encryption/deletion-protection by
default, uptime, decommission, and engineering standards but left four
gaps that v1.9 closes (user-directed, 2026-07-23):

1. **Design doc refresh.** `core/hitl_matrix_design.md` and
   `core/audit_ledger_design.md` are stale — both still describe the
   v1.1 spike scope ("dev-only; HITL not exercised"; "spike scope =
   hash chain + outbox write; Object Lock + JWS are v1.2"). v1.9 brings
   them up to date with the shipped v1.8 platform and the v1.9 wiring.
2. **Contract interpolation (variable expansion).** Contracts cannot
   reference environment onboarding values today — bucket names, account
   IDs, regions are hardcoded literals. v1.9 adds `${env.<field>}` and
   `${contract.<field>}` expansion in the resolver, sourced from the
   environment onboarding JSON. Naming patterns like
   `acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}`
   become expressible. The S3 bucket naming-pattern requirement is the
   binding example.
3. **Per-environment CI jobs (no field editing for promotion).** Today a
   promotion dev → qa requires editing the `environment:` field in the
   contract YAML. v1.9 ships a hybrid model: (a) per-environment contract
   files (`.acdl/static-assets.dev.yaml`, `...qa.yaml`, etc.) and (b) an
   `environment` `workflow_call` input on the reusable deploy workflow
   that overrides the contract's environment at load time. There is one
   CI job per environment, each pointing at its respective contract (or
   the same contract + the env input). Promotion = running the matching
   job; no field editing.
4. **Stub implementation.** Identify and implement the stubbed
   functionality: `separation_of_duties.route_halt_artifact` (logs only →
   real SNS + outbox event); HITL qa/prod/dr pre-execution attestation
   gates (only decommission SRE gates are wired today); the full
   8-concern attestation matrix (offline-testable subset implemented;
   operator-supplied concerns accept signed evidence artifacts); the Wiz
   adapter (stub → real API client with graceful degrade); the Kyverno
   adapter (fleshed out translator, still inactive for Terraform-only
   stacks). The audit-ledger S3 Object Lock + JWS + async worker + DLQ +
   daily checkpoints build-out is **deferred** to a future milestone
   (D-083) — it requires non-offline-testable AWS infra (Object Lock
   bucket, KMS signing key, SQS DLQ, Lambda worker).
5. **Post-hoc requirement from previous milestones.** P1-1 from the v1.2
   review (adapter ECS/ALB/VPC hardcoded defaults — `desired_count = 1`,
   `launch_type = "FARGATE"`, `target_type = "ip"`,
   `load_balancer_type = "application"`, `family = "app"`, `Name = ...`
   — should be parameterized via the L1 interfaces, deferred to v1.3,
   never implemented) is closed. The adapter becomes a thin translator;
   the defaults move into `interface.json` inputs.

The milestone also reconstructs `.ciagent/REVIEW.md`, which still holds
v1.2 review content (v1.3–v1.8 reviews were not persisted). The v1.9
review overwrites it with current milestone content; a note records the
historical gap (no git-history rewrite).

## Milestone v1.9 Phases

| Phase | Name | Goal |
|-------|------|------|
| 39 | design-doc-refresh-and-p1-1-parameterization | Refresh `hitl_matrix_design.md` + `audit_ledger_design.md` to current. Move adapter ECS/ALB/VPC hardcoded defaults into L1 `interface.json` inputs (P1-1 closure). |
| 40 | contract-interpolation | `${env.<field>}` + `${contract.<field>}` resolver expansion from environment onboarding JSON. Environment JSON schema. Sample contracts use naming patterns (region + account id + environment). |
| 41 | per-environment-ci-jobs | Per-env contract files + `environment` workflow_call input on the deploy workflow. 1 CI job per environment (dev/qa/prod/dr), each pointing at its respective contract. HITL attestation gate structure wired (qa/prod/dr). |
| 42 | stub-implementation | `route_halt_artifact` real (SNS + outbox). HITL qa/prod/dr attestation gates. 8-concern attestation matrix (offline-testable subset). Wiz real client. Kyverno translator fleshed out. |
| 43 | verify-review-audit-complete | 4-layer verify. Multi-persona review. Audit. Complete v1.9 (tag `v1.9.0`, floating tags, `uses:` bump `@v1.6` → `@v1.9`). |

Milestone COMPLETE gate: review → ship `v1.9.0` (feature milestone, next
minor per run.md — v1.8 shipped `v1.8.0`) → audit.

## Patch v1.9.1 (complete, tag `v1.9.1`)

Docs-only NFR patch on the v1.9 line. Two leadership-facing presentation
decks (How the Platform Works + The Developer Experience) for senior
leadership (CTO, Head of Cloud, Head of Infrastructure, Head of DevOps).
Each deck has a full markdown source of truth (with speaker notes + mermaid
diagrams) and a lean Marp deck (no speaker notes, embedded PNG diagrams). A
README documents the 3-step slide creation process (full markdown → Marp
synthesis → PPTX export) with conventions, build commands, and maturity
framing rules. No code changes; 494 tests pass; `run_ci.sh` +
`run_platform.sh --check-only` green.

## Patch v1.9.2 (complete, tag `v1.9.2`)

Docs-only NFR patch on the v1.9 line. Applies the S&P Global Energy brand
visual identity to both Marp presentation decks. Brand colors extracted
from the live spglobal.com compiled Tailwind CSS and SVG logo: red-core
`#D6002A`, grey-90 `#1B1B1B`, grey-80 `#2E2E2E`, grey-5 `#F0F0F0`, Akkurat
Pro corporate typeface. Title headers changed to full platform name.
Footer changed from 'Confidential · For Senior Leadership' to 'Internal'.
Title slide subtitle removed. Last DX slide renamed from 'The Outcome for
Leadership' to 'The Desired Outcomes'. Marp `theme: default` kept as base.
No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green.

## Patch v1.9.3 (complete, tag `v1.9.3`)

Docs-only NFR patch on the v1.9 line. Renders both Marp presentation decks
to self-contained HTML (committed to `docs/presentations/`, base64-embedded
images, full S&P Global Energy brand theme) and PPTX (uploaded to the Gitea
release as downloadable attachments). The HTML files are viewable in any
browser and on the git forge — they render the red accent bar, dark
title-slide background, red H1 headings, and Akkurat Pro font stack. README
updated to document HTML as committed artifacts (re-render when Marp source
changes) and PPTX as release attachments (binary, not committed to git).
No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green.

## Patch v1.9.4 (complete, tag `v1.9.4`)

Docs-only NFR patch on the v1.9 line. Two categories of changes:

1. **Presentation slide updates** — title slide redesigned (deck title as H1
   slightly bigger, 'Agentic Cloud Delivery Platform' as H3 subtitle on dark
   background). DX deck: removed Local Reproducibility slide (not beneficial
   for DX narrative), redesigned Safe Promotion Path with side-by-side
   HTML table layout for Approaches A and B, 'an agent' → 'an AI agent' on
   slides 2 and 3, What a Developer Does diagram floated to the right side.
   Running header simplified to just the deck name.

2. **Complete removal of a compliance framework** — all references to a
   specific healthcare compliance framework removed from 25 files
   across the codebase: presentation source files (Marp + full markdown),
   all module READMEs (S3, RDS, ECR, ECS, VPC, IAM, KMS, CloudFront, ALB,
   uptime), top-level README, consumer guide, docs index, module standards.
   Compliance milestone lists now read: GDPR, SOX, SOC2, DORA. All section
   references from that framework removed from compliance annotations.
   Rendered HTML decks re-generated from updated Marp source.

No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green. PPTX files uploaded to Gitea release.

## Patch v1.9.5 (complete, tag `v1.9.5`)

Docs-only NFR patch on the v1.9 line. 9 requirements implemented:

1. DX closing slide strengthened with 'Infrastructure as a utility, not a
   craft' bullet — conveys the full vision (infrastructure consumed, not
   maintained; platform compounds value over time).
2. PW Problem slide: 'moving a merged change' → 'promoting a change'.
3. PW Problem slide: added 'Red tape' and 'Scalability without increasing
   headcount' bullets (4 frictions, not 2).
4. PW Roadmap slide: redesigned with side-by-side HTML table layout
   (Testing | Planned), 16px font, no overflow.
5. PW deck: new slide 'What This Platform Is — and Isn't' after North Star
   (sovereign boundary, infrastructure as utility, 4 anti-goals). PW deck
   now 16 slides.
6. Maturity nomenclature: 'Available today'/'shipped' → 'Testing' across
   both decks + source markdown. New .testing badge (blue/teal). The
   platform has 0 consumer adoption — 'shipped' was inaccurate.
7. Global: 'substrate' → 'engine' across entire project (88 matches, 30+
   files including .ciagent/, docs/, modules/, adapters/, schemas/, code).
8. Presentation files only: 'forge' → 'VCS' (6 occurrences in 4 files).
   'forge' retained in all technical docs and code.
9. New .agentic badge (purple/violet) appended to agentic features in both
   decks: confidence signal, autonomous dev, pattern recognition, dynamic
   module creation, citizen developer surface, auto-promotion.

Also: Change Request ID format changed from 'CR-2026-001' to 'CHG0678912'
across presentation files, consumer guide, and test fixtures.

No code changes (test fixture strings only); 494 tests pass; `run_ci.sh` +
`run_platform.sh --check-only` green. PPTX files uploaded to Gitea release.

## Patch v1.9.6 (complete, tag `v1.9.6`)

Docs-only NFR patch on the v1.9 line. Both Marp presentation decks
consolidated to 10 high-impact slides each — every slide high-impact, fluff
eliminated.

**How The Platform Works (16 → 10):**
- Merged Problem + North Star + What It Is/Isn't → 1 slide (4 frictions →
  North Star → 3 success criteria → 2 anti-goals)
- Merged Policy & Security + Secure by Default → 'Security by Construction'
- Merged Immutable Audit + Human-in-the-Loop → 'Accountability & Audit'
- Folded Observability, Platform-Managed Environments, Portability into
  existing slides as bullets
- Added 'The Vision Realized' closing slide

**The Developer Experience (15 → 10):**
- Merged What Dev Does + Contract + No Platform Code → 'The Contract — The
  Entire Consumer Surface'
- Merged Instant Feedback + Deploy Outputs → 'The Developer Feedback Loop'
- Merged Safe Promotion Path + Rising Bar → 1 slide
- Cut Citizen Developer Experience standalone (mentioned on slides 2 + 10)
- Kept Versioned Releases, Friendly Onboarding, Safe Decommission

**Also:** Removed '5-line YAML' claim from both decks (credibility — complex
stacks require more lines). Source markdown files unchanged (remain complete
reference with speaker notes for all original slides).

No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green. PPTX files uploaded to Gitea release.

## Patch v1.9.7 (complete, tag `v1.9.7`)

Docs-only NFR patch on the v1.9 line. Created two talking points markdown
files — one per deck — distilling the source of truth (speaker notes +
content) into presenter-ready cues indexed by the Marp deck's 10-slide
structure. Each file has one section per Marp slide with 3-6 talking point
bullets (punchy, actionable cues) + a key takeaway per slide. The talking
points are the middle layer between the source of truth (full detail) and
the Marp deck (what the audience sees). README updated from 3-step to 4-step
process (added Step 4: talking points), with updated diagram, directory
layout, checklist, and decks table.

No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green.

## Patch v1.9.8 (complete, tag `v1.9.8`)

Docs-only NFR patch on the v1.9 line. Major presentation rework based on
leadership feedback. 6 new mermaid diagrams created and rendered to PNG:
scope boundary (x2 — one per deck, showing upstream → contract → ACDL →
AWS), confidence signal (6 inputs → weighted sum → threshold gate →
proceed/halt), attestation flow (deploy → gate → approver → evidence),
promotion journey (dev → qa → prod → dr with rising thresholds), and road
to the North Star (phased timeline v1.0 → v1.9 → v1.10 → v2.0 → North Star).

Both Marp decks restructured to 10 main + 6 appendix slides (PW: 17 total,
DX: 16 total). Key changes:

1. NEW scope slide ("Where ACDL Sits in Your World") clarifying ACDL is
   infrastructure only. Upstream is anything (IDE, agentic SDLC, citizen
   dev vibe coding). ACDL provisions and governs AWS resources; application
   deployment is upstream.
2. Contract examples fixed: `image:` field removed, replaced with
   infrastructure inputs (cpu, memory, desired_count, port).
3. Story arc: every slide has an italic story beat line connecting the
   narrative progression.
4. Confidence signal diagram added (slide 7) showing 6 inputs → score →
   gate. Clarified: manually tuned weights, observable inputs, auditable
   breakdown.
5. Attestation flow diagram added (slide 9) showing deploy → gate →
   approver reviews → attestation recorded → evidence. QA clarification
   added: QA attests to infrastructure readiness (contract + Terraform plan
   + evidence), not application code.
6. QA attestation reclassified: "Design tested" → "Planned". Dev autonomous
   = Testing. qa/prod/dr attestation = Planned.
7. DX deck: Two Consumer Surfaces slide replaced by scope boundary slide
   showing both consumer paths. Promotion journey diagram added.
8. Rising bar table annotated: dev=Testing, qa/prod/dr=Planned.
9. Appendix (6 slides per deck): TOC, detail-heavy slides moved from main
   deck, Road to the North Star phased timeline (annotated "proposed
   phasing, not formally planned"), full Testing vs. Planned inventory,
   glossary.
10. Old two-surfaces diagram replaced by scope boundary diagram.

Source markdown, talking points, and README all updated to mirror the new
structure. Also includes scripts/sync_to_nova.sh (manual-only "2nd release"
into ~/nova — a separate GitLab consumer-facing repo with its own history;
domain-based conventional commits, never triggered by CI; REQ-229).

No code changes; 494 tests pass; `run_ci.sh` + `run_platform.sh --check-only`
green. PPTX files uploaded to Gitea release.

## Objective for Milestone v1.18 (active — Citizen Developer & Production-Grade Guidance)

v1.18 advances Nova from a platform that governs infrastructure delivery
to one that **instructs the citizen developer on production-grade
engineering** and defines a **clear, machine-checkable contract for what
is acceptable to start**. Five user-directed inputs drive the milestone:

1. **S&P Global theme restoration.** The v1.17 P5 deck rebuild consolidated
   two decks into one unified narrative deck but lost the S&P Global Energy
   brand visual identity (introduced v1.9.2 / P45, commit `ae0cb58`). The
   Marp `style:` block (red-core `#D6002A`, grey-90 `#1B1B1B`, Akkurat Pro
   font, 8px top accent bar) is restored to the unified deck. The mermaid
   `sp-theme.json` survived; only the Marp CSS theme was lost.

2. **PDLC-upstream scope made explicit.** Core Tenet #2 already states the
   platform "does not reach into upstream product/SDLC" and Anti-Goal #1 says
   "Not an upstream development platform." v1.18 promotes this from a
   buried tenet to a dedicated, unmissable scope statement in PROJECT.md +
   `docs/scope.md` + a deck slide: **the PDLC (Product Development
   Lifecycle — product backlog, code authorship, IDE) is upstream of Nova;
   Nova governs infra + delivery only; integration is through the validated
   contract boundary.**

3. **RACI matrix.** A three-role responsibility matrix clarifies who owns
   what: **Citizen Developer** (Responsible for all Functional Requirements
   + User Acceptance Testing, via their AI coding agent / upstream agentic
   SDLC / upstream development platform — the source does not matter as all
   are subject to the same compliance standards), **Platform** (Responsible
   for all NFRs + Infrastructure + QA + Production deployments to cloud),
   **Release Management** (co-owned: QA + SRE attestations required by the
   actual release, performed agentically but overseen & triggered by the
   Citizen Developer). Source of truth in PROJECT.md + `docs/raci.md` + a
   deck slide.

4. **Nova input contract — "what is acceptable to start."** A JSON Schema
   (`schemas/submission-readiness.schema.json`) defines the
   acceptable-to-start gate as a superset *above* contract-schema validity:
   schema-valid contract + required Nova tags + per-env mandatory metadata
   (per W3.E) + declared policy preconditions + (for L3B) `profile:agentic`
   markers + `appSource` pointer. A validator (`core/submission_readiness.py`,
   invoked as `contract_ingestor.py --check-readiness`) returns a structured
   `ReadinessResult` with reason codes. On fail → citizen-developer-facing
   error (not a stack trace); on pass → proceeds to existing ingestion.

5. **Atelier integration — production-grade guidance + agentic validation.**
   Nova consumes `coreci/atelier` (a first-principles docs-as-code
   engineering framework — 8 core principles, 19 domains, 190 P-rules) via
   two surfaces: **skills** (markdown files under `skills/` keyed to Atelier
   domain paths, surfaced to the citizen developer's AI agent, extending the
   BA.A 5-skill catalog) and an **MCP server** (`mcp/atelier/server.py`,
   plugin-registry architecture, stdio transport, vendored Atelier snapshot
   for audit reproducibility) exposing tools for principle-lookup,
   domain-listing, matrix-lookup, and agentic validation against the
   Atelier agent-checklist — validation that goes beyond deterministic
   scanners (Wiz/Checkmarx/Mend) by catching correctness/clarity/simplicity/
   observability gaps.

**Deck automation (cross-cutting):** any phase modifying
`docs/presentations/*-marp.md` or `docs/presentations/assets/` MUST
re-render HTML + PPTX, **commit the PPTX to git** (binary, no LFS), and
attach it to the phase's Gitea release. New scripts:
`scripts/render_deck.sh` (HTML + PPTX render) and
`scripts/attach_release_asset.py` (Gitea release asset upload).

**Milestone type:** Feature (P1 S&P theme restoration + P3 readiness
schema/validator + P5 MCP server are new code/features). Tags run on the
**v1.17.x** patch line (previous minor per branch-strategy): `v1.17.0` (P0)
→ `v1.17.1..v1.17.6` (P1–P6) → `v1.17.7` (P7 final = milestone release).

**Phase count:** 8 (P0 pre-execution + 6 execution + 1 final).

**Hard constraints:**
- DO NOT make anything up (NORTH_STAR.md honesty model).
- The submission-readiness schema is a superset gate above
  `contract.schema.json`, NOT a duplicate — it references but does not
  redefine contract fields.
- The MCP server is plugin-registry extensible (future capabilities drop
  in as new plugin files, no `server.py` edits).
- Atelier is vendored (pinned tag) for audit reproducibility — an agentic
  validation result must be replayable against the exact principles that
  produced it.
- PPTX is a first-class artifact: committed (history) + attached (download)
  — both always, not optional.

## 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; engine-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_hash` chain).
- **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: agentic` marker 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`) referencing
  `l1-s3`.
- **REQ-26:** Terraform adapter compiles the IR to a real `terraform plan`
  against 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 engine-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-microservice` thin-composition + contract schema extended
  for microservice inputs (image, port, env, healthcheck).
- **REQ-33:** `terraform apply` (dev, autonomous) — real provisioning, not
  just `plan`.
- **REQ-34:** Consumer repo `acdl-consumer-microservice` with 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.sh` mirrors the CI pipeline locally (lint →
  test → check-only), exiting 0 with "CI PIPELINE OK".
- **REQ-45:** `scripts/run_platform.sh` streams terraform/checkov output by
  default (with `--quiet` for log-only mode). Both workflows byte-identical.

## Key Decisions (v1.9)

Resolved at the CLARIFY stage (full autonomy — all within locked
constraints or user-directed scope). New v1.9 decisions (numbered
D-080+ to avoid collision with v1.8 research decisions D-073..D-077):

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-080 | New milestone v1.9 (feature); ship tag `v1.9.0`. | v1.8 is complete (audit PASS, tag v1.8.0). The work (design doc updates + interpolation + per-env CI + stubs + P1-1) is a new feature milestone, not v1.8 post-hoc patching. | 5 phases (39–43) in one milestone. |
| D-081 | Interpolation syntax: `${env.<field>}` + `${contract.<field>}` (dotted paths supported, e.g. `${env.state_backend.bucket}`). Expanded by the resolver post-schema-validation, pre-IR-resolution. Fail loud on unresolved tokens (`ValueError`). | Shell-style syntax is familiar, unambiguous, and has no conflict with YAML or the contract schema. The `env` context is the loaded environment onboarding JSON; `contract` is the contract dict. | Phase 40 implements the expansion + environment JSON schema. |
| D-082 | Hybrid per-environment promotion model: (a) per-env contract files AND (b) an `environment` `workflow_call` input on the reusable deploy workflow that overrides the contract's environment at load time. One CI job per environment. | User chose to support both shapes. Per-env contracts let env-specific values differ via interpolation; the env input lets a single contract be promoted without editing. Promotion = running the matching job; no `environment:` field editing. | Phase 41 ships per-env contracts + the env input + caller-workflow docs. |
| D-083 | Audit ledger S3 Object Lock + JWS detached signatures + async worker + DLQ + daily checkpoints **deferred** to a future milestone. | Requires non-offline-testable AWS infra (Object Lock bucket, KMS signing key, SQS DLQ, Lambda worker). The hash-chain + DynamoDB-outbox path remains the v1.9 production audit record. `audit_ledger_design.md` marks this clearly. | Phase 39 updates the design doc; no build-out in v1.9. |
| D-084 | 8-concern attestation matrix: offline-testable concerns (contract NFRs, schema validity, policy pass) run for real; operator-supplied concerns (k6 load test, DR drill, FinOps forecast) accept signed evidence artifacts validated for freshness + schema, failing loud if missing/expired for prod/dr. | The platform cannot run live load tests / DR drills / FinOps forecasts inline. Accepting signed evidence artifacts with freshness + schema validation is the regulatorily-defensible middle ground. | Phase 42 implements `core/attestation_matrix.py`. |
| D-085 | P1-1 closure: adapter ECS/ALB/VPC hardcoded defaults (`desired_count = 1`, `launch_type = "FARGATE"`, `target_type = "ip"`, `load_balancer_type = "application"`, `family = "app"`, `Name = ...`) move into L1 `interface.json` inputs with defaults. The adapter reads inputs (falling back to interface defaults) and is a thin translator. | P1-1 was flagged in the v1.2 review (deferred to v1.3, never implemented). Defaults belong in the L1 interface, not the adapter. | Phase 39 closes P1-1. |
| D-086 | `.ciagent/REVIEW.md` reconstructed at v1.9 complete; v1.3–v1.8 reviews noted as not-persisted (no git-history rewrite). | REVIEW.md still holds v1.2 content — later milestone reviews were not persisted or were overwritten. The v1.9 review overwrites it with current content; a note records the historical gap. | Phase 43 reconstructs REVIEW.md. |
| D-090 | No cap on the v1.1→v1.8 capability re-verification sweep. Fix every advertised capability in-sweep; all must end Verified. | The user rejected a phase cap. Unbounded-risk trade-off accepted for full integrity: decks stay frozen until every advertised capability is Verified. Recorded as a traceable decision, not silent scope creep. | Phase 54 executes the sweep under D-090. |
| D-091 | Add a regression-class VERIFY that re-runs capability checks (not just diff checks), at minimum on milestone completion. | VERIFY is currently diff-scoped (structural defect); 8 NFR-patch phases passed while the platform decayed. Without regression memory the pipeline cannot keep the sweep honest. | Phase 52 implements the regression-class VERIFY. |
| D-092 | Build local emulating adapters (flat-file outbox, local ECS emulator, local S3 state, local Lambda stub) so the platform is fully locally testable without cloud credentials. | Required for the sweep's local tier and for durable regression testing without AWS access. Cloud interactions are emulated with flat files in temp folders + local shell. | Phase 53 builds the local emulating adapters. |
| D-093 | Re-verify every v1.1→v1.8 advertised capability. v1.0 demo excluded as archived/superseded. Headline E2E runs both live-AWS and local-emulator tiers (both must pass); all other capabilities run locally via emulating adapters. | Tiered verification: live for cloud-backed headline, local for the rest. The bar is what an exec could see demonstrated. | Phase 54 executes the re-verification sweep. |
| D-094 | Rewrite PROJECT/ROADMAP/decks to match verified reality; decks unfrozen only after this lands. | Decks were sequenced backwards for 8 phases (polish before re-verify). The honest order is re-verify → rewrite → unfreeze. | Phase 55 rewrites docs/decks to verified reality. |

### CLARIFY auto-resolved parameters (full autonomy)

| Parameter | Value | Rationale |
|---|---|---|
| Per-env `qa.json/prod.json/dr.json` account_id | `000000000000` placeholder + stderr warning at load if account_id is `000000000000` and env ≠ dev | Consistent with `dev.json`; prompts real binding without breaking offline tests. |
| SNS topic for `route_halt_artifact` | Defined in `terraform/platform/main.tf` AND code reads `ACDL_SOD_HALT_TOPIC_ARN` | Consistent with the existing Lambda/KMS/Secrets pattern (Terraform defines, code reads env). |

## Constraints

- **Forge:** Gitea at `https://git.cloudinit.dev`, org `continuous-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.
- **Angine:** Terraform adapter in v1 (the only adapter). L1/L2 are
  engine-agnostic in shape; the adapter is the only engine-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 `acdl` repo exists at the org root. `acdl-contracts` and
  `acdl-evidence` exist from the v1.0 demo and continue as the developer
  surface and the audit-timeline host respectively.
- `docs/vision.md` and `docs/architecture.md` (v0.2) are the upstream
  vision/architecture sources, pulled from `origin/main` at 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 engine.

## 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. **Extended v1.18 (REQ-221/222):** the BA.A 5-skill catalog is extended with 9 Atelier-derived production-grade engineering skills under `skills/` (api, security, data, testing, observability, errors, devops, infrastructure-as-code, compliance), indexed by `docs/skills.md`. The Atelier skills extend, not replace, the BA.A catalog. |
| 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 (engine- 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 engine 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-credentials` action on act_runner** — if
  unavailable, fall back to `aws sts assume-role-with-web-identity` from a
  step.

## Objective for Milestone v1.14 (active — NFR Refinement)

Bug fixes, security posture improvements, stub/missing-functionality
identification + implementation, and documentation + NFR refinement across
the entire codebase. **No new features.** This is an NFR milestone — the
final phase's patch IS the deliverable (no separate milestone tag).

The v1.13 line shipped the presentation polish + config.json schema
migration + badge cleanup. The v1.11/v1.12 multi-persona reviews left a
backlog of P1/P2 findings (5 P1 + 4 P2 open in `REVIEW.md`), the codebase
has 6+ swallowed-error sites and 15+ hardcoded account-ID references, 7
scripts have no test coverage, the regression gate's CAP-017..022 evidence
is an offline proxy, ARCHITECTURE.md has no v1.11–v1.13 addendum, and
consumer-facing docs reference stale `@v1.6`–`@v1.9` workflow tags. v1.14
clears all of it in a 20-phase sweep.

**Scope axes (user-directed, 2026-07-29):**
1. **Bug fixes** — clear all open P1/P2 findings from the v1.11 review
   (adapter dedup silent drop, static-assets unwired inputs, lifecycle
   script vestigial args, regression-gate offline-proxy evidence, ALB
   name_prefix, missing unit tests).
2. **Security posture** — narrow 6 swallowed-`except` sites; externalize
   the hardcoded account ID; scope 6 `Resource: "*"` IAM statements to
   `acdl-*` ARNs; harden contract-ingestor identity validation; add
   `additionalProperties: false` + format validation to schemas; add
   credential-pattern catch-all to `.gitignore`.
3. **Stub / missing functionality** — resolve the discarded
   `--kube-version` flag in the Kyverno adapter; clean up orphan bytecode
   + dead config.
4. **Documentation + NFR refinement** — ARCHITECTURE.md v1.11–v1.14
   addenda; bump stale `@v1.6–1.9` → `@v1.13` across 12+ sites; sync
   decks/COST.md/GRILL G-005+G-008/IAM_POLICY.md; reconcile
   modules/STANDARDS.md; record the D-083 audit-ledger deferral
   explicitly.
5. **Test coverage** — add unit tests for 7 untested scripts + the
   adapter dedup/remote-state-key behaviors.

**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).

**Milestone type:** NFR (all phases are fix/test/docs/chore/refactor).
**Ship tag:** final phase patch on the v1.13.x line IS the release.

## Milestone v1.14 Phases

| Phase | Name | Goal |
|-------|------|------|
| 0 | pre-execution | SPECIFY → CLARIFY → RESEARCH → IDEATE → PLAN → GRILL. Establish v1.14 milestone shell; ideate finds the concrete requirements; plan decomposes into 20 execution phases. |
| 1–20 | execution | 20 phases of bug fixes, security hardening, stub resolution, test coverage, docs sync (wave-ordered). See ROADMAP.md §v1.14 for the phase list. |
| 21 | final-review-ship | Multi-persona review + audit + milestone ship (merge to main, tag final patch = release). |

## Key Decisions (v1.14)

Resolved at the CLARIFY stage (full autonomy — all within locked
constraints or user-directed scope). New v1.14 decisions (numbered
D-095+ to continue from v1.10's D-094):

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-095 | v1.14 is an NFR milestone (no feat phases); final patch IS the release. | User directed: "No new features, only bug fixes, security posture improvements, identifying stub and implement missing/lacking functionality, refine all documentation + NFRs." NFR model per branch-strategy.md:181 — progressive patches, final patch = deliverable, no separate milestone tag. | 20 execution phases (P1–P20) + 1 final (P21). Tags v1.13.3 → v1.13.24. |
| D-096 | D-083 (audit ledger JWS + S3 Object Lock + SQS DLQ + async worker) remains deferred; documented explicitly in ARCHITECTURE.md (P19), not implemented. | User chose "Skip — keep D-083 deferred." Requires non-offline-testable AWS infra (Object Lock bucket, KMS signing key, SQS). The hash-chain + DynamoDB outbox remains the v1.14 audit record. | P14 (originally JWS) replaced with orphan-artifact-and-dead-config-cleanup. D-083 deferral recorded in P19. |
| D-097 | 20 execution phases is the target (not consolidated to ~10). | User chose "20 phases as planned." Finer ship granularity; longer milestone. G-007 (per-phase regression) accepted — regression gate runs at milestone COMPLETE. | 20 phases + 1 final = 21-phase milestone. |
| D-098 | Wave ordering: W1 (P1–P6 bug fixes), W2 (P7–P12 security), W3 (P13–P17 stub/test/CI/hygiene), W4 (P18–P20 standards/docs/VPC). | Prerequisite chains: P2 depends on P1 (composition needs correct dedup); P9 depends on P8 (IAM ARNs reference externalized account ID); P15 depends on P7 (script tests benefit from hardened errors); P17 depends on P14 (both touch config.json); P19 lands last (reflects all prior phases). | 4 sequential waves; phases within a wave are independent (parallelizable when parallelization.enabled=true). |
| D-099 | `--ideate` flag: run the IDEATE stage between RESEARCH and PLAN (per ideate.md:218). The ideation tiers mine the 50 `partial:` + 16 `lessons:` + 3 `escalation:` + 16 `decisions:` git-native signals to validate/enrich the 20-phase scope. | User invoked with `--ideate`. The v1.14 scope is already user-directed (20 phases defined), so IDEATE acts as validation + enrichment, not scope discovery. Accepted ideas become IDEATE-NN IDs appended to REQUIREMENTS.md. | IDEATE stage runs; interactive validation gate (accept/skip/modify). |
| D-100 | Accept all 20 ideation findings as the v1.14 requirement set (REQ-135..REQ-154). | User accepted all 20 at the interactive validation gate. Mechanical + backend-enriched tiers confirmed the user-directed scope. | 20 REQs locked; PLAN.md formalizes the task decomposition. |
| D-101 | E-001 (P8 state-bucket continuity residual risk) auto-resolved at full autonomy: accept the residual risk. G-102's binding mitigation (fallback bound to live account ID + workflow env wiring) is the control. The lifecycle pipeline defaults to plan-only (REQ-134) — full-mode runs are workflow_dispatch only, reducing the accident surface. | Grill escalation E-001 (confidence 0.55) re-exposes the v1.11 4-VPC root cause. At full autonomy, auto-decide with assumption logging. The residual risk (misconfigured env at live-run time) is runtime-dependent, not plan-resolvable. If the user prefers zero residual risk, direct that P8 exclude the state-bucket name from externalization entirely. | E-001 resolved; G-102 binding decision enforced in PLAN.md P8. |

---

## Milestone v1.15 — Nova (Rebrand)

**Active milestone.** A full rebrand from ACDL → Nova across docs,
decks, code, configs, CI, env var prefixes, the consumer contract path,
SSM parameter paths, AWS tag keys, and AWS resource names — with a
staged infrastructure migration to avoid breakage.

**Milestone type:** Major (breaking — consumer-facing path, env var
prefixes, SSM path, AWS tag keys, and AWS resource names all change).
Tags run on the v1.15.x minor line: `v1.15.0` (P0) → `v1.15.4` (P5
final = milestone release). (G-104 binding: Major milestones tag on
their own minor line, not the previous minor's patch line.)

**In scope (v1.15):**
- Prose/decks/mermaid/pyproject/release-title rebrand (P1).
- Code identifiers, env var prefixes (`ACDL_*`→`NOVA_*` dual-read),
  consumer path (`.acdl/`→`.nova/`) (P2).
- SSM path (`/acdl/`→`/nova/`) + AWS tag keys (`acdl:*`→`nova:*` ABAC)
  (P3).
- AWS resource names (`acdl-*`→`nova-*`) with migration (P4).
- Final review + audit + remove dual-read fallback + milestone ship (P5).

**Out of scope (v1.15):**
- Renaming the real Gitea org/repo or GitHub org `acdl` (config stays
  `acdl`; doc URLs updated to `nova` for prose only).
- Renaming the S&P Global Energy visual theme (`sp-theme.json`) —
  client branding.
- Past Gitea release titles — only future releases use `Nova vX.Y.Z`.
- Git branch/tag naming — no brand name present.

**Milestone type:** Major (breaking). **Ship tag:** final phase patch
on the v1.15.x minor line IS the release (`v1.15.4`).

## Milestone v1.15 Phases

| Phase | Name | Goal |
|-------|------|------|
| 0 | pre-execution | SPECIFY → CLARIFY → RESEARCH → IDEATE → PLAN → GRILL. Establish v1.15-Nova milestone shell; ideation finds the 10 Nova requirements (REQ-155..164); plan decomposes into 4 execution phases. |
| 1 | docs-decks-prose | Rebrand all prose/decks/mermaid/pyproject/release-titles ACDL→Nova; add Nova tagline; ship consumer migration guide. |
| 2 | code-envvars-consumer-path | Rename acdl_tagging.py→nova_tagging.py; ACDL_*→NOVA_* dual-read; .acdl/→.nova/ contract path. |
| 3 | ssm-tagkeys | SSM /acdl/→/nova/ + AWS tag keys acdl:*→nova:* with parallel-tag ABAC migration. |
| 4 | aws-resource-migration | Rename all acdl-* AWS resources → nova-* with staged migration + runbook. |
| 5 | final-review-ship | Multi-persona review + audit + remove dual-read fallback + milestone ship (merge to main, tag final patch = release). |

## Key Decisions (v1.15)

Resolved at the CLARIFY stage (full autonomy — all within locked
constraints or user-directed scope). New v1.15 decisions (numbered
D-102+ to continue from v1.14's D-101). The high-judgment scope
decisions (D-102..D-107) were locked in by the user during the planning
conversation before execution; D-108..D-112 resolved at CLARIFY.

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-102 | AWS resource names: full rename with migration. | User chose "Full rename with migration." All `acdl-*` AWS resources → `nova-*` including state bucket migration, DynamoDB data migration, IAM re-bootstrap, ECR re-push. Accepts downtime + multi-phase migration. | P4 implements the staged migration + rollback runbook. |
| D-103 | Env var prefixes: full rename to `NOVA_*`. | User chose "Full rename to `NOVA_*`." All 21 `ACDL_*` prefixes → `NOVA_*` including `.env.secrets` (key names only, values stay) + Gitea secrets. | P2 renames + implements dual-read fallback; P5 removes fallback. |
| D-104 | Tag keys + SSM path + consumer path: full rename all three. | User chose "Full rename all three." AWS tag keys `acdl:*`→`nova:*` (ABAC re-scope), SSM path `/acdl/`→`/nova/` (param migration), consumer path `.acdl/`→`.nova/`. | P2 (consumer path) + P3 (SSM + tag keys) implement. |
| D-105 | External URLs: illustrative — update them. | User chose "URLs are illustrative — update them." Doc URLs (`github.com/acdl/...`, `git.cloudinit.dev/.../acdl*`) → `nova` for prose consistency. Real Gitea repo name (`release.gitea.repo`) stays `acdl`. | P1 updates doc URLs; config.json unchanged. |
| D-106 | Nova tagline: add alongside existing North Star. | User chose "Add Nova tagline alongside existing North Star." Tagline "The New Dawn of DevSecOps — security as a seamless enabler of fast deployments" added to README header, deck title slides, `docs/vision.md`. Existing "consumers declare intent" framing retained. | P1 adds tagline; no prose removed. |
| D-107 | S&P visual theme: leave untouched. | User chose "Leave S&P theme untouched." `sp-theme.json` (#D6002A red, Akkurat Pro) is client branding, not the Nova product brand. Only product-brand text (ACDL→Nova) changes in decks. | P1 edits deck text only; theme/CSS unchanged. |
| D-108 | Dual-read fallback centralized in a new `core/env.py` helper. | No centralized env loader exists today (env vars read via scattered `os.environ.get("ACDL_*")`). A new `core/env.py` `get_env(name)` helper reads `NOVA_X` then falls back to `ACDL_X`, returning `None` if neither. All call sites migrate to the helper in P2; P5 removes the fallback. | P2 creates `core/env.py` + migrates call sites; P5 removes fallback. |
| D-109 | Checkov custom rule `nova_tagging.py` warns during P2, hard-fails from P3. | During P2 (before tag-key migration), existing resources still carry `acdl:*` tags — a hard fail would break the regression gate. P2 rule warns on `acdl:*`; P3 (after parallel-tag + ABAC swap) hard-fails on `acdl:*` and enforces `nova:*`. | P2: warn mode; P3: hard mode. |
| D-110 | Schema `$id` URLs (`https://acdl.cloudinit.dev/schemas/...`) → `https://nova.cloudinit.dev/schemas/...`. | These are illustrative schema identifiers (no real DNS resolution required for JSON-schema validation). Renamed for brand consistency in P1. Existing `$id` values in test fixtures updated. | P1 renames schema `$id` + fixture references. |
| D-111 | Lambda env-var defaults (`CONTRACTS_TABLE` default `"acdl-contracts"`, etc.) → `nova-contracts`. | `core/lambda/contract_ingestor.py` has hardcoded `acdl-*` default table names. These become `nova-*` in P4 (resource migration). P2 changes the env-var name (`ACDL_*`→`NOVA_*`); P4 changes the default values to `nova-*`. | P4 updates Lambda defaults. |
| D-112 | `nova` slug: no `project:` prefix on branches (single-project mode). | `config.json` has `projects[]` with one entry (slug `acdl`) but `git.branching_strategy` is `flat` and the established convention since v1.0 is flat branches (no `<slug>/` prefix). Nova rebrand does NOT change the branch prefix convention. Commit `---ci---` blocks use `project: acdl` (the config slug, unchanged). | Branches stay `milestone/v1.15-nova`, `phase/NN-*`; no `acdl/` or `nova/` prefix. |

## Objective for Milestone v1.16 (complete — NFR Simplification, tag `v1.15.26`)

A 20-phase NFR sweep (no new features) themed around five axes the user
directed during ideation: **Simplify without regressions**, **Security**,
**Maintainability**, **User/Developer Experience**, and **No Humans
Onboarding Flow**. The v1.15 rebrand left a fresh layer of residual debt
(stale brand strings, a state-bucket drift, a Kyverno policy that
contradicts the Nova tagging standard, dead code) that this milestone
clears, alongside genuine simplification (dedup helpers, a workflow
generator, file splits) and the first self-service onboarding request
path (request-path only; real AWS account provisioning stays a future
feature).

**Milestone type:** NFR (all phases fix/chore/docs/refactor/test). The
final phase's patch IS the deliverable — no separate milestone tag. Tags
run on the v1.15.x line: `v1.15.5` (P0) → `v1.15.6..v1.15.25` (P1–P20) →
`v1.15.26` (P21 final = milestone release).

**Wave ordering:**
- Wave 1 (P1–P4): correctness + brand regression fixes — P1 first
  (state-bucket drift + Kyverno label contradiction are the highest-
  severity findings, both correctness regressions left by the rebrand).
- Wave 2 (P5–P9): simplify without regressions — P5 before P6/P9
  (regression-verify dedup is independent); P8 changes the workflow test.
- Wave 3 (P10–P14): security + maintainability — P10 before P11
  (identity enforcement before payload validation); P12/P13 independent
  splits.
- Wave 4 (P15–P17): developer experience — independent; P17 last
  (reflects the consolidated path).
- Wave 5 (P18–P20): no-humans onboarding — P18 (schema+Lambda action)
  before P19 (env-file autogen consumes the schema) before P20 (cross-
  account role, offline-proven).

**Verification gates:** the regression gate (D-091) runs after Wave 2
(P9) and at P21 — all 22 capabilities must stay Verified (no
regressions from simplification). A mid-milestone checkpoint runs after
Wave 3 (P14), offline.

## Milestone v1.16 Phases

| Phase | Name | Goal |
|-------|------|------|
| 01 | state-bucket-and-kyverno-rebrand-fix | `adapter.py:117` `acdl-tfstate`→`nova-tfstate`; Kyverno `require-resource-labels.yml` `acdl:*`→`nova:*` labels. Regression-risk fix. |
| 02 | user-facing-acdl-to-nova-sweep | Onboarding msg, alert title/body, PR comments, CI banner, module docstrings → Nova. |
| 03 | dead-code-and-stale-prefix-cleanup | Dead `ACDL_ENVIRONMENT_OVERRIDE` export; stale dual-read comments; `acdl_*` temp prefixes → `nova_*`. |
| 04 | migrate-ssm-except-narrowing | `migrate_ssm_paths.py` `except Exception`→`ParameterNotFound`. |
| 05 | regression-verify-dedup | Extract shared live-plan/resolver/lifecycle-resolve helpers (~70 lines saved). |
| 06 | run-platform-deadcode-and-hitl-fn | Remove dead export; extract `run_hitl_gate()` shell fn; drop hardcoded UUID/`v18` stamp. |
| 07 | contract-resolver-envloader-and-kind | Import env loader from environment_check; add `kind` field to registry; replace `is_l2` heuristic. |
| 08 | workflow-generator-dedup | `scripts/sync_workflows.py` (one source → both dirs); replace byte-identity test with generator-output test. |
| 09 | run-platform-split | Extract decommission + uptime blocks into `scripts/run_decommission.sh` + `scripts/run_uptime.sh`. |
| 10 | contract-ingestor-defense-in-depth | Fail closed on missing IAM identity; derive env enum from `core/environments/` dir. |
| 11 | contract-ingestor-payload-validation | Contract blob size cap + schema validation; consistent error/stackTrace caps. |
| 12 | split-contract-resolver | 638 lines → resolve / decommission-transform / cli modules. |
| 13 | split-regression-verify | 670 lines → capability checks / live-plan helpers / cli modules. |
| 14 | schema-driven-outputs-and-cache | `SAFE_OUTPUT_NAMES` from interface.json; cache loaded schemas in resolver. |
| 15 | run-platform-help-and-flags-doc | Real `--help`; document `--deploy-uptime`; surface `--local` in README. |
| 16 | workflows-readme-catalog | `.github/workflows/README.md` — triggers, inputs, secrets, reusable-workflow contracts. |
| 17 | getting-started-consolidation | Single getting-started section: offline happy path first, AWS path second. |
| 18 | onboarding-schema-and-lambda-action | `schemas/onboarding.schema.json` + `onboard_consumer` action → CMDB row pending grant. |
| 19 | onboarding-envfile-autogen | `core/onboarding.py` generates `<env>.json` from a request + emits a PR; rebrand onboarding message. |
| 20 | cross-account-role-automation-offline | Terraform for consumer deploy-role + `nova:owner` ABAC tag (offline-proven only). |
| 21 | final-review-ship | Review + audit + milestone ship `v1.15.26` + merge to main. |

Milestone COMPLETE gate: review → ship `v1.15.26` (NFR milestone; final
patch IS the release) → audit.

## Key Decisions (v1.16)

Resolved at the CLARIFY stage (full autonomy — all within locked
constraints or user-directed scope). New v1.16 decisions numbered D-113+
to continue from v1.15's D-112. The four high-judgment scope decisions
(D-113..D-116) were locked in by the user during the ideation planning
conversation; D-117..D-119 resolved at CLARIFY.

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-113 | Onboarding scope = request-path only (NFR-shaped). | User chose "Request-path only." Full self-service AWS account/network/state provisioning is a feature (creates real cloud resources), not an NFR. v1.16 removes the human handoff from the *request* step (schema + Lambda action + env-file autogen + ABAC grant hook); real AWS account creation stays a future feature milestone. | P18–P20 implement the request path; real provisioning deferred. |
| D-114 | Cross-account Terraform = offline-proven only. | User chose "Offline-proven only." P20 Terraform for the consumer deploy-role + ABAC tag is authored + `terraform validate` + `--check-only` only; no live apply (consistent with `NOVA_LIFECYCLE_MODE=plan` default). No new AWS resources created in this NFR milestone. | P20 validates offline; live apply deferred. |
| D-115 | Workflow dedup = generator (not status quo). | User chose "Generator." `scripts/sync_workflows.py` writes one source → both `.gitea/`+`.github/` dirs; the byte-identity test in `test_pipeline_contract.py` is replaced with a "generated outputs match committed files" test. Removes ~20 KB manual-sync risk. | P8 implements the generator + test swap. |
| D-116 | Drift fixes = P1 of v1.16 (not a hotfix to main). | User chose "P1 of v1.16." The state-bucket drift (`adapter.py:117`) and Kyverno label contradiction are correctness regressions but latent in plan-only mode (no live apply in the default path), so they are not an active outage. Fixing them as P1 keeps the milestone self-contained. | P1 fixes both; no hotfix to main. |
| D-117 | v1.14 NFR categories are NOT re-proposed. | v1.14 already swept over-broad excepts (REQ-141), hardcoded account-ID (REQ-142), IAM `Resource:"*"` scoping (REQ-143), contractId/env validation (REQ-144), `.gitignore` catch-all (REQ-146), `--kube-version` removal (REQ-147), orphan cleanup (REQ-148), `set -euo pipefail` parity (REQ-150). v1.16 finds NEW residual signals (the v1.15 rebrand left a fresh debt layer) and does not duplicate completed work. | Wave 1–5 target only fresh debt. |
| D-118 | Regression gate (D-091) gates Wave 2 completion and P21. | "Simplify without regressions" is only credible if the regression gate runs after the simplification wave. The gate runs after P9 (Wave 2 done) and at P21 (milestone complete); any non-Verified capability halts W3. Mid-milestone checkpoint after P14 (offline). | P9 + P21 run the gate; P14 checkpoint. |
| D-119 | `onboard_consumer` action stores a CMDB row pending grant (not auto-provisions). | The request-path-only scope (D-113) means the Lambda accepts an onboarding request and writes a `pending` row to `nova-contracts` (or a new `nova-onboarding` partition key); the platform automation that grants the ABAC role is the P20 Terraform (offline-proven). No AWS resources are created by the Lambda action itself. | P18 writes the pending row; P20 proves the grant Terraform offline. |

## Objective for Milestone v1.17 (active — Strategic Direction, Leadership Metrics & Unified Story)

**Milestone type:** Feature (P1–P3 feat; P4 docs; P5 docs+test; P6 test;
P7 review+audit+ship). Tags on the v1.16.x line: `v1.16.0` (P0) →
`v1.16.1..v1.16.7` (P1–P7) → `v1.16.8` (P8 final = milestone release).

**Three pillars:**

- **Pillar A — Strategic Direction.** A durable, PO-authored
  `.ciagent/NORTH_STAR.md` encodes the platform's vision, 4 strategic
  objectives, anti-goals, v1.17 non-goals, 12–18mo targets (with a
  grounding column), and success criteria. CIAgent reads it in every
  future `/ci-run` so the direction survives across milestones. The
  attestation clarification is reflected: human attestation required at
  stage gates (QA for production, SRE for operational readiness); autonomy
  in operations, not in accountability. **v1.21 refinement:** Strategic
  Objective #4 reframed from "default substrate for agentic consumption" to
  integrating with externally owned PDLC/SDLC/Agentic/Citizen Developer
  platforms regardless of source (Nova provides skills + MCP endpoints;
  all prod intents go through the same controls). Objective #2 reworded:
  trust is established by deterministic scripts that calculate a score —
  the platform functions without AI. Objective #3 reworded with four
  CTO-grade metrics (Lead Time PR→Prod, Infrastructure Vulnerability
  Count trend, MTTR, Cloud Spend Reduction) all flowing into PowerBI.
  Anti-goals #1, #4, #5 removed; replaced with "not an upstream
  development platform" and "not a replacement for the PDLC".

- **Pillar B — Leadership Metrics + PowerBI.** Instrument Nova to
  collect, aggregate, and surface leadership-grade metrics that prove the
  "no-humans" autonomous-infrastructure value proposition (reframed in
  v1.21 to "autonomous cloud delivery" — professional framing; the
  platform delivers safe production deployment without an operator in
  the loop of normal operations). Nova-native
  minimal tech (CloudEvents 1.0 envelope, JSONL event log, SQLite cold
  store, hash-chained Decision Ledger via `outbox_writer.py` extension)
  + Infracost for pre-apply cost estimates. Hybrid model: existing
  file-based signals (REGRESSION_REPORT.json, pcr.json, signal.json,
  junit XML) are sources the collector reads and projects into events;
  new emitters emit CloudEvents directly. PowerBI export = CSV/JSON
  views (fact + dimension tables + 8 empty placeholder views for
  deferred metrics). **Hard constraint: DO NOT make anything up.** Every
  metric is `grounded` (cites source file + schema), `derived`
  (documented formula), or `deferred` (cites decision ID — D-096/D-083/
  D-113/D-114/D-119). The 8 deferred metrics: drift detection, GreenOps/
  carbon, predictive/reactive, live CUR reconciliation, multi-cloud,
  red-team MTTR, self-healing velocity, SLA/downtime.

- **Pillar C — Unified Narrative Deck.** Merge the two existing decks
  (`how-the-platform-works` + `the-developer-experience`) into one unified
  narrative deck "Nova — The No-Humans Infrastructure Platform" with a
  single arc: Problem → Vision/Direction (NORTH_STAR) → How it works →
  Proof (metrics) → Roadmap/Ask. The "tell them x3" structure applies at
  deck level AND per slide (each slide opens with what it covers,
  delivers, closes with an explicit "benefit of this stage" callout).
  Fluid transitions between slides. Both old decks retired.

**Key decisions resolved in the planning conversation (D-120+):**

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-120 | Tech stack = Nova-native + Infracost, drift deferred. | The PO's technical-direction document specifies Kafka/Prometheus/ClickHouse/QLDB/OTel — none exist in Nova today. Adopt the PRINCIPLES (events as source of truth, CloudEvents envelope, decision ledger, definition-of-success docs, dashboards-as-projections) but implement with Nova-native minimal tech (JSONL + SQLite + hash-chained ledger). No Kafka/Prometheus/ClickHouse/QLDB. Infracost adopted (runs offline on plan JSON). Drift detection deferred (D-096 + no scheduler). | P1–P3 use Nova-native tech; Infracost in P1; drift deferred. |
| D-121 | Decision Ledger = extend outbox_writer.py → SQLite append-only hash chain. | The direction's #1 priority is the Decision Ledger. Nova already has a hash-chained outbox (outbox_writer.py). Extend it to a SQLite append-only table with hash chain; add ai.decision.made + attestation.recorded events. Honors D-083 (no S3 Object Lock/JWS). | P1 extends outbox_writer; ledger is SQLite hash-chain. |
| D-122 | AI Planner framing = map Nova's real decision points. | The direction assumes an "AI Planner/Reasoner" (planner-v3.2). Nova's actual decision path is confidence_signal + HITL gate. Model ai.decision.made from confidence_signal (decision_id=run_id, chosen_action=band, confidence=score, alternatives=perInput, human_override=HITL block). LLM planner marked future/aspirational. | P1 emits honest decision events; no fabricated LLM. |
| D-123 | Deferred metrics = all 8 (drift, GreenOps, predictive/reactive, live CUR, multi-cloud, red-team MTTR, self-healing, SLA/downtime). | These require live AWS (D-096) or new external systems. Ship as empty PowerBI placeholder views with documented schemas. | P3 ships 8 placeholder views; METRICS.md marks them deferred. |
| D-124 | NORTH_STAR = strategy; tech direction = engineering input. | The PO's technical-direction document is engineering architecture, not strategy. NORTH_STAR.md captures strategic vision/objectives/anti-goals (PO-authored). The tech direction becomes the telemetry reference architecture section in RESEARCH.md/ARCHITECTURE.md, cited by NORTH_STAR's engineering objectives. | P0 writes NORTH_STAR; RESEARCH writes the telemetry reference. |
| D-125 | Events vs files = hybrid. | Existing file-based signals (REGRESSION_REPORT.json, pcr.json, signal.json, junit) stay as files; the collector reads them and emits normalized CloudEvents into JSONL + SQLite. New emitters emit CloudEvents directly. | P2 collector reads files + events. |
| D-126 | Hot/cold split = cold-only SQLite (hot path deferred). | Nova has no live ops dashboard (no live AWS, D-096). The SQLite store is cold-only (batch/historical). The hot path is documented as deferred. | P2 SQLite is cold-only. |
| D-127 | Definition-of-success = per-KPI docs. | The direction's §11 requires a definition-of-success doc for every executive KPI. Adopt this standard; docs live in `docs/metrics/`. | P4 writes per-KPI docs. |
| D-128 | Storage location = metrics/ at repo root. | metrics/runs/ (per-run manifests), metrics/nova_metrics.db (SQLite), metrics/events.jsonl (event log), metrics/powerbi/ (export). | P1–P3 use metrics/ at repo root. |
| D-129 | PowerBI delivery = CSV/JSON files, folder connector. | Nova is offline-first; no live connector to a running service. PowerBI ingests via the folder connector. | P3 emits CSV/JSON to metrics/powerbi/. |
| D-130 | Deck arc = Problem → Vision → How → Proof → Roadmap. | The unified narrative deck's 5-act structure. x3 arc at deck + slide level. Per-slide benefit callouts. Fluid transitions. Both old decks retired. | P5 builds the unified deck; old decks deleted. |
| D-131 | MTTR scope = platform-run MTTR. | The <60s MTTR target refers to platform-run failures (apply.failed → successful retry), not infra-incident MTTR (no incident detection system). Infra-incident MTTR deferred. | P4 grounds platform-run MTTR. |
| D-132 | Attestation instrumentation = emit attestation.recorded events. | The attestation system (hitl_gates.py + attestation_matrix.py + separation_of_duties.py) already exists. Instrument it: emit attestation.recorded events into the Decision Ledger + PowerBI. Attestation Coverage = 100% target grounded from outbox approver_* attributes. | P1 emits attestation events; P4 grounds Attestation Coverage. |

## Key Decisions (v1.18)

Resolved at the CLARIFY stage (full autonomy — all within locked
constraints or user-directed scope). New v1.18 decisions:

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-133 | Submission-readiness validator location = extend `contract_ingestor.py --check-readiness`. | Adding a new CLI binary is unnecessary; the ingestor is the existing entry point for contract submission. The validator is a subcommand that runs before ingestion proceeds. No new binary, no new entry point to maintain. | P3 implements the subcommand; no new CLI binary. |
| D-134 | Deck slide budget = 18 → 21 slides (no act restructure). | The 3 new slides (scope/RACI/atelier) are leadership-relevant and append after the existing 18. The 5-act arc (D-130) is preserved; the new slides are append-only context, not a new act. | P6 appends 3 slides → 21 total. |
| D-135 | Atelier MCP transport = stdio now; HTTP-ready (same server object). | stdio is the local-agent transport (the citizen developer's AI agent spawns the server as a subprocess). The MCP Python SDK v2 supports Streamable HTTP on the same `MCPServer` object, so adding HTTP later is a transport-only change in `server.py`, not a rewrite. | P5 ships stdio; HTTP deferred (documented in README). |
| D-136 | Atelier source = vendor pinned tag under `mcp/atelier/vendor/`. | An agentic validation result is only reproducible if the principles that produced it are pinned. Live-fetch breaks replayability (Atelier `main` drifts). Vendoring matches the v1.16 P15 offline-first precedent and the Nova thesis (provable trust). `mcp/atelier/vendor/VERSION.md` records the pinned tag; `scripts/update_atelier_vendor.sh` is the intentional upgrade path. | P5 vendors Atelier; live-fetch not implemented. |
| D-137 | MCP server language = Python (MCP Python SDK v2, `modelcontextprotocol/python-sdk`). | Nova's `core/` is Python. The MCP Python SDK v2 (23.9k stars, MIT, stable) matches the codebase; type hints become JSON Schema automatically (`@mcp.tool()` decorator). | P5 uses Python SDK v2. |
| D-138 | Skill catalog format = markdown files under `skills/` keyed to Atelier domain paths. | Markdown is the established Nova docs format (Jekyll Pages, 4-step deck process). Each skill file names the Atelier source path, distills the first-principles, links to agent-checklist triggers, and maps to the BA.A catalog. | P4 authors 9 markdown skill files. |
| D-139 | RACI role names = Citizen Developer / Platform / Release Management (co-owned). | User-specified. The 3 roles are the columns of the RACI table. Release Management is co-owned: QA + SRE attestations are required by the actual release (performed agentically, overseen & triggered by the Citizen Developer). | P2 authors the RACI with these 3 roles. |
| D-140 | MCP server extensibility = plugin-registry (`plugins/<name>.py` implementing `register(mcp)`). | Future capabilities (new scanners, policy evaluators, cost tools) drop in as new plugin files — no `server.py` edits. `server.py` scans `plugins/` and calls `register` on each. This is the extensibility insurance: plugins are decoupled from the server entrypoint. | P5 implements the plugin-registry; initial plugins are `principles.py` + `validation.py`. |
| D-141 | PPTX storage = commit binary directly to `docs/presentations/` (no LFS). | Decks are small (~1-5 MiB); git handles binary blobs. LFS requires server-side support (unverified for git.cloudinit.dev) + client config. Committing directly is simplest and works without any repo/server config. Binary diffs are not delta-friendly, but deck changes are infrequent. | P1/P2/P6 commit .pptx directly. |
| D-142 | Deck render trigger = any phase modifying `docs/presentations/*-marp.md` or `docs/presentations/assets/` must re-render HTML + PPTX, commit PPTX, and attach to the Gitea release. | PPTX was previously manual + release-only (not committed). v1.18 makes it a first-class artifact: committed (history) + attached (download), both always, not optional. Automated via `scripts/render_deck.sh` + `scripts/attach_release_asset.py`. | P1/P2/P6 run the render+commit+attach pipeline. |
## Objective for Milestone v1.19 (complete — Nova 2nd-Release Sync)

> **NFR-only chore milestone.** Ships a patch on the v1.18.x line (tag
> `v1.18.0`). Single execution phase. Establishes the manual-only "2nd
> release" pipeline from `~/acdl` (CIAgent-managed source of truth, full audit
> trail) into `~/nova` (GitLab `jonathanchery/nova` — separate repo, separate
> history, consumer / platform-team audience).

### Why

`~/acdl` is the engineering source of truth and carries the full CIAgent
audit trail (`.ciagent/`, milestone branches, `---ci---` blocks, Gitea
releases). Consumers and the platform team should consume a clean,
conventional-commit-shaped tree without the CIAgent plumbing. The old
`scripts/sync_to_gl.sh` mirrored `~/acdl → ~/gl/acdl` with a single
kitchen-sink `chore: sync from source mirror <ts>` commit — wrong audience,
wrong commit standard, wrong repo.

### What

- **`scripts/sync_to_nova.sh`** replaces `scripts/sync_to_gl.sh`.
- **Manual-only gate**: refuses without `--release` / `RELEASE_CONFIRMED=1`
  (exit 2). Never triggerable by CI.
- **Consumer subset only**: excludes `.ciagent/`, `.gitea/`, `.env*`,
  `terraform/`, `demo/`, runtime metrics artifacts, and internal-only scripts
  (the `EXCLUDE_SCRIPTS` list — CIAgent/ops/release plumbing). Keeps
  consumer-facing runbooks (`run_ci.sh`, `run_platform.sh`, etc.) and the
  metrics export views (`metrics/README.md`, `powerbi/`, `TRUST_SNAPSHOT.md`).
- **Destination history protected**: rsync `--filter=P .git` ensures
  `~/nova/.git` is never touched.
- **Domain-based commits**: 13 fixed-order domains (config → core → adapters
  → modules → contracts → schemas → pipelines → mcp → skills → scripts →
  tests → docs → workflows). Each changed domain gets its own conventional
  commit, supplied positionally via repeated `-m` flags. No kitchen-sink.
- **Conventional-commit validation**: regex-enforced
  (`feat|fix|docs|chore|refactor|perf|test|build|ci|style|revert`); bypass via
  `--no-verify-format`.
- **Modes**: `--list-domains` (print order), `--dry-run` (preview rsync +
  messages), `--no-push` (commit without pushing), `-v` (verbose).

### Out of Scope

- **coreci / Atelier review gate on the synced tree** — deferred. A future
  milestone may run a vendored-Atelier review pass before commit and block on
  P0 findings.
- **Tagging releases on the `~/nova` side** — could add `--tag <semver>`
  later.
- **Deleting `~/gl`** — the old mirror dir is left on disk; only the sync
  script targeting it is removed.

### Requirements

- **REQ-229** — `scripts/sync_to_nova.sh` replaces `sync_to_gl.sh` with the
  manual-only, consumer-subset, domain-committed 2nd-release pipeline
  described above. (Phase P1)

### Phase Plan

| Phase | Name | Status |
|-------|------|--------|
| P1 | nova-sync-script | complete |
| P2 | final-review-ship | pending |

### Decisions

| ID | Decision | Rationale | Outcome |
|----|----------|-----------|---------|
| D-143 | 2nd release target = `~/nova` (separate GitLab repo), not `~/gl/acdl`. | `~/nova` is consumer/platform-team-facing with its own history; `~/gl/acdl` was an internal mirror with a kitchen-sink commit standard. Separate audience → separate repo → separate commit standard. | `sync_to_nova.sh` targets `~/nova`; `sync_to_gl.sh` removed. |
| D-144 | Commit standard for `~/nova` = real conventional commits per domain (not the `---ci---` audit blocks used in `~/acdl`). | `~/acdl` commits carry CIAgent audit metadata (`---ci---` blocks) for the ciagent auditing workflow; that's noise for platform consumers. `~/nova` gets clean `feat/fix/docs/chore(scope): subject` commits grouped by domain. | Script validates conventional format; domain-based commits via positional `-m`. |
| D-145 | Trigger = manual-only (`--release` / `RELEASE_CONFIRMED=1`). | The 2nd release is a deliberate human action, not a CI side-effect. The gate guarantees it can never fire from Gitea Actions, GitHub Actions, or accidental invocation. | Script exits 2 without `--release`. |
| D-146 | Domain grouping = 13 fixed-order domains by path prefix; messages map positionally over CHANGED domains only. | Avoids the kitchen-sink commit; gives `~/nova` a reviewable, conventional history tailored to platform consumers. Positional-over-changed mapping lets the human supply exactly the messages needed, in domain order, without padding for unchanged domains. | `--list-domains` prints order; `--dry-run` previews; count-mismatch errors clearly. |
| D-147 | coreci / Atelier review gate = deferred this milestone. | The vendored Atelier (`mcp/atelier/vendor`) could review the synced tree before commit and block on P0, but that's an additive hardening step, not part of establishing the pipeline. Deferred to a future milestone. | Sync ships consumer contents as-is; no review gate. |

### CLARIFY auto-resolved parameters (full autonomy)

The following ambiguities were identified and auto-resolved at full
autonomy (no human escalation needed — confidence > 0.6 threshold):

1. **Fix scope** — comprehensive (theme CSS + render scripts + mermaid
   re-layout + deck content + tests) vs. minimal. **Resolved: comprehensive.**
   The root cause spans all four layers; a theme-only fix would leave
   the extreme-aspect-ratio diagrams and the stale `render_deck.sh`
   unfixed. Confidence: 0.95.

2. **Pipeline depth** — full pipeline (SPECIFY→CLARIFY→RESEARCH→PLAN→
   GRILL→EXECUTE→VERIFY→SHIP) vs. lighter path. **Resolved: full pipeline.**
   This is a new milestone (v1.22); the full pipeline ensures the plan
   is grilled and the audit trail is complete. Confidence: 0.9.

3. **Mermaid diagram fixes** — re-layout to LR + re-render vs. CSS-only
   fix. **Resolved: re-layout to LR + re-render at 2x transparent.**
   The `telemetry-live-ops.mmd` uses `flowchart TB` (produced a 1024×1628
   PNG — aspect 0.63); the README (line 168) explicitly says to use
   horizontal layouts for wide diagrams. CSS-only cannot fix the aspect
   ratio. Confidence: 0.95.

4. **`render_deck.sh` disposition** — fix (add `--theme`) vs. delete.
   **Resolved: delete.** The README already documents `render_slides.sh`
   as canonical; `render_deck.sh` is unreferenced by the build-commands
   section and is a footgun (produces unthemed output). Confidence: 0.9.

5. **Slide count change** — keep 18 main + 1 appendix vs. split
   overflowing slides. **Resolved: split slides 3 and 8** (18 → 20 main
   + 1 appendix). The `test_marp_deck_slide_count` test + README
   convention are updated to match. Confidence: 0.85.

No human escalation. All decisions logged with confidence scores above
the 0.6 threshold.

## Objective for Milestone v1.22 (active — Nova Deck Layout Fix)

v1.22 fixes the systemic layout/formatting problems in the Nova
presentation deck that made every slide look "out of whack" after the
v1.21 P5 re-render. A full investigation determined the root cause is
**not a P5 regression** — the `nova-sp-theme.css` has had zero `section`
padding since it was authored (it declares `/* @theme nova-sp */` as a
comment, not the `@theme` directive, and does not `@import` Marp's
default theme, so Marp's default `section { padding: 56px 64px }` never
applies). Combined with `overflow:hidden` (silent clip), a blunt
`img { max-height: 320px }` rule, header+footer chrome on every slide,
and two new P5 diagrams with extreme aspect ratios (13.52× and 0.63×),
8 of 19 slides overflow and the rest look jammed against the edges.

This milestone is a **comprehensive fix** across four layers: (1) the
theme CSS (padding, overflow handling, aspect-ratio-aware image rules,
title-slide chrome suppression, paragraph/list/table spacing); (2) the
render scripts (delete the stale unthemed `render_deck.sh`, pin
marp-cli/mermaid-cli versions, add 2x scale + transparent bg to
mermaid); (3) the two problematic mermaid diagrams (re-layout to LR +
2-row wrap); (4) the deck content (trim/split the 8 overflowing slides,
remove the redundant `header:` from frontmatter). It also adds the
**layout/aspect-ratio/theme-structural tests** that were missing — the
gap that let this regression through undetected.

**Milestone type:** NFR (all phases are fix/docs/test — no feat/breaking).
Tags run on the **v1.21.x** patch line (previous minor per
branch-strategy): `v1.21.0` (P0) → `v1.21.1..v1.21.5` (P1–P5) →
`v1.21.6` (P6 final = milestone release).

**Phase count:** 7 (P0 pre-execution + 5 execution + 1 final).

**Wave ordering:**
- Wave 1 (P1 + P2, parallel): theme CSS + render scripts — no
  interdependency. P1 establishes the padding/overflow/image budget that
  P4's content trimming relies on; P2 fixes the render pipeline that P3's
  PNG re-render depends on.
- Wave 2 (P3 + P4, parallel): mermaid re-layout + deck content. P3
  depends on P2 (2x scale flag); P4 depends on P1 (padding budget).
- Wave 3 (P5): re-render HTML + PPTX + add tests. Depends on all above.
- Wave 4 (P6): final review + audit + milestone ship.

**Hard constraints:**
- DO NOT change the deck narrative or the 4-beat arc (Problem → Solution
  → Proof → Roadmap + Ask) — only fix layout/formatting.
- DO NOT re-introduce badges, version strings, or internal citations
  (D-###/REQ-###/.py paths) that v1.21 removed.
- The slide count may change from 18 main + 1 appendix to 20 main + 1
  appendix (splitting slides 3 and 8 to relieve overflow). The
  `test_marp_deck_slide_count` test + README "18 main + 1 appendix"
  convention must be updated to match.
- PPTX remains a first-class committed artifact + release attachment.
- No code changes outside `docs/presentations/`, `scripts/render*.sh`,
  and `tests/test_slides_pipeline.py`.

### Requirements

New requirements REQ-254..REQ-262 — see `REQUIREMENTS.md` §v1.22. Summary:

- **REQ-254:** Theme CSS — add `section` padding + overflow handling.
- **REQ-255:** Theme CSS — aspect-ratio-aware image rules (replace blunt
  `max-height:320px`).
- **REQ-256:** Theme CSS — title-slide chrome suppression + paragraph/
  list/table spacing tightening.
- **REQ-257:** Render scripts — delete `render_deck.sh` (or fix `--theme`);
  pin marp-cli/mermaid-cli versions.
- **REQ-258:** `render_slides.sh` — add `-s 2 -b transparent` to mermaid-cli
  (README spec).
- **REQ-259:** Re-layout `telemetry-live-ops.mmd` from `flowchart TB` →
  `flowchart LR`; re-render PNG at 2x transparent.
- **REQ-260:** Re-layout `platform-pipeline.mmd` to 2-row subgraph wrap;
  re-render PNG at 2x transparent.
- **REQ-261:** Trim/split 8 overflowing slides (3, 5, 6, 8, 9, 12, 15,
  A1) + remove redundant `header:` from frontmatter.
- **REQ-262:** Re-render HTML + PPTX + add layout/aspect-ratio/theme-
  structural tests.

## v1.23 — Nova Deck Cleanup & Python PPTX

> **Active milestone.** NFR (docs/render/test only; no features).
> Branch: `milestone/v1.23-deck-cleanup-python-pptx`. Tags run on the
> **v1.22.x** patch line: `v1.22.0` (P0) → `v1.22.1..v1.22.5` (P1–P5) →
> `v1.22.6` (P6 final = milestone release).

Driven by user feedback that the deck looked "out of whack" and the
desire to return to the clean, well-formatted style of the old
`the-developer-experience.html`. Investigation revealed the "clean"
reference was itself MARP output (using Marp's built-in `default` theme
+ an inline `style:` block); the current deck's standalone
`nova-sp-theme.css` re-derives all base spacing from scratch and had a
zero-padding bug (fixed in v1.22, but the standalone approach is
fragile). The milestone delivers:

- **Single-document consolidation** — `*-marp.md` becomes the sole
  source of truth; the plain `.md` is deleted; speaker notes + talking
  points are embedded as Marp HTML comments.
- **Clean style restoration** — revert to `theme: default` + inline
  `style:` block (S&P palette); `nova-sp-theme.css` retained as a
  reference, retired from render.
- **Self-contained HTML** — base64-inline all images for
  redistribution.
- **Parallel python-pptx generator** — structured, editable, S&P-themed
  PPTX alongside the MARP image-of-slide PPTX.
- **Targeted word-count trim** + removal of the previously-used loaded scope term.

**Phase count:** 7 (P0 pre-execution + 5 execution + 1 final).

**Hard constraints:**
- DO NOT change the deck narrative or the 4-beat arc (Problem → Solution
  → Proof → Roadmap + Ask) — only trim word count.
- DO NOT re-introduce badges, version strings, or internal citations.
- DO NOT remove MARP — it stays for HTML + PPTX; python-pptx runs in
  parallel.
- `nova-sp-theme.css` is retained (not deleted) as a styling reference.

### Requirements

New requirements REQ-263..REQ-275 — see `REQUIREMENTS.md` §v1.23.
Summary: consolidation (REQ-263,264), style restoration (REQ-265,266,267),
image inlining (REQ-268), python-pptx generator (REQ-269,270), word-count
trim + loaded-scope-term removal (REQ-271,272), CI/tests/README (REQ-273,274,275).

## v1.25 — kyverno-json Unified Policy Engine

> **Active milestone.** Feature milestone (the primary compliance/policy
> tool becomes kyverno-json, implemented behind a swappable adapter).
> Branch: `milestone/v1.25-kyverno-json`. Tags run on the **v1.24.x**
> patch line: `v1.24.0` (P0) → `v1.24.1..v1.24.4` (P1–P4) → `v1.24.5`
> (P5 final = milestone release).

[Nova](https://github.com/kyverno/kyverno-json) `kyverno-json` is a
runtime from the Kyverno ecosystem that applies Kyverno policies to
**any JSON or YAML payload** — not just Kubernetes manifests. This
milestone makes kyverno-json the **primary tool of choice for
compliance / policy checks** in Nova, implemented as an **adapter**
(the `PolicyEngine` protocol) so the platform may one day replace it
with something else (e.g. OPA) without touching the confidence signal
or the pipeline.

### Why

Nova's policy posture today is split across three engines with three
different rule languages and three adapter shapes:

- **Checkov** (`adapters/terraform/policy/checkov_adapter.py`) — the
  runtime scanner over `terraform_plan` JSON; carries the
  `NOVA_TAG_NAMING` custom rule. Imperative YAML+Python rules.
- **Wiz** (`adapters/wiz/wiz_adapter.py`) — security findings from the
  Wiz API; inactive unless credentials are present.
- **Kyverno (K8s)** (`adapters/kyverno/kyverno_adapter.py`) — translates
  Kyverno `PolicyReport` results; **inactive for Terraform-only stacks**
  (the platform emits Terraform, not K8s manifests — D-053).

All three emit the same `schemas/policy_check_result.schema.json` shape
that `core/confidence_signal.py` consumes engine-agnostically. The
*contract* is already right; the *orchestration* is fragmented. There is
no single place where "what Nova considers compliant" is declared —
tagging lives in a Checkov custom rule, public-ingress in Checkov's
`RULE_MAP`, env-transition destroy in `core/env_transition.py`
(imperative Python), and capability regression in
`core/regression_verify.py` (imperative Python). Each is a different
language, each drifts independently, and the K8s Kyverno adapter can't
help because it only speaks to K8s manifests.

`kyverno-json` fixes this: one declarative policy language (Kyverno
policies with JMESPath assertions) that applies to **any** Nova
artifact — the consumer contract, the resolved Stack IR, the
Terraform plan JSON, and even the PolicyCheckResult list itself
(meta-validation). It becomes the **unified orchestrator** of compliance
checks, while Checkov and Wiz remain as raw-finding adapters that feed
*into* kyverno-json meta-policies (so Nova-specific posture rules sit
on top of, not beside, the scanner findings).

### What the milestone delivers

- **Swappable `PolicyEngine` protocol** (`core/policy_engine.py`) — a
  Python Protocol + registry selected from `config.json` (`policy.engine`,
  default `"kyverno-json"`). `KyvernoJsonEngine` implements it (shells
  to the `kyverno-json` CLI); a future `OpaEngine` implements the same
  protocol. The confidence signal and pipeline never import the engine
  directly — they go through the registry.
- **`KyvernoJsonEngine` adapter** (`adapters/kyverno-json/`) —
  `evaluate(payload, policies) -> list[PolicyCheckResult]` translates
  kyverno-json native output to the existing PCR schema. Mirrors the
  Checkov/Wiz adapter pattern. `is_configured()` guard skips gracefully
  when the `kyverno-json` binary is absent (same pattern as the Wiz
  adapter — emits `SKIPPED`, never breaks the pipeline).
- **Policies over all four Nova artifacts** under
  `adapters/kyverno-json/policies/`:
  - `contract/` — consumer contract JSON (shape + env-promotion rules).
  - `stack-ir/` — resolved Target Stack IR (tagging standard,
    public-ingress, encryption-by-default — ports of the v1.0/v1.8
    imperative rules into declarative policies).
  - `plan-json/` — `terraform show -json` output (plaintext secrets,
    IAM wildcards, KMS references — ports of Checkov's `RULE_MAP`).
  - `meta/` — policies over the merged PolicyCheckResult list itself
    (e.g. `block-on-any-critical` — the single declarative source of
    truth for "critical = block", with the existing
    `confidence_signal.py` hard-override kept as defense-in-depth).
- **`run_platform.sh` Step 5 wiring** — Checkov/Wiz still run and emit
  raw PCRs; `KyvernoJsonEngine.evaluate()` runs plan-JSON policies in
  parallel; both PCR lists merge into the confidence signal's `policy`
  input. No change to `core/confidence_signal.py` (it already consumes
  `list[PolicyCheckResult]` engine-agnostically).
- **Regression-gate-as-policy** (P4 — quality improvement from the
  IDEATE pass): the capability checks in
  `core/regression_verify.py` (CAP-013, CAP-023, CAP-024) become
  declarative kyverno-json policies over the capability-inventory JSON
  frontmatter. Capability regression becomes an audit artifact, not
  imperative Python.
- **`policy-engineer` persona** (custom, added in RESEARCH) — owns the
  policy territory; declarative-policies constraint; kyverno-json +
  JMESPath frameworks.

**Phase count:** 6 (P0 pre-execution + 4 execution + 1 final).

**Hard constraints:**
- DO NOT change `schemas/policy_check_result.schema.json` shape in a way
  that breaks existing adapters — the contract is the moat. The
  `engine` enum already includes `"kyverno"` and `"opa"`; v1.25 records
  carry `engine: "kyverno"` (no new enum value — decision in CLARIFY).
- DO NOT remove Checkov or Wiz adapters — they remain as raw-finding
  sources feeding into kyverno-json meta-policies.
- DO NOT remove the `confidence_signal.py` `PENALTY["critical"]: None`
  hard-override — it stays as defense-in-depth behind the declarative
  `block-on-any-critical` meta-policy (decision in CLARIFY).
- DO NOT change `core/confidence_signal.py`'s input contract — it
  already consumes `list[PolicyCheckResult]`; v1.25 only changes *who
  produces* that list, not *what* the list is.
- The platform must function with `kyverno-json` absent — `is_configured()`
  returns false → `SKIPPED` records → confidence signal proceeds (no
  hard dependency that breaks the "platform functions without AI /
  deterministic scripts" tenet — kyverno-json is deterministic, not AI).

### Requirements

New requirements REQ-291..REQ-309 — see `REQUIREMENTS.md` §v1.25.
Summary: engine protocol + registry (REQ-291,292), kyverno-json engine
impl (REQ-293,294), contract policies (REQ-295,296), stack-IR policies
(REQ-297,298,299), plan-JSON policies + pipeline wiring (REQ-300,301,302),
meta-policies (REQ-303), regression-gate policies (REQ-304,305), docs +
adapter README (REQ-306,307), tests (REQ-308,309).

## v1.26 — Live Pilot Estate Activation (active)

> **Active milestone.** Feature milestone — the first real consumer
> estate (a stock exchange on a homegrown PoA blockchain, equities
> only) is activated against live AWS account `581513795199`, lifting
> D-096. Branch: `milestone/v1.26-pilot-activation`. Tags run on the
> **v1.25.x** patch line: `v1.25.0` (P0) → `v1.25.1..v1.25.4` (P1–P4)
> → `v1.25.5` (P5 final = milestone release).
>
> **Multi-project mode:** this milestone introduces a 2nd tracked
> project — `nova-blockchain-exchange` (Gitea repo
> `continuous-intelligence/nova-blockchain-exchange`, local clone
> `/root/nova-blockchain-exchange`). The platform repo (`acdl`) remains
> the platform source; the consumer repo owns the app code +
> `contract.yaml`. Both projects share the v1.26 milestone; `.ciagent/`
> paths are per-project (`.ciagent/acdl/` for platform files — note: the
> platform's existing flat `.ciagent/` files remain the primary set for
> v1.26; the consumer's files live in `.ciagent/nova-blockchain-exchange/`).

### Why

NORTH_STAR.md has three Post-Pilot targets (Touchless Resolution ≥99%,
Human Escalation <0.1%, AI Decision Accuracy ≥99.5%) whose measurement
*pipeline* is grounded but whose *denominator* is zero — no consumer
estate has ever run. v1.25 shipped the swappable policy engine; v1.26
ships the first real consumer. The D-096 deferral (live AWS
re-provisioning) is the single blocker; the pre-run (Workstream A)
re-created the state bucket + outbox table, so the platform components
exist. The milestone grounds the metrics (outcome backfill +
escalation reason), wires the env JSON to the real account, and runs
the pilot end-to-end.

### What the milestone delivers

- **Homegrown PoA blockchain** (`nova-blockchain-exchange` repo) —
  append-only blocks, single validator (pilot), deterministic block
  production, T+1 settlement finality = block commit. Equities only
  (bonds/derivatives/options deferred).
- **Order-matching engine** — limit order book, price-time priority.
- **Settlement service** — T+1, idempotent, finality = block commit.
- **Consumer `contract.yaml`** — declares the exchange stack; validated
  against `schemas/contract.schema.json`; per-env variants.
- **Consumer deploy via `deploy.yml@v1.25`** — the reusable workflow
  applies the contract, runs the policy engine, computes the
  confidence signal, gates qa/prod/dr with HITL attestation, and records
  every decision in the Decision Ledger.
- **3 Post-Pilot metrics grounded** — outcome backfill (AI Decision
  Accuracy), `reason='confidence'` escalation tag (Human Escalation
  Frequency), and the pilot run itself (Touchless Resolution Rate
  denominator activates).
- **3 kyverno-json policies extending v1.25** — settlement-finality
  (securities-specific), pilot-readiness (no placeholder account),
  and the existing meta-policies (block-on-any-critical,
  tagging-rules-agree) apply over the pilot's PCRs.
- **Env-JSON `state_backend` wiring reconciliation** — the adapter
  reads `state_backend.bucket` from the env JSON (closing the wiring
  gap); the env JSONs are bound to account `581513795199`.

### Requirements

New requirements REQ-310..REQ-322 — see
`.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` §v1.26. Summary:
blockchain core (REQ-310), order engine (REQ-311), settlement
(REQ-312), consumer contract (REQ-313), deploy invocation (REQ-314),
settlement-finality policy (REQ-315), pilot regression CAP (REQ-316),
outcome backfill (REQ-317), escalation reason (REQ-318), env-JSON
wiring (REQ-319), pilot-readiness policy (REQ-320), docs (REQ-321),
DynamoDB L1 primitive (REQ-322 — the single platform-side module
build-out; ECS + S3 already exist).

### Hard constraints

- DO NOT lift D-083 (S3 Object Lock/JWS) — stays deferred; the SQLite
  hash-chain + DynamoDB outbox is the pilot's audit record.
- DO NOT lift D-126 (hot path) — cold-only metrics are sufficient for
  the pilot.
- DO NOT add multi-cloud (Azure/GCP) — Nova is AWS-only this milestone.
- DO NOT add ML forecasting — the Predictive/Reactive metric stays
  deferred.
- DO NOT add bonds/derivatives/options — equities only (D-200).
- DO NOT add multi-validator BFT — single validator PoA (D-201).
- The consumer deploy MUST go through `deploy.yml@v1.25` — no direct
  `terraform apply` bypassing the platform's gates.
