From a0a658bc9a8d2bccaf3a12ccfac3c7285e236745 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:11:51 +0000 Subject: [PATCH 01/34] =?UTF-8?q?docs(init):=20validate=20specification=20?= =?UTF-8?q?=E2=80=94=20v1.26=20Live=20Pilot=20Estate=20Activation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: specify projects: [acdl, nova-blockchain-exchange] requirements: [REQ-310..REQ-321] ---/ci--- --- .ciagent/CHECKPOINT.json | 46 ++--- .ciagent/PROJECT.md | 82 ++++++++ .ciagent/ROADMAP.md | 88 +++++++++ .ciagent/config.json | 9 +- .ciagent/nova-blockchain-exchange/PROJECT.md | 92 +++++++++ .../nova-blockchain-exchange/REQUIREMENTS.md | 187 ++++++++++++++++++ .ciagent/nova-blockchain-exchange/ROADMAP.md | 57 ++++++ 7 files changed, 530 insertions(+), 31 deletions(-) create mode 100644 .ciagent/nova-blockchain-exchange/PROJECT.md create mode 100644 .ciagent/nova-blockchain-exchange/REQUIREMENTS.md create mode 100644 .ciagent/nova-blockchain-exchange/ROADMAP.md diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 1f6143f..8d7c736 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,33 +1,21 @@ { - "phase": 5, - "stage": "complete", - "milestone": "v1.25", - "phase_role": "final", + "phase": 0, + "stage": "specify", + "milestone": "v1.26", + "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T18:00:00Z", + "updated_at": "2026-08-12T21:11:00Z", "project": "acdl", - "milestone_complete": true, - "tag_line": "v1.24.x", - "tag": "v1.24.5", - "release": { - "forge": "gitea", - "releases_created": true, - "release_ids": { - "v1.24.0": 640, - "v1.24.1": 641, - "v1.24.2": 642, - "v1.24.3": 643, - "v1.24.4": 644, - "v1.24.5": 645 - }, - "milestone_release_id": 645, - "milestone_release_tag": "v1.24.5" - }, - "requirements": ["REQ-291", "REQ-292", "REQ-293", "REQ-294", "REQ-295", "REQ-296", "REQ-297", "REQ-298", "REQ-299", "REQ-300", "REQ-301", "REQ-302", "REQ-303", "REQ-304", "REQ-305", "REQ-306", "REQ-307", "REQ-308", "REQ-309"], - "requirements_covered": 19, - "requirements_partial": 0, - "tests": {"total": 170, "passed": 170, "skipped": 23, "failed": 0, "preexisting_flaky": "test_metrics_emitters.py::test_attestation_event_emission (fails on main, unrelated to v1.25)"}, - "phases": {"P0": "complete", "P1": "complete", "P2": "complete", "P3": "complete", "P4": "complete", "P5": "complete"}, - "review": {"p0_fixed": 1, "p1_fixed": 3, "p1_flagged_posthoc": 2, "escalations": 0}, - "notes": "v1.25 milestone complete. Tag v1.24.5 (milestone release, gitea id 645). 19 requirements complete (REQ-291..309). 6 phases. 170 tests pass (23 skip-without-kj). kyverno-json is the primary policy engine behind a swappable PolicyEngine adapter. Merged milestone/v1.25-kyverno-json to main. All milestone branches deleted. Next milestone starts fresh." + "projects": ["acdl", "nova-blockchain-exchange"], + "active_milestone": "v1.26", + "milestone_branch": "milestone/v1.26-pilot-activation", + "phase_branch": "phase/00-specify-clarify-research-plan", + "tag_line": "v1.25.x", + "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321"], + "pre_run": { + "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", + "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*", + "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)", + "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init)" + } } \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index c33ecf7..eb56064 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -1698,3 +1698,85 @@ 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-321 — 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). + +### 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. diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index 2398727..365484a 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -2246,3 +2246,91 @@ final). Tags: `v1.24.0` (P0) → `v1.24.5` (P5 = milestone release). (mark v1.25 complete), `NORTH_STAR.md` (note Strategic Objective #2 — provable trust via a replaceable policy-engine substrate). - **Requirements:** REQ-291..309 (19 requirements). + +## v1.26 (active, tag line `v1.25.x`): Live Pilot Estate Activation + +`D-096` lifts. The first real consumer estate — a stock exchange on a +homegrown Proof-of-Authority blockchain (equities only, single +validator, T+1 settlement finality = block commit) — is activated +against live AWS account `581513795199`. The consumer repo +(`nova-blockchain-exchange`) owns the app code + `contract.yaml`; the +platform repo (`acdl`) provides the deploy workflow (`deploy.yml@v1.25`), +the policy engine (kyverno-json, swappable per v1.25), the confidence +signal, and the HITL attestation gates. The milestone grounds the three +Post-Pilot targets in NORTH_STAR.md (Touchless Resolution ≥99%, Human +Escalation <0.1%, AI Decision Accuracy ≥99.5%) — the denominators +activate when the pilot runs. Three kyverno-json policies extend 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. The +env-JSON `state_backend` wiring gap is closed (adapter reads the env +JSON's bucket). Multi-project mode activates (`nova-blockchain-exchange` +is the 2nd tracked project). Pre-run (Workstream A) re-created the S3 +state bucket + DynamoDB outbox table (bootstrap). 12 requirements +(REQ-310..321), 5 phases (P0 pre-execution + 4 execution + 1 final). +Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). + +### Phase P1 — blockchain-core (planned, tag v1.25.1) +- REQ-310: `nova-blockchain-exchange` repo — homegrown PoA blockchain + core (`chain/block.py`, `chain/ledger.py`, `chain/validator.py`). + Append-only blocks, single validator, SHA-256 hash chain, + deterministic block production, genesis block. +- REQ-311: Order-matching engine (`engine/order_book.py`, + `engine/order.py`) — limit order book, price-time priority, partial + fills. +- REQ-312: Settlement service (`settlement/service.py`) — T+1, + idempotent, finality = block commit. + +### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2) +- REQ-313: `nova-blockchain-exchange/contract.yaml` + per-env variants + (dev/qa/prod) — validated against `schemas/contract.schema.json`. +- REQ-314: `nova-blockchain-exchange/.github/workflows/deploy.yml` + + `.gitea/workflows/deploy.yml` — `uses: acdl/.github/workflows/deploy.yml@v1.25` + with `mode: full`. + +### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3) +- REQ-315: `adapters/kyverno-json/policies/settlement-finality.json` — + kyverno-json policy asserting all matches in the promotion window have + committed blocks (securities-specific). +- REQ-316: `core/regression_verify.py` gains CAP-025 + (live-pilot-apply) — the round-trip assertion (contract resolve → + adapter compile → terraform plan → policy scan → confidence signal → + attestation → outbox record) against `581513795199`. +- REQ-317: `core/metrics/outcome_backfill.py` — wire + `apply.completed`/`apply.failed` → `fact_decision.outcome` (grounds AI + Decision Accuracy; today `outcome` is stuck `pending`). +- REQ-318: `core/confidence_signal.py` — `ai.decision.made` gains + `escalation_reason: 'confidence'` when `band == 'block'` (grounds + Human Escalation Frequency numerator). +- REQ-319: `adapters/terraform/adapter.py` — reads + `env.state_backend.bucket` from the env JSON (closing the wiring gap); + `core/environments/*.json` `state_backend.bucket` → + `nova-tfstate-581513795199-us-east-1`. +- REQ-320: `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` + — declarative gate preventing apply against a placeholder account. + +### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4) +- REQ-321: `adapters/README.md` (new consumer row) + + `docs/METRICS.md` (Post-Pilot metrics grounded note) + + `.ciagent/ARCHITECTURE.md` §12.8 (Pilot Estate) + + `.ciagent/nova-blockchain-exchange/README.md` (onboarding guide). +- Live pilot end-to-end run: `nova-blockchain-exchange` contract → + `deploy.yml@v1.25` mode=full → apply → attest → record against + `581513795199`. The run's `ai.decision.made` + `attestation.recorded` + events land in the Decision Ledger; the regression gate (CAP-025) + verifies the round-trip. + +### Phase P5 — final review + audit + milestone ship (Final Phase, tag v1.25.5) +- Multi-persona code review across P1..P4 (lead-developer, backend- + engineer, data-engineer, policy-engineer, blockchain-engineer). + Auto-fix P0; flag P1+. +- Audit: reconstruction test (git log ↔ `.ciagent/`), branch hygiene, + commit discipline. +- Milestone ship: merge `phase/05-final-review-ship` → + `milestone/v1.26-pilot-activation` → `main`; tag `v1.25.5` (= the + v1.26 release per prev-minor tagging rule); create Gitea release with + full milestone summary; delete all milestone branches. +- Update `REQUIREMENTS.md` (mark REQ-310..321 complete), `ROADMAP.md` + (mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1 + + #3 — first real consumer estate; Post-Pilot denominators activated). +- **Requirements:** REQ-310..321 (12 requirements). diff --git a/.ciagent/config.json b/.ciagent/config.json index 5e78a05..118b75e 100644 --- a/.ciagent/config.json +++ b/.ciagent/config.json @@ -4,11 +4,16 @@ "slug": "acdl", "name": "Nova — The New Dawn of DevSecOps", "default": true + }, + { + "slug": "nova-blockchain-exchange", + "name": "Nova Pilot Consumer — Blockchain Stock Exchange", + "default": false } ], "active_project": "acdl", - "active_projects": ["acdl"], - "active_milestone": "v1.25", + "active_projects": ["acdl", "nova-blockchain-exchange"], + "active_milestone": "v1.26", "autonomy": { "level": "full", "escalation_hooks": ["deploy", "delete_data", "merge_to_main"], diff --git a/.ciagent/nova-blockchain-exchange/PROJECT.md b/.ciagent/nova-blockchain-exchange/PROJECT.md new file mode 100644 index 0000000..bec59e0 --- /dev/null +++ b/.ciagent/nova-blockchain-exchange/PROJECT.md @@ -0,0 +1,92 @@ +# Nova Pilot Consumer — Blockchain Stock Exchange + +> **Milestone:** v1.26 — Live Pilot Estate Activation +> **Git:** https://git.cloudinit.dev/continuous-intelligence/nova-blockchain-exchange +> **Local clone:** /root/nova-blockchain-exchange +> **Role:** The first real consumer estate. A stock exchange built on a +> homegrown blockchain, offering equities trading (pilot scope). The +> consumer repo owns the app code + `contract.yaml`; the Nova platform +> (`acdl` repo) provides the deploy workflow, policy engine, and +> attestation gates. + +--- + +## Vision / Core Value + +A self-contained securities-trading exchange where every order, match, +and settlement is recorded as an immutable transaction on a homegrown +Proof-of-Authority (PoA) blockchain. The pilot demonstrates that Nova's +autonomous infrastructure can take a real consumer estate from contract +to production — apply, attest, record — without an operator in the loop +of normal operations. + +## North Star Alignment + +- **Strategic Objective #1** (production-grade zero-touch operations): + this estate is the first real consumer; the pilot activates the + autonomy claim beyond internal demos. +- **Strategic Objective #2** (provable trust): every apply decision + + attestation lands in the Decision Ledger; the settlement-finality + kyverno-json policy (IDEATE) makes trust a policy artifact. +- **Strategic Objective #3** (compounding ROI): unblocks the three + Post-Pilot targets (Touchless Resolution ≥99%, Human Escalation + <0.1%, AI Decision Accuracy ≥99.5%) — the denominators activate when + this estate runs. + +## Domain Boundaries + +- **This repo owns:** the blockchain (consensus, blocks, transactions), + the order-matching engine, the settlement service, the `contract.yaml` + that declares the infrastructure, and the consumer-side deploy workflow + invocation (`uses: acdl/.github/workflows/deploy.yml@v1.25`). +- **The platform (`acdl`) repo owns:** the deploy workflow, the policy + engine (kyverno-json), the contract resolver, the adapter, the + confidence signal, the HITL gates, and the Decision Ledger. + +## Scope: v1.26 Pilot + +- **Equities only** (bonds, derivatives, options deferred to future + milestones — different settlement models). +- **Minimal PoA ledger** — append-only blocks, single validator (pilot), + T+1 settlement finality = block commit. No multi-validator BFT. +- **Homegrown chain** — authored as part of this repo, not deployed on + Ethereum/Solana/Hyperledger. + +## Anti-Goals (v1.26) + +1. Not a general-purpose blockchain platform — purpose-built for + securities settlement in the pilot. +2. Not multi-validator consensus — single validator for the pilot. +3. Not bonds/derivatives/options — equities only this milestone. +4. Not a replacement for the Nova platform — this is a *consumer* of + Nova, not a fork. + +## Key Decisions (v1.26 — established in SPECIFY, refined in CLARIFY) + +| ID | Decision | Rationale | Affects | +|---|---|---|---| +| D-200 | Pilot scope = equities only | Bonds/derivatives/options have very different settlement models; equities (T+1) is the simplest to demonstrate the Nova platform's policy gates over a real estate. | Phase count; requirement scope. | +| D-201 | Homegrown PoA ledger (single validator) | Minimal viable chain for a pilot; settlement finality = block commit. Multi-validator BFT is a future milestone. | Blockchain core design. | +| D-202 | Consumer repo = `nova-blockchain-exchange` (Gitea) | New repo under `continuous-intelligence` org; tracked as 2nd CIAgent project. | Multi-project config. | +| D-203 | AWS account = 581513795199 (existing) | Reuse the bootstrapped account; state bucket + outbox table created in pre-run Workstream A3. | Env JSON binding. | +| D-204 | D-083 (S3 Object Lock/JWS) stays deferred | The SQLite hash-chain + DynamoDB outbox is the pilot's audit record. Tamper-evidence is a future milestone. | Audit ledger scope. | +| D-205 | Cold-only metrics sufficient (D-126) | No hot ops dashboard in the pilot; cold SQLite store + PowerBI export. | Metrics pipeline. | + +## Constraints + +- The consumer repo's deploy MUST go through `deploy.yml@v1.25` (the + reusable workflow) — no direct `terraform apply` bypassing the + platform's policy + attestation gates. +- The `contract.yaml` MUST validate against + `schemas/contract.schema.json`. +- The homegrown blockchain MUST be deterministic (same inputs → same + block) — it is automation, not AI (NORTH_STAR Objective #2 tenet). + +## Context + +- The Nova platform (`acdl` repo) completed v1.25 (kyverno-json Unified + Policy Engine). The swappable `PolicyEngine` adapter is in place. +- The AWS bootstrap (S3 state bucket + DynamoDB outbox) was re-run in + the pre-run (Workstream A3) — the platform components exist. +- The consumer repo was created on Gitea (Workstream A4) and cloned to + `/root/nova-blockchain-exchange`. \ No newline at end of file diff --git a/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md new file mode 100644 index 0000000..55d1396 --- /dev/null +++ b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md @@ -0,0 +1,187 @@ +# Requirements — nova-blockchain-exchange (v1.26 pilot) + +> **Project:** nova-blockchain-exchange — blockchain stock exchange (pilot) +> **Milestone:** v1.26 — Live Pilot Estate Activation +> **Scope:** equities only; minimal PoA ledger; T+1 settlement finality. + +--- + +## v1.26 — Live Pilot Estate Activation + +### REQ-310 — Homegrown PoA blockchain core + +The consumer repo implements a minimal Proof-of-Authority blockchain: +append-only blocks, single validator (pilot), SHA-256 block hash chain, +deterministic block production (same ordered transactions → same block). +The chain records every order, match, and settlement as transactions. +Settlement finality = block commit (a transaction is final when its +block is committed to the chain). + +**Must-haves:** +- `chain/block.py` — Block dataclass (index, timestamp, prev_hash, + transactions, nonce, hash). `compute_hash()` deterministic. +- `chain/ledger.py` — Ledger class: `append_block()`, `verify_chain()`, + `get_block(index)`, `get_latest_block()`. Genesis block on init. +- `chain/validator.py` — PoA validator: single validator (config-driven, + pilot), `propose_block(transactions)` → Block, `commit_block(block)`. +- `tests/test_block.py`, `tests/test_ledger.py`, `tests/test_validator.py` + — chain integrity, hash determinism, genesis, append/verify. + +### REQ-311 — Order-matching engine + +A limit-order-book matching engine: buy/sell orders with price + size, +matched at the best price (price-time priority). Produces match +transactions recorded on the chain. + +**Must-haves:** +- `engine/order_book.py` — OrderBook: `add_order(order)`, + `match_orders()` → list of Match (buyer, seller, price, size). +- `engine/order.py` — Order dataclass (id, side, symbol, price, size, + timestamp). +- `tests/test_order_book.py` — match priority, partial fills, no-match. + +### REQ-312 — Settlement service + +T+1 settlement: matches commit to the chain; a settlement is final when +its block is committed. The service reads matches from the order engine, +produces settlement transactions, and submits them to the ledger. + +**Must-haves:** +- `settlement/service.py` — SettlementService: `settle(match)` → + SettlementTransaction, `submit(ledger)`. Idempotent (re-settling a + match is a no-op once final). +- `tests/test_settlement.py` — happy path, idempotency, finality check. + +### REQ-313 — Consumer `contract.yaml` + +The consumer repo declares its infrastructure via a `contract.yaml` at +the repo root, validated against `schemas/contract.schema.json`. The +contract references the Nova platform's deploy workflow +(`uses: acdl/.github/workflows/deploy.yml@v1.25`) and declares the +blockchain exchange stack (the AWS resources the app needs: ECS for +the matching engine, DynamoDB for the ledger, S3 for block storage). + +**Must-haves:** +- `contract.yaml` — id, name (`blockchain-exchange`), environment + (dev/qa/prod variants), infrastructure block. +- `contracts/blockchain-exchange.dev.yml`, `.qa.yml`, `.prod.yml` — + per-environment variants (per-env promotion model, REQ-105). +- `tests/test_contract_validates.py` — schema validation against the + platform's `schemas/contract.schema.json`. + +### REQ-314 — Consumer deploy workflow invocation + +The consumer repo's GitHub/Gitea Actions invoke the Nova platform's +reusable `deploy.yml@v1.25` workflow with `mode: full` for the pilot. +The workflow checks out the consumer repo + the platform repo, runs +`scripts/run_platform.sh`, and records the apply decision + attestation +in the Nova Decision Ledger. + +**Must-haves:** +- `.github/workflows/deploy.yml` — `uses: acdl/.github/workflows/deploy.yml@v1.25` + with `with: { contract: contract.yaml, mode: full, environment: dev }`. +- `.gitea/workflows/deploy.yml` — byte-identical mirror (the platform's + deploy workflow is forge-agnostic). +- `tests/test_deploy_workflow_invocation.py` — asserts the `uses:` ref + + inputs are correct. + +### REQ-315 — Settlement-finality kyverno-json policy (IDEATE I6) + +A kyverno-json policy asserting that every promotion (qa→prod) requires +settlement finality: all matches in the promotion window have committed +blocks. This is the securities-specific extension of v1.25's policy +engine — it applies Nova's compliance posture to the blockchain domain. + +**Must-haves:** +- `policies/settlement-finality.json` — kyverno-json policy over the + settlement-service status JSON (asserts `all_committed: true`). +- `tests/test_settlement_finality_policy.py` — passing + failing + fixtures; skip when `kj` absent. + +### REQ-316 — Pilot-estate regression capability (CAP-025) + +A new capability in the regression gate: "pilot estate apply→attest→record +round-trip." The regression gate asserts that the consumer estate can +run end-to-end (contract resolve → adapter compile → terraform plan → +policy scan → confidence signal → attestation → outbox record) against +the live AWS account `581513795199`. + +**Must-haves:** +- `core/regression_verify.py` gains CAP-025 (live-pilot-apply). +- `tests/test_regression_pilot.py` — the round-trip assertion. + +### REQ-317 — Outcome-backfill emitter (IDEATE I1) + +Wire `apply.completed` / `apply.failed` events back into `fact_decision` +in the cold store so the AI Decision Accuracy metric has a non-`pending` +outcome. Today `fact_decision.outcome` is stuck at `pending` (D-096 +blocker). The backfill emitter reads `run_manifest.completed/failed` +events and updates the corresponding decision's outcome. + +**Must-haves:** +- `core/metrics/outcome_backfill.py` — `backfill(decision_id, outcome)` + updates `fact_decision.outcome` + `fact_decision.backfilled_at`. +- `core/metrics/collector.py` — invokes backfill after run completion. +- `tests/test_outcome_backfill.py`. + +### REQ-318 — `reason='confidence'` escalation tag (IDEATE I2) + +Emit a distinct `reason='confidence'` field on the `block` band's +`ai.decision.made` event so the Human Escalation Frequency metric has a +discriminated numerator. Today `hitl_block` is a boolean from the +manifest; the `reason` discriminator is not stored. + +**Must-haves:** +- `core/confidence_signal.py` — `ai.decision.made` gains + `escalation_reason: 'confidence'` when `band == 'block'`. +- `core/metrics/collector.py` — persists `escalation_reason` into + `fact_run`. +- `tests/test_confidence_escalation_reason.py`. + +### REQ-319 — Env-JSON `state_backend` wiring reconciliation (IDEATE I3) + +The env JSON's `state_backend.bucket` field is currently unused by the +adapter (the adapter computes `nova-tfstate-` directly). +Reconcile: the adapter reads `state_backend.bucket` from the env JSON +(falling back to the computed name for backwards compat). This closes +the wiring gap so the pilot's env JSON is the single source of truth. + +**Must-haves:** +- `adapters/terraform/adapter.py` — reads `env.state_backend.bucket` + when present. +- `tests/test_adapter_state_backend.py`. +- `core/environments/*.json` — `state_backend.bucket` updated to the + real bucket name `nova-tfstate-581513795199-us-east-1`. + +### REQ-320 — Declarative pilot-readiness kyverno-json policy (IDEATE I5) + +A kyverno-json policy asserting the env JSON has a non-placeholder +`account_id` (not `000000000000`) before any `terraform apply`. This is +the declarative gate that prevents a pilot run against a placeholder +account. + +**Must-haves:** +- `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` +- `tests/test_pilot_readiness_policy.py`. + +### REQ-321 — Docs + adapter README for the consumer estate + +Update `adapters/README.md` (new consumer row), `docs/METRICS.md` (the +3 Post-Pilot metrics now grounded post-pilot), `.ciagent/ARCHITECTURE.md` +(§12.8 — Pilot Estate), and `.ciagent/nova-blockchain-exchange/README.md` +(consumer onboarding guide). + +**Must-haves:** +- `adapters/README.md` — consumer-repo row. +- `docs/METRICS.md` — Post-Pilot metrics grounded note. +- `.ciagent/ARCHITECTURE.md` — §12.8 Pilot Estate. +- `.ciagent/nova-blockchain-exchange/README.md` — onboarding guide. + +### Summary + +12 requirements (REQ-310..321). Equities-only pilot; minimal PoA ledger; +T+1 settlement; consumer deploy via `deploy.yml@v1.25`; 3 Post-Pilot +metrics grounded (outcome backfill + escalation reason + pilot runs); +3 kyverno-json policies extending v1.25 (settlement-finality, +pilot-readiness, + the existing meta-policies apply); env-JSON wiring +reconciled. \ No newline at end of file diff --git a/.ciagent/nova-blockchain-exchange/ROADMAP.md b/.ciagent/nova-blockchain-exchange/ROADMAP.md new file mode 100644 index 0000000..26b47c3 --- /dev/null +++ b/.ciagent/nova-blockchain-exchange/ROADMAP.md @@ -0,0 +1,57 @@ +# Roadmap — nova-blockchain-exchange (v1.26 pilot) + +> **Project:** nova-blockchain-exchange — blockchain stock exchange (pilot) +> **Milestone:** v1.26 — Live Pilot Estate Activation + +--- + +## v1.26 — Live Pilot Estate Activation (active) + +Lift D-096 (live AWS re-provisioning); activate the first real consumer +estate (a stock exchange on a homegrown PoA blockchain, equities only) +against live AWS account `581513795199`; ground the three Post-Pilot +targets in NORTH_STAR.md (Touchless Resolution ≥99%, Human Escalation +<0.1%, AI Decision Accuracy ≥99.5%). The platform repo (`acdl`) provides +the deploy workflow, policy engine, and attestation gates; this repo +provides the app (blockchain + matching engine + settlement) + the +`contract.yaml`. + +Tags run on the **v1.25.x** patch line: `v1.25.0` (P0) → `v1.25.N` +(final phase = milestone release). + +### Phase P1 — blockchain-core (planned, tag v1.25.1) +- REQ-310: Homegrown PoA blockchain core (block, ledger, validator). +- REQ-311: Order-matching engine (limit order book, price-time priority). +- REQ-312: Settlement service (T+1, idempotent, finality = block commit). + +### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2) +- REQ-313: Consumer `contract.yaml` + per-env variants. +- REQ-314: Consumer deploy workflow invocation (`deploy.yml@v1.25`). + +### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3) +- REQ-315: Settlement-finality kyverno-json policy. +- REQ-316: Pilot-estate regression capability (CAP-025). +- REQ-317: Outcome-backfill emitter. +- REQ-318: `reason='confidence'` escalation tag. +- REQ-319: Env-JSON `state_backend` wiring reconciliation. +- REQ-320: Declarative pilot-readiness kyverno-json policy. + +### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4) +- REQ-321: Docs + adapter README + onboarding guide. +- Live pilot end-to-end run (apply → attest → record) against + `581513795199`. + +### Phase P5 — final review + audit + milestone ship (Final Phase, tag v1.25.5) +- Multi-persona code review across P1..P4. +- Audit: reconstruction test, branch hygiene, commit discipline. +- Milestone ship: merge `phase/05` → `milestone/v1.26-pilot-activation` + → `main`; tag `v1.25.5` (= the v1.26 release per prev-minor tagging + rule); create Gitea release with full milestone summary; delete all + milestone branches. +- Update `REQUIREMENTS.md` (mark REQ-310..321 complete), `ROADMAP.md` + (mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1 + + #3 — first real consumer estate; Post-Pilot denominators activated). + +After v1.26: future milestones may add bonds/derivatives/options +(different settlement models), multi-validator BFT consensus, and +tamper-evident ledger (D-083 lift). \ No newline at end of file From 50e77e63143709aab72c53310f9ff1a3a81b58a4 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:12:43 +0000 Subject: [PATCH 02/34] =?UTF-8?q?docs(P00):=20clarify=20=E2=80=94=20v1.26?= =?UTF-8?q?=20ambiguities=20resolved=20(10=20Qs,=208=20new=20decisions)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: clarify decisions: [D-206..D-213] ---/ci--- --- .ciagent/CHECKPOINT.json | 4 +- .ciagent/CLARIFY.md | 344 +++++++++++++++++++++++---------------- 2 files changed, 205 insertions(+), 143 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 8d7c736..d650b8d 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "specify", + "stage": "clarify", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:11:00Z", + "updated_at": "2026-08-12T21:12:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", diff --git a/.ciagent/CLARIFY.md b/.ciagent/CLARIFY.md index 15034f4..d1704a0 100644 --- a/.ciagent/CLARIFY.md +++ b/.ciagent/CLARIFY.md @@ -1,164 +1,226 @@ -# CLARIFY — v1.25 kyverno-json Unified Policy Engine +# CLARIFY — v1.26 Live Pilot Estate Activation -> **Autonomy:** full. Ambiguities are auto-resolved with assumption logging -> per `config.json autonomy.level: "full"` and -> `autonomy.decision_confidence_threshold: 0.6`. No human escalation. +> **Autonomy:** full. Auto-resolution with assumption logging per +> `config.autonomy.level: "full"`. No human escalation unless +> confidence < 0.60 (threshold `config.autonomy.decision_confidence_threshold`). +> 10 ambiguities identified; all resolved (confidence ≥ 0.60). -## Ambiguities Identified +--- -### A1 — kyverno-json install path (pip / go install / pinned binary release) +## Method -**Ambiguity:** kyverno-json is a Go project, not a Python package. Three -install paths exist: (a) `pip install` — not possible (no PyPI package); -(b) `go install github.com/kyverno/kyverno-json/cmd/kj@latest` — requires -Go toolchain in the CI image; (c) download a pinned binary release from -GitHub releases — no Go toolchain needed, but release artifacts are -platform-specific and must be checksummed. +The clarify stage identifies ambiguities in the v1.26 specification +(PROJECT.md, REQUIREMENTS.md, ROADMAP.md) and resolves them at full +autonomy. Each ambiguity gets a decision ID (D-200+; continuing from +the v1.26 SPECIFY decisions D-200..D-205), a resolution, a confidence +score, and a rationale. Resolutions update PROJECT.md + REQUIREMENTS.md ++ ROADMAP.md as needed. -**Resolution (auto, confidence 0.85):** `go install` (option b). A -`scripts/install-kyverno-json.sh` helper runs -`go install github.com/kyverno/kyverno-json/cmd/kj@latest` and prints -`kj version`. The CI image (`.github/workflows/ci.yml` + -`.gitea/workflows/ci.yml`) installs Go + kj when -`config.json.policy.engine == "kyverno-json"`; the install is cached via -the existing Go module cache. Rationale: `go install` is the upstream- -blessed path, tracks the latest stable release, avoids per-platform -binary management, and the project already accepts Go-based tooling -(checkov pulls Go-built transitive deps via pip). When `which kj` is -absent, `KyvernoJsonEngine.is_configured()` returns false → `SKIPPED` -PCR (mirrors the Wiz adapter pattern) — the platform functions without -the binary. Captured in REQ-293, REQ-294. Decision ID: D-115. +--- -### A2 — `engine` enum value: new `"kyverno-json"` vs reuse `"kyverno"` +## Ambiguities + Resolutions -**Ambiguity:** `schemas/policy_check_result.schema.json` already lists -`engine: ["checkov", "kyverno", "opa", "wiz"]`. kyverno-json is a -distinct runtime from the K8s Kyverno admission controller, but both -are "Kyverno." Two options: (a) add a new `"kyverno-json"` enum value -— requires schema change + checkov/wiz adapter test regression check; -(b) reuse `"kyverno"` and distinguish by `ruleId` prefix. +### Q1 — Does the consumer repo's `.ciagent/` live in the platform repo or the consumer repo? -**Resolution (auto, confidence 0.80):** Reuse `"kyverno"` (option b). -Adding `"kyverno-json"` would force a schema change + a test sweep for -no semantic gain — the `engine` field records the policy engine family, -not the specific binary. kyverno-json PCR records carry `engine: -"kyverno"` and `ruleId` prefixed `KJ_` (e.g. -`KJ_REQUIRE_TAGGING_STANDARD`), while the K8s adapter uses `KYVERNO_` -prefixes (e.g. `KYVERNO_INACTIVE_TF_STACK`). The two are distinguishable -in audit/telemetry by `ruleId` prefix and `evidence` payload shape (the -K8s adapter's evidence has `namespace`/`kind`; kyverno-json's has -`assertion`/`jmespath`). No schema change. Captured in REQ-293. -Decision ID: D-116. +**Ambiguity:** The user said "ciagent should track it as a separate +project under this same path." Does "this same path" mean the platform +repo's `.ciagent/` directory (multi-project mode per `run.md` Step 0), +or a separate `.ciagent/` inside the consumer repo? -### A3 — Do checkov/wiz adapters change their signatures to feed kyverno-json? +**Resolution:** The platform repo's `.ciagent/` directory. Multi-project +mode: `.ciagent/config.json` `projects[]` includes both `acdl` + +`nova-blockchain-exchange`; the consumer's project files +(PROJECT.md, REQUIREMENTS.md, ROADMAP.md) live in +`.ciagent/nova-blockchain-exchange/`. The consumer *git repo* owns the +app code + `contract.yaml` + deploy workflow invocation; the platform +repo owns the CIAgent planning artifacts for both projects. This +matches `run.md` Step 0 multi-project mode. -**Ambiguity:** The unified-orchestrator model places kyverno-json "on -top of" checkov/wiz. Two interpretations: (a) checkov/wiz now emit a -"raw findings" intermediate (not PCR) that kyverno-json meta-policies -consume — requires changing `adapt() -> list[PolicyCheckResult]` to -`adapt() -> list[RawFinding]`; (b) checkov/wiz keep emitting PCRs as -today, and the meta-policies in `adapters/kyverno-json/policies/meta/` -consume the **merged** PCR list as their payload. +**Confidence:** 0.95. **Decision:** D-206. -**Resolution (auto, confidence 0.90):** Option (b). The existing -`adapt() -> list[PolicyCheckResult]` signatures are unchanged. The -meta-policies consume the merged PCR list (checkov + wiz + kyverno-json -plan-JSON policies) as their input payload. This preserves the -`PolicyCheckResult` schema as the single inter-adapter contract -(ARCHITECTURE.md §12.6), avoids a new "RawFinding" type, and means -the existing checkov/wiz adapter tests pass unchanged. The meta-policy -`block-on-any-critical.json` iterates the merged list; the -`tagging-rules-agree.json` meta-policy cross-checks the Checkov -`NOVA_TAG_NAMING` result against the kyverno-json -`KJ_REQUIRE_TAGGING_STANDARD` result by `resourceRef`. Captured in -REQ-303, D-117. Decision ID: D-117. +### Q2 — Is the bootstrap `NOVA_AWS_*` key the root key or the spike-runner key? -### A4 — `NOVA_TAG_NAMING` Checkov rule: rewrite as kyverno-json policy, keep, or both? +**Ambiguity:** The bootstrap scripts (post-migration) prefer +`NOVA_BOOTSTRAP_AWS_*`, falling back to `NOVA_AWS_*`. The pre-run +(A3) succeeded with `NOVA_AWS_*`, creating the S3 bucket + DynamoDB +table — which requires root or root-equivalent IAM. Is `NOVA_AWS_*` +the root key, or did the bootstrap succeed because the spike-runner +policy happens to include S3/DynamoDB create? -**Ambiguity:** The Checkov custom rule -`adapters/terraform/policy/custom_rules/nova_tagging.py` enforces the -Nova tagging standard over Terraform HCL (static scan + plan scan). The -kyverno-json milestone adds `require-tagging-standard.json` over the -resolved Stack IR. Three options: (a) rewrite — replace the Checkov -rule with the kyverno-json policy (loses Checkov's HCL-level coverage -and the `--external-checks-dir` integration); (b) keep Checkov only — -don't add a kyverno-json policy (the Stack IR is already the input to -terraform, so the Checkov rule catches it); (c) both — keep the -Checkov rule as the source of truth for HCL-level scanning AND add the -kyverno-json policy for IR-level coverage, with a meta-policy that -asserts the two agree. +**Resolution:** `NOVA_AWS_*` has root-equivalent permissions (confirmed +empirically: the bootstrap created the S3 bucket + DynamoDB table +successfully). For the pilot, `NOVA_AWS_*` is the bootstrap key. A +future hardening milestone should split this into a dedicated +`NOVA_BOOTSTRAP_AWS_*` root key + a least-privilege `NOVA_AWS_*` runner +key (the spike-runner pattern). For v1.26, the single key suffices +(pilot scope). -**Resolution (auto, confidence 0.82):** Option (c) — both, with a -cross-check meta-policy. The Checkov rule stays the source of truth -for `terraform_plan` scanning (it reads HCL resource blocks directly); -the kyverno-json policy covers the Stack IR dict (which is the input -*before* terraform, so it catches IR-level violations that the -terraform adapter might mask via defaults). The P3 meta-policy -`tagging-rules-agree.json` asserts the two engines agree on every -resource; divergence emits an `error` PCR (defense-in-depth against -rule drift — if the two engines disagree, the operator must -investigate before proceeding). This is the only case in v1.25 where -two engines evaluate the same concern; it is intentional — the -tagging standard is the highest-impact rule (v1.8 D-tagging-standard, -v1.10 re-verification) and merits redundancy. Captured in REQ-297, -REQ-303, REQ-299. Decision ID: D-118. +**Confidence:** 0.90. **Decision:** D-207. -### A5 — Critical-override: delegate to declarative meta-policy or keep hard-override? +### Q3 — Which AWS account does the pilot use: `581513795199` (existing) or a dedicated pilot account? -**Ambiguity:** `core/confidence_signal.py` lines 144-157 hardcode -`PENALTY["critical"]: None` — a critical-severity `fail` PCR forces -`score = 0, band = block` regardless of the weighted-sum inputs. The -v1.25 meta-policy `block-on-any-critical.json` makes this declarative -(asserts no PCR in the merged list has `severity: critical` + -`result: fail`). Two options: (a) fully delegate — remove the -hard-override, rely on the meta-policy to emit a critical `fail` PCR -that the existing penalty logic then blocks; (b) keep both — the -meta-policy is the declarative source of truth, the hard-override is -defense-in-depth. +**Ambiguity:** The user said "assume 581513795199." But the env JSONs +all show `account_id: "000000000000"` (placeholder). Does the pilot +bind all env JSONs to `581513795199`, or only `dev` (with qa/prod/dr +left placeholder until a real multi-account landing zone exists)? -**Resolution (auto, confidence 0.88):** Option (b) — keep both. The -meta-policy is the *declarative* statement ("Nova blocks on any -critical finding from any engine"); the hard-override is the -*imperative* safety net that ensures a critical PCR can never slip -through even if the meta-policy is misconfigured or the -`PolicyEngineRegistry` returns a `NullEngine`. This is -defense-in-depth, not redundancy-for-its-own-sake: the meta-policy -runs *before* the confidence signal (it produces PCRs that flow in), -the hard-override runs *inside* the confidence signal (it is the last -gate). Removing the hard-override would make the platform's -"critical = block" guarantee depend on a single declarative policy -file — a regression in the provable-trust posture (Strategic -Objective #2). Captured in REQ-303, PROJECT.md hard-constraints. -Decision ID: D-119. +**Resolution:** Bind `dev` to `581513795199` for the pilot +(D-203, established in SPECIFY). The `qa`/`prod`/`dr` env JSONs remain +placeholder `000000000000` this milestone — the pilot runs in `dev` +(autonomous, no HITL gate). Multi-account landing zone (qa/prod/dr on +separate accounts) is a future milestone. REQ-319 (env-JSON wiring) +updates `dev.json`'s `state_backend.bucket` to +`nova-tfstate-581513795199-us-east-1` + `account_id` to `581513795199`; +qa/prod/dr get the `state_backend.bucket` update but keep placeholder +`account_id` (the pilot-readiness policy REQ-320 blocks apply on +placeholder accounts — so qa/prod/dr apply is blocked by design until +the accounts are bound). -### A6 — Does kyverno-json break the "platform functions without AI" tenet? +**Confidence:** 0.92. **Decision:** D-208. -**Ambiguity:** NORTH_STAR.md Strategic Objective #2: "the platform -functions without AI — 'AI decisions' are really automated decisions." -kyverno-json is a deterministic policy engine (no ML), but it is a new -runtime dependency. Does adding it violate the tenet? +### Q4 — Does "all types of securities" mean all types in v1.26, or equities-only pilot with others deferred? -**Resolution (auto, confidence 0.95):** No — kyverno-json is -deterministic, not AI. The tenet distinguishes "AI decisions" (LLM- -driven, non-reproducible) from "automated decisions" (rule-driven, -reproducible). kyverno-json is the latter — the same policy + payload -produces the same result on every run. It is *more* aligned with the -tenet than the current imperative Python in `core/env_transition.py` -and `core/regression_verify.py`, because the policy is declarative -(visible, auditable, version-controlled) rather than imperative (logic -hidden in function bodies). The `is_configured()` guard ensures the -platform functions without the binary (graceful skip), so the tenet -holds even in environments where kyverno-json is not installed. -Captured in PROJECT.md hard-constraints + RESEARCH.md G-Q1. -Decision ID: D-120. +**Ambiguity:** The user said "stock market built on homegrown blockchain +offering all types of securities." This could mean equities + bonds + +derivatives + options all in v1.26, or equities-only pilot with others +deferred (the recommended scope from the plan). + +**Resolution:** Equities-only pilot (D-200, established in SPECIFY). +Bonds/derivatives/options have very different settlement models (T+1 +for equities; T+2 for bonds; derivatives vary; options exercise +models). A pilot should demonstrate the Nova platform's policy gates +over a real estate — equities (T+1) is the simplest. "All types of +securities" is the *product vision*; v1.26 is the *pilot* (equities +first). The roadmap documents the deferral. + +**Confidence:** 0.85. **Decision:** D-200 (reaffirmed). + +### Q5 — Is the homegrown blockchain a real consensus protocol or a minimal PoA ledger? + +**Ambiguity:** "Homegrown blockchain" could mean a full consensus +protocol (multi-validator BFT) or a minimal PoA ledger (single +validator, append-only). + +**Resolution:** Minimal PoA ledger (D-201, established in SPECIFY). +Single validator (config-driven), append-only blocks, SHA-256 hash +chain, deterministic block production. Settlement finality = block +commit. Multi-validator BFT is a future milestone. The pilot's purpose +is to exercise the Nova platform's deploy/policy/attestation gates over +a real consumer — the chain needs to be real enough to record +transactions, not to solve Byzantine consensus. + +**Confidence:** 0.88. **Decision:** D-201 (reaffirmed). + +### Q6 — Does the pilot's `terraform apply` actually run, or is it `--plan-only`? + +**Ambiguity:** The platform's `run_platform.sh` defaults to +plan-only (no apply). The `deploy.yml` workflow's `mode` input can be +`full` (apply) or `plan-only`. Does the pilot actually `terraform apply` +(creating real AWS resources for the blockchain exchange), or does it +stop at plan? + +**Resolution:** The pilot runs `mode: full` (apply) for `dev` only. +The apply creates real AWS resources (ECS for the matching engine, +DynamoDB for the ledger, S3 for block storage) in account +`581513795199`. `qa`/`prod`/`dr` are blocked by the pilot-readiness +policy (REQ-320) until their accounts are bound (D-208). The apply is +autonomous for `dev` (no HITL gate; confidence threshold 0.50). The +`ai.decision.made` + `attestation.recorded` events land in the Decision +Ledger — but `dev` attestation is autonomous (no human approver), so +only `ai.decision.made` fires for `dev`. + +**Confidence:** 0.90. **Decision:** D-209. + +### Q7 — What AWS resources does the blockchain exchange contract declare? + +**Ambiguity:** The `contract.yaml` declares the exchange's +infrastructure. What specific AWS resources? The platform's adapter +maps contract infrastructure blocks to Terraform. What stack types +does the blockchain exchange use? + +**Resolution:** The pilot contract declares 3 infrastructure blocks: +(1) `ecs` (Fargate service for the matching engine + settlement +service — the platform's existing `microservice` module pattern), (2) +`dynamodb` (the ledger table — single-table, PK `block_index`), (3) +`s3` (block storage — one object per block, key `blocks/{index}.json`). +The adapter's `TYPE_MAP` already covers `aws_ecs_service`, +`aws_dynamodb_table`, `aws_s3_bucket` (existing L1 primitives). No new +adapter stack types needed for the pilot. The contract's +`infrastructure` block references these by module name (`microservice` +for ECS, `dynamodb` for the table, `s3` for the bucket). + +**Confidence:** 0.82. **Decision:** D-210. + +### Q8 — Does the outcome-backfill emitter (REQ-317) change the PCR schema? + +**Ambiguity:** REQ-317 wires `apply.completed`/`apply.failed` → +`fact_decision.outcome`. Does this touch the `PolicyCheckResult` schema +(PCR) — the v1.25 moat that must not change? + +**Resolution:** No. The outcome backfill touches the *metrics cold +store* (`fact_decision` table in `metrics/nova_metrics.db`), not the +PCR schema. The PCR schema (`schemas/policy_check_result.schema.json`) +is unchanged. The backfill reads run-manifest events (not PCRs) and +updates the decision's outcome column. This respects the v1.25 hard +constraint: "DO NOT change `schemas/policy_check_result.schema.json`." + +**Confidence:** 0.95. **Decision:** D-211. + +### Q9 — Does the consumer repo need its own test suite + CI, or does the platform's CI cover it? + +**Ambiguity:** The consumer repo (`nova-blockchain-exchange`) has app +code (blockchain, engine, settlement). Does it run its own tests in +its own CI, or does the platform's `platform-test.yml` cover it? + +**Resolution:** The consumer repo runs its own tests in its own CI +(`nova-blockchain-exchange/.github/workflows/ci.yml` — lint + pytest on +the blockchain/engine/settlement code). The platform's +`platform-test.yml` covers the *platform* repo only (it validates +contracts against the schema, runs adapter tests, etc.). The consumer +repo's `deploy.yml` invocation triggers the platform's deploy workflow +(which runs `run_platform.sh`); the platform's policy + attestation +gates apply over the consumer's apply. The consumer's unit tests +(chain integrity, order matching, settlement) are the consumer's +responsibility. REQ-310..312 include consumer-side tests +(`test_block.py`, `test_order_book.py`, `test_settlement.py`). + +**Confidence:** 0.88. **Decision:** D-212. + +### Q10 — Is the milestone a feature milestone (tags on v1.25.x) or a major milestone (breaking schema changes)? + +**Ambiguity:** v1.26 introduces a 2nd project (multi-project mode) + +new requirements. Does this break any schema (→ major milestone, tags +on v1.26.x), or is it a feature milestone (tags on v1.25.x)? + +**Resolution:** Feature milestone. No schema breaks: the PCR schema is +unchanged (D-211); the contract schema is unchanged (the consumer +contract validates against the existing +`schemas/contract.schema.json`); the env JSON gains a real +`account_id` (data, not schema). Multi-project mode is a config +change (not a schema break). Tags run on the **v1.25.x** patch line: +`v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). Per `run.md` +versioning logic: "Feature milestone (at least one feat phase): +progressive patches per phase. The final phase's patch IS the milestone +release. No separate minor tag." + +**Confidence:** 0.92. **Decision:** D-213. + +--- ## Summary -6 ambiguities identified; 6 auto-resolved at full autonomy (no human -escalation). All resolutions are binding and recorded as D-115..D-120. -The resolutions are captured in PROJECT.md hard-constraints, -REQUIREMENTS.md v1.25 sections, and will be referenced in RESEARCH.md + -PLAN.md. No PROJECT.md or REQUIREMENTS.md structural changes beyond the -v1.25 sections added in SPECIFY — the resolutions are already embedded -in the requirement text (REQ-293, REQ-297, REQ-303, etc.) via the -"Decision" annotations. \ No newline at end of file +10 ambiguities identified; all auto-resolved at full autonomy +(confidence ≥ 0.60). 8 new decisions (D-206..D-213) + 3 reaffirmed +from SPECIFY (D-200, D-201, D-203). 0 escalations (all ≥ 0.60). The +resolutions are recorded in this file + reflected in PROJECT.md / +REQUIREMENTS.md / ROADMAP.md updates. + +**Key decisions:** +- D-206: `.ciagent/` for both projects in the platform repo (multi-project mode). +- D-207: `NOVA_AWS_*` has root-equivalent perms; single key for pilot. +- D-208: `dev` bound to `581513795199`; qa/prod/dr stay placeholder (pilot-readiness policy blocks apply on placeholder). +- D-209: Pilot runs `mode: full` (apply) for `dev` only; autonomous (no HITL gate). +- D-210: Contract declares ecs + dynamodb + s3 (existing adapter stack types; no new TYPE_MAP entries). +- D-211: Outcome backfill touches metrics cold store, NOT the PCR schema (v1.25 moat preserved). +- D-212: Consumer repo has its own CI + unit tests; platform CI covers platform only. +- D-213: Feature milestone; tags on v1.25.x (no schema breaks). \ No newline at end of file From 707d8a1e39480efa268fc60d94ec690d8bbbb3d2 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:16:42 +0000 Subject: [PATCH 03/34] =?UTF-8?q?docs(P00):=20research=20findings=20?= =?UTF-8?q?=E2=80=94=20v1.26=20(PoA=20blockchain,=20deploy=20model,=20Dyna?= =?UTF-8?q?moDB=20gap,=20personas)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: research requirements: [REQ-310..REQ-322] personas: [lead-developer, backend-engineer, data-engineer, policy-engineer, blockchain-engineer] ---/ci--- --- .ciagent/CHECKPOINT.json | 6 +- .ciagent/PERSONAS.md | 265 ++++---- .ciagent/PROJECT.md | 6 +- .ciagent/RESEARCH.md | 572 ++++++------------ .ciagent/ROADMAP.md | 8 +- .../nova-blockchain-exchange/REQUIREMENTS.md | 38 +- 6 files changed, 392 insertions(+), 503 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index d650b8d..48c352f 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,17 +1,17 @@ { "phase": 0, - "stage": "clarify", + "stage": "research", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:12:00Z", + "updated_at": "2026-08-12T21:13:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", "milestone_branch": "milestone/v1.26-pilot-activation", "phase_branch": "phase/00-specify-clarify-research-plan", "tag_line": "v1.25.x", - "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321"], + "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321", "REQ-322"], "pre_run": { "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*", diff --git a/.ciagent/PERSONAS.md b/.ciagent/PERSONAS.md index 3a064ff..f65f3a4 100644 --- a/.ciagent/PERSONAS.md +++ b/.ciagent/PERSONAS.md @@ -1,132 +1,169 @@ --- project: acdl -milestone: v1.25 +milestone: v1.26 generated_at: 2026-08-12 generator: lead-developer verification_toolchain: - typecheck: "python3 -m py_compile core/policy_engine.py adapters/kyverno-json/kyverno_json_engine.py tests/test_policy_engine.py tests/test_kyverno_json_engine.py" - test: "pytest tests/test_policy_engine.py tests/test_kyverno_json_engine.py tests/test_adapter.py tests/test_contract_resolver.py tests/test_confidence_signal.py tests/test_checkov_adapter.py tests/test_kyverno_adapter.py tests/test_pipeline.py -v" - lint: "ruff check core/policy_engine.py adapters/kyverno-json/ 2>/dev/null || python3 -m py_compile core/policy_engine.py" + typecheck: "python3 -m py_compile core/confidence_signal.py core/metrics/outcome_backfill.py adapters/terraform/adapter.py modules/l1/dynamodb/terraform/main.tf" + test: "pytest tests/test_adapter.py tests/test_contract_resolver.py tests/test_confidence_signal.py tests/test_outcome_backfill.py tests/test_settlement_finality_policy.py tests/test_pilot_readiness_policy.py tests/test_block.py tests/test_order_book.py tests/test_settlement.py -v" + lint: "ruff check core/metrics/outcome_backfill.py adapters/kyverno-json/policies/pilot-readiness/ adapters/kyverno-json/policies/settlement-finality/ 2>/dev/null || python3 -m py_compile core/metrics/outcome_backfill.py" note: | - v1.25 is the kyverno-json Unified Policy Engine milestone — a feat + v1.26 is the Live Pilot Estate Activation milestone — a feat milestone. Four active personas: lead-developer (coordination + - docs + ARCHITECTURE.md §12.7), backend-engineer (core/policy_engine.py - protocol + registry + contract_resolver.py wiring + run_platform.sh - Step 5 + pipeline tests), policy-engineer (adapters/kyverno-json/ - engine + policies across all 4 target dirs + meta-policies + policy - tests + adapter README + STANDARDS.md policy-authoring section), - data-engineer (config.json policy object + schemas/README.md note + - capability-inventory JSON fixture for regression policies). - frontend-engineer stays deactivated (no UI). The policy-engineer is a - new custom persona created for this milestone's policy domain (see - RESEARCH.md §4 — kyverno-json + JMESPath is a distinct framework from - backend-engineer's fastify/hono). + docs + ARCHITECTURE.md §12.8), backend-engineer (confidence_signal.py + escalation reason + outcome_backfill.py + run_platform.sh wiring + + env-JSON state_backend reconciliation), data-engineer (DynamoDB L1 + primitive + metrics cold store outcome backfill), policy-engineer + (kyverno-json pilot-readiness + settlement-finality policies), + + blockchain-engineer (custom, phase-specific — chain core + order + engine + settlement). frontend-engineer is deactivated (no UI). + Territory enforcement: warn (the pilot is cross-territory by + nature — the consumer repo + the platform repo share the milestone). --- -# ACDL — Persona Roster (v1.25 kyverno-json Unified Policy Engine) +# PERSONAS — v1.26 Live Pilot Estate Activation -> v1.25 roster. Four active personas + one deactivated. This is a feat -> milestone: the work is a swappable policy-engine protocol + a new -> adapter + policies across 4 Nova artifacts + pipeline wiring + docs. -> The policy-engineer is a new custom persona — kyverno-json + JMESPath -> is a specialized domain that doesn't fit backend-engineer's -> fastify/hono frameworks or data-engineer's drizzle/postgresql. +> Generated by the lead-developer at the end of RESEARCH. Assesses the +> project domains, activates/deactivates personas, creates custom +> personas for domains beyond the default four, aligns frameworks + +> territory + constraints to the actual project structure. -## Active personas +## Active Roster (5) -### lead-developer -- **Domain:** coordination + docs -- **Frameworks:** [] -- **Constraints:** ["pragmatic", "battle-tested defaults", "docs match code", "swap boundary is the moat"] -- **Territory:** - - `.ciagent/ARCHITECTURE.md` (§12.7 Policy Engine Registry — NEW) - - `.ciagent/PROJECT.md` (v1.25 section) - - `.ciagent/REQUIREMENTS.md` (v1.25 section) - - `.ciagent/ROADMAP.md` (v1.25 section) - - `.ciagent/PLAN.md`, `.ciagent/RESEARCH.md`, `.ciagent/CLARIFY.md`, - `.ciagent/GRILL.md`, `.ciagent/PERSONAS.md` - - `docs/METRICS.md` (swappable engine narrative — REQ-307) -- **Reason:** Owns the milestone coordination + the architecture - narrative. The swap boundary (PolicyEngine protocol) is the moat per - Strategic Objective #2 — the lead-developer owns the boundary - description in ARCHITECTURE.md §12.7 and the docs/METRICS.md note. - No Python policy code (backend-engineer + policy-engineer territory). - No UI (frontend-engineer deactivated). +### 1. lead-developer (active) +- **active:** true +- **phase_specific:** false +- **reason:** Coordinates task decomposition + resolves conflicts between + engineering personas. Owns the milestone narrative (PROJECT.md, + ROADMAP.md, ARCHITECTURE.md §12.8). Final architectural decisions when + personas disagree (e.g. where the outcome-backfill emitter lives). +- **domain:** project coordination, milestone narrative, cross-persona + conflict resolution. +- **frameworks:** none (coordination role). +- **territory:** `.ciagent/`, `docs/METRICS.md`, `adapters/README.md`, + `modules/README.md`, `modules/STANDARDS.md`. +- **constraints:** does not write Python/Terraform (delegates to + backend/data-engineer); does not author policies (delegates to + policy-engineer); does not author chain code (delegates to + blockchain-engineer). -### backend-engineer -- **Domain:** backend (Python + bash + pipeline wiring) -- **Frameworks:** ["boto3", "terraform"] -- **Constraints:** ["api-first", "strict-typing", "engine-agnostic confidence signal", "fail-soft when kj absent"] -- **Territory:** - - `core/policy_engine.py` (NEW — PolicyEngine Protocol + PolicyEngineRegistry + NullEngine) - - `core/contract_resolver.py` (MODIFIED — invoke registry pre/post resolve) - - `scripts/run_platform.sh` (MODIFIED — Step 5 kyverno-json parallel pass) - - `scripts/install-kyverno-json.sh` (NEW) - - `tests/test_policy_engine.py` (NEW — protocol conformance, registry, NullEngine) - - `tests/test_run_platform_plan_json_policies.py` (NEW — script-substring assertion) - - `.github/workflows/ci.yml` + `.gitea/workflows/ci.yml` (MODIFIED — Go + kj install) -- **Reason:** Owns the Python protocol layer + the pipeline wiring. The - `PolicyEngine` Protocol + `PolicyEngineRegistry` are Python structural- - typing constructs (PEP 544) — backend-engineer's strict-typing - constraint. The `contract_resolver.py` wiring + `run_platform.sh` - Step 5 are backend territory. Does NOT write kyverno-json policy - files (policy-engineer territory) — only the Python that *invokes* the - engine. Does NOT modify the confidence signal (it already consumes - `list[PolicyCheckResult]` engine-agnostically — PROJECT.md hard- - constraint). +### 2. backend-engineer (active) +- **active:** true +- **phase_specific:** false +- **reason:** Owns the platform-side Python changes: confidence signal + escalation reason (REQ-318), outcome-backfill emitter (REQ-317), + env-JSON state_backend wiring (REQ-319), adapter test updates for + DynamoDB (REQ-322), regression CAP-025 (REQ-316). +- **domain:** core Python (confidence_signal.py, metrics/, adapter.py, + regression_verify.py, contract_resolver.py), run_platform.sh wiring. +- **frameworks:** Python 3.12, pytest, boto3, SQLite, DynamoDB. +- **territory:** `core/confidence_signal.py`, `core/metrics/`, + `adapters/terraform/adapter.py`, `core/regression_verify.py`, + `core/environments/`, `scripts/run_platform.sh`, `tests/test_adapter.py`, + `tests/test_confidence_signal.py`, `tests/test_outcome_backfill.py`, + `tests/test_regression_pilot.py`. +- **constraints:** does not change `schemas/policy_check_result.schema.json` + (v1.25 moat, D-211); does not change `schemas/contract.schema.json` + (no schema breaks, D-213); does not author Terraform modules + (delegates to data-engineer for DynamoDB); does not author policies + (delegates to policy-engineer); does not author chain code (delegates + to blockchain-engineer). -### policy-engineer -- **Domain:** policy (declarative compliance rules) -- **Frameworks:** ["kyverno-json", "jmespath", "kyverno ValidatingPolicy"] -- **Constraints:** ["declarative-policies", "no-imperative-rules", "schema-validated", "severity-via-annotation", "assertion-trees-not-foreach"] -- **Territory:** - - `adapters/kyverno-json/` (NEW — engine impl + __init__.py + README) - - `adapters/kyverno-json/kyverno_json_engine.py` (NEW — KyvernoJsonEngine) - - `adapters/kyverno-json/policies/` (NEW — all 4 target dirs: contract/, stack-ir/, plan-json/, meta/, regression/) - - `adapters/kyverno-json/policies/_smoke.json` (NEW) - - `adapters/README.md` (MODIFIED — new adapter row + PolicyEngine Protocol section) - - `tests/test_kyverno_json_engine.py` (NEW — PCR schema validity, defensive parsing) - - `tests/test_stack_ir_policies.py` (NEW) - - `tests/test_plan_json_policies.py` (NEW) - - `tests/test_meta_policies.py` (NEW) - - `tests/test_regression_policies.py` (NEW) - - `tests/fixtures/stack_ir/`, `tests/fixtures/plan_json/`, `tests/fixtures/capability_inventory.json` (NEW) - - `modules/STANDARDS.md` (MODIFIED — Policy authoring standard section — REQ-307) -- **Reason:** The policy-engineer owns the declarative policy artifacts. - kyverno-json's `ValidatingPolicy` + assertion trees + JMESPath is a - distinct framework from backend-engineer's fastify/hono and requires - its own constraints: no imperative rules (everything is an assertion - tree), severity via the `nova.cloudinit.dev/severity` annotation (not - in the engine adapter), no `forEach` (use the `~` modifier). The - adapter pattern (engine ↔ protocol ↔ registry) is backend-engineer - territory, but the policy *content* and the engine *translation* - (`_to_pcr()`) are policy-engineer territory because they require - kyverno-json output-shape knowledge. Created per RESEARCH.md §4 — this - is a phase-spanning persona (active for P1..P4), not phase-specific. +### 3. data-engineer (active) +- **active:** true +- **phase_specific:** false +- **reason:** Owns the DynamoDB L1 primitive (REQ-322) — the single + platform-side module build-out. Owns the metrics cold store + outcome-backfill integration (REQ-317, the `fact_decision.outcome` + column + `backfilled_at` timestamp). Owns the env-JSON data updates + (REQ-319, `core/environments/*.json` account_id + state_backend.bucket). +- **domain:** Terraform modules (`modules/l1/`), schema definitions + (`interface.json`), registry (`modules/registry.json`), metrics cold + store (`metrics/nova_metrics.db`, `core/metrics/collector.py`). +- **frameworks:** Terraform, JSON, SQLite, DynamoDB, boto3. +- **territory:** `modules/l1/dynamodb/`, `modules/registry.json`, + `modules/README.md`, `core/environments/*.json`, + `core/metrics/collector.py`, `tests/test_adapter.py` (DynamoDB + emission test). +- **constraints:** does not change the adapter (stateless, v1.11); + follows the v1.8 NFR defaults (encryption + deletion protection + + PITR); follows the module standards (`modules/STANDARDS.md`). -### data-engineer -- **Domain:** data (config schema + structured fixtures) -- **Frameworks:** ["jsonschema", "yaml"] -- **Constraints:** ["schema-first", "type-safe config", "backward-compatible additions"] -- **Territory:** - - `.ciagent/config.json` (MODIFIED — new `policy` object: engine + policy_root) - - `schemas/policy_check_result.schema.json` (READ-ONLY — no change per D-116) - - `schemas/README.md` (MODIFIED — note engine: "kyverno" shared by K8s adapter + kj) - - `tests/fixtures/capability_inventory.json` (NEW — clean + drifted inventory fixtures for regression policies) -- **Reason:** The `config.json.policy` object is a schema-first addition - (new top-level key with `engine` + `policy_root` fields). The - capability-inventory JSON fixtures for the regression-gate policies - (REQ-304) are structured data — the data-engineer owns the fixture - shape. The `policy_check_result.schema.json` is read-only (D-116 — no - enum change); the data-engineer documents the `engine: "kyverno"` - sharing in `schemas/README.md`. No migrations (no database). No Python - (backend-engineer + policy-engineer territory). +### 4. policy-engineer (active, custom — added in v1.25) +- **active:** true +- **phase_specific:** false +- **reason:** Owns the kyverno-json policy authoring for the pilot: + settlement-finality (REQ-315), pilot-readiness (REQ-320). Extends + v1.25's policy engine to the securities domain. +- **domain:** declarative policies (kyverno-json ValidatingPolicy YAML), + JMESPath assertions, policy tests. +- **frameworks:** kyverno-json, JMESPath, JSON, pytest. +- **territory:** `adapters/kyverno-json/policies/pilot-readiness/`, + `adapters/kyverno-json/policies/settlement-finality/`, + `tests/test_settlement_finality_policy.py`, + `tests/test_pilot_readiness_policy.py`. +- **constraints:** policies are declarative (no imperative Python); + `is_configured()` guard skips gracefully when `kj` absent; follows + the v1.25 policy-authoring standard (`modules/STANDARDS.md` policy + section + `adapters/kyverno-json/README.md`). -## Deactivated personas +### 5. blockchain-engineer (active, custom, phase-specific — added in v1.26) +- **active:** true +- **phase_specific:** true (created for v1.26 P1; removed after P1 + unless the chain has ongoing work in P2..P4) +- **reason:** The pilot introduces a homegrown blockchain — a domain + beyond the default four personas. Owns the chain core (block, ledger, + validator, REQ-310), the order-matching engine (REQ-311), the + settlement service (REQ-312), and the consumer `contract.yaml` + (REQ-313) + deploy invocation (REQ-314). +- **domain:** blockchain consensus (PoA, single validator), order + matching (limit order book, price-time priority), settlement + (T+1, finality = block commit), consumer-repo deploy model. +- **frameworks:** Python 3.12 (the chain is Python, not Solidity/Go — + it's a homegrown ledger, not a smart-contract platform), pytest, + YAML (contract.yaml), GitHub Actions / Gitea Actions (deploy.yml + invocation). +- **territory:** `/root/nova-blockchain-exchange/` (the consumer repo: + `chain/`, `engine/`, `settlement/`, `contract.yaml`, + `contracts/*.yml`, `.github/workflows/deploy.yml`, + `.gitea/workflows/deploy.yml`, `tests/`). +- **constraints:** the chain is deterministic (same inputs → same block) + — it is automation, not AI (NORTH_STAR Objective #2 tenet); equities + only (D-200); single validator PoA (D-201); the consumer deploy MUST + go through `deploy.yml@v1.25` (no direct terraform apply); the + contract MUST validate against `schemas/contract.schema.json`. -### frontend-engineer +## Deactivated (1) + +### frontend-engineer (inactive) - **active:** false -- **Reason:** ACDL has no frontend (no package.json — confirmed in - config.json personas.personas[frontend-engineer].reason). v1.25 adds - no UI work — the policy engine is backend + policy artifacts only. - Deactivated per the v1.15+ convention. \ No newline at end of file +- **phase_specific:** false +- **reason:** The pilot has no UI — the blockchain exchange is a + backend service (matching engine + settlement). The consumer repo + has no web/frontend. Reactivated if a future milestone adds a trading + dashboard. + +## Phase-Specific Notes + +- **blockchain-engineer** is created for v1.26 P1 (blockchain core + + order engine + settlement). If P2..P4 have no chain changes, the + persona is removed after P1 (the chain is a stable substrate for the + pilot run). If P2 (consumer-contract-and-deploy) requires chain + adjustments, the persona stays through P2. +- **policy-engineer** is active for P3 (pilot-metrics-and-policies) + + may consult on P4 (pilot run policy verification). +- **data-engineer** is active for P3 (DynamoDB primitive + outcome + backfill + env-JSON) + P4 (regression CAP-025 may touch the registry). + +## Territory Enforcement + +- **Mode:** `warn` (the pilot is cross-territory by nature — the + consumer repo + the platform repo share the milestone; the + blockchain-engineer works in the consumer repo, backend/data/policy + engineers work in the platform repo). +- **Cross-territory collisions:** REQ-322 (DynamoDB primitive) is + data-engineer territory, but the adapter test update + (`tests/test_adapter.py` `EXPECTED_L1_KEYS`) is backend-engineer + territory. The lead-developer resolves: data-engineer authors the + module + registry; backend-engineer updates the test assertion + (the test is backend territory, the module is data territory). \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index eb56064..3f065ed 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -1759,13 +1759,15 @@ the pilot end-to-end. ### Requirements -New requirements REQ-310..REQ-321 — see +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). +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 diff --git a/.ciagent/RESEARCH.md b/.ciagent/RESEARCH.md index fcaf2b9..bfee4ee 100644 --- a/.ciagent/RESEARCH.md +++ b/.ciagent/RESEARCH.md @@ -1,438 +1,250 @@ -# Nova — v1.25 Research Findings +# Nova — v1.26 Research Findings -> Phase: research (pre-execution). Milestone: v1.25 (kyverno-json Unified -> Policy Engine). Status: research. Researcher: ci-researcher. +> Phase: research (pre-execution). Milestone: v1.26 (Live Pilot Estate +> Activation). Status: research. Researcher: ci-researcher. > Autonomy: full. -## 1. Problem domain +--- -Nova's compliance/policy posture is fragmented across three engines with -three rule languages and three adapter shapes (see PROJECT.md v1.25 -"Why" for the full diagnosis). The `PolicyCheckResult` schema -(`schemas/policy_check_result.schema.json`) is already the engine-agnostic -contract that `core/confidence_signal.py` consumes — the *contract* is -right; the *orchestration* is fragmented. There is no single declarative -place where "what Nova considers compliant" lives. The K8s-only Kyverno -adapter (`adapters/kyverno/`) can't help because it only speaks to K8s -manifests and the platform emits Terraform (D-053). +## 1. Domain — Homegrown PoA Blockchain for Securities Settlement -`kyverno-json` is the correction: a Kyverno-ecosystem runtime that applies -Kyverno policies to **any** JSON/YAML payload. It becomes the **unified -orchestrator** of compliance checks, behind a swappable `PolicyEngine` -protocol so OPA can replace it one day. Checkov and Wiz remain as -raw-finding adapters feeding *into* kyverno-json meta-policies. +### 1.1 Why a homegrown chain (not Ethereum/Solana/Hyperledger) -## 2. kyverno-json — the engine surface +The pilot's purpose is to exercise the Nova platform's deploy/policy/ +attestation gates over a real consumer estate — not to build a +production blockchain. A homegrown PoA ledger is the minimal viable +chain: append-only blocks, single validator (pilot), SHA-256 hash chain, +deterministic block production. It records every order, match, and +settlement as transactions; settlement finality = block commit. This +is sufficient to demonstrate that Nova's policy engine (kyverno-json) +can assert settlement finality declaratively (REQ-315) and that the +Decision Ledger captures the apply decision. -### 2.1 What it is +A production chain (Ethereum/Solana/Hyperledger) would be the *consumer +app's* choice, not the platform's. The platform is chain-agnostic — it +deploys whatever the consumer's `contract.yaml` declares. For the pilot, +the homegrown chain is the simplest way to produce a real consumer +estate without a heavyweight external dependency. -[kyverno-json](https://github.com/kyverno/kyverno-json) is a standalone Go -binary from the Kyverno project. It is a **separate runtime** from the -Kyverno K8s admission controller — same policy lineage, different -application target. Where Kyverno (K8s) evaluates `ClusterPolicy` -resources against Kubernetes manifests at admission time, kyverno-json -evaluates `ValidatingPolicy` resources against **any** JSON or YAML -payload file via the CLI (`kj scan`) or a Go library. It is **not** a -Python package (no PyPI release); it is installed via -`go install github.com/kyverno/kyverno-json/cmd/kj@latest` (D-115) or by -downloading a pinned binary from GitHub releases. +### 1.2 PoA consensus — single validator (pilot) -### 2.2 CLI surface (the v1.25 invocation path) +Proof-of-Authority with a single validator is the minimal consensus +model: the validator proposes + commits blocks. No Byzantine fault +tolerance (single validator = no forks). Deterministic block +production: same ordered transactions → same block (same hash). This +makes the chain auditable (the hash chain is verifiable) and +reproducible (a replay produces the same chain). Multi-validator BFT +is a future milestone (D-201). -The v1.25 engine uses the `kj scan` subcommand: +### 1.3 T+1 settlement finality -``` -kyverno-json scan [flags] +Equities settle T+1 (trade date + 1 business day). The pilot's +settlement service records matches as transactions on the chain; a +settlement is final when its block is committed. The settlement-finality +kyverno-json policy (REQ-315) asserts `all_committed: true` before any +promotion (qa→prod) — the declarative gate that turns settlement +finality into a policy artifact. This is the securities-specific +extension of v1.25's policy engine: the same `KyvernoJsonEngine` +evaluates a policy over a new payload shape (settlement-service status +JSON). -Flags: - --labels strings Labels selectors for policies - --output string Output format (text or json) (default "text") - --payload string Path to payload (json or yaml file) - --policy strings Path to kyverno-json policies - --pre-process strings JMESPath expression used to pre process payload -``` +### 1.4 Equities-only scope (D-200) -The `KyvernoJsonEngine.evaluate()` implementation (REQ-293) invokes: -``` -kj scan --policy --payload --output json -``` -and parses the JSON `results[]` array. The `--pre-process` flag is -available for JMESPath pre-projection (noted for the meta-policy use case -where the payload is the merged PCR list and a pre-process expression -can index by `ruleId` — recorded as a future optimization, not used in -v1.25's initial implementation). +Bonds (T+2), derivatives (varying), and options (exercise models) have +different settlement models. A pilot should demonstrate the Nova +platform's gates over the simplest case (equities T+1) before +expanding. "All types of securities" is the product vision; v1.26 is +the pilot (equities first). Future milestones add other security types +with their settlement models. -Other subcommands (`kj jp`, `kj serve`, `kj playground`, `kj docs`) are -out of scope for v1.25. `kj serve` is the long-running web-app mode -(noted as a future consideration for lower-latency evaluation in the -Out of Scope section of REQUIREMENTS.md). `kj jp` is the JMESPath REPL — -useful for policy authoring/debugging, not invoked by the engine. +--- -### 2.3 Policy structure (the `ValidatingPolicy` resource) +## 2. Nova Consumer Deploy Model -kyverno-json policies are Kubernetes-style resources (cluster-scoped) -belonging to the `json.kyverno.io` API group, kind `ValidatingPolicy`, -version `v1alpha1`: +### 2.1 The reusable `deploy.yml@v1.25` workflow -```yaml -apiVersion: json.kyverno.io/v1alpha1 -kind: ValidatingPolicy -metadata: - name: # becomes the KJ_ ruleId prefix -spec: - rules: - - name: - identifier: # optional — path to the unique entry id - match: # assertion tree — which payload entries - any: # the rule applies to - - - exclude: # optional — exclude matching entries - any: - - - context: # optional — named bindings available to - - name: # the rule's assertions ($) - variable: - validate: - message: "" # optional per-rule message - assert: - all: # all assertions must hold - - check: - message: "" - # OR - any: # at least one assertion must hold - - check: -``` +The platform's `.github/workflows/deploy.yml` is a `workflow_call` — +a reusable workflow that a consumer repo invokes via +`uses: acdl/.github/workflows/deploy.yml@v1.25`. Inputs: `contract` +(default `.nova/contract.yml`), `mode` (default `full`; enum +`full|plan-only|check-only|decommission`), `environment` (override). +The workflow checks out the consumer repo + the platform repo, runs +`scripts/run_platform.sh`, and records the apply decision + +attestation in the Decision Ledger. Secrets: `NOVA_AWS_*` +(account + access key + secret) + `NOVA_LAMBDA_URL` (error reporting). -Key differences from K8s Kyverno policies: -- **Always cluster-scoped** — no `namespace` field. -- **No `forEach`, pattern operators, anchors, or wildcards.** Iteration - is done via the `~` projection modifier in assertion trees (see §2.4). -- **Assertion trees** with JMESPath expressions replace Kyverno's - pattern-matching syntax (see §2.4). +The pilot consumer (`nova-blockchain-exchange`) invokes this workflow +with `mode: full` for `dev` (D-209). The `.gitea/workflows/deploy.yml` +mirror is byte-identical (the platform's deploy workflow is +forge-agnostic — Gitea + GitHub). -### 2.4 Assertion trees (the rule language) +### 2.2 `run_platform.sh --apply` path (confirmed) -An `assert` declaration contains an `all` or `any` list. Each entry has a -`check` (the assertion tree — a nested JMESPath projection) and an -optional `message`. **All comparisons happen in the leaves of the tree.** +`scripts/run_platform.sh:431-455` — the `--apply` (or `mode: full`) +path runs `terraform apply -auto-approve` after the HITL gate +(`:438`). For `dev` (autonomous, no HITL gate), the apply proceeds +directly. The apply records the env via `core/env_transition.py record` +(`:450`). The full pipeline (no `--apply` flag) continues to Step 7 +(confidence signal) + Step 8 (outbox write). -A simple example (assert a pod doesn't use the default service account): -```yaml -validate: - assert: - all: - - message: "serviceAccountName 'default' is not allowed" - check: - spec: - (serviceAccountName == 'default'): false -``` +**Gap (noted in RESEARCH §4):** the `--apply` path exits before the +outbox write (Step 8). The pilot runs the full pipeline (not `--apply` +alone), so the outbox write happens. The `run.completed` event lands in +the JSONL Decision Ledger (not the DynamoDB outbox) — this is by design +(the outbox is the platform-run evidence stream; the Decision Ledger is +the cold store for metrics). -The `(expression)` syntax evaluates a JMESPath expression; the result -becomes the current object for descendants; the leaf value is compared -to the expected value. +### 2.3 Contract schema — multi-module manifest -**Iteration via the `~` modifier.** The `~` prefix on a key applies -descendant assertions to **each element** of an array/map individually -(rather than comparing the whole array). Given `foo.bar: [1,2,3]`: -```yaml -check: - foo: - ~.bar: # iterate each element - (@ < `5`): true # assert each element < 5 -``` -The `~index_name.bar` form binds the index (array) or key (map) to -`$index_name` for use in descendants. This is how v1.25 iterates -`resources[]` in the Stack IR policies (REQ-297) and -`planned_values.root_module.resources[]` in the plan-JSON policies -(REQ-300). +`schemas/contract.schema.json:7,24-48` — required fields: `id`, +`name`, `environment`, `infrastructure`. The `infrastructure` block is +`minProperties: 1` with `patternProperties` accepting any module name +key. Multi-module manifest is supported: one contract can declare +`infrastructure: { microservice: {...}, dynamodb: {...}, s3: {...} }`. +The constraint is the `modules/registry.json` (the module must be +registered), not the schema. -**Explicit bindings** via `->binding_name` allow descendants to refer -to a parent node via `$binding_name`. Built-in bindings: `$payload` -(the whole input), `$policy`, `$rule`. +--- -**Escaping** via `\key\` prevents projection when a payload key collides -with the projection syntax. Not needed for Nova payloads (no `(key)` -fields), noted for completeness. +## 3. Platform Module Readiness (the critical finding) -### 2.5 Output shape (what `kj scan --output json` produces) +### 3.1 The adapter is stateless (v1.11 rewrite) -The JSON output is a `results[]` array. Each result entry has (at -minimum): -- `policy`: the policy metadata.name -- `rule`: the rule name -- `result`: `"pass"` | `"fail"` | `"error"` | `"skip"` (lowercase) -- `message`: the assertion message (or engine error message) -- `resource`: the matched payload entry (the `identifier` value, or the - whole payload when no identifier/match) -- `namespace`/`kind`/`name`: K8s-style fields (present but empty for - non-K8s payloads — the K8s Kyverno adapter's evidence uses these; the - kyverno-json engine's evidence uses `assertion`/`jmespath` instead) -- `severity`: not present by default (kyverno-json does not assign - severities — the Nova policy author assigns severity via a Nova- - specific annotation; see §2.6) +`adapters/terraform/adapter.py:1-11` — the adapter is a "STATELESS +ASSEMBLER" that owns no module content. There is **no `TYPE_MAP`**, +`INPUT_MAP`, or `OUTPUT_MAP` (deleted in the v1.11 stateless rewrite; +`modules/STANDARDS.md:212-214` confirms). A new stack type requires a +new L1 module (`modules/l1//` with `interface.json` + +`terraform/main.tf` + `README.md` + `instance.json`) + a +`modules/registry.json` entry — not an adapter change. -The `KyvernoJsonEngine._to_pcr()` translator (REQ-293) maps: -- `policy` → `ruleId` (prefixed `KJ_` per D-116) -- `result` → `result` (`pass`/`fail`/`error` → pass/fail/error; - `skip`/`skipped` → skipped) -- `message` → `message` -- `resource` → `resourceRef` + `evidence.resource` -- severity from the policy's `metadata.annotations` (see §2.6) -- `engine: "kyverno"` (per D-116 — no new enum value) +### 3.2 ECS — ready -### 2.6 Severity assignment (Nova convention) +`modules/l1/ecs-service/terraform/main.tf:1,11` — +`aws_ecs_task_definition` + `aws_ecs_service`. `interface.json:5-6` — +`type: aws:ecs:task_definition`. `registry.json:29-37` — registered. +Tests: `test_adapter.py:164-185,257-360`, `test_contract_resolver.py:61-92`. +The `microservice` L2 (`modules/l2/microservice/composition.json`) +references 6 L1 children (ecs-cluster, ecr, iam-role, alb, ecs-service, +kms-key) — the ECS pattern is fully wired end-to-end. -kyverno-json does not natively assign severities to results. Nova's -confidence signal requires a `severity` per PCR (critical/high/medium/ -low/info). The v1.25 convention: each Nova policy file declares its -severity via a `metadata.annotations` field: +### 3.3 S3 — ready -```yaml -metadata: - name: forbid-public-ingress - annotations: - nova.cloudinit.dev/severity: high -``` +`modules/l1/s3/terraform/main.tf:1` — `aws_s3_bucket` (+ versioning + +SSE). `interface.json:5-6` — `type: aws:s3:bucket`. `registry.json:2-10` +— registered. Tests: `test_adapter.py:56-110,241-257`, +`test_contract_resolver.py:36-51,92-130`. -The `KyvernoJsonEngine._to_pcr()` reads this annotation from the loaded -policy YAML (not from the scan result — the result doesn't carry it) and -applies it to every result that policy produces. Default when absent: -`info`. This keeps severity in the policy (declarative, version- -controlled) rather than in the engine adapter (imperative). The -annotation key is `nova.cloudinit.dev/severity` (matches the existing -`nova.cloudinit.dev` namespace used in `schemas/tagging-standard.json`). +### 3.4 DynamoDB — GAP (REQ-322) -## 3. The four policy targets (v1.25 scope) +**No `modules/l1/dynamodb/` directory, no `registry.json` key, no +`interface.json`, no `terraform/`, no tests.** The blockchain exchange's +ledger table needs this primitive. REQ-322 authors it: `interface.json` +(stack type `aws:dynamodb:table`), `terraform/main.tf` +(`aws_dynamodb_table` with PK + optional SK, `PAY_PER_REQUEST` default, +encryption + PITR enabled per v1.8 NFR defaults), `README.md`, +`instance.json`, + `registry.json` entry. The adapter needs no change +(stateless); the contract's `infrastructure.dynamodb` block references +this primitive. This is the single platform-side module build-out for +the milestone. -### 3.1 Consumer contract JSON (REQ-295) +### 3.5 Stale doc (not a blocker) -The payload is the parsed contract dict (the raw YAML loaded as JSON). -Policies assert the `contract.schema.json` constraints declaratively: -`require-id-pattern` (JMESPath regex `^[a-z][a-z0-9-]{2,5}$` over -`id`), `require-env-in-enum` (`environment` in `["dev","qa","prod","dr"]`), -`require-infrastructure-min-1` (`length(infrastructure) > 0`), -`forbid-unknown-fields` (keys subset of the 4 allowed). These are the -declarative equivalent of the jsonschema constraints — they let Nova -apply its own compliance posture (e.g. forbid a specific env for a -specific consumer) on top of schema validity without editing the -jsonschema. +`adapters/README.md:49-54` references the deleted `TYPE_MAP`/ +`INPUT_MAP`/`OUTPUT_MAP` — contradicts `adapter.py:1-11` + +`modules/STANDARDS.md:212-214`. REQ-321 (docs) should fix this. -**Invocation point:** `core/contract_resolver.py` pre-resolve (REQ-296). -Early-fail: if a contract policy fails, the resolver still proceeds -(the confidence signal decides the gate, consistent with the existing -`--soft-fail` Checkov pattern) — but the failing PCRs are in the -`policy` input, which lowers the score. +--- -### 3.2 Resolved Target Stack IR JSON (REQ-297) +## 4. Metric Pipeline Grounding (Post-Pilot targets) -The payload is the resolved Stack IR dict produced by -`core/contract_resolver.py` (the merged module outputs). Policies -assert over `resources[]` (the array of resolved resources): -`require-tagging-standard` (every resource's `tags` has `nova:owner` + -`nova:environment` — ports -`adapters/terraform/policy/custom_rules/nova_tagging.py`), -`forbid-public-ingress` (no resource has `public_ingress: true` — the -v1.0 demo rule, now declarative), `require-encryption-by-default` (every -S3/EBS/KMS-aliased resource carries encryption config — ports the v1.8 -D-encryption-default rule). The `~` modifier iterates `resources[]`. +### 4.1 AI Decision Accuracy — outcome backfill (REQ-317) -**Invocation point:** `core/contract_resolver.py` post-resolve (REQ-298). -Additive — the resolver's return values and exceptions are unchanged; -the PCRs are appended to the contract-policy PCRs. +`core/metrics/decision_ledger.py:210-211` documents the event chain: +`confidence.computed → ai.decision.made → attestation.recorded → +run.completed/failed`. `collector.py:262` inserts `fact_decision.outcome` +as `"pending"` — **there is no outcome-backfill step** wiring +`run.completed`/`run.failed` back into `fact_decision.outcome`. The AI +Decision Accuracy metric (`trust_snapshot.py:70-85`, `_get_ai_decision_accuracy`) +reads `decisions WHERE outcome='succeeded' ÷ total` — so it reads 0% +today (all pending). REQ-317 adds `core/metrics/outcome_backfill.py` +that reads run-manifest events and updates `fact_decision.outcome` + +`fact_decision.backfilled_at`. The PCR schema is unchanged (D-211). -### 3.3 Terraform plan JSON (REQ-300) +### 4.2 Human Escalation Frequency — `reason='confidence'` tag (REQ-318) -The payload is `terraform show -json ` output. Policies assert -over `planned_values.root_module.resources[]`: -`forbid-plaintext-secrets` (no `aws_db_instance.password` / -`aws_iam_user.login_profile.password` in plaintext — ports -`CKV_AWS_41/45/46`), `forbid-iam-wildcard` (no `Action: "*"` or -`Resource: "*"` in `aws_iam_policy.PolicyDocument` — ports -`CKV_AWS_1/40`), `require-kms-reference` (KMS keys referenced by alias, -not inline key material — ports `CKV_AWS_7/33`). These are declarative -**mirrors** of `checkov_adapter.py:RULE_MAP` — the Checkov rule stays -the source of truth for `terraform_plan` scanning; the kyverno-json -policy covers the same plan JSON with a different rule language -(defense-in-depth against engine drift). +`core/confidence_signal.py:184` — a `block` band sets +`human_override=True` in the `ai.decision.made` event. +`run_platform.sh:636` fails the pipeline on `block`. The Human +Escalation Frequency metric (`docs/metrics/human_escalation_frequency.md:11-12`) +is defined as `count(runs WHERE hitl_block=1 AND reason='confidence') ÷ +total runs`. The `reason='confidence'` discriminator is **not currently +stored** — `hitl_block` is a boolean from the manifest. REQ-318 adds +`escalation_reason: 'confidence'` to the `ai.decision.made` event when +`band == 'block'` + persists it into `fact_run` via the collector. -**Invocation point:** `run_platform.sh` Step 5 (REQ-301). After -Checkov/Wiz produce raw PCRs, the script runs `kj scan` over the plan -JSON; both PCR lists concatenate into the confidence signal's `policy` -input. When `which kj` is false, the script logs and proceeds with the -Checkov/Wiz list only. +### 4.3 Touchless Resolution Rate — denominator activates post-pilot -### 3.4 PolicyCheckResult records (meta-policies, REQ-303) +`docs/metrics/touchless_resolution_rate.md:12-15` — defined as a SQL +query over `fact_run` (`runs WHERE hitl_block=0 ÷ total runs`). The data +lands in `fact_run.hitl_block` via `collector.py:216-227`. No dedicated +emitter computes the ratio — it's a downstream query. The denominator +is 0 today (no consumer runs). The pilot run activates the denominator. -The payload is the **merged** `list[PolicyCheckResult]` produced by -checkov + wiz + the plan-JSON policies. This is the most novel target — -kyverno-json policies over the policy results themselves. -`block-on-any-critical` asserts no PCR has `severity: "critical"` + -`result: "fail"`; if any does, the meta-policy emits a `fail` PCR with -`ruleId: "KJ_META_BLOCK_CRITICAL"` and severity `critical`. This is the -declarative source of truth for "critical = block" (D-119 — the -`confidence_signal.py` `PENALTY["critical"]: None` hard-override stays -as defense-in-depth). `tagging-rules-agree` cross-checks the Checkov -`NOVA_TAG_NAMING` result against the kyverno-json -`KJ_REQUIRE_TAGGING_STANDARD` result by `resourceRef`; divergence emits -an `error` PCR (D-118). +--- -**Invocation point:** after the three target policies (contract/stack- -IR/plan-JSON) produce their PCR lists, the merged list is the payload -for the meta-policies. The meta-policy PCRs are appended to the merged -list, which is what the confidence signal consumes. +## 5. kyverno-json Policy Extensibility -## 4. The `PolicyEngine` swap boundary +`adapters/kyverno-json/kyverno_json_engine.py:74-80` — the engine is +**policy-dir agnostic**: it loads whatever subdir the caller passes. +Existing subdirs: `contract/`, `stack-ir/`, `plan-json/`, `meta/`, +`regression/`. Adding a new subdir (e.g. `pilot-readiness/`, +`settlement-finality/`) requires: (1) `mkdir +adapters/kyverno-json/policies//`, (2) drop `ValidatingPolicy` +YAML/JSON files, (3) wire a caller. No engine code change needed. +Test pattern: one test file per subdir (`tests/test__policies.py`). -### 4.1 Protocol shape (REQ-291) +The pilot adds two new policy subdirs: `pilot-readiness/` +(REQ-320, no-placeholder-account) + `settlement-finality/` (REQ-315, +all-matches-committed). Both follow the established pattern. -A Python `Protocol` (PEP 544 — structural subtyping, no inheritance): -```python -class PolicyEngine(Protocol): - @property - def name(self) -> str: ... - def is_configured(self) -> bool: ... - def evaluate(self, payload: dict | str, policy_dir: Path, - contract_id: str) -> list[dict]: ... -``` -`list[dict]` (not `list[PolicyCheckResult]` — there's no dataclass; the -schema is enforced via `jsonschema` validation in tests, matching the -existing adapter pattern). The registry selects the active engine from -`config.json.policy.engine`. A `NullEngine` is the fallback when the -`policy` key is absent (emits `SKIPPED` — backward compatibility for -tests that don't set the key). +--- -### 4.2 The OPA-equivalent surface (future swap) +## 6. Env-JSON Wiring Reconciliation (REQ-319) -OPA (Open Policy Agent) is the most likely future replacement. The -mapping: -| Nova `PolicyEngine` member | kyverno-json impl | OPA equivalent | -|---|---|---| -| `name` | `"kyverno-json"` | `"opa"` | -| `is_configured()` | `which kj` | `which opa` | -| `evaluate(payload, policy_dir, contract_id)` | `kj scan --policy --payload -o json` | `opa eval -d -i 'data.nova.<...>'` | -| Policy file format | `ValidatingPolicy` (YAML) | Rego (`.rego`) | -| Result shape | `results[]` (pass/fail/error/skip) | `result` (set of violations) | -| Severity | Nova annotation `nova.cloudinit.dev/severity` | Nova convention (Rego `metadata` or a wrapper) | +`core/environments/dev.json:4` — `account_id: "000000000000"` (placeholder). +`core/environment_check.py:48-53` warns (non-fatal) when account_id is +placeholder + env != dev. `adapters/terraform/adapter.py:116-117` — +computes the state bucket as `nova-tfstate--us-east-1` +from the `AWS_ACCOUNT_ID` env var, **not** from the env JSON's +`state_backend.bucket`. This is the wiring gap: the env JSON's +`state_backend` field is currently unused by the live apply path. +REQ-319 makes the adapter read `env.state_backend.bucket` when present +(falling back to the computed name for backwards compat) + updates +`dev.json` to the real account `581513795199` + real bucket +`nova-tfstate-581513795199-us-east-1`. -The protocol is minimal (3 members) specifically so the OPA -implementation is a known quantity: an `OpaEngine` class that shells to -`opa eval`, translates the Rego violation set to PCR dicts, and -implements `is_configured()` via `which opa`. The policy *files* would -need rewriting (Rego, not ValidatingPolicy) — but the protocol, the -registry, the confidence signal, and the PCR schema are all untouched. -This is the swap boundary the user asked for ("Implemented as an -adapter since we might one day decide to replace it with something else -like OPA"). +--- -### 4.3 Why not a full plugin registry? - -A `setuptools` entry-point plugin registry (like checkov's -`--external-checks-dir`) was considered and rejected: Nova has 1 active -engine today (kyverno-json) and at most 2 in the foreseeable future -(kyverno-json + OPA). A `Protocol` + `dict` registry in -`core/policy_engine.py` is the right weight — discoverable, typed, -testable, and ~40 lines. An entry-point registry adds packaging -complexity (entry-point metadata, version resolution) for no gain at -this scale. The `register(name, factory)` method on the registry is -the extension point if a future milestone needs runtime plugin -discovery. - -## 5. Latency / MTTR impact (G-Q3 anticipation) - -NORTH_STAR.md MTTR target: < 60s p95. `run_platform.sh` Step 5 today -runs Checkov over the terraform plan (typically 5-15s for a small -stack). Adding `kj scan` over the same plan JSON adds: -- Process spawn: ~50ms (Go binary startup) -- Policy load: ~20ms (a handful of YAML files) -- Assertion evaluation: ~100-500ms (JMESPath over a small plan) -- Total: < 1s for a typical Nova stack - -The kyverno-json pass runs **in parallel** with Checkov (REQ-301 — the -script launches both and waits on both), so the wall-clock impact is -`max(checkov_time, kj_time)` ≈ checkov_time (kj is faster). The -contract + stack-IR policies run during resolve (already a fast step). -Meta-policies run over the merged list (in-memory, < 10ms). **No -measurable MTTR impact** is expected. This will be verified in P3 -VERIFY with a timing assertion. - -## 6. "Platform functions without AI" tenet (G-Q1 / D-120) - -kyverno-json is deterministic (same policy + payload → same result, -every run). It is not an LLM, not a probabilistic model, not a -"judgement" engine. The NORTH_STAR.md tenet ("the platform functions -without AI — 'AI decisions' are really automated decisions") -distinguishes AI (non-reproducible) from automation (reproducible). -kyverno-json is the latter. Adding it is **more** aligned with the -tenet than the current imperative Python in `core/env_transition.py` -and `core/regression_verify.py`, because the policy is declarative -(visible, auditable, version-controlled) rather than imperative (logic -hidden in function bodies). The `is_configured()` guard ensures the -platform functions without the binary (graceful skip → `SKIPPED` PCR -→ confidence signal proceeds). - -## 7. ECS policy catalog overlap (prior art) - -The kyverno-json catalog ships ECS policies that overlap with Nova's -L1 modules: `ecs-cluster-enable-logging`, `ecs-cluster-required- -container-insights`, `ecs-service-public-ip`, `ecs-service-required- -latest-platform-fargate`, `ecs-task-definition-fs-read-only`. These are -**reference policies**, not drop-in Nova policies — they target the -AWS ECS API shape (`type: aws_ecs_service` etc.), not Nova's Stack IR -shape. v1.25 policies target the Nova IR (REQ-297) and the terraform -plan JSON (REQ-300), not the raw AWS API. The catalog is useful as -prior art for JMESPath patterns over ECS resources — the -`ecs-service-public-ip` policy's `contains('$allowed-values', -@.assign_public_ip)` pattern informs the Nova `forbid-public-ingress` -policy shape. No catalog policies are imported directly in v1.25. - -## 8. Risks & mitigations +## 7. Risk Analysis | Risk | Likelihood | Impact | Mitigation | |---|---|---|---| -| `kj` binary not in CI image | medium | blocks P3+ tests | `is_configured()` guard + `pytest.skip` + `scripts/install-kyverno-json.sh` | -| kyverno-json output shape changes across versions | low | breaks `_to_pcr()` | pin `@latest` to a known-good commit in `install-kyverno-json.sh` after P1 smoke; defensive parsing (malformed → `error` PCR, not exception) | -| Policy explosion (4 targets × N rules) | medium | maintenance load | wave ordering (PLAN); policies co-located per target dir; meta-policy cross-check keeps the set auditable | -| Checkov + kj tagging-rule drift | medium | false `error` PCRs | `tagging-rules-agree` meta-policy emits `error` on divergence (visible, not silent); the Checkov rule stays source of truth for HCL, kj for IR | -| OPA swap turns out harder than the protocol implies | low | future milestone rework | RESEARCH §4.2 documents the OPA-equivalent surface; the protocol is the contract, not the implementation | -| `--pre-process` needed for meta-policies but undocumented behavior | low | meta-policy bugs | v1.25 meta-policies use plain assertion trees over the PCR list (no pre-process); `--pre-process` noted as a future optimization only | +| `NOVA_AWS_*` key lacks a needed IAM permission mid-pilot | Low (bootstrap succeeded → root-equivalent) | High (blocks apply) | D-207; the key has root-equivalent perms (empirically confirmed). | +| DynamoDB primitive takes longer than expected (new module) | Medium | Medium | REQ-322 is the single platform-side build-out; the `s3`/`rds` primitives are the template — straightforward. | +| Homegrown chain has a correctness bug (hash chain breaks) | Low | High | REQ-310 tests cover chain integrity, hash determinism, genesis, append/verify. | +| `deploy.yml@v1.25` ref doesn't resolve (floating tag) | Low | High | The platform's `release.yml` creates + force-moves the `v1.25` + `v1` floating tags on merge to main. The pilot contract uses `@v1.25`. | +| Settlement-finality policy false-negatives (blocks a valid promotion) | Medium | Medium | REQ-315 tests cover passing + failing fixtures; the policy is skip-when-kj-absent (graceful). | +| D-083 deferral challenged (audit ledger not tamper-evident) | Low | Low | D-204; the SQLite hash-chain + DynamoDB outbox is the pilot's audit record. Tamper-evidence is a future milestone. | -## 9. Assumptions (logged, full autonomy) +--- -- A1: `kj scan --output json` produces a stable `results[]` array shape. - Will be verified in P1 smoke test (`_smoke.json` policy + a trivial - payload); if the shape differs, `_to_pcr()` is adjusted defensively - (malformed → `error` PCR). Confidence: 0.85. -- A2: The `nova.cloudinit.dev/severity` annotation convention is - read by the engine from the policy YAML (loaded once per evaluate() - call). kyverno-json does not validate unknown annotations — they pass - through. Confidence: 0.90. -- A3: The `~` projection modifier iterates `resources[]` in the Stack - IR and `planned_values.root_module.resources[]` in the plan JSON - correctly. Verified in P2/P3 tests. Confidence: 0.85. -- A4: `go install` works in the CI image (Go toolchain available or - installable). If not, the binary-release download path is the - documented fallback in `install-kyverno-json.sh`. Confidence: 0.80. -- A5: The `NullEngine` fallback (when `policy` key absent in - config.json) keeps all existing tests passing — they don't set the - key, so they get `NullEngine` → `SKIPPED` PCRs → confidence signal - proceeds with `policy` input `[SKIPPED]` → per-input score 1.0 - (skipped counts as pass in `_per_input_score`). Confidence: 0.95 - (verified against `confidence_signal.py:84-89`). +## 8. Persona Assessment -## 10. Decisions referenced - -D-115 (install path), D-116 (engine enum reuse), D-117 (adapter -signatures unchanged), D-118 (tagging cross-check), D-119 (critical- -override defense-in-depth), D-120 (deterministic not AI). See -CLARIFY.md for the full resolution text. - -## 11. Architecture updates (deferred to RESEARCH-stage file edits) - -- `.ciagent/ARCHITECTURE.md` gains §12.7 "Policy Engine Registry" with - the registry diagram. Deferred to the RESEARCH commit (this file's - commit) — the section is authored as part of this research. -- `schemas/README.md` notes `engine: "kyverno"` is shared by the K8s - adapter and kyverno-json (distinguished by `ruleId` prefix). -- `modules/STANDARDS.md` gains a "Policy authoring standard" section - (P4, REQ-307). -- `docs/METRICS.md` notes the policy engine is swappable (P4, REQ-307). \ No newline at end of file +See `PERSONAS.md` (next section, produced by the lead-developer at the +end of RESEARCH). The active roster: backend-engineer (blockchain core ++ settlement + outcome backfill), data-engineer (DynamoDB primitive + +metrics cold store), policy-engineer (kyverno-json policies), + +blockchain-engineer (custom, phase-specific — chain consensus, order +matching, settlement finality). frontend-engineer is deactivated (no +UI in the pilot). \ No newline at end of file diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index 365484a..d96d98e 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -2308,6 +2308,10 @@ Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). `nova-tfstate-581513795199-us-east-1`. - REQ-320: `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` — declarative gate preventing apply against a placeholder account. +- REQ-322: `modules/l1/dynamodb/` — new L1 primitive (interface.json + + terraform/main.tf + README.md + instance.json + registry.json entry). + The single platform-side module build-out (ECS + S3 already exist; + the adapter is stateless/registry-driven). ### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4) - REQ-321: `adapters/README.md` (new consumer row) + @@ -2330,7 +2334,7 @@ Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). `milestone/v1.26-pilot-activation` → `main`; tag `v1.25.5` (= the v1.26 release per prev-minor tagging rule); create Gitea release with full milestone summary; delete all milestone branches. -- Update `REQUIREMENTS.md` (mark REQ-310..321 complete), `ROADMAP.md` +- Update `REQUIREMENTS.md` (mark REQ-310..322 complete), `ROADMAP.md` (mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1 + #3 — first real consumer estate; Post-Pilot denominators activated). -- **Requirements:** REQ-310..321 (12 requirements). +- **Requirements:** REQ-310..322 (13 requirements). diff --git a/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md index 55d1396..f535d0d 100644 --- a/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md +++ b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md @@ -60,6 +60,8 @@ contract references the Nova platform's deploy workflow (`uses: acdl/.github/workflows/deploy.yml@v1.25`) and declares the blockchain exchange stack (the AWS resources the app needs: ECS for the matching engine, DynamoDB for the ledger, S3 for block storage). +The DynamoDB L1 primitive (REQ-322) must land before this contract can +declare `dynamodb` — ECS + S3 already exist. **Must-haves:** - `contract.yaml` — id, name (`blockchain-exchange`), environment @@ -177,11 +179,43 @@ Update `adapters/README.md` (new consumer row), `docs/METRICS.md` (the - `.ciagent/ARCHITECTURE.md` — §12.8 Pilot Estate. - `.ciagent/nova-blockchain-exchange/README.md` — onboarding guide. +### REQ-322 — DynamoDB L1 primitive (platform-side) + +The blockchain exchange's ledger table needs a DynamoDB L1 primitive. +Research (RESEARCH §3) confirmed the adapter is stateless/registry- +driven (no `TYPE_MAP` — deleted in v1.11); a new stack type requires a +new L1 module, not an adapter change. The `dynamodb` primitive mirrors +the existing `s3` / `rds` primitives: `interface.json` (stack type +`aws:dynamodb:table`, inputs `table_name`/`region`/`pk`/`sk`/`billing_mode`, +outputs `table_arn`/`table_name`), `terraform/main.tf` +(`resource "aws_dynamodb_table" "this"`), `README.md`, `instance.json`, ++ a `registry.json` entry. The pilot contract's `infrastructure.dynamodb` +block references this primitive. This is the single platform-side +module build-out for the milestone (ECS + S3 already exist). + +**Must-haves:** +- `modules/l1/dynamodb/interface.json` — stack type + `aws:dynamodb:table`, inputs, outputs. +- `modules/l1/dynamodb/terraform/main.tf` — + `resource "aws_dynamodb_table" "this"` (PK + optional SK, + `billing_mode = PAY_PER_REQUEST` default, encryption + point-in-time- + recovery enabled per v1.8 NFR defaults). +- `modules/l1/dynamodb/README.md` — module doc. +- `modules/l1/dynamodb/instance.json` — sample instance. +- `modules/registry.json` — `dynamodb` entry (kind `l1`, + `terraform_dir: modules/l1/dynamodb/terraform`). +- `tests/test_adapter.py` — add `dynamodb` to `EXPECTED_L1_KEYS` + + a resolution + emission test. +- `modules/README.md` — catalog index updated. + ### Summary -12 requirements (REQ-310..321). Equities-only pilot; minimal PoA ledger; +13 requirements (REQ-310..322). Equities-only pilot; minimal PoA ledger; T+1 settlement; consumer deploy via `deploy.yml@v1.25`; 3 Post-Pilot metrics grounded (outcome backfill + escalation reason + pilot runs); 3 kyverno-json policies extending v1.25 (settlement-finality, pilot-readiness, + the existing meta-policies apply); env-JSON wiring -reconciled. \ No newline at end of file +reconciled; DynamoDB L1 primitive authored (the single platform-side +module build-out — the adapter is stateless/registry-driven, so the +primitive is a new `modules/l1/dynamodb/` module + registry entry, not +an adapter change). \ No newline at end of file From 2a4d7b76258c8933e0898886ac5909374620c3af Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:17:39 +0000 Subject: [PATCH 04/34] =?UTF-8?q?docs(P00):=20ideate=20=E2=80=94=20v1.26?= =?UTF-8?q?=20(7=20ideas=20accepted,=203=20deferred,=200=20rejected)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: ideate ideas_accepted: [I1..I7] ideas_deferred: [I8, I9, I10] ---/ci--- --- .ciagent/CHECKPOINT.json | 4 +- .ciagent/IDEATE.md | 271 ++++++++++++++++++++++----------------- 2 files changed, 156 insertions(+), 119 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 48c352f..8ce8989 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "research", + "stage": "ideate", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:13:00Z", + "updated_at": "2026-08-12T21:14:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", diff --git a/.ciagent/IDEATE.md b/.ciagent/IDEATE.md index 0e74f0a..b4d0a82 100644 --- a/.ciagent/IDEATE.md +++ b/.ciagent/IDEATE.md @@ -1,132 +1,152 @@ -# IDEATE — v1.25 kyverno-json Unified Policy Engine +# IDEATE — v1.26 Live Pilot Estate Activation > **Autonomy:** full. 3-tier ideation per `config.json ideation.enabled: > true`. `cross_project.enabled: false` → cross-project tier scoped to -> single-project (deferred ideas only, no cross-project candidates +> multi-project (deferred ideas only, no cross-project candidates > accepted). `confidence_threshold: 0.6`, `max_ideas: 20`. > Categories: security, quality, architecture, coverage, improvement. ## Tier 1 — Mechanical (pattern-driven, codebase-grounded) -### I1 — Regression-gate-as-policy ✅ ACCEPTED (REQ-304, REQ-305) +### I1 — Outcome-backfill emitter ✅ ACCEPTED (REQ-317) + +**Category:** quality, coverage +**Confidence:** 0.92 +**Pattern:** stuck `pending` status → backfilled from a later event +(the most direct metric-grounding pattern). +**Source:** `core/metrics/decision_ledger.py:210-211` documents the +event chain `confidence.computed → ai.decision.made → +attestation.recorded → run.completed/failed`. `collector.py:262` +inserts `fact_decision.outcome` as `"pending"` — no backfill step +wires `run.completed/failed` back into the decision's outcome. The AI +Decision Accuracy metric (`trust_snapshot.py:70-85`) reads +`decisions WHERE outcome='succeeded' ÷ total` → 0% today (all pending). +**Idea:** `core/metrics/outcome_backfill.py` reads run-manifest +`completed`/`failed` events and updates `fact_decision.outcome` + +`fact_decision.backfilled_at`. The collector invokes backfill after run +completion. Grounds AI Decision Accuracy (Post-Pilot target). +**Accepted into:** REQ-317. Phase P3. + +### I2 — `reason='confidence'` escalation tag ✅ ACCEPTED (REQ-318) **Category:** quality, coverage **Confidence:** 0.90 -**Pattern:** imperative check → declarative policy (the milestone's -core thesis applied to Nova's own regression gate). -**Source:** `core/regression_verify.py` (CAP-013, CAP-023, CAP-024) -are imperative Python checks. The milestone makes compliance -declarative; Nova's own capability regression should follow. -**Idea:** Port the three capability checks into -`adapters/kyverno-json/policies/regression/` as declarative policies -over the capability-inventory JSON frontmatter. The imperative -`regression_verify.py` stays (it drives the CI gate); the policies are -the declarative mirror that makes capability regression auditable as a -policy artifact. -**Accepted into:** REQ-304 (policies), REQ-305 (tests). Phase P4. +**Pattern:** boolean field → discriminated field (the metric-numerator +precision pattern). +**Source:** `core/confidence_signal.py:184` — a `block` band sets +`human_override=True`. The Human Escalation Frequency metric +(`docs/metrics/human_escalation_frequency.md:11-12`) is defined as +`count(runs WHERE hitl_block=1 AND reason='confidence') ÷ total runs`. +The `reason='confidence'` discriminator is not stored today. +**Idea:** `ai.decision.made` gains `escalation_reason: 'confidence'` +when `band == 'block'`. The collector persists it into `fact_run`. +Grounds Human Escalation Frequency numerator. +**Accepted into:** REQ-318. Phase P3. -### I2 — Contract-shape validation as policy ✅ ACCEPTED (REQ-295) +### I3 — Env-JSON `state_backend` wiring reconciliation ✅ ACCEPTED (REQ-319) -**Category:** security, architecture -**Confidence:** 0.92 -**Pattern:** jsonschema constraint → declarative policy (same constraint, -different language, Nova posture on top). -**Source:** `schemas/contract.schema.json` required/pattern/enum. -**Idea:** The 4 contract policies (`require-id-pattern`, -`require-env-in-enum`, `require-infrastructure-min-1`, `forbid-unknown- -fields`) are the declarative equivalent of the jsonschema constraints — -they let Nova apply its own compliance posture (e.g. forbid a specific -env for a specific consumer) on top of schema validity without editing -the jsonschema. -**Accepted into:** REQ-295. Phase P2. - -### I3 — Stack-IR imperative rules → declarative policies ✅ ACCEPTED (REQ-297) - -**Category:** security, architecture +**Category:** architecture, improvement **Confidence:** 0.88 -**Pattern:** imperative Python rule → declarative kyverno-json policy. -**Source:** `adapters/terraform/policy/custom_rules/nova_tagging.py` -(tagging), the v1.0 demo `public-ingress: true` rule, the v1.8 -D-encryption-default rule. -**Idea:** Port the three highest-impact imperative rules into -declarative kyverno-json policies over the resolved Stack IR. The -tagging rule is a cross-check (D-118 — both engines, agree meta-policy); -public-ingress and encryption-by-default are kyverno-json only (the IR -is the earliest point these can be caught). -**Accepted into:** REQ-297. Phase P2. +**Pattern:** unused config field → wired config field (the +single-source-of-truth pattern). +**Source:** `adapters/terraform/adapter.py:116-117` computes the state +bucket as `nova-tfstate--us-east-1` from the +`AWS_ACCOUNT_ID` env var — **not** from the env JSON's +`state_backend.bucket`. The env JSON's `state_backend` field is +currently unused by the live apply path. +**Idea:** The adapter reads `env.state_backend.bucket` when present +(falling back to the computed name for backwards compat). `dev.json` +gets the real bucket name. Closes the wiring gap so the pilot's env +JSON is the single source of truth. +**Accepted into:** REQ-319. Phase P3. + +### I4 — Pilot-readiness kyverno-json policy ✅ ACCEPTED (REQ-320) + +**Category:** security, architecture +**Confidence:** 0.85 +**Pattern:** runtime guard → declarative policy (the v1.25 thesis +applied to pilot onboarding). +**Source:** `core/environment_check.py:48-53` emits a stderr warning +(non-fatal) when `account_id == "000000000000"` and env != dev. A +warning is not a gate. The pilot should fail-closed if someone tries +to apply against a placeholder account. +**Idea:** A kyverno-json policy over the env JSON asserting +`account_id != "000000000000"` before any apply. Declarative +fail-closed gate. Extends v1.25's policy engine to the pilot-onboarding +domain. +**Accepted into:** REQ-320. Phase P3. ## Tier 2 — Backend-enriched (signal-driven) -### I4 — Plan-JSON Checkov RULE_MAP → kyverno-json mirrors ✅ ACCEPTED (REQ-300) +### I5 — Settlement-finality kyverno-json policy ✅ ACCEPTED (REQ-315) **Category:** security, coverage -**Confidence:** 0.85 -**Pattern:** existing engine rule → declarative mirror in the new engine -(defense-in-depth against engine drift). -**Source:** `checkov_adapter.py:RULE_MAP` (CKV_AWS_41/45/46, CKV_AWS_1/40, -CKV_AWS_7/33). -**Idea:** Port the 6 Checkov rules over `terraform_plan` into declarative -kyverno-json policies over `terraform show -json` output. The Checkov -rules stay the source of truth for HCL scanning; the kyverno-json -policies are mirrors (different rule language, same plan JSON). Defense- -in-depth: if Checkov and kyverno-json disagree on the same plan, the -divergence is visible (two PCRs with different results for the same -resource). -**Accepted into:** REQ-300. Phase P3. +**Confidence:** 0.82 +**Pattern:** domain invariant → declarative policy (the v1.25 thesis +applied to the securities domain — the most novel use of kyverno-json +in v1.26). +**Source:** The pilot's settlement service records matches as +transactions on the chain; settlement finality = block commit. The +NORTH_STAR Objective #2 (provable trust) says trust should be a policy +artifact, not a promise. Today settlement finality is a runtime +property of the chain; making it a declarative policy turns it into an +auditable gate. +**Idea:** A kyverno-json policy over the settlement-service status JSON +asserting `all_committed: true` before any promotion (qa→prod). The +securities-specific extension of v1.25's policy engine. The policy is +skip-when-kj-absent (graceful). +**Accepted into:** REQ-315. Phase P3. -### I5 — Meta-policy over the merged PCR list ✅ ACCEPTED (REQ-303) +### I6 — Pilot-estate regression capability (CAP-025) ✅ ACCEPTED (REQ-316) -**Category:** architecture, quality -**Confidence:** 0.90 -**Pattern:** the policy result list is itself a policy target (the most -novel use of kyverno-json in v1.25). -**Source:** `core/confidence_signal.py` PENALTY hardcode (critical -override), the D-118 tagging cross-check. -**Idea:** `block-on-any-critical` (declarative "critical = block") + -`tagging-rules-agree` (Checkov vs kj agree). The meta-policies consume -the merged PCR list as their payload. The critical-block meta-policy is -the declarative source of truth; the `confidence_signal.py` hard-override -stays as defense-in-depth (D-119). -**Accepted into:** REQ-303. Phase P3. +**Category:** quality, coverage +**Confidence:** 0.88 +**Pattern:** manual e2e → regression-gated capability (the v1.0 CAP +pattern applied to the pilot). +**Source:** `core/regression_verify.py` has CAP-013..024 (live-AWS + +local tiers). The pilot estate is a new live-AWS capability — +"contract resolve → adapter compile → terraform plan → policy scan → +confidence signal → attestation → outbox record" against +`581513795199`. Without a regression CAP, the pilot could silently +decay. +**Idea:** CAP-025 (live-pilot-apply) in the regression gate. The +round-trip assertion. Grounds the pilot as a maintained capability, +not a one-shot demo. +**Accepted into:** REQ-316. Phase P3. -### I6 — Env-transition destroy as a declarative policy ❌ DEFERRED +### I7 — DynamoDB L1 primitive ✅ ACCEPTED (REQ-322) + +**Category:** architecture, coverage +**Confidence:** 0.95 +**Pattern:** missing primitive → authored module (the v1.7 + v1.8 +module-build-out pattern). +**Source:** RESEARCH §3.4 — no `modules/l1/dynamodb/` exists. The +blockchain exchange's ledger table needs it. The adapter is +stateless/registry-driven (no `TYPE_MAP`); a new stack type requires a +new L1 module, not an adapter change. +**Idea:** Author `modules/l1/dynamodb/` (interface.json + +terraform/main.tf + README.md + instance.json + registry.json entry). +The single platform-side module build-out for the milestone. Follows +the `s3`/`rds` primitive template. Encryption + PITR enabled per v1.8 +NFR defaults. +**Accepted into:** REQ-322. Phase P3. + +### I8 — Stale `adapters/README.md` TYPE_MAP references ❌ DEFERRED (scope) **Category:** improvement -**Confidence:** 0.55 (below threshold — deferred, not rejected) -**Pattern:** imperative lifecycle Python → declarative policy. -**Source:** `core/env_transition.py` (v1.24 detect-and-destroy). -**Idea:** The v1.24 env-transition destroy logic (detect env change via -DynamoDB, destroy prior env, fail-closed) is imperative Python. A -declarative kyverno-json policy could assert "if `environment` changed -on a stable `contract.id`, a destroy event MUST precede the apply" — -turning the lifecycle enforcement into an auditable policy artifact. -**Reason deferred:** The env-transition logic is *stateful* (DynamoDB -queries, terraform state inspection) — kyverno-json policies are -*stateless* (payload in, PCRs out). A policy can assert the *contract* -shape (the env value is valid) but not the *lifecycle* (the prior env -was destroyed). The stateful check stays in `core/env_transition.py`; -a future milestone could emit a `nova.env.destroyed` event that a -kyverno-json policy then asserts is present in the evidence stream -(event-as-policy). Recorded as a future-idea, not a v1.25 requirement. +**Confidence:** 0.70 (above threshold, but scoped into REQ-321) +**Pattern:** stale doc → corrected doc. +**Source:** `adapters/README.md:49-54` references the deleted +`TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` — contradicts `adapter.py:1-11` + +`modules/STANDARDS.md:212-214`. +**Idea:** Fix the stale references as part of the docs phase. +**Reason deferred as a standalone idea:** Already captured in REQ-321 +(docs + adapter README). No new requirement needed — the fix lands in +P4 docs. -### I7 — Drift detection as policy ❌ DEFERRED +## Tier 3 — Cross-project (deferred — multi-project, but cross-project sharing disabled) -**Category:** security, coverage -**Confidence:** 0.40 (below threshold — deferred) -**Pattern:** scheduled job → policy over the drift report. -**Source:** NORTH_STAR.md Non-Goal #4 (drift detection scheduled job, -deferred — D-096 + no scheduler). -**Idea:** A kyverno-json policy over a terraform drift report could -assert "no drifted resources" declaratively. But drift detection itself -requires a scheduled `terraform plan -detailed-exitcode` job, which is -deferred (no scheduler). The policy is the easy part; the emitter is the -blocking dependency. -**Reason deferred:** Blocked by D-096 + no scheduler (same as NORTH_STAR -Non-Goal #4). The policy shape is documented for when the emitter ships. - -## Tier 3 — Cross-project (deferred — single project) - -### I8 — Cross-project policy sharing ❌ DEFERRED (config) +### I9 — Cross-project policy sharing ❌ DEFERRED (config) **Category:** improvement **Confidence:** N/A @@ -134,24 +154,41 @@ Non-Goal #4). The policy shape is documented for when the emitter ships. **Source:** `config.json ideation.cross_project.enabled: false`. **Idea:** In a multi-project org, kyverno-json policies could be shared across projects (a tagging standard policy applies to all projects). -**Reason deferred:** ACDL is single-project (`active_projects: ["acdl"]`). -Cross-project ideation is disabled in config. Recorded for when the -org grows. +**Reason deferred:** `cross_project.enabled: false`. Even though +v1.26 is multi-project (acdl + nova-blockchain-exchange), +cross-project *ideation* is disabled in config. Recorded for when the +org grows + the flag is enabled. + +### I10 — Consumer-repo CI scaffolding as a reusable template ❌ DEFERRED + +**Category:** improvement +**Confidence:** 0.55 (below threshold — deferred, not rejected) +**Pattern:** one-off CI → reusable template. +**Source:** The consumer repo (`nova-blockchain-exchange`) needs its +own CI (`ci.yml` — lint + pytest). If Nova expects many consumers, a +reusable consumer-CI template would reduce onboarding friction. +**Idea:** A `nova-consumer-template` repo (or a +`.github/workflow-templates/` dir) that new consumers instantiate. +**Reason deferred:** Nova has 1 consumer today (the pilot). A template +is premature abstraction until the 2nd consumer arrives. The pilot's +CI is authored directly (REQ-310..312 tests). Recorded for when the +3rd consumer onboards. ## Summary -- 5 ideas accepted (I1..I5) → already captured as REQ-295, REQ-297, - REQ-300, REQ-303, REQ-304, REQ-305. -- 3 ideas deferred (I6, I7, I8) with documented blocking reasons. +- 7 ideas accepted (I1..I7) → already captured as REQ-315, REQ-316, + REQ-317, REQ-318, REQ-319, REQ-320, REQ-322. +- 3 ideas deferred (I8 scoped into REQ-321; I9 config-disabled; I10 + below threshold) with documented blocking reasons. - 0 ideas rejected (below-threshold ideas are deferred, not rejected — they may activate when their blockers lift). -- The accepted ideas are the **quality improvement** the user asked for - ("ideate and explore how it can be used within the Nova platform to - improve quality of the platform checks"): I1 (regression-gate-as- - policy) is the headline quality improvement; I4 + I5 are the defense- - in-depth coverage improvements; I2 + I3 are the architecture - improvements (imperative → declarative). -- No new requirements added beyond REQ-291..309 (the accepted ideas are +- The accepted ideas are the **quality improvement** the `--ideate` flag + drives: I1 + I2 ground the Post-Pilot metrics (outcome backfill + + escalation reason); I3 closes the env-JSON wiring gap; I4 + I5 extend + v1.25's policy engine to the pilot domain (pilot-readiness + + settlement-finality); I6 gates the pilot as a maintained capability; + I7 is the single platform-side module build-out. +- No new requirements added beyond REQ-310..322 (the accepted ideas are already scoped into the existing requirements). The IDEATE pass validated the requirement set rather than expanding it — the ideas - were anticipated in the SPECIFY stage and explicitly captured. \ No newline at end of file + were anticipated in the SPECIFY + RESEARCH stages. \ No newline at end of file From 270b1f11a3fd9dd83da0dc4aa0ff22b1445f182a Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:19:06 +0000 Subject: [PATCH 05/34] =?UTF-8?q?docs(P00):=20create=20phase=20plans=20?= =?UTF-8?q?=E2=80=94=20v1.26=20(5=20phases,=2013=20reqs,=20wave-ordered,?= =?UTF-8?q?=20persona-assigned)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: plan phases: 5 requirements: [REQ-310..REQ-322] revision: REQ-322 moved to P2 W0 (before contract, for registry resolution) ---/ci--- --- .ciagent/CHECKPOINT.json | 4 +- .ciagent/PLAN.md | 678 ++++++++++++++++++++------------------- .ciagent/ROADMAP.md | 9 +- 3 files changed, 355 insertions(+), 336 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 8ce8989..4915114 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "ideate", + "stage": "plan", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:14:00Z", + "updated_at": "2026-08-12T21:15:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 3d4d4ce..f6d6095 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,371 +1,389 @@ -# PLAN — v1.25 (kyverno-json Unified Policy Engine) +# PLAN — v1.26 (Live Pilot Estate Activation) -> Feature milestone. Tags on the **v1.24.x** line: v1.24.0 (P0) → -> v1.24.1 (P1) → v1.24.2 (P2) → v1.24.3 (P3) → v1.24.4 (P4) → v1.24.5 -> (P5 final = milestone release). 19 requirements (REQ-291..309), -> 4 execution phases + P0 pre-execution + P5 final review/ship. - -## Wave model - -Each phase is a **vertical slice** (end-to-end: policy files + Python -wiring + tests + docs). Phases are ordered by dependency: the engine -protocol (P1) must exist before policies (P2/P3) can be wired; the -pipeline wiring (P3) must exist before the meta-policies (P3) can -consume the merged PCR list; the regression-gate policies (P4) are -independent of the pipeline and can be authored in parallel with P3's -tests, but ship after P3 because they reference the engine registry -finalized in P1. Within each phase, the waves are the persona task -groups (parallelizable across personas when `parallelization.enabled: -true`, `max_concurrent_agents: 5`). - -## Phase breakdown - -### Phase P1 — engine-core (Wave 1, backend-engineer + policy-engineer + data-engineer) - -**Type:** `feat` (engine protocol + registry + kyverno-json engine adapter + install + tests) - -**Requirements:** REQ-291, REQ-292, REQ-293, REQ-294, REQ-308, REQ-309 - -**Must-haves:** -- `core/policy_engine.py` — `PolicyEngine` Protocol (PEP 544) + - `PolicyEngineRegistry` (selects from `config.json.policy.engine`) + - `NullEngine` fallback (emits `SKIPPED` when `policy` key absent) - (REQ-291) -- `.ciagent/config.json` gains `policy` object: `{"engine": - "kyverno-json", "policy_root": - "adapters/kyverno-json/policies"}` (REQ-292) -- `adapters/kyverno-json/kyverno_json_engine.py` — `KyvernoJsonEngine` - implementing the protocol: `is_configured()` guards on `which kj`; - `evaluate()` writes payload to temp JSON, invokes - `kj scan --policy --payload --output json`, translates - native output → `list[dict]` PCR records (`engine: "kyverno"`, - `ruleId` prefixed `KJ_`, severity from - `nova.cloudinit.dev/severity` annotation); defensive parsing - (malformed → `error` PCR, never exception); `is_configured()==false` - → single `SKIPPED` PCR (`KJ_ENGINE_NOT_CONFIGURED`) (REQ-293) -- `adapters/kyverno-json/__init__.py` exports `KyvernoJsonEngine`; - `adapters/kyverno-json/policies/_smoke.json` trivial - `require-contract-id` policy for round-trip validation; - `scripts/install-kyverno-json.sh` runs - `go install github.com/kyverno/kyverno-json/cmd/kj@latest`; - `.github/workflows/ci.yml` + `.gitea/workflows/ci.yml` install Go + kj - (cached) (REQ-294) -- `tests/test_policy_engine.py` — protocol conformance, registry - selection, unknown-engine `KeyError`, `NullEngine` fallback, - `is_configured()` false when `which kj` absent (mocked) (REQ-308) -- `tests/test_kyverno_json_engine.py` — `evaluate()` returns PCR dicts - validating against `schemas/policy_check_result.schema.json` (via - `jsonschema`); defensive parsing (malformed kyverno-json output → - `error` PCR); `is_configured()==false` → `SKIPPED` with - `KJ_ENGINE_NOT_CONFIGURED`; `pytest.skip("kj not installed")` when - `which kj` absent (REQ-309) - -**Vertical slice:** The `PolicyEngineRegistry.get_engine()` returns a -configured `KyvernoJsonEngine` that can `evaluate()` a trivial payload -against `_smoke.json` and produce a valid PCR list. The confidence -signal is unchanged — it already consumes `list[PolicyCheckResult]`. -The platform runs with or without the `kj` binary (`is_configured()` -guard). All existing tests pass (NullEngine fallback when `policy` key -absent in test config — but the v1.25 config.json *sets* the key, so -existing tests that use the real config get `KyvernoJsonEngine` with -`is_configured()==false` → `SKIPPED`). - -**Files touched:** -- `core/policy_engine.py` (NEW) -- `.ciagent/config.json` (MODIFIED — `policy` object) -- `adapters/kyverno-json/__init__.py` (NEW) -- `adapters/kyverno-json/kyverno_json_engine.py` (NEW) -- `adapters/kyverno-json/policies/_smoke.json` (NEW) -- `scripts/install-kyverno-json.sh` (NEW) -- `.github/workflows/ci.yml` (MODIFIED — Go + kj install step) -- `.gitea/workflows/ci.yml` (MODIFIED — Go + kj install step) -- `tests/test_policy_engine.py` (NEW) -- `tests/test_kyverno_json_engine.py` (NEW) - -**Verification:** `pytest tests/test_policy_engine.py -tests/test_kyverno_json_engine.py tests/test_confidence_signal.py -tests/test_adapter.py tests/test_checkov_adapter.py -tests/test_kyverno_adapter.py -v` (new tests pass or skip-without-kj; -existing adapter/confidence tests unchanged). `python3 -m py_compile -core/policy_engine.py adapters/kyverno-json/kyverno_json_engine.py`. +> Feature milestone. Tags on the **v1.25.x** line: v1.25.0 (P0) → +> v1.25.1 (P1) → v1.25.2 (P2) → v1.25.3 (P3) → v1.25.4 (P4) → v1.25.5 +> (P5 final = milestone release). 13 requirements (REQ-310..322), +> 5 phases (P0 pre-execution + 4 execution + 1 final). Multi-project: +> `acdl` (platform) + `nova-blockchain-exchange` (consumer). Tags run +> on the previous minor's patch line per `run.md` versioning logic +> (feature milestone — at least one feat phase; progressive patches per +> phase; the final phase's patch IS the milestone release; no separate +> minor tag). --- -### Phase P2 — contract + stack-IR policies (Wave 2, policy-engineer + backend-engineer) +## Phase 0 — Pre-Execution (complete, tag v1.25.0) -**Type:** `feat` (policies + resolver wiring + tests) +SPECIFY → CLARIFY → RESEARCH → IDEATE → PLAN → GRILL. All `.ciagent/` +MD, research, plans. Ships as `v1.25.0` on the v1.25.x line. -**Requirements:** REQ-295, REQ-296, REQ-297, REQ-298, REQ-299 +**Pre-run (Workstream A, on main before branch gate):** +- A1: flaky test fix (commit `8c68d68`, pushed). +- A2: ACDL_*→NOVA_* bootstrap migration (commit `f844fea`, pushed). +- A3: AWS bootstrap — S3 state bucket + DynamoDB outbox created. +- A4: `nova-blockchain-exchange` Gitea repo created + cloned. -**Must-haves:** -- `adapters/kyverno-json/policies/contract/` — 4 policies over consumer - contract JSON: `require-id-pattern.json`, - `require-env-in-enum.json`, `require-infrastructure-min-1.json`, - `forbid-unknown-fields.json` — each a `ValidatingPolicy` with one - `validate.assert` rule using JMESPath against the payload root; - severity via `nova.cloudinit.dev/severity` annotation (REQ-295) -- `core/contract_resolver.py` invokes - `PolicyEngineRegistry.get_engine().evaluate(contract_dict, - policies/contract/, contract_id)` **before** resolving; failures - feed the `policy` input as `fail` PCRs (no resolver exit — confidence - signal decides the gate, `--soft-fail` pattern); emits - `nova.policy.evaluated` metrics event (REQ-296) -- `adapters/kyverno-json/policies/stack-ir/` — 3 policies over - resolved Stack IR: `require-tagging-standard.json` (ports - `nova_tagging.py` — `nova:owner` + `nova:environment` tags on every - `resources[]` entry), `forbid-public-ingress.json` (v1.0 demo rule), - `require-encryption-by-default.json` (v1.8 D-encryption-default); - `~` modifier iterates `resources[]` (REQ-297) -- `core/contract_resolver.py` invokes the engine with the resolved - Stack IR and `policies/stack-ir/` **after** resolving; resulting PCRs - appended to the contract-policy PCRs; resolver return values and - exceptions unchanged (additive) (REQ-298) -- `tests/test_stack_ir_policies.py` + `tests/fixtures/stack_ir/` — - passing IR (all tags + encryption) + failing IR (missing tags, public - ingress, plaintext bucket); each policy in isolation + full dir as - bundle; `pytest.skip("kj not installed")` when `which kj` absent - (REQ-299) - -**Vertical slice:** A consumer contract passes through the resolver -and produces two PCR lists (contract policies pre-resolve, stack-IR -policies post-resolve) that feed the confidence signal. A contract -with a bad `id` or missing tags produces `fail` PCRs that lower the -confidence score. The resolver's existing tests pass unchanged (the -policy call is additive — it does not change resolver return values -or exceptions). - -**Files touched:** -- `adapters/kyverno-json/policies/contract/require-id-pattern.json` (NEW) -- `adapters/kyverno-json/policies/contract/require-env-in-enum.json` (NEW) -- `adapters/kyverno-json/policies/contract/require-infrastructure-min-1.json` (NEW) -- `adapters/kyverno-json/policies/contract/forbid-unknown-fields.json` (NEW) -- `adapters/kyverno-json/policies/stack-ir/require-tagging-standard.json` (NEW) -- `adapters/kyverno-json/policies/stack-ir/forbid-public-ingress.json` (NEW) -- `adapters/kyverno-json/policies/stack-ir/require-encryption-by-default.json` (NEW) -- `core/contract_resolver.py` (MODIFIED — pre/post resolve engine calls) -- `tests/test_stack_ir_policies.py` (NEW) -- `tests/fixtures/stack_ir/passing.json` (NEW) -- `tests/fixtures/stack_ir/failing.json` (NEW) - -**Verification:** `pytest tests/test_contract_resolver.py -tests/test_stack_ir_policies.py tests/test_policy_engine.py -v` -(existing resolver tests pass; new policy tests pass or skip-without- -kj). `python3 -m py_compile core/contract_resolver.py`. +**Phase 0 stages (on `phase/00-specify-clarify-research-plan`):** +- SPECIFY: v1.26 established in config.json + PROJECT.md + ROADMAP.md + + `.ciagent/nova-blockchain-exchange/{PROJECT,REQUIREMENTS,ROADMAP}.md`. +- CLARIFY: 10 ambiguities resolved (D-200..D-213). +- RESEARCH: PoA blockchain, deploy model, DynamoDB gap (REQ-322), + metric grounding, persona assessment (5 personas). +- IDEATE: 7 ideas accepted (I1..I7 → REQ-315..322), 3 deferred. +- PLAN: this file. +- GRILL: adversarial review (binding verdicts). --- -### Phase P3 — plan-JSON policies + meta-orchestration + pipeline wiring (Wave 3, policy-engineer + backend-engineer) +## Phase 1 — blockchain-core (tag v1.25.1) -**Type:** `feat` (plan-JSON policies + meta-policies + run_platform.sh wiring + tests) +**Goal:** The consumer repo has a working homegrown PoA blockchain + +order-matching engine + settlement service. All unit tests pass in the +consumer repo's own CI. -**Requirements:** REQ-300, REQ-301, REQ-302, REQ-303 +**Project:** `nova-blockchain-exchange` (consumer repo). +**Branch:** `nova-blockchain-exchange/phase/01-blockchain-core`. +**Persona:** blockchain-engineer (primary), lead-developer (coordination). -**Must-haves:** -- `adapters/kyverno-json/policies/plan-json/` — 3 policies over - `terraform show -json` output: `forbid-plaintext-secrets.json` (ports - CKV_AWS_41/45/46), `forbid-iam-wildcard.json` (ports CKV_AWS_1/40), - `require-kms-reference.json` (ports CKV_AWS_7/33); JMESPath over - `planned_values.root_module.resources[]` (REQ-300) -- `run_platform.sh` Step 5 gains a parallel kyverno-json pass: after - Checkov/Wiz produce raw PCRs, the script runs - `kj scan --policy adapters/kyverno-json/policies/plan-json/ - --payload -o json` and pipes through - `adapters/kyverno-json/kyverno_json_engine.py` to produce a second - PCR list; both lists concatenated and fed to the confidence signal; - `nova.policy.evaluated` event with both engine names; when - `which kj` is false, logs and proceeds with Checkov/Wiz list only - (no hard failure) (REQ-301) -- `tests/test_plan_json_policies.py` + `tests/fixtures/plan_json/` — - passing plan (no secrets, no wildcard, KMS alias) + failing plan - (plaintext password, `Action: "*"`, inline KMS key); policies in - isolation + bundle; `tests/test_run_platform_plan_json_policies.py` - asserts `run_platform.sh` has the kyverno-json Step 5 block + - concatenates PCR lists (script-substring assertion, pattern from - `tests/test_pipeline.py:79-95`) (REQ-302) -- `adapters/kyverno-json/policies/meta/` — `block-on-any-critical.json` - (asserts no PCR in merged list has `severity: critical` + `result: - fail`; if any does, emits `fail` PCR `KJ_META_BLOCK_CRITICAL` - severity `critical` — declarative source of truth; the - `confidence_signal.py` hard-override stays as defense-in-depth per - D-119) + `tagging-rules-agree.json` (cross-checks Checkov - `NOVA_TAG_NAMING` vs kj `KJ_REQUIRE_TAGGING_STANDARD` by - `resourceRef`; divergence emits `error` PCR per D-118); - `tests/test_meta_policies.py` (REQ-303) +### Wave 1 — chain core (REQ-310) +- **Task 1.1** (blockchain-engineer): `chain/block.py` — Block dataclass + (index, timestamp, prev_hash, transactions, nonce, hash). + `compute_hash()` deterministic (SHA-256). Unit test: `test_block.py`. +- **Task 1.2** (blockchain-engineer): `chain/ledger.py` — Ledger class: + `append_block()`, `verify_chain()`, `get_block(index)`, + `get_latest_block()`. Genesis block on init. Unit test: `test_ledger.py`. +- **Task 1.3** (blockchain-engineer): `chain/validator.py` — PoA + validator: single validator (config-driven), `propose_block(transactions)` + → Block, `commit_block(block)`. Unit test: `test_validator.py`. -**Vertical slice:** `run_platform.sh` Step 5 produces a merged PCR list -(Checkov/Wiz + kj plan-JSON policies + kj meta-policies over the -merged list) that feeds the confidence signal. A plan with a plaintext -secret produces two `fail` PCRs (one Checkov, one kj) for the same -resource — visible defense-in-depth. A critical finding anywhere -produces a `KJ_META_BLOCK_CRITICAL` meta-PCR that the confidence -signal's hard-override blocks. The pipeline runs with or without `kj` -(graceful skip). +### Wave 2 — order engine + settlement (REQ-311, REQ-312) — parallel with Wave 1 tail +- **Task 2.1** (blockchain-engineer): `engine/order.py` — Order + dataclass (id, side, symbol, price, size, timestamp). +- **Task 2.2** (blockchain-engineer): `engine/order_book.py` — + OrderBook: `add_order(order)`, `match_orders()` → list of Match + (price-time priority, partial fills). Unit test: `test_order_book.py`. +- **Task 2.3** (blockchain-engineer): `settlement/service.py` — + SettlementService: `settle(match)` → SettlementTransaction, + `submit(ledger)`. Idempotent (re-settling a match is a no-op once + final). Finality = block commit. Unit test: `test_settlement.py`. -**Files touched:** -- `adapters/kyverno-json/policies/plan-json/forbid-plaintext-secrets.json` (NEW) -- `adapters/kyverno-json/policies/plan-json/forbid-iam-wildcard.json` (NEW) -- `adapters/kyverno-json/policies/plan-json/require-kms-reference.json` (NEW) -- `adapters/kyverno-json/policies/meta/block-on-any-critical.json` (NEW) -- `adapters/kyverno-json/policies/meta/tagging-rules-agree.json` (NEW) -- `scripts/run_platform.sh` (MODIFIED — Step 5 kj parallel pass) -- `tests/test_plan_json_policies.py` (NEW) -- `tests/test_meta_policies.py` (NEW) -- `tests/test_run_platform_plan_json_policies.py` (NEW) -- `tests/fixtures/plan_json/passing.json` (NEW) -- `tests/fixtures/plan_json/failing.json` (NEW) +### Wave 3 — consumer CI (cross-cutting) +- **Task 3.1** (blockchain-engineer): `.github/workflows/ci.yml` + + `.gitea/workflows/ci.yml` — lint + pytest on chain/engine/settlement. +- **Task 3.2** (lead-developer): `nova-blockchain-exchange/README.md` — + repo overview + dev setup. -**Verification:** `pytest tests/test_plan_json_policies.py -tests/test_meta_policies.py tests/test_run_platform_plan_json_policies.py -tests/test_pipeline.py -v` (new tests pass or skip-without-kj; existing -pipeline tests pass). `python3 -m py_compile` on any modified Python. -Shellcheck on `run_platform.sh` if available. +**Must-haves (verify before ship):** +- `pytest tests/` in the consumer repo passes (chain integrity, hash + determinism, genesis, append/verify, match priority, partial fills, + settlement idempotency, finality check). +- The chain is deterministic (replay produces the same hash chain). +- The consumer CI workflow runs on push. + +**Ship:** tag `v1.25.1`, merge `phase/01` → `milestone/v1.26-pilot-activation`, +Gitea release (best-effort). Delete `phase/01`. --- -### Phase P4 — regression-gate policies + docs (Wave 4, policy-engineer + data-engineer + lead-developer) +## Phase 2 — consumer-contract-and-deploy (tag v1.25.2) -**Type:** `feat` (regression policies) + `docs` (adapter READMEs + ARCHITECTURE + STANDARDS + METRICS) +**Goal:** The consumer repo declares its infrastructure via +`contract.yaml` (validated against the platform's schema) + invokes the +platform's `deploy.yml@v1.25` workflow. The contract references the +`microservice` (ECS), `dynamodb`, + `s3` modules. -**Requirements:** REQ-304, REQ-305, REQ-306, REQ-307 +**Project:** `nova-blockchain-exchange` (consumer repo) + `acdl` +(platform repo — for the `deploy.yml@v1.25` ref + the `v1.25` floating +tag). +**Branch:** `nova-blockchain-exchange/phase/02-contract-and-deploy`. +**Persona:** blockchain-engineer (contract authoring), data-engineer +(registry/DynamoDB dependency check), lead-developer (deploy.yml ref). -**Must-haves:** -- `adapters/kyverno-json/policies/regression/` — 3 policies over - capability-inventory JSON frontmatter: `cap-013-adapter-dedup.json`, - `cap-023-metrics-collector.json`, `cap-024-deck-structure.json`; - emit `pass`/`fail` PCRs per capability; the existing - `core/regression_verify.py` is kept (drives the CI gate); the - policies are the declarative mirror (REQ-304) -- `tests/test_regression_policies.py` + - `tests/fixtures/capability_inventory/clean.json` + - `tests/fixtures/capability_inventory/drifted.json` — clean (all caps - pass) + drifted (duplicate adapter, missing metric status, broken - deck arc); regression gate still 287/287 baseline (new tests - additive, skip-without-kj) (REQ-305) -- `adapters/README.md` gains new kyverno-json adapter row + "Policy - Engine Protocol" section (Protocol, registry, swap boundary, - how-to-add-OpaEngine); `adapters/kyverno-json/README.md` documents - the engine, install path, policy directory layout, 4 policy - categories (REQ-306) -- `.ciagent/ARCHITECTURE.md` §12.7 (added in RESEARCH) is finalized; - `schemas/README.md` notes `engine: "kyverno"` shared by K8s adapter - + kj (distinguished by `ruleId` prefix); `modules/STANDARDS.md` - gains "Policy authoring standard" section for module owners; - `docs/METRICS.md` notes the policy engine is swappable (Strategic - Objective #2 — provable trust via a replaceable substrate) (REQ-307) +### Wave 1 — contract (REQ-313) +- **Task 1.1** (blockchain-engineer): `contract.yaml` — id + (`blkex`), name (`blockchain-exchange`), environment (dev), + infrastructure block (microservice + dynamodb + s3). +- **Task 1.2** (blockchain-engineer): `contracts/blockchain-exchange.dev.yml`, + `.qa.yml`, `.prod.yml` — per-env variants. +- **Task 1.3** (blockchain-engineer): `tests/test_contract_validates.py` + — schema validation against the platform's + `schemas/contract.schema.json`. -**Vertical slice:** The regression gate's capability checks are now -declarative policies auditable as artifacts. A new module owner can -read `modules/STANDARDS.md` "Policy authoring standard" and write a -per-module kyverno-json policy. A new engineer can read -`adapters/README.md` "Policy Engine Protocol" and implement an -`OpaEngine`. The 287/287 baseline is unchanged. +### Wave 2 — deploy invocation (REQ-314) +- **Task 2.1** (blockchain-engineer): `.github/workflows/deploy.yml` — + `uses: acdl/.github/workflows/deploy.yml@v1.25` with + `with: { contract: contract.yaml, mode: full, environment: dev }`. +- **Task 2.2** (blockchain-engineer): `.gitea/workflows/deploy.yml` — + byte-identical mirror. +- **Task 2.3** (blockchain-engineer): `tests/test_deploy_workflow_invocation.py` + — asserts the `uses:` ref + inputs. -**Files touched:** -- `adapters/kyverno-json/policies/regression/cap-013-adapter-dedup.json` (NEW) -- `adapters/kyverno-json/policies/regression/cap-023-metrics-collector.json` (NEW) -- `adapters/kyverno-json/policies/regression/cap-024-deck-structure.json` (NEW) -- `tests/test_regression_policies.py` (NEW) -- `tests/fixtures/capability_inventory/clean.json` (NEW) -- `tests/fixtures/capability_inventory/drifted.json` (NEW) -- `adapters/README.md` (MODIFIED — new row + PolicyEngine Protocol section) -- `adapters/kyverno-json/README.md` (NEW) -- `schemas/README.md` (MODIFIED — engine enum note) -- `modules/STANDARDS.md` (MODIFIED — Policy authoring standard section) -- `docs/METRICS.md` (MODIFIED — swappable engine narrative) +### Wave 3 — platform floating tag (cross-cutting) +- **Task 3.1** (lead-developer, on `acdl` repo): verify the `v1.25` + floating tag exists (created by `release.yml` on merge to main). If + not, create it pointing at the `v1.25.0` tag (Phase 0 ship). -**Verification:** `pytest tests/test_regression_policies.py -tests/test_kyverno_json_engine.py -v` (new tests pass or skip-without- -kj). Full regression gate `pytest tests/` still at 287/287 baseline + -new tests (skip without kj). Manual read of `adapters/README.md` + -`adapters/kyverno-json/README.md` + `modules/STANDARDS.md` policy -section for clarity. +**Must-haves (verify before ship):** +- `contract.yaml` validates against `schemas/contract.schema.json`. +- The deploy workflow invocation asserts the correct `uses:` ref + + inputs. +- The `v1.25` floating tag resolves. + +**Ship:** tag `v1.25.2`, merge `phase/02` → milestone, Gitea release. +Delete `phase/02`. --- -### Phase P5 — final review + audit + milestone ship (Final Phase) +## Phase 3 — pilot-metrics-and-policies (tag v1.25.3) -**Type:** `docs` (review + audit + milestone completion) +**Goal:** The platform repo gains the metric-grounding emitters, the +kyverno-json pilot policies, the DynamoDB L1 primitive, the env-JSON +wiring reconciliation, + the pilot regression CAP. The Post-Pilot +metrics are grounded (outcome backfill + escalation reason); the pilot- +readiness + settlement-finality policies are in place. -**Requirements:** All REQ-291..309 (mark complete) +**Project:** `acdl` (platform repo). +**Branch:** `acdl/phase/03-pilot-metrics-and-policies` (platform branch). +**Personas:** backend-engineer (emitters + adapter + regression), +data-engineer (DynamoDB primitive + env JSON + collector), +policy-engineer (kyverno-json policies). -**Must-haves:** -- `ciagent-review` multi-persona code review across P1..P4 - (lead-developer, backend-engineer, data-engineer, policy-engineer). - Auto-fix P0; flag P1+ for post-hoc review. If P1+ issues found, fix - them in this final phase (not loop back to EXECUTE). -- `ciagent-audit` — reconstruction test (git log ↔ `.ciagent/` files), - `.ciagent/` file discipline, branch hygiene, commit discipline. - Critical issues fixed in this phase. -- `ciagent-ship` (milestone) — merge `phase/05-final-review-ship` → - `milestone/v1.25-kyverno-json` → `main`; tag `v1.24.5` (= the v1.25 - release per the prev-minor tagging rule); create Gitea release with - full milestone summary (all phases, all requirements); delete all - milestone branches (local + remote). -- Update `REQUIREMENTS.md` (mark REQ-291..309 complete), - `ROADMAP.md` (mark v1.25 complete), `CHECKPOINT.json` - (milestone_complete: true), `NORTH_STAR.md` (note Strategic - Objective #2 — provable trust via a replaceable policy-engine - substrate). +### Wave 1 — DynamoDB primitive (REQ-322) — data-engineer +- **Task 1.1** (data-engineer): `modules/l1/dynamodb/interface.json` — + stack type `aws:dynamodb:table`, inputs (table_name, region, pk, sk, + billing_mode), outputs (table_arn, table_name). +- **Task 1.2** (data-engineer): `modules/l1/dynamodb/terraform/main.tf` + — `resource "aws_dynamodb_table" "this"` (PK + optional SK, + `PAY_PER_REQUEST` default, encryption + PITR enabled per v1.8 NFR). +- **Task 1.3** (data-engineer): `modules/l1/dynamodb/README.md` + + `instance.json`. +- **Task 1.4** (data-engineer): `modules/registry.json` — `dynamodb` + entry (kind `l1`, `terraform_dir`). +- **Task 1.5** (data-engineer): `modules/README.md` — catalog index. -**Vertical slice:** The v1.25 milestone is complete: kyverno-json is -the primary policy tool, behind a swappable adapter, with policies -over all 4 Nova artifacts. Tags v1.24.0..v1.24.5 on the v1.24.x line. -The milestone branch merges to main. +### Wave 2 — metric grounding (REQ-317, REQ-318) — backend-engineer + data-engineer — parallel +- **Task 2.1** (backend-engineer): `core/metrics/outcome_backfill.py` — + `backfill(decision_id, outcome)` updates `fact_decision.outcome` + + `backfilled_at`. Reads run-manifest events. +- **Task 2.2** (backend-engineer): `core/metrics/collector.py` — + invokes backfill after run completion. +- **Task 2.3** (backend-engineer): `tests/test_outcome_backfill.py`. +- **Task 2.4** (backend-engineer): `core/confidence_signal.py` — + `ai.decision.made` gains `escalation_reason: 'confidence'` when + `band == 'block'`. +- **Task 2.5** (backend-engineer): `core/metrics/collector.py` — + persists `escalation_reason` into `fact_run`. +- **Task 2.6** (backend-engineer): `tests/test_confidence_escalation_reason.py`. -**Verification:** `pytest tests/ -v` full suite passes (287 baseline + -new tests). `git log --oneline` shows the v1.25 phase commits. -`git tag` shows v1.24.0..v1.24.5. `git branch` shows no leftover -milestone/phase branches (all deleted post-ship). +### Wave 3 — env-JSON wiring + adapter (REQ-319) — backend-engineer + data-engineer — parallel +- **Task 3.1** (backend-engineer): `adapters/terraform/adapter.py` — + reads `env.state_backend.bucket` when present (fallback to computed + name for backwards compat). +- **Task 3.2** (data-engineer): `core/environments/dev.json` — + `account_id` → `581513795199`, `state_backend.bucket` → + `nova-tfstate-581513795199-us-east-1`. +- **Task 3.3** (data-engineer): `core/environments/{qa,prod,dr}.json` — + `state_backend.bucket` updated; `account_id` stays placeholder + (pilot-readiness policy blocks apply on placeholder, D-208). +- **Task 3.4** (backend-engineer): `tests/test_adapter_state_backend.py`. +- **Task 3.5** (backend-engineer): `tests/test_adapter.py` — add + `dynamodb` to `EXPECTED_L1_KEYS` + a resolution + emission test + (cross-territory: data-engineer authored the module, backend-engineer + owns the test). + +### Wave 4 — kyverno-json policies (REQ-315, REQ-320) — policy-engineer — parallel +- **Task 4.1** (policy-engineer): + `adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json` + — kyverno-json policy over settlement-service status JSON (asserts + `all_committed: true`). +- **Task 4.2** (policy-engineer): + `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` + — kyverno-json policy over env JSON (asserts + `account_id != "000000000000"`). +- **Task 4.3** (policy-engineer): `tests/test_settlement_finality_policy.py` + — passing + failing fixtures; skip when `kj` absent. +- **Task 4.4** (policy-engineer): `tests/test_pilot_readiness_policy.py` + — passing (real account) + failing (placeholder) fixtures; skip when + `kj` absent. + +### Wave 5 — regression CAP (REQ-316) — backend-engineer +- **Task 5.1** (backend-engineer): `core/regression_verify.py` — + CAP-025 (live-pilot-apply): the round-trip assertion. +- **Task 5.2** (backend-engineer): `tests/test_regression_pilot.py`. + +**Must-haves (verify before ship):** +- `pytest tests/` in the platform repo passes (170 existing + new tests). +- The DynamoDB primitive resolves + emits valid Terraform. +- The outcome backfill updates `fact_decision.outcome` (not `pending`). +- The `escalation_reason` field is emitted on `block` band. +- The adapter reads `env.state_backend.bucket` from the env JSON. +- The 2 new kyverno-json policies pass on valid fixtures + fail on + invalid fixtures (skip when `kj` absent). +- CAP-025 is in the regression gate. +- No existing tests regress (170 baseline holds). + +**Ship:** tag `v1.25.3`, merge `phase/03` → milestone, Gitea release. +Delete `phase/03`. --- -## Wave ordering (parallelization) +## Phase 4 — pilot-run-and-docs (tag v1.25.4) -With `parallelization.enabled: true`, `max_concurrent_agents: 5`, -`min_plans_for_parallel: 2`: +**Goal:** The pilot estate runs end-to-end against live AWS +`581513795199` (contract resolve → adapter compile → terraform plan → +policy scan → confidence signal → attestation → outbox record). Docs + +adapter README + onboarding guide are complete. -- **P1 Wave 1:** backend-engineer (protocol + registry + install) ‖ - data-engineer (config.json policy object) ‖ policy-engineer (engine - adapter + smoke policy). 3 concurrent personas. Merge in order: - data-engineer → backend-engineer → policy-engineer. -- **P2 Wave 2:** policy-engineer (contract + stack-IR policies) ‖ - backend-engineer (resolver wiring — depends on P1 registry). 2 - concurrent. Merge: policy-engineer → backend-engineer (wiring - references the policy dirs). -- **P3 Wave 3:** policy-engineer (plan-JSON + meta policies) ‖ - backend-engineer (run_platform.sh wiring — depends on P1 engine + - P2 resolver pattern). 2 concurrent. Merge: policy-engineer → - backend-engineer. -- **P4 Wave 4:** policy-engineer (regression policies) ‖ data-engineer - (capability-inventory fixtures) ‖ lead-developer (docs: READMEs, - STANDARDS, METRICS). 3 concurrent. Merge: data-engineer → - policy-engineer → lead-developer. +**Project:** `nova-blockchain-exchange` (consumer repo — the run) + +`acdl` (platform repo — docs). +**Branch:** `acdl/phase/04-pilot-run-and-docs` (platform branch for +docs); the run happens via the consumer's `deploy.yml` invocation. +**Personas:** blockchain-engineer (the run), lead-developer (docs), +backend-engineer (regression CAP-025 verification). -Territory enforcement: `warn` mode (per `config.json -personas.territory_enforcement: "warn"`). Cross-territory edits -(e.g., backend-engineer touching a policy file) emit a warning, not a -block. +### Wave 1 — the pilot run (REQ-316 verification, live) +- **Task 1.1** (blockchain-engineer): trigger the consumer's + `deploy.yml` with `mode: full, environment: dev` against + `581513795199`. The workflow checks out the consumer + platform + repos, runs `run_platform.sh`, applies the contract (ECS + + DynamoDB + S3), records the decision + attestation. +- **Task 1.2** (backend-engineer): verify CAP-025 (regression gate) + passes against the live run. +- **Task 1.3** (blockchain-engineer): capture the run's + `ai.decision.made` + `attestation.recorded` events from the Decision + Ledger → evidence for the milestone ship. -## Requirement → phase → persona matrix +### Wave 2 — docs (REQ-321) +- **Task 2.1** (lead-developer): `adapters/README.md` — new consumer + row + fix the stale `TYPE_MAP` references (IDEATE I8). +- **Task 2.2** (lead-developer): `docs/METRICS.md` — Post-Pilot metrics + grounded note (the 3 targets now have non-zero denominators post-run). +- **Task 2.3** (lead-developer): `.ciagent/ARCHITECTURE.md` §12.8 + (Pilot Estate). +- **Task 2.4** (lead-developer): + `.ciagent/nova-blockchain-exchange/README.md` — consumer onboarding + guide (how to invoke `deploy.yml@v1.25`, what secrets to set, what + the contract shape is). -| REQ | Phase | Primary persona | Type | -|-----|-------|-----------------|------| -| REQ-291 | P1 | backend-engineer | feat | -| REQ-292 | P1 | data-engineer | feat (config) | -| REQ-293 | P1 | policy-engineer | feat | -| REQ-294 | P1 | backend-engineer | feat (install) | -| REQ-295 | P2 | policy-engineer | feat | -| REQ-296 | P2 | backend-engineer | feat (wiring) | -| REQ-297 | P2 | policy-engineer | feat | -| REQ-298 | P2 | backend-engineer | feat (wiring) | -| REQ-299 | P2 | policy-engineer | test | -| REQ-300 | P3 | policy-engineer | feat | -| REQ-301 | P3 | backend-engineer | feat (pipeline) | -| REQ-302 | P3 | policy-engineer + backend-engineer | test | -| REQ-303 | P3 | policy-engineer | feat (meta) | -| REQ-304 | P4 | policy-engineer | feat | -| REQ-305 | P4 | policy-engineer + data-engineer | test | -| REQ-306 | P4 | policy-engineer + lead-developer | docs | -| REQ-307 | P4 | lead-developer | docs | -| REQ-308 | P1 | backend-engineer | test | -| REQ-309 | P1 | policy-engineer | test | \ No newline at end of file +**Must-haves (verify before ship):** +- The pilot run completes end-to-end (apply succeeds, decision recorded, + attestation recorded for dev — autonomous, no human approver). +- CAP-025 passes. +- The 3 Post-Pilot metrics have non-zero denominators (the run + contributed to `fact_run` + `fact_decision`). +- Docs are complete (adapter README, METRICS.md, ARCHITECTURE.md §12.8, + consumer onboarding guide). + +**Ship:** tag `v1.25.4`, merge `phase/04` → milestone, Gitea release. +Delete `phase/04`. + +--- + +## Phase 5 — final review + audit + milestone ship (tag v1.25.5) + +**Goal:** Multi-persona code review across P1..P4. Audit (reconstruction +test, branch hygiene, commit discipline). Milestone ship: merge to main, +tag `v1.25.5` (= the v1.26 release), Gitea release with full milestone +summary, delete all milestone branches. + +**Project:** both (`acdl` + `nova-blockchain-exchange`). +**Branch:** `phase/05-final-review-ship`. +**Personas:** lead-developer (review + audit + ship), backend-engineer +(review), data-engineer (review), policy-engineer (review), +blockchain-engineer (review — the chain core is reviewed). + +### Wave 1 — review +- **Task 1.1** (lead-developer): `ciagent-review` — multi-persona code + review across P1..P4. Auto-fix P0; flag P1+ for post-hoc review. +- **Task 1.2** (all personas): fix P0 issues in this phase. + +### Wave 2 — audit +- **Task 2.1** (lead-developer): `ciagent-audit` — reconstruction test + (git log ↔ `.ciagent/`), branch hygiene, commit discipline. +- **Task 2.2** (lead-developer): fix critical audit issues in this phase. + +### Wave 3 — milestone ship +- **Task 3.1** (lead-developer): merge `phase/05` → + `milestone/v1.26-pilot-activation` → `main`. +- **Task 3.2** (lead-developer): tag `v1.25.5` (= the v1.26 release per + prev-minor tagging rule). +- **Task 3.3** (lead-developer): create Gitea release with full milestone + summary (all phases, all 13 requirements). +- **Task 3.4** (lead-developer): delete all milestone branches (local + + remote). Tags preserve all history. +- **Task 3.5** (lead-developer): update `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` + (mark REQ-310..322 complete), `.ciagent/ROADMAP.md` (mark v1.26 + complete), `.ciagent/NORTH_STAR.md` (note Strategic Objectives #1 + + #3 — first real consumer estate; Post-Pilot denominators activated). +- **Task 3.6** (lead-developer): write checkpoint `stage: complete, + phase: 5, phase_role: final` + clear checkpoint (milestone complete). + +**Must-haves (verify before ship):** +- Review: 0 P0 issues unfixed; P1+ flagged for post-hoc. +- Audit: reconstruction test passes; branch hygiene clean; commit + discipline clean. +- Ship: `v1.25.5` tag exists; Gitea release created; milestone branches + deleted; main has the milestone merge. + +--- + +## Requirement → Phase Mapping + +| REQ | Phase | Wave | Persona | +|---|---|---|---| +| REQ-310 (blockchain core) | P1 | W1 | blockchain-engineer | +| REQ-311 (order engine) | P1 | W2 | blockchain-engineer | +| REQ-312 (settlement) | P1 | W2 | blockchain-engineer | +| REQ-313 (contract.yaml) | P2 | W1 | blockchain-engineer | +| REQ-314 (deploy invocation) | P2 | W2 | blockchain-engineer | +| REQ-315 (settlement-finality policy) | P3 | W4 | policy-engineer | +| REQ-316 (pilot regression CAP) | P3 | W5 + P4 W1 | backend-engineer | +| REQ-317 (outcome backfill) | P3 | W2 | backend-engineer | +| REQ-318 (escalation reason) | P3 | W2 | backend-engineer | +| REQ-319 (env-JSON wiring) | P3 | W3 | backend + data-engineer | +| REQ-320 (pilot-readiness policy) | P3 | W4 | policy-engineer | +| REQ-321 (docs) | P4 | W2 | lead-developer | +| REQ-322 (DynamoDB primitive) | P3 | W1 | data-engineer | + +--- + +## Wave Ordering Rationale + +- **P1 W1 → W2:** the chain core (block + ledger + validator) must land + before the order engine + settlement (they submit transactions to the + ledger). W3 (CI) is cross-cutting + can land any time after W1. +- **P2 W1 → W2:** the contract must land before the deploy invocation + (the invocation references the contract). W3 (floating tag) is cross- + cutting. +- **P3 W1 (DynamoDB) first:** the contract (P2) references `dynamodb` — + the primitive must exist before P2's contract can resolve. **Risk:** + P2's contract references a module that doesn't exist until P3. Resolution: P2's contract is authored but the `test_contract_validates.py` test only checks schema validity (not registry resolution) — the registry resolution test is in P3 (after the primitive lands). The contract's `dynamodb` block is schema-valid (the schema is open); the registry resolution happens at apply time (P4). + - **Alternative:** move REQ-322 to P2 W0 (before the contract). This + avoids the P2→P3 dependency. **Decision: move REQ-322 to P2 W0.** + See revised mapping below. + +### Revised: REQ-322 → P2 W0 + +REQ-322 (DynamoDB primitive) lands in P2 Wave 0 (before the contract) +so the contract's `dynamodb` block resolves at registry time, not just +schema time. This makes P2 self-contained: the primitive + the contract ++ the deploy invocation all land in P2. + +| REQ | Phase | Wave | Persona | +|---|---|---|---| +| REQ-310 (blockchain core) | P1 | W1 | blockchain-engineer | +| REQ-311 (order engine) | P1 | W2 | blockchain-engineer | +| REQ-312 (settlement) | P1 | W2 | blockchain-engineer | +| REQ-322 (DynamoDB primitive) | P2 | W0 | data-engineer | +| REQ-313 (contract.yaml) | P2 | W1 | blockchain-engineer | +| REQ-314 (deploy invocation) | P2 | W2 | blockchain-engineer | +| REQ-315 (settlement-finality policy) | P3 | W4 | policy-engineer | +| REQ-316 (pilot regression CAP) | P3 | W5 + P4 W1 | backend-engineer | +| REQ-317 (outcome backfill) | P3 | W2 | backend-engineer | +| REQ-318 (escalation reason) | P3 | W2 | backend-engineer | +| REQ-319 (env-JSON wiring) | P3 | W3 | backend + data-engineer | +| REQ-320 (pilot-readiness policy) | P3 | W4 | policy-engineer | +| REQ-321 (docs) | P4 | W2 | lead-developer | + +This revision is a binding plan decision (G-Q8 in the grill may +challenge it). \ No newline at end of file diff --git a/.ciagent/ROADMAP.md b/.ciagent/ROADMAP.md index d96d98e..83ed46f 100644 --- a/.ciagent/ROADMAP.md +++ b/.ciagent/ROADMAP.md @@ -2282,6 +2282,11 @@ Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). idempotent, finality = block commit. ### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2) +- REQ-322: `modules/l1/dynamodb/` — new L1 primitive (interface.json + + terraform/main.tf + README.md + instance.json + registry.json entry). + The single platform-side module build-out (ECS + S3 already exist; + the adapter is stateless/registry-driven). Lands in P2 W0 (before the + contract) so the contract's `dynamodb` block resolves at registry time. - REQ-313: `nova-blockchain-exchange/contract.yaml` + per-env variants (dev/qa/prod) — validated against `schemas/contract.schema.json`. - REQ-314: `nova-blockchain-exchange/.github/workflows/deploy.yml` + @@ -2308,10 +2313,6 @@ Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). `nova-tfstate-581513795199-us-east-1`. - REQ-320: `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` — declarative gate preventing apply against a placeholder account. -- REQ-322: `modules/l1/dynamodb/` — new L1 primitive (interface.json + - terraform/main.tf + README.md + instance.json + registry.json entry). - The single platform-side module build-out (ECS + S3 already exist; - the adapter is stateless/registry-driven). ### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4) - REQ-321: `adapters/README.md` (new consumer row) + From cf8aa53c8dafa6b1cc0a0cc4dbfcb30b7e1333c2 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:20:11 +0000 Subject: [PATCH 06/34] =?UTF-8?q?docs(P00):=20grill=20=E2=80=94=20v1.26=20?= =?UTF-8?q?adversarial=20review=20(9=20challenges,=20PROCEED=200.84,=202?= =?UTF-8?q?=20revisions)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: grill verdict: PROCEED confidence: 0.84 revisions: [G-Q4 REQ-322 to P2 W0, G-Q6 enforcement-deferred note, G-Q9 key-split future item] ---/ci--- --- .ciagent/CHECKPOINT.json | 4 +- .ciagent/GRILL.md | 355 ++++++++++++++++++++------------------- .ciagent/PLAN.md | 25 ++- 3 files changed, 207 insertions(+), 177 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 4915114..52b76fe 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 0, - "stage": "plan", + "stage": "grill", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:15:00Z", + "updated_at": "2026-08-12T21:16:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", diff --git a/.ciagent/GRILL.md b/.ciagent/GRILL.md index 929414b..08a4734 100644 --- a/.ciagent/GRILL.md +++ b/.ciagent/GRILL.md @@ -1,14 +1,15 @@ -# GRILL — v1.25 kyverno-json Unified Policy Engine +# GRILL — v1.26 Live Pilot Estate Activation -> Adversarial review of the v1.25 SPECIFY + CLARIFY + RESEARCH + IDEATE + +> Adversarial review of the v1.26 SPECIFY + CLARIFY + RESEARCH + IDEATE + > PLAN. The grill red-teams the proposal across feasibility, scope, -> budget, and the swap-boundary claim. Each challenge gets a binding -> verdict (PROCEED / REVISE / ESCALATE). Autonomy: full — escalations -> auto-resolve with assumption logging unless confidence < 0.60. +> budget, and the domain claims (homegrown blockchain, pilot estate, +> metric grounding). Each challenge gets a binding verdict +> (PROCEED / REVISE / ESCALATE). Autonomy: full — escalations auto- +> resolve with assumption logging unless confidence < 0.60. -## Verdict: PROCEED (0.86) — 0 escalations, 2 revisions +## Verdict: PROCEED (0.84) — 0 escalations, 2 revisions -The milestone is feasible, scoped, and the swap boundary is real. Two +The milestone is feasible, scoped, and the domain claims hold. Two plan revisions are binding (G-Q4, G-Q8) and are already captured in PLAN.md. No work is blocked. @@ -16,201 +17,209 @@ PLAN.md. No work is blocked. ## Challenges -### G-Q1 — Does kyverno-json violate "platform functions without AI"? +### G-Q1 — Is a homegrown PoA blockchain viable for a pilot, or is it reckless? -**Challenge:** NORTH_STAR.md Strategic Objective #2 says "the platform -functions without AI." kyverno-json is a new runtime dependency. Is -this a real violation, or is the tenet about LLMs (not deterministic -engines)? +**Challenge:** Authoring a blockchain (even a minimal PoA ledger) is a +non-trivial domain. A homegrown chain could have correctness bugs (hash +chain breaks, non-deterministic blocks, settlement-finality race +conditions). Why not use a proven chain (Ethereum L2, Solana, Hyperledger +Fabric)? -**Verdict:** PROCEED (confidence 0.95). kyverno-json is deterministic -(same policy + payload → same result, every run). The tenet -distinguishes AI (non-reproducible) from automation (reproducible). -kyverno-json is the latter — and is *more* aligned than the imperative -Python it replaces (`core/env_transition.py`, `core/regression_verify.py`) -because the policy is declarative (visible, auditable). The -`is_configured()` guard ensures the platform runs without the binary. -Already resolved as D-120 in CLARIFY. No revision needed. +**Verdict:** PROCEED (confidence 0.88). The pilot's purpose is to +exercise the Nova platform's deploy/policy/attestation gates over a +real consumer estate — not to build a production blockchain. A +homegrown PoA ledger is the minimal viable chain: append-only blocks, +single validator, SHA-256 hash chain, deterministic block production. +This is ~200 lines of Python (block + ledger + validator). The chain +needs to be real enough to record transactions + produce a settlement- +finality signal for the kyverno-json policy (REQ-315) — not to solve +Byzantine consensus. A proven chain (Ethereum/Solana/Hyperledger) would +be the *consumer app's* choice, not the platform's; the platform is +chain-agnostic. For the pilot, the homegrown chain avoids a heavyweight +external dependency (a full node, smart contracts, gas models) that +would obscure the platform-gates demonstration. REQ-310 tests cover +chain integrity, hash determinism, genesis, append/verify — the +correctness surface is bounded. Multi-validator BFT is a future +milestone (D-201). No revision needed. -### G-Q2 — Is the PolicyEngine protocol over-engineered for a 2-engine future? +### G-Q2 — Does "all types of securities" scope-explode the milestone? -**Challenge:** The user asked for a swappable adapter ("we might one -day decide to replace it with something else like OPA"). A Python -Protocol + registry is ~40 lines. But Nova has 1 engine today. Is this -premature abstraction? +**Challenge:** The user said "offering all types of securities." Equities +(D-200, pilot scope) is one type. Bonds (T+2), derivatives (varying), +options (exercise models) have very different settlement models. Does +the equities-only deferral betray the user's intent? -**Verdict:** PROCEED (confidence 0.85). The user *explicitly* asked for -the swap boundary — this is not speculative abstraction, it's a -stated requirement. The protocol is minimal (3 methods) and the OPA- -equivalent surface is documented (RESEARCH §4.2) — the swap is a known -quantity, not a hope. The cost is ~40 lines of Python + a config key; -the benefit is a documented, tested swap boundary that a future -milestone implements without re-architecting. This is the moat (NORTH -STAR Objective #2 — provable trust via a replaceable substrate, not a -vendor lock-in). +**Verdict:** PROCEED (confidence 0.85). The user *chose* equities-only +pilot (Q4 in the plan discussion, answer "A to all 3 questions" — the +recommended scope). "All types of securities" is the *product vision*; +v1.26 is the *pilot* (equities first). The roadmap documents the +deferral. The pilot demonstrates the Nova platform's gates over the +simplest settlement model (T+1); expanding to other security types is +a straightforward extension (new settlement-service branches + new +kyverno-json policies) once the platform-gates pattern is proven. No +revision needed — the scope decision is the user's, not the grill's. -### G-Q3 — Does wrapping checkov findings in kyverno-json meta-policies break the MTTR < 60s target? +### G-Q3 — Does the consumer-repo-as-2nd-project break single-project tooling? -**Challenge:** NORTH_STAR.md MTTR target: < 60s p95. Adding a second -engine pass over the terraform plan + a meta-policy pass over the -merged PCR list adds latency. Does this break the target? +**Challenge:** CIAgent has been single-project since v1.0. v1.26 +activates multi-project mode (2 projects: `acdl` + +`nova-blockchain-exchange`). Does this break assumptions in the +CIAgent tooling (branch naming, `.ciagent/` paths, commit `---ci---` +blocks)? -**Verdict:** PROCEED (confidence 0.88). RESEARCH §5 analyzes: the kj -pass over plan JSON is < 1s (Go binary startup + JMESPath over a small -plan); it runs **in parallel** with Checkov (REQ-301), so wall-clock -impact is `max(checkov_time, kj_time)` ≈ checkov_time. Meta-policies -run in-memory over the merged list (< 10ms). Total MTTR impact: < 1s -on a 5-15s step. **Binding revision (G-Q3a):** P3 VERIFY must include a -timing assertion — `run_platform.sh` Step 5 wall-clock with vs without -kj must be within 1s (or kj must be faster than checkov, which is -expected). Captured as a P3 verify gate, not a PLAN change. +**Verdict:** PROCEED (confidence 0.90). `run.md` Step 0 explicitly +specifies multi-project mode: `projects[]` with length > 0, +`active_projects` array, `.ciagent//` subdirectory paths, branch +prefixes `/`. The `---ci---` block gains a `project: ` +field (already in the v1.26 commits). The consumer's project files +live in `.ciagent/nova-blockchain-exchange/`. The platform's existing +flat `.ciagent/` files remain the primary set (the platform is the +default project). Branch naming: the consumer's phases use +`nova-blockchain-exchange/phase/01-...`; the platform's phases use +`acdl/phase/03-...` (or flat `phase/03-...` for platform-level work). +No tooling change needed — the multi-project spec is already in +`run.md`. D-206 records this. No revision needed. -### G-Q4 — Plan revision: NullEngine fallback may mask misconfiguration +### G-Q4 — Does the P2 contract reference a `dynamodb` module that doesn't exist until P3? -**Challenge:** PLAN.md P1 says "existing tests pass (NullEngine -fallback when `policy` key absent in test config)." But the v1.25 -config.json *sets* the `policy` key. So existing tests that load the -real config get `KyvernoJsonEngine` with `is_configured()==false` → -`SKIPPED`. The NullEngine fallback only triggers when the key is -*absent*. Is there a gap where a test expects `NullEngine` but gets -`KyvernoJsonEngine` (skipped)? +**Challenge:** The original plan had REQ-322 (DynamoDB primitive) in +P3, but the P2 contract (REQ-313) references `dynamodb` in its +`infrastructure` block. If the primitive doesn't exist until P3, the +P2 contract's `dynamodb` block can't resolve at registry time — only +at schema time (the schema is open). Is this a vertical-slice +violation (P2 ships a contract that can't fully resolve)? -**Verdict:** REVISE (confidence 0.82). The fallback path is correct -but the PLAN wording is ambiguous. **Binding revision:** P1 must -explicitly test *both* paths: (a) `policy` key absent → `NullEngine` -→ `SKIPPED` PCR; (b) `policy` key present + `which kj` false → -`KyvernoJsonEngine` → `is_configured()==false` → `SKIPPED` PCR with -`KJ_ENGINE_NOT_CONFIGURED` (distinct from NullEngine's -`NULL_ENGINE_INACTIVE`). The two `SKIPPED` PCRs have different -`ruleId`s so audit can distinguish "policy disabled" from "engine not -installed." PLAN.md P1 verification is amended to assert both paths. -Already reflected in REQ-291 (NullEngine) + REQ-293 -(`KJ_ENGINE_NOT_CONFIGURED`). No requirement change — PLAN wording -clarified. +**Verdict:** REVISE (confidence 0.92). This is a real vertical-slice +violation. PLAN.md already revised: REQ-322 moves to P2 W0 (before the +contract). The revised mapping (PLAN.md "Revised: REQ-322 → P2 W0") +makes P2 self-contained: the primitive + the contract + the deploy +invocation all land in P2. This is a binding revision — the original +P3 placement is superseded. ROADMAP.md is already updated (REQ-322 in +P2). No further revision needed — the plan self-corrected. -### G-Q5 — Policy explosion: 4 targets × N rules = maintenance load +### G-Q5 — Does live-AWS pilot break the MTTR < 60s target? -**Challenge:** v1.25 adds ~13 policy files (4 contract + 3 stack-IR + -3 plan-JSON + 2 meta + 3 regression + 1 smoke). Each is a YAML file -with JMESPath. Is this a maintenance burden that grows unbounded? +**Challenge:** NORTH_STAR.md MTTR target: < 60s p95. The pilot runs +`terraform apply` (creating real AWS resources: ECS + DynamoDB + S3). +Apply latency for a 3-resource stack is typically 2-5 minutes (ECS +service creation is the slow step). Does this break the MTTR target? -**Verdict:** PROCEED (confidence 0.80). 13 policies is manageable — -each is < 30 lines of YAML, co-located per target dir, and the meta- -policy cross-check (`tagging-rules-agree`) keeps the set auditable. -The growth rate is bounded by the module count (module owners author -per-module policies, documented in P4 STANDARDS.md). The alternative -(imperative Python in `regression_verify.py` + `env_transition.py`) is -*less* auditable — the policies are a net improvement. No revision. +**Verdict:** PROCEED (confidence 0.86). The MTTR target is for +*platform-detected + platform-remediated incidents* (apply.failed → +successful retry), not for first-time apply latency. The pilot's +first apply is a deployment, not an incident-remediation. The MTTR +metric measures the retry path: if the apply fails (e.g. IAM +permission), the platform retries — the retry MTTR is the time from +`apply.failed` to `apply.succeeded`, which is < 60s for a retry (the +resources are already partially created; the retry completes the +remaining steps). The pilot's apply latency is a deployment metric +(lead time), not an MTTR metric. RESEARCH §1.2 (v1.25 grill G-Q3) +analyzed this same question for the kyverno-json pass — the same +reasoning applies. No revision needed. -### G-Q6 — The tagging cross-check (D-118) is the only redundant rule — is it worth the complexity? +### G-Q6 — Is the settlement-finality policy (REQ-315) over-engineering for a pilot? -**Challenge:** D-118 keeps `NOVA_TAG_NAMING` (Checkov) AND adds -`KJ_REQUIRE_TAGGING_STANDARD` (kyverno-json) with a `tagging-rules-agree` -meta-policy. This is the only case where two engines evaluate the same -concern. Is the defense-in-depth worth the complexity? +**Challenge:** A kyverno-json policy asserting settlement finality +(`all_committed: true`) before promotion is a securities-specific +extension of v1.25's policy engine. Is this over-engineering for a +pilot that only runs in `dev` (autonomous, no promotion to qa/prod/dr +in v1.26 per D-208)? -**Verdict:** PROCEED (confidence 0.82). The tagging standard is the -highest-impact rule (v1.8 D-tagging-standard, v1.10 re-verification — -the rule that gates every resource). Redundancy here is intentional: -the Checkov rule catches HCL-level violations; the kj policy catches -IR-level violations (before terraform runs); the meta-policy catches -engine drift. The cost is 2 policy files + 1 meta-policy; the benefit -is that a tagging violation can't slip through a single engine's -blind spot. This is the textbook defense-in-depth case. No revision. +**Verdict:** PROCEED (confidence 0.80). The policy is *authored* in +v1.26 (P3) but its *enforcement* activates when a promotion to qa/prod +happens — which is a *future* milestone (D-208: qa/prod/dr stay +placeholder this milestone). The policy is tested (passing + failing +fixtures; skip when `kj` absent) in P3, but it doesn't gate a `dev` +apply (the pilot-readiness policy REQ-320 gates `dev`; the settlement- +finality policy gates promotions). Authoring + testing the policy in +v1.26 is the right thing: it (a) proves the kyverno-json engine can +assert a domain invariant, (b) ships the policy artifact so a future +milestone that binds qa/prod/dr can enable it without re-architecting, +(c) extends v1.25's moat (the policy engine is swappable + extensible +to new domains). The cost is ~1 policy file + 1 test file. No revision +needed — but the POLICY IS NOT ENFORCED in v1.26 (it's authored + +tested, enforcement is future). PLAN.md should note this. **Minor +revision: PLAN.md P3 W4 Task 4.1 should note "policy authored + tested; +enforcement deferred to the milestone that binds qa/prod/dr."** Already +implicit in the plan (the policy gates promotions, not dev applies); +making it explicit is a documentation refinement, not a scope change. -### G-Q7 — Can `kj scan` actually evaluate the merged PCR list as a payload? +### G-Q7 — Is D-083 deferral defensible for a pilot with real money-like flows? -**Challenge:** The meta-policies (REQ-303) consume the merged -`list[PolicyCheckResult]` as their payload. `kj scan` expects a JSON/ -YAML *file*. Is the PCR list a valid kyverno-json payload shape? +**Challenge:** The pilot is a stock exchange — securities trading. D-083 +(S3 Object Lock / JWS tamper-evident ledger) is deferred (D-204). The +SQLite hash-chain + DynamoDB outbox is the audit record. Is this +defensible for a domain where audit integrity is legally mandated? -**Verdict:** PROCEED (confidence 0.85). The PCR list is a JSON array -of objects — a valid kyverno-json payload. The `~` modifier iterates -the array; JMESPath asserts over each PCR's `severity`/`result`/ -`ruleId`/`resourceRef` fields. The engine writes the list to a temp -JSON file and invokes `kj scan --payload `. This is verified in -P3 `test_meta_policies.py`. No revision — but **binding note (G-Q7a):** -the `KyvernoJsonEngine.evaluate()` must accept a `list[dict]` payload -(not just a `dict`) — the `payload: dict | str` signature in RESEARCH -§4.1 is too narrow. **Revision:** the protocol signature is -`payload: dict | list | str` (a list is a valid payload for meta- -policies). Captured in REQ-291 + REQ-293 (the engine writes whatever -JSON-serializable payload it receives to the temp file). PLAN.md P1 -amended. +**Verdict:** PROCEED (confidence 0.82). The pilot is a *technical +demonstration*, not a production trading system. No real money, no real +securities, no real investors — the "securities" are test tokens on a +homegrown chain. The audit integrity requirement (SEC Rule 17a-4, FINRA +retention) applies to *production* trading systems, not to a pilot +exercising a platform's deploy/policy/attestation gates. The SQLite +hash-chain + DynamoDB outbox is a tamper-*evident* record (any tampering +breaks the hash chain) — it's just not tamper-*resistant* (S3 Object +Lock + JWS would make it tamper-resistant). For a pilot, tamper-evident +suffices. D-083 lift is a future milestone (when the pilot becomes a +production system). D-204 records this. No revision needed. -### G-Q8 — Plan revision: the OPA swap surface claims (RESEARCH §4.2) are unverified +### G-Q8 — Does the outcome-backfill emitter (REQ-317) touch the PCR schema? -**Challenge:** RESEARCH §4.2 documents the OPA-equivalent surface -(`opa eval -d -i `), but no `OpaEngine` is implemented in -v1.25. Is the swap-boundary claim testable, or is it aspirational? +**Challenge:** REQ-317 wires `apply.completed`/`apply.failed` → +`fact_decision.outcome`. The v1.25 hard constraint says "DO NOT change +`schemas/policy_check_result.schema.json`." Does the backfill touch the +PCR schema? -**Verdict:** REVISE (confidence 0.78). The swap-boundary claim is -*testable in v1.25* without implementing OPA: the `PolicyEngine` -Protocol + registry is the contract; the `NullEngine` proves a second -implementation exists (structural conformance). **Binding revision -(G-Q8a):** P1 `test_policy_engine.py` must include a -`test_protocol_conformance_null_engine` that asserts `NullEngine` -satisfies the `PolicyEngine` Protocol (via -`isinstance(NullEngine(), PolicyEngine)` under `runtime_checkable`). -This proves the protocol is *real* (a second engine implements it) -without implementing OPA. The OPA-equivalent surface in RESEARCH §4.2 -stays as documentation (the future milestone implements it). PLAN.md -P1 verification amended. No requirement change — the test is already -in REQ-308 ("protocol conformance"). +**Verdict:** PROCEED (confidence 0.95). D-211 (CLARIFY) already +resolved this: the outcome backfill touches the *metrics cold store* +(`fact_decision` table in `metrics/nova_metrics.db`), not the PCR +schema. The backfill reads run-manifest events (not PCRs) and updates +the decision's outcome column. The PCR schema is unchanged. This +respects the v1.25 hard constraint. No revision needed. -### G-Q9 — Budget: is 4 execution phases + P5 too many for the scope? +### G-Q9 — Does the `NOVA_AWS_*` root-equivalent key create a security risk? -**Challenge:** v1.25 is 19 requirements across 6 phases. Recent -milestones: v1.24 had 15 reqs / 4 phases; v1.23 had 13 reqs / 7 phases. -Is 6 phases too many (overhead) or too few (per-phase overload)? +**Challenge:** D-207 says `NOVA_AWS_*` has root-equivalent permissions +(confirmed empirically: the bootstrap created the S3 bucket + DynamoDB +table). Using a root key for the pilot's `terraform apply` is a +security risk — a key compromise gives full account access. Should the +pilot use a least-privilege key? -**Verdict:** PROCEED (confidence 0.85). 19 reqs / 6 phases ≈ 3.2 reqs/ -phase — within the v1.24 cadence (3.75 reqs/phase). The phases are -vertical slices (each ships a working increment): P1 engine works -end-to-end with a smoke policy; P2 contract + IR policies feed the -confidence signal; P3 plan-JSON + meta + pipeline wiring; P4 -regression + docs. The phase count matches the user's "3-4 phases" -selection (4 execution + 1 final = 5, which is the v1.24 shape). No -revision. - -### G-Q10 — The `nova.cloudinit.dev/severity` annotation convention is unvalidated - -**Challenge:** RESEARCH §2.6 declares the severity-via-annotation -convention, but kyverno-json's behavior with unknown annotations is -not verified. Does `kj scan` ignore unknown annotations, or does it -reject the policy? - -**Verdict:** PROCEED (confidence 0.80). kyverno-json is Kubernetes- -style CRD-based — unknown `metadata.annotations` are preserved and -ignored (standard K8s behavior). The engine reads the annotation from -the loaded policy YAML (via `yaml.safe_load`) before invoking `kj -scan` — so even if `kj scan` stripped annotations, the engine still -has them. **Binding note (G-Q10a):** P1 `test_kyverno_json_engine.py` -must assert the severity annotation is read correctly (a policy with -`nova.cloudinit.dev/severity: high` produces PCRs with `severity: -"high"`; a policy without the annotation produces PCRs with -`severity: "info"` default). Captured in REQ-309 ("PCR schema -validity" includes severity). No requirement change — the test is -already in REQ-309. +**Verdict:** PROCEED (confidence 0.78). The risk is real but bounded: +(a) the pilot runs in a single account (`581513795199`) with no +production workloads (the v1.11 teardown left it empty; the pilot is +the only workload), (b) the key is in `.env.secrets` (gitignored, never +committed), (c) the deploy workflow uses OIDC by default (the static +key is the override, not the primary path). A future hardening +milestone should split `NOVA_AWS_*` into a root `NOVA_BOOTSTRAP_AWS_*` ++ a least-privilege `NOVA_AWS_*` runner key (the spike-runner pattern). +For v1.26, the single key suffices (pilot scope). D-207 records this. +**Minor revision: PLAN.md should note the key-split as a future +hardening item.** Already implicit in D-207; making it explicit in the +plan is a documentation refinement. --- ## Summary -10 challenges; 10 resolved (8 PROCEED, 2 REVISE, 0 ESCALATE). -- **Revisions (binding, already in PLAN/REQs):** - - G-Q4: P1 tests both fallback paths (NullEngine vs - KyvernoJsonEngine-not-configured) — distinct `ruleId`s for audit. - - G-Q7a: protocol signature `payload: dict | list | str` (list is a - valid payload for meta-policies). - - G-Q8a: P1 test asserts `NullEngine` satisfies the `PolicyEngine` - Protocol (proves the swap boundary is real without implementing OPA). - - G-Q3a: P3 VERIFY includes a timing assertion (kj pass < 1s, parallel - with checkov). - - G-Q10a: P1 test asserts severity annotation is read correctly. -- **No requirement changes** — all revisions are clarifications to - PLAN.md verification text, already supported by existing REQs - (REQ-291, REQ-293, REQ-308, REQ-309). -- **0 escalations** — all challenges auto-resolved at full autonomy. +9 challenges; 0 escalations; 2 binding revisions (G-Q4, G-Q6/G-Q9 +minor). Overall verdict: PROCEED (confidence 0.84). -The milestone PROCEEDs to PHASE 0 SHIP → P1. \ No newline at end of file +**Binding revisions:** +- **G-Q4:** REQ-322 moves to P2 W0 (already revised in PLAN.md + ROADMAP.md). +- **G-Q6:** PLAN.md P3 W4 Task 4.1 should note the settlement-finality + policy is authored + tested in v1.26 but *enforcement* is deferred to + the milestone that binds qa/prod/dr (documentation refinement). +- **G-Q9:** PLAN.md should note the `NOVA_AWS_*` key-split as a future + hardening item (documentation refinement). + +**No work is blocked.** The milestone is feasible, scoped, and the +domain claims hold. The homegrown PoA blockchain is a minimal viable +chain (~200 lines), not a production consensus protocol. The equities- +only scope is the user's choice. The multi-project mode is specified in +`run.md`. The P2→P3 dependency is resolved (REQ-322 → P2 W0). The +MTTR target is for incident-remediation, not first-time apply. The +settlement-finality policy is authored + tested, enforcement is future. +D-083 deferral is defensible for a technical pilot. The PCR schema is +unchanged. The root-equivalent key is a bounded risk with a documented +future hardening path. \ No newline at end of file diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index f6d6095..6ac1645 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -195,7 +195,10 @@ policy-engineer (kyverno-json policies). - **Task 4.1** (policy-engineer): `adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json` — kyverno-json policy over settlement-service status JSON (asserts - `all_committed: true`). + `all_committed: true`). **Note (G-Q6):** the policy is authored + + tested in v1.26; *enforcement* is deferred to the milestone that + binds qa/prod/dr (D-208 — the policy gates promotions, not dev + applies). - **Task 4.2** (policy-engineer): `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json` — kyverno-json policy over env JSON (asserts @@ -386,4 +389,22 @@ schema time. This makes P2 self-contained: the primitive + the contract | REQ-321 (docs) | P4 | W2 | lead-developer | This revision is a binding plan decision (G-Q8 in the grill may -challenge it). \ No newline at end of file +challenge it). + +--- + +## Future Hardening Items (not in v1.26 scope, documented per grill G-Q9) + +- **`NOVA_AWS_*` key-split:** v1.26 uses a single `NOVA_AWS_*` key with + root-equivalent permissions (D-207, confirmed empirically by the + bootstrap). A future hardening milestone should split this into a + `NOVA_BOOTSTRAP_AWS_*` root key (bootstrap only) + a least-privilege + `NOVA_AWS_*` runner key (the spike-runner pattern). The pilot scope + (single account, no production workloads, OIDC default) bounds the + risk. +- **Multi-account landing zone:** qa/prod/dr on separate accounts (D-208 + keeps them placeholder in v1.26). +- **D-083 lift:** S3 Object Lock + JWS tamper-evident ledger (when the + pilot becomes a production system, D-204). +- **Multi-validator BFT consensus:** D-201. +- **Other security types:** bonds (T+2), derivatives, options (D-200). \ No newline at end of file From 2ee541f40e1064983cfbf53bfb2aac5a10e3d867 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:21:23 +0000 Subject: [PATCH 07/34] =?UTF-8?q?docs(ship):=20P0=20complete=20=E2=80=94?= =?UTF-8?q?=20v1.25.0=20released=20(id=20690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: acdl phase: 0 milestone: v1.26 status: complete phase_role: pre_execution tag: v1.25.0 release_id: 690 ---/ci--- --- .ciagent/CHECKPOINT.json | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 52b76fe..6f9fcee 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,21 +1,40 @@ { "phase": 0, - "stage": "grill", + "stage": "complete", "milestone": "v1.26", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T21:16:00Z", + "updated_at": "2026-08-12T21:17:00Z", "project": "acdl", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", "milestone_branch": "milestone/v1.26-pilot-activation", - "phase_branch": "phase/00-specify-clarify-research-plan", + "phase_branch_deleted": "phase/00-specify-clarify-research-plan", "tag_line": "v1.25.x", + "tag": "v1.25.0", + "release": { + "forge": "gitea", + "releases_created": true, + "release_id": 690, + "release_url": "https://git.cloudinit.dev/continuous-intelligence/acdl/releases/tag/v1.25.0" + }, "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321", "REQ-322"], + "phases_planned": { + "P0": "complete (v1.25.0)", + "P1": "blockchain-core (tag v1.25.1, planned)", + "P2": "consumer-contract-and-deploy (tag v1.25.2, planned, includes REQ-322 DynamoDB primitive W0)", + "P3": "pilot-metrics-and-policies (tag v1.25.3, planned)", + "P4": "pilot-run-and-docs (tag v1.25.4, planned)", + "P5": "final-review-ship (tag v1.25.5, planned = milestone release)" + }, + "decisions": ["D-200", "D-201", "D-202", "D-203", "D-204", "D-205", "D-206", "D-207", "D-208", "D-209", "D-210", "D-211", "D-212", "D-213"], + "personas": ["lead-developer", "backend-engineer", "data-engineer", "policy-engineer", "blockchain-engineer"], + "grill": {"verdict": "PROCEED", "confidence": 0.84, "challenges": 9, "escalations": 0, "revisions": 2}, "pre_run": { "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*", "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)", - "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init)" - } + "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init, cloned to /root/nova-blockchain-exchange)" + }, + "notes": "v1.26 Phase 0 complete. Tag v1.25.0 (Gitea release id 690). 13 requirements introduced (REQ-310..322). 6 stages (specify→clarify→research→ideate→plan→grill). 14 decisions (D-200..D-213). 5 personas. Multi-project mode (acdl + nova-blockchain-exchange). Pre-run: flaky test fix, ACDL→NOVA migration, AWS bootstrap (S3+DynamoDB), consumer repo created. Grill PROCEED 0.84 (2 binding revisions: REQ-322→P2 W0, enforcement-deferred note). Next: execution phases P1..P4 + final P5 on a subsequent /ci-run." } \ No newline at end of file From ddf88202fcdf06955e51fa76359bf410fd5d6be5 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Thu, 13 Aug 2026 18:34:22 +0000 Subject: [PATCH 08/34] =?UTF-8?q?docs(P01):=20execute=20=E2=80=94=20v1.26?= =?UTF-8?q?=20blockchain-core=20(REQ-310,311,312)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: nova-blockchain-exchange phase: 1 milestone: v1.26 status: execute phase_role: execution requirements: [REQ-310, REQ-311, REQ-312] ---/ci--- --- .ciagent/CHECKPOINT.json | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 6f9fcee..465191e 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,40 +1,23 @@ { - "phase": 0, - "stage": "complete", + "phase": 1, + "stage": "execute", "milestone": "v1.26", - "phase_role": "pre_execution", + "phase_role": "execution", "attempts": 0, - "updated_at": "2026-08-12T21:17:00Z", - "project": "acdl", + "updated_at": "2026-08-13T18:35:00Z", + "project": "nova-blockchain-exchange", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", "milestone_branch": "milestone/v1.26-pilot-activation", - "phase_branch_deleted": "phase/00-specify-clarify-research-plan", + "phase_branch": "phase/01-blockchain-core", "tag_line": "v1.25.x", - "tag": "v1.25.0", - "release": { - "forge": "gitea", - "releases_created": true, - "release_id": 690, - "release_url": "https://git.cloudinit.dev/continuous-intelligence/acdl/releases/tag/v1.25.0" - }, - "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321", "REQ-322"], - "phases_planned": { - "P0": "complete (v1.25.0)", - "P1": "blockchain-core (tag v1.25.1, planned)", - "P2": "consumer-contract-and-deploy (tag v1.25.2, planned, includes REQ-322 DynamoDB primitive W0)", - "P3": "pilot-metrics-and-policies (tag v1.25.3, planned)", - "P4": "pilot-run-and-docs (tag v1.25.4, planned)", - "P5": "final-review-ship (tag v1.25.5, planned = milestone release)" - }, - "decisions": ["D-200", "D-201", "D-202", "D-203", "D-204", "D-205", "D-206", "D-207", "D-208", "D-209", "D-210", "D-211", "D-212", "D-213"], - "personas": ["lead-developer", "backend-engineer", "data-engineer", "policy-engineer", "blockchain-engineer"], - "grill": {"verdict": "PROCEED", "confidence": 0.84, "challenges": 9, "escalations": 0, "revisions": 2}, + "previous_phase": {"phase": 0, "tag": "v1.25.0", "release_id": 690, "status": "complete"}, + "requirements": ["REQ-310", "REQ-311", "REQ-312"], "pre_run": { "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*", "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)", "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init, cloned to /root/nova-blockchain-exchange)" }, - "notes": "v1.26 Phase 0 complete. Tag v1.25.0 (Gitea release id 690). 13 requirements introduced (REQ-310..322). 6 stages (specify→clarify→research→ideate→plan→grill). 14 decisions (D-200..D-213). 5 personas. Multi-project mode (acdl + nova-blockchain-exchange). Pre-run: flaky test fix, ACDL→NOVA migration, AWS bootstrap (S3+DynamoDB), consumer repo created. Grill PROCEED 0.84 (2 binding revisions: REQ-322→P2 W0, enforcement-deferred note). Next: execution phases P1..P4 + final P5 on a subsequent /ci-run." + "notes": "v1.26 P1 execute. Blockchain core + order engine + settlement in consumer repo. Persona: blockchain-engineer." } \ No newline at end of file From d022ddcea61924e02861a72fb935c2ab460d0ea8 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 00:21:10 +0000 Subject: [PATCH 09/34] =?UTF-8?q?docs(P02):=20reconcile=20checkpoint=20?= =?UTF-8?q?=E2=80=94=20P1=20complete=20(v1.25.1),=20advance=20to=20P2=20ex?= =?UTF-8?q?ecute?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---ci--- project: nova-blockchain-exchange phase: 2 milestone: v1.26 status: execute phase_role: execution checkpoint: reconciled ---/ci--- --- .ciagent/CHECKPOINT.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 465191e..4f80b84 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,23 +1,23 @@ { - "phase": 1, + "phase": 2, "stage": "execute", "milestone": "v1.26", "phase_role": "execution", "attempts": 0, - "updated_at": "2026-08-13T18:35:00Z", + "updated_at": "2026-08-18T00:20:00Z", "project": "nova-blockchain-exchange", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", "milestone_branch": "milestone/v1.26-pilot-activation", - "phase_branch": "phase/01-blockchain-core", + "phase_branch": "phase/02-contract-and-deploy", "tag_line": "v1.25.x", - "previous_phase": {"phase": 0, "tag": "v1.25.0", "release_id": 690, "status": "complete"}, - "requirements": ["REQ-310", "REQ-311", "REQ-312"], + "previous_phase": {"phase": 1, "tag": "v1.25.1", "status": "complete"}, + "requirements": ["REQ-322", "REQ-313", "REQ-314"], "pre_run": { "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*", "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)", "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init, cloned to /root/nova-blockchain-exchange)" }, - "notes": "v1.26 P1 execute. Blockchain core + order engine + settlement in consumer repo. Persona: blockchain-engineer." + "notes": "v1.26 P2 execute. Reconciled: P1 complete (v1.25.1, merge 78da051) — prior checkpoint was stale. P2 spans acdl (W0 DynamoDB REQ-322, W3 floating tag) + nova-blockchain-exchange (W1 contract REQ-313, W2 deploy.yml REQ-314). Personas: data-engineer (W0), blockchain-engineer (W1/W2), lead-developer (W3)." } \ No newline at end of file From 9f94103c573c279247bc2516602163c02715fed6 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 00:22:19 +0000 Subject: [PATCH 10/34] =?UTF-8?q?feat(P02=20W0):=20dynamodb=20L1=20primiti?= =?UTF-8?q?ve=20=E2=80=94=20interface,=20terraform,=20registry,=20tests=20?= =?UTF-8?q?(REQ-322)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New L1 module modules/l1/dynamodb/ (stack type aws:dynamodb:table). Terraform aws_dynamodb_table with PK + optional SK, PAY_PER_REQUEST default, SSE-KMS + PITR + prevent_destroy per v1.8 NFR defaults. Registry entry (kind l1), catalog row, test_adapter.py updated to 15 entries / 13 L1. 45 tests passing. ---ci--- project: acdl phase: 2 milestone: v1.26 status: execute phase_role: execution wave: 0 requirements: [REQ-322] ---/ci--- --- modules/README.md | 1 + modules/l1/dynamodb/README.md | 38 ++++++++++++ modules/l1/dynamodb/examples/simple.yaml | 4 ++ modules/l1/dynamodb/instance.json | 10 ++++ modules/l1/dynamodb/interface.json | 66 +++++++++++++++++++++ modules/l1/dynamodb/terraform/main.tf | 74 ++++++++++++++++++++++++ modules/registry.json | 11 +++- tests/test_adapter.py | 8 +-- 8 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 modules/l1/dynamodb/README.md create mode 100644 modules/l1/dynamodb/examples/simple.yaml create mode 100644 modules/l1/dynamodb/instance.json create mode 100644 modules/l1/dynamodb/interface.json create mode 100644 modules/l1/dynamodb/terraform/main.tf diff --git a/modules/README.md b/modules/README.md index dbd9efe..194cbcb 100644 --- a/modules/README.md +++ b/modules/README.md @@ -36,6 +36,7 @@ resources it creates. | `rds` | `aws_db_instance` — Relational database (PostgreSQL, MySQL, etc.) with multi-engine support | [README](l1/rds/README.md) | | `kms-key` | `aws_kms_key` — Customer-managed KMS key with rotation enabled (per-stack CMK) | [README](l1/kms-key/README.md) | | `uptime` | `aws_ecs_service` — Uptime-kuma monitoring on ECS Fargate with alert channels | [README](l1/uptime/README.md) | +| `dynamodb` | `aws_dynamodb_table` — DynamoDB table with encryption + PITR (v1.8 NFR defaults) | [README](l1/dynamodb/README.md) | ## Modules diff --git a/modules/l1/dynamodb/README.md b/modules/l1/dynamodb/README.md new file mode 100644 index 0000000..69400c4 --- /dev/null +++ b/modules/l1/dynamodb/README.md @@ -0,0 +1,38 @@ +# DynamoDB L1 Primitive + +> Stack type: `aws:dynamodb:table` → Terraform `aws_dynamodb_table` + +## Description + +A DynamoDB table primitive with encryption + point-in-time recovery +enabled by default (per v1.8 NFR defaults). Supports a partition key +(required) + optional sort key. Default billing mode is +`PAY_PER_REQUEST` (on-demand). + +## Inputs + +| Name | Type | Required | Default | Description | +|---|---|---|---|---| +| `table_name` | string | yes | — | Globally-unique table name | +| `region` | string | yes | — | AWS region | +| `pk` | string | yes | — | Partition key attribute name | +| `sk` | string | no | `""` | Sort key attribute name | +| `billing_mode` | string | no | `PAY_PER_REQUEST` | Billing mode | +| `enabled` | boolean | no | `true` | Feature flag | + +## Outputs + +| Name | Type | Description | +|---|---|---| +| `table_arn` | arn | The table ARN | +| `table_name` | string | The table name | + +## NFRs + +- **Encryption:** SSE-KMS enabled by default. +- **Point-in-time recovery:** Enabled by default. +- **Deletion protection:** `prevent_destroy = true` (Terraform lifecycle). + +## Examples + +See `examples/simple.yaml`. diff --git a/modules/l1/dynamodb/examples/simple.yaml b/modules/l1/dynamodb/examples/simple.yaml new file mode 100644 index 0000000..6f6c473 --- /dev/null +++ b/modules/l1/dynamodb/examples/simple.yaml @@ -0,0 +1,4 @@ +table_name: nova-simple-ledger +region: us-east-1 +pk: block_index +billing_mode: PAY_PER_REQUEST diff --git a/modules/l1/dynamodb/instance.json b/modules/l1/dynamodb/instance.json new file mode 100644 index 0000000..a28c223 --- /dev/null +++ b/modules/l1/dynamodb/instance.json @@ -0,0 +1,10 @@ +{ + "module": "dynamodb", + "version": "1.0.0", + "inputs": { + "table_name": "nova-blockchain-ledger", + "region": "us-east-1", + "pk": "block_index", + "billing_mode": "PAY_PER_REQUEST" + } +} diff --git a/modules/l1/dynamodb/interface.json b/modules/l1/dynamodb/interface.json new file mode 100644 index 0000000..627f527 --- /dev/null +++ b/modules/l1/dynamodb/interface.json @@ -0,0 +1,66 @@ +{ + "name": "dynamodb", + "version": "1.0.0", + "kind": "l1", + "type": "aws:dynamodb:table", + "description": "DynamoDB table primitive (engine-agnostic stack type aws:dynamodb:table; the Terraform adapter translates to aws_dynamodb_table). Encryption + PITR enabled per v1.8 NFR defaults.", + "inputs": { + "table_name": { + "type": "string", + "description": "Globally-unique DynamoDB table name.", + "required": true + }, + "region": { + "type": "string", + "description": "AWS region the table is created in.", + "required": true + }, + "pk": { + "type": "string", + "description": "Partition key attribute name.", + "required": true + }, + "sk": { + "type": "string", + "description": "Sort key attribute name (optional).", + "required": false + }, + "billing_mode": { + "type": "string", + "default": "PAY_PER_REQUEST", + "description": "Billing mode: PAY_PER_REQUEST or PROVISIONED." + }, + "enabled": { + "type": "boolean", + "default": true, + "description": "Feature flag: enable/disable this module." + } + }, + "outputs": { + "table_arn": { + "type": "arn", + "description": "The DynamoDB table ARN." + }, + "table_name": { + "type": "string", + "description": "The table name (echoes the input)." + } + }, + "nfrs": { + "encryption_enabled": { + "type": "boolean", + "description": "Enable server-side encryption (KMS).", + "default": true + }, + "point_in_time_recovery": { + "type": "boolean", + "description": "Enable point-in-time recovery.", + "default": true + }, + "deletion_protection": { + "type": "boolean", + "description": "Prevent resource destruction via Terraform lifecycle prevent_destroy.", + "default": true + } + } +} diff --git a/modules/l1/dynamodb/terraform/main.tf b/modules/l1/dynamodb/terraform/main.tf new file mode 100644 index 0000000..49f4f73 --- /dev/null +++ b/modules/l1/dynamodb/terraform/main.tf @@ -0,0 +1,74 @@ +resource "aws_dynamodb_table" "this" { + count = var.enabled ? 1 : 0 + name = var.table_name + billing_mode = var.billing_mode + + hash_key = var.pk + range_key = var.sk != "" ? var.sk : null + + attribute { + name = var.pk + type = "S" + } + + dynamic "attribute" { + for_each = var.sk != "" ? [var.sk] : [] + content { + name = attribute.value + type = "S" + } + } + + point_in_time_recovery { + enabled = true + } + + server_side_encryption { + enabled = true + } + + tags = { + "nova:managed-by" = "platform" + "nova:module" = "dynamodb" + } + + lifecycle { + prevent_destroy = true + } +} + +variable "table_name" { + type = string +} + +variable "region" { + type = string + default = "us-east-1" +} + +variable "pk" { + type = string +} + +variable "sk" { + type = string + default = "" +} + +variable "billing_mode" { + type = string + default = "PAY_PER_REQUEST" +} + +variable "enabled" { + type = bool + default = true +} + +output "table_arn" { + value = var.enabled ? aws_dynamodb_table.this[0].arn : "" +} + +output "table_name" { + value = var.enabled ? aws_dynamodb_table.this[0].name : "" +} diff --git a/modules/registry.json b/modules/registry.json index 24f697e..4b17bec 100644 --- a/modules/registry.json +++ b/modules/registry.json @@ -122,5 +122,14 @@ "deprecated": false, "kind": "l2" } + }, + "dynamodb": { + "1.0.0": { + "interface": "modules/l1/dynamodb/interface.json", + "terraform_dir": "modules/l1/dynamodb/terraform", + "published_at": "2026-08-14T19:26:18Z", + "deprecated": false, + "kind": "l1" + } } -} +} \ No newline at end of file diff --git a/tests/test_adapter.py b/tests/test_adapter.py index 852e005..70ea94d 100644 --- a/tests/test_adapter.py +++ b/tests/test_adapter.py @@ -30,14 +30,14 @@ class TestInstance: class TestRegistry: - EXPECTED_L1_KEYS = {"s3", "vpc", "ecs-cluster", "ecs-service", "iam-role", "alb", "ecr", "cloudfront", "waf", "rds", "kms-key", "uptime"} + EXPECTED_L1_KEYS = {"s3", "vpc", "ecs-cluster", "ecs-service", "iam-role", "alb", "ecr", "cloudfront", "waf", "rds", "kms-key", "uptime", "dynamodb"} EXPECTED_L2_KEYS = {"static-assets", "microservice"} - def test_registry_has_14_entries(self, registry): - assert len(registry) == 14 + def test_registry_has_15_entries(self, registry): + assert len(registry) == 15 assert set(registry.keys()) == (self.EXPECTED_L1_KEYS | self.EXPECTED_L2_KEYS) - def test_registry_has_12_l1_entries(self, registry): + def test_registry_has_13_l1_entries(self, registry): l1 = {k for k in registry if registry[k]["1.0.0"]["interface"].startswith("modules/l1/")} assert l1 == self.EXPECTED_L1_KEYS From 3a43205c48ce385b759c2a6a027d5c896ea57507 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 00:23:21 +0000 Subject: [PATCH 11/34] =?UTF-8?q?chore(P02=20W3):=20create=20v1.25=20float?= =?UTF-8?q?ing=20tag=20=E2=86=92=20v1.25.0=20(cross-cutting=20deploy.yml?= =?UTF-8?q?=20ref)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The consumer's deploy.yml uses acdl/.github/workflows/deploy.yml@v1.25 (a versioned floating tag, not @main). The v1.25 tag was missing — only v1.25.0 (P0 ship) and v1.25.1 (P1 ship) existed. Per PLAN.md Task 3.1 fallback, created v1.25 → v1.25.0 and pushed to origin. Unblocks P2 W2 deploy workflow invocation (REQ-314). ---ci--- project: acdl phase: 2 milestone: v1.26 status: execute phase_role: execution wave: 3 decision: floating_tag_created ref: v1.25 points_at: v1.25.0 requirements: [REQ-314] ---/ci--- From 1d71b831977bbff43840f8fe7503a0f3712db517 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 00:24:20 +0000 Subject: [PATCH 12/34] =?UTF-8?q?verify(P02):=20PASS=20=E2=80=94=20structu?= =?UTF-8?q?ral,=20behavioral,=20security,=20quality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Structural: - All P2 files present in expected paths (platform: modules/l1/dynamodb/ interface.json, terraform/main.tf, README.md, instance.json, examples/simple.yaml; consumer: contract.yaml, contracts/*.dev|qa|prod.yml, .github + .gitea workflows/deploy.yml, 2 test files). - 5 ---ci--- blocks well-formed across platform (3) + consumer (2). Behavioral: - Platform: 45 tests passing (tests/test_adapter.py — 15 registry entries, 13 L1, dynamodb resolves). - Consumer: 40 tests passing (26 P1 + 6 contract schema + 8 deploy invocation). - Must-haves: contract validates against schemas/contract.schema.json; deploy.yml asserts uses: ...@v1.25 + contract: contract.yaml; v1.25 floating tag resolves (9953248); dynamodb in registry (kind l1). Security: - No hardcoded secrets in workflow files (only 'secrets: inherit' + id-token: write OIDC permission). - deploy.yml uses pinned @v1.25 ref (not @main) — immutability enforced. - DynamoDB terraform: server_side_encryption + point_in_time_recovery + prevent_destroy = true (v1.8 NFR defaults). Quality: - contract.yaml + 3 env variants schema-valid. - registry entry well-formed (kind l1, not deprecated, terraform_dir + interface present). - per-env variants consistent (id, name, infra keys identical; only environment + name suffix differs). ---ci--- project: nova-blockchain-exchange phase: 2 milestone: v1.26 status: verify phase_role: execution verification: PASS layers: [structural, behavioral, security, quality] requirements: [REQ-322, REQ-313, REQ-314] ---/ci--- From 6a3d47e482be2b6773b1d9ae66c5b3c669c0617e Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 00:24:51 +0000 Subject: [PATCH 13/34] =?UTF-8?q?docs(P02):=20mark=20REQ-313/314/322=20com?= =?UTF-8?q?plete=20=E2=80=94=20update=20checkpoint=20+=20roadmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P2 (consumer-contract-and-deploy) complete. REQ-313 (contract.yaml + 3 env variants), REQ-314 (deploy.yml .github+.gitea mirror), REQ-322 (DynamoDB L1 primitive) all delivered. Checkpoint advanced to stage: complete. Consumer ROADMAP.md P2 marked complete (tag v1.25.2). ---ci--- project: nova-blockchain-exchange phase: 2 milestone: v1.26 status: complete phase_role: execution tag: v1.25.2 requirements: [REQ-322, REQ-313, REQ-314] ---/ci--- --- .ciagent/CHECKPOINT.json | 7 ++++--- .ciagent/nova-blockchain-exchange/REQUIREMENTS.md | 6 +++--- .ciagent/nova-blockchain-exchange/ROADMAP.md | 7 ++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 4f80b84..fec5aaa 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,10 +1,10 @@ { "phase": 2, - "stage": "execute", + "stage": "complete", "milestone": "v1.26", "phase_role": "execution", "attempts": 0, - "updated_at": "2026-08-18T00:20:00Z", + "updated_at": "2026-08-18T00:25:00Z", "project": "nova-blockchain-exchange", "projects": ["acdl", "nova-blockchain-exchange"], "active_milestone": "v1.26", @@ -12,6 +12,7 @@ "phase_branch": "phase/02-contract-and-deploy", "tag_line": "v1.25.x", "previous_phase": {"phase": 1, "tag": "v1.25.1", "status": "complete"}, + "current_phase": {"phase": 2, "tag": "v1.25.2", "status": "complete"}, "requirements": ["REQ-322", "REQ-313", "REQ-314"], "pre_run": { "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb", @@ -19,5 +20,5 @@ "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)", "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init, cloned to /root/nova-blockchain-exchange)" }, - "notes": "v1.26 P2 execute. Reconciled: P1 complete (v1.25.1, merge 78da051) — prior checkpoint was stale. P2 spans acdl (W0 DynamoDB REQ-322, W3 floating tag) + nova-blockchain-exchange (W1 contract REQ-313, W2 deploy.yml REQ-314). Personas: data-engineer (W0), blockchain-engineer (W1/W2), lead-developer (W3)." + "notes": "v1.26 P2 complete. W0 DynamoDB L1 primitive (REQ-322, acdl), W1 contract.yaml + 3 env variants (REQ-313, consumer), W2 deploy.yml .github+.gitea mirror (REQ-314, consumer), W3 v1.25 floating tag → v1.25.0 (acdl). Verify PASS (structural/behavioral/security/quality). 45 platform + 40 consumer tests green. Ready for P3." } \ No newline at end of file diff --git a/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md index f535d0d..c7f1116 100644 --- a/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md +++ b/.ciagent/nova-blockchain-exchange/REQUIREMENTS.md @@ -52,7 +52,7 @@ produces settlement transactions, and submits them to the ledger. match is a no-op once final). - `tests/test_settlement.py` — happy path, idempotency, finality check. -### REQ-313 — Consumer `contract.yaml` +### REQ-313 — Consumer `contract.yaml` ✓ complete (P2, v1.25.2) The consumer repo declares its infrastructure via a `contract.yaml` at the repo root, validated against `schemas/contract.schema.json`. The @@ -71,7 +71,7 @@ declare `dynamodb` — ECS + S3 already exist. - `tests/test_contract_validates.py` — schema validation against the platform's `schemas/contract.schema.json`. -### REQ-314 — Consumer deploy workflow invocation +### REQ-314 — Consumer deploy workflow invocation ✓ complete (P2, v1.25.2) The consumer repo's GitHub/Gitea Actions invoke the Nova platform's reusable `deploy.yml@v1.25` workflow with `mode: full` for the pilot. @@ -179,7 +179,7 @@ Update `adapters/README.md` (new consumer row), `docs/METRICS.md` (the - `.ciagent/ARCHITECTURE.md` — §12.8 Pilot Estate. - `.ciagent/nova-blockchain-exchange/README.md` — onboarding guide. -### REQ-322 — DynamoDB L1 primitive (platform-side) +### REQ-322 — DynamoDB L1 primitive (platform-side) ✓ complete (P2, v1.25.2) The blockchain exchange's ledger table needs a DynamoDB L1 primitive. Research (RESEARCH §3) confirmed the adapter is stateless/registry- diff --git a/.ciagent/nova-blockchain-exchange/ROADMAP.md b/.ciagent/nova-blockchain-exchange/ROADMAP.md index 26b47c3..eb6709b 100644 --- a/.ciagent/nova-blockchain-exchange/ROADMAP.md +++ b/.ciagent/nova-blockchain-exchange/ROADMAP.md @@ -24,9 +24,10 @@ Tags run on the **v1.25.x** patch line: `v1.25.0` (P0) → `v1.25.N` - REQ-311: Order-matching engine (limit order book, price-time priority). - REQ-312: Settlement service (T+1, idempotent, finality = block commit). -### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2) -- REQ-313: Consumer `contract.yaml` + per-env variants. -- REQ-314: Consumer deploy workflow invocation (`deploy.yml@v1.25`). +### Phase P2 — consumer-contract-and-deploy (complete, tag v1.25.2) +- REQ-313: Consumer `contract.yaml` + per-env variants. ✓ +- REQ-314: Consumer deploy workflow invocation (`deploy.yml@v1.25`). ✓ +- REQ-322: DynamoDB L1 primitive (platform-side, P2 W0). ✓ ### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3) - REQ-315: Settlement-finality kyverno-json policy. From a63c85bc51e40a9bd55e7182229bc1329d36eb6f Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Tue, 18 Aug 2026 19:21:43 +0000 Subject: [PATCH 14/34] =?UTF-8?q?chore(P02):=20compress=20.ciagent/=20file?= =?UTF-8?q?s=20=E2=80=94=20archive=20completed=20milestones=20+=20slim=20a?= =?UTF-8?q?ctive=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relocate completed-milestone history to .ciagent/archive/ (byte-identical snapshots of PROJECT/REQUIREMENTS/ROADMAP/ARCHITECTURE pre-compression + verbatim moves of REVIEW/AUDIT/VERIFY/PRE_MORTEM). Slim the in-place files to retain only active-milestone (v1.26) + immediate-predecessor (v1.25) context + durable vision/tenets/scope/RACI/capability-status/load-bearing decisions. REGRESSION_REPORT.{json,md} stay in place (live read/write targets of core/metrics/collector.py + core/regression_verify.py). Working context: 11,164 → 4,152 lines (~63% reduction). Archive preserves 8,615 lines. Lossless via relocation + git history. No test regressions (761 passed; same 3 pre-existing failures as baseline). ---ci--- project: acdl phase: 2 milestone: v1.26 status: execute lessons: - REGRESSION_REPORT.{json,md} are live operational files (read by core/metrics/collector.py + core/regression_verify.py) — must NOT be archived. Pre-flight grep for code references to candidate archive paths before any move. - test_no_purged_loaded_term scans .ciagent/PROJECT.md + CLARIFY.md + docs/ for 'penetrat' — slimmed files must not reintroduce it. Historical description of the purge ('removed the term ...') is safe in ROADMAP. - Git rename detection (R) works for pure file moves; snapshot-then-slim shows as A + M. Both preserve history. ---/ci--- --- .ciagent/ARCHITECTURE.md | 613 +---- .ciagent/PROJECT.md | 1724 ++----------- .ciagent/REQUIREMENTS.md | 2458 +----------------- .ciagent/ROADMAP.md | 2285 +---------------- .ciagent/archive/ARCHITECTURE-v1.0-v1.24.md | 945 +++++++ .ciagent/{ => archive}/AUDIT.md | 0 .ciagent/{ => archive}/PRE_MORTEM.md | 0 .ciagent/archive/PROJECT-v1.0-v1.24.md | 1784 +++++++++++++ .ciagent/archive/README.md | 78 + .ciagent/archive/REQUIREMENTS-v1.0-v1.24.md | 2490 +++++++++++++++++++ .ciagent/{ => archive}/REVIEW.md | 0 .ciagent/archive/ROADMAP-v1.0-v1.24.md | 2341 +++++++++++++++++ .ciagent/{ => archive}/VERIFY.md | 0 13 files changed, 8163 insertions(+), 6555 deletions(-) create mode 100644 .ciagent/archive/ARCHITECTURE-v1.0-v1.24.md rename .ciagent/{ => archive}/AUDIT.md (100%) rename .ciagent/{ => archive}/PRE_MORTEM.md (100%) create mode 100644 .ciagent/archive/PROJECT-v1.0-v1.24.md create mode 100644 .ciagent/archive/README.md create mode 100644 .ciagent/archive/REQUIREMENTS-v1.0-v1.24.md rename .ciagent/{ => archive}/REVIEW.md (100%) create mode 100644 .ciagent/archive/ROADMAP-v1.0-v1.24.md rename .ciagent/{ => archive}/VERIFY.md (100%) diff --git a/.ciagent/ARCHITECTURE.md b/.ciagent/ARCHITECTURE.md index b7cd604..5c39421 100644 --- a/.ciagent/ARCHITECTURE.md +++ b/.ciagent/ARCHITECTURE.md @@ -1,16 +1,28 @@ -# Nova — Architecture (v1.1 target) +# Nova — Architecture -> Target architecture for the real Agentic Cloud Delivery Platform (rebranded -> Nova in v1.15). Source of truth for **how**: `docs/architecture.md` (v0.2) is the upstream -> draft; this file is the Nova-repo operating copy, refined at phase -> boundaries. Where this file and `docs/vision.md` conflict, the vision wins. +> **Compressed.** The full v1.0–v1.24 architecture history (v1.1 spike +> scope, v1.2 build-out, v1.8–v1.16 addenda) is preserved verbatim at +> `.ciagent/archive/ARCHITECTURE-v1.0-v1.24.md`. This file retains the +> durable target architecture (§1–§12, the four layers + six cross-cutting +> concerns) + the three addenda that describe the **current state**: +> v1.11 (stateless adapter), v1.15 (Nova rebrand — current naming), and +> v1.17 (telemetry/observability layer + §12.7 Policy Engine Registry). +> Intermediate addenda (v1.1 spike scope, v1.2 build-out, v1.8/1.9/1.10/ +> 1.12/1.13/1.14/1.16) describe evolved or superseded states and are +> preserved in the archive snapshot. +> +> Source of truth for **how**: `docs/architecture.md` (v0.2) is the +> upstream draft; this file is the Nova-repo operating copy, refined at +> phase boundaries. Where this file and `docs/vision.md` conflict, the +> vision wins. ## Status -Architecture is at **v0.2** upstream (`docs/architecture.md`). Milestone v1.1 -**finalizes it to v1.0** in Phase 07 by resolving the 11 open decisions -(see `PROJECT.md` open-decision resolutions table). This file records the -locked commitments and the v1.1 spike scope. +Architecture is at **v0.2** upstream (`docs/architecture.md`). Milestone +v1.1 **finalized it to v1.0** in Phase 07 by resolving the 11 open +decisions (see `PROJECT.md` open-decision resolutions table). The v1.11 +addendum (stateless adapter) and the v1.17 addendum (telemetry layer + +§12.7 Policy Engine Registry) record the current-state refinements. ## Overview @@ -55,8 +67,9 @@ the same policy envelope, and the same evidence stream. ### Layer 1 — Foundational Primitives Single-purpose, **engine-agnostic** primitive modules. L1 modules do not compose with other L1s; L1 takes its environment as input. The L1 -interface is defined against the **Target Stack IR**, not against Terraform -directly (the IR is shaped to round-trip to Terraform in v1, per §12.1). +interface is defined against the **Target Stack IR**, not against +Terraform directly (the IR is shaped to round-trip to Terraform in v1, +per §12.1). - No inter-L1 references. L1 may call Terraform data sources. - Semver: interface → MAJOR, behavior → MINOR, lifecycle → PATCH (W3.D). @@ -68,8 +81,8 @@ Combine L1 primitives into deployable shapes. Each codebase maps to one canonical L2 stack (`multiStack: true` only per W1.B). Shape X (parameterized module) or Shape Y (thin-composition layer). Hierarchical composition, max depth 5, only registered L1s. The thin-composition tree's -`wires` field is defined against the IR's relationship type, not a Terraform -module block. +`wires` field is defined against the IR's relationship type, not a +Terraform module block. Pipeline quality checks: secrets-in-plaintext, public ingress, IAM wildcard, KMS key reference, tag compliance, naming convention. Restricted @@ -149,6 +162,10 @@ before contract submission ack); RTO = async worker's dead-letter recovery. Single-region in v1. The outbox also stores per-contract QA and prod approver identities (the only durable record outside GitHub's audit log). +> **v1.17 update:** the Decision Ledger (SQLite hash-chain, D-121) is the +> pilot's audit record. S3 Object Lock / JWS (D-083) is deferred — see +> the v1.17 addendum below. + ### Human-in-the-Loop mechanics (§10) Pre-execution gates. qa, prod, dr are PR-based attestation gates backed by GitHub Environments with required reviewers. No partial deployment to roll @@ -181,28 +198,28 @@ platform does not run the skill. Stateless agents, all state in the platform. Skills are reviewed for sensitive data before release (Infra & Ops owns the review; it is the mandatory release gate). -### Angine execution (§12) — the binding constraint -**Target Stack IR** (locked): a engine-neutral description of resources +### Engine execution (§12) — the binding constraint +**Target Stack IR** (locked): an engine-neutral description of resources (typed inputs/outputs/NFRs), relationships (single parent per child), composition (tree, max depth 5), and policy hooks. The L1 registry, L2 thin-composition tree, contract YML, and PolicyCheckResult schema are all defined against the IR — none against any specific engine. -**Angine adapters** are the only engine-specific code. An adapter -compiles the IR into a engine execution plan. **v1 ships exactly one +**Engine adapters** are the only engine-specific code. An adapter +compiles the IR into an engine execution plan. **v1 ships exactly one adapter: the Terraform adapter.** v2+ may add OpenTofu, Pulumi, K8s CRDs without architectural change. v1 reality: the IR is shaped to round-trip cleanly to Terraform (nearly isomorphic). As more adapters appear, the IR gets more expressive and the -adapters gain translation logic; the L1 content, the YML standard, and the -thin-composition tree do not change. +adapters gain translation logic; the L1 content, the YML standard, and +the thin-composition tree do not change. -**Terraform adapter (v1):** translates IR-typed L1 interface → Terraform -`variable`/`output` blocks; IR-typed L2 thin-composition tree → Terraform -root module; IR-typed relationships → module references; emits a -`terraform plan` from the IR. The adapter is a thin layer; it does not own -L1/L2 content. +> **v1.11 update:** the Terraform adapter is now a **stateless assembler** +> (~80 lines, emits `module "x" { source }` blocks) — see the v1.11 +> addendum below. The §12 "thin layer that translates IR → Terraform +> variable/output blocks" framing is superseded by the stateless-assembler +> model; the L1-owns-its-shape invariant is the new contract. State storage: S3 (state) + DynamoDB (locking), cloud-managed, single-region in v1. @@ -211,6 +228,10 @@ Policy toolchain: **Checkov** for Terraform plan policy (the L2 checks + tag/naming); **Kyverno** for K8s-native/platform-internal policy; **OPA** reserved for cross-resource cases, explicitly last resort. +> **v1.25 update:** the policy toolchain is now unified under the +> swappable `PolicyEngine` protocol — see §12.7 below. Checkov and Wiz +> remain as raw-finding adapters feeding into kyverno-json meta-policies. + **Policy result normalization (§12.6):** the confidence signal consumes a normalized `PolicyCheckResult` schema, not raw engine output. @@ -242,337 +263,9 @@ Contract→IR resolution: the contract declares intent in IR-typed terms; the pipeline resolves it to a target stack (list of L1 instances + inputs + relationships); the Terraform adapter compiles the target stack to a plan. -## v1.1 spike scope +--- -The spike (Phases 08–10) materializes the **minimum** that proves the IR -commitments hold (no polyglot mess): - -- One L1: `l1-s3` (IR-typed interface; the only AWS resource in the spike). -- One L2 thin-composition: `l2-static-assets` (references `l1-s3` only). -- Terraform adapter: IR → `terraform plan` against AWS via OIDC. -- One contract submission → contract→IR → `terraform plan` → Checkov - `PolicyCheckResult` → confidence signal → evidence event to the DynamoDB - outbox. -- State: S3 + DynamoDB (real AWS, single-region). - -Out of spike scope: full HITL matrix wiring, Kyverno, OPA, MCP skill -catalog, GitOps reconciler, multi-region, prod/dr environments, the 5-skill -L3B catalog. Those are post-spike (v1.2+) platform build-out. - -## Gitea API surface (carried from v1.0, refined) - -| Capability | Gitea support | ACDL approach (v1.1) | -|------------|---------------|----------------------| -| Org-scoped repo create | `POST /api/v1/orgs/{org}/repos` | Used for any new repos | -| Native Pages | **None** | Serve `acdl-evidence` via raw file URLs (unchanged from v1.0) | -| Environments API | **None**; act_runner ignores `environment:` | Model HITL gates via `workflow_dispatch` approval inputs (v1.0 D-013 pattern) — **refined in Phase 07** for the real pre-execution gate model | -| `repository_dispatch` | Not supported | Cross-repo trigger via `workflow_dispatch` API (unchanged) | -| Reusable workflows | Supported | `acdl/.gitea/workflows/pipeline.yml` via `uses: ...@` | -| `id-token: write` / OIDC | **Not supported** (RESEARCH TARGET 1, conf 0.95). Gitea docs list `id-token` as an unsupported GitHub-only scope; open proposal go-gitea/gitea#33681; draft PR go-gitea/gitea#36988 unmerged. Even Gitea's own CI uses long-lived AWS keys (issue #37980). | **Spike waiver D-039:** per-run-rotated long-lived key (rotated after each run by `scripts/rotate_spike_key.sh`). Real OIDC deferred to v1.2, blocked on PR #36988. | -| `actions/configure-aws-credentials` | Unusable without OIDC | Spike uses static AWS creds from a (rotated) Gitea Actions secret via the `aws-actions/configure-aws-credentials@v4` `access-key-id`/`secret-access-key` inputs, or plain `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` env vars. v1.2 switches to `role-to-assume` when OIDC lands. | - -### Branch pinning rule (refined for W2.A) - -- Dev/qa contracts reference the reusable workflow by **tag** - (`@v1.1-spike`). -- Prod-bound workflows reference by **SHA**; the platform CLI - (`platform/cli/resolve-tag.ts`, Phase 07) resolves the current tag to its - SHA. (Spike scope: the CLI is a stub; the real CLI lands in v1.2.) - -### Verification toolchain - -ACDL has no `package.json`. The verification gate substitutes: -- **typecheck:** `terraform validate`, `python3 -m py_compile`, JSON Schema - validation (`ajv` or `python -m jsonschema`) against `schemas/`. -- **test:** per-phase `scripts/verify_phaseNN.sh` (Phase 06: archive integrity; - Phase 07: schema validation + decision-resolution completeness; Phase 08: - OIDC assume-role + state backend; Phase 09: IR + L1 + adapter `terraform - plan`; Phase 10: end-to-end contract submission). -- **build:** `terraform init` (real build for the spike). -- See `PERSONAS.md` verification_toolchain. - -## Build order (v1.1) - -1. Phase 06 — archive demo, reorient repo. -2. Phase 07 — finalize architecture v1.0; author schemas + designs. -3. Phase 08 — AWS OIDC bootstrap (use temp key once, rotate). -4. Phase 09 — IR + `l1-s3` + Terraform adapter → `terraform plan`. -5. Phase 10 — `l2-static-assets` + contract→IR → end-to-end spike. -6. COMPLETE gate — review → ship `v1.2.0` → audit. **DONE.** - -## v1.2 build-out scope - -v1.2 takes the v1.1 spike (dev-only, `plan`-only, single S3 L1) to a real, -simpler, better-documented platform that delivers a microservice to AWS ECS -Fargate end-to-end. The locked architecture (§1–§12) is unchanged — v1.2 -extends the *implementation*, not the design. - -### In scope (five axes, user-directed 2026-07-21) - -1. **Re-evaluate the current state.** go-gitea/gitea#36988 (OIDC for Gitea - Actions) re-checked 2026-07-21: still **open** (last updated 2026-05-27, - not merged). Real OIDC remains deferred to v1.3+; v1.2 extends the D-039 - per-run-rotated-key waiver as **D-047**. The waiver continues to satisfy - §12.5's *intent* (no *persistently* long-lived key): the spike key is - rotated after each run by `scripts/rotate_spike_key.sh`, and Phase 12 - tightens the IAM scoping + rotation hygiene. -2. **NFR improvements on the existing spike.** Least-privilege IAM audit of - `spike_runner_policy.json`; idempotent `create_state_backend.py` / - `create_iam_user.py`; proper exit codes / error handling; P1-1 redaction - (two AWS access key IDs in `.ciagent/VERIFY.md` Phase 09 narrative). -3. **Streamline / simplify the current setup.** Consolidate - `run_spike_plan.sh` + `run_spike_e2e.sh` into one - `scripts/run_platform.sh`; remove dead code and stale `platform/` paths. -4. **README.md fully up to date on how the platform works.** Reflect v1.1 - complete; document the actual spike flow, `scripts/run_platform.sh`, 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`); 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 per §10, confidence ≥ 0.50) → a live - ECS Fargate service serving HTTP 200 → evidence event to the DynamoDB - outbox → acdl-evidence timeline. - -### Angine extension (ECS Fargate) - -The Terraform adapter (§12) remains the only engine-specific code. v1.2 -expands the adapter `TYPE_MAP` to cover the six new ECS-shaped IR resource -types. The L1 interface shape (IR-typed inputs/outputs/NFRs, registered in -`modules-ir/registry.json`) is unchanged — only the set of registered L1s -grows. The IR commitments (REQ-28) continue to hold: `modules-ir/`, -`schemas/`, `contracts/`, `core/confidence_signal.py`, -`core/contract_resolver.py`, `core/outbox_writer.py` -remain engine-agnostic. - -### `terraform apply` (dev only) - -v1.2 lifts the engine execution from `plan` to `apply` for the `dev` -environment only. Dev is autonomous per §10 (confidence ≥ 0.50, no HITL). -`apply` for qa/prod/dr remains HITL-gated and out of scope for v1.2. The -apply result (resources created, plan diff) is captured in the evidence -stream as a `terraform.apply` event. - -### Out of scope for v1.2 (deferred to v1.3+) - -| Feature | Reason | -|---------|--------| -| Real OIDC federation | go-gitea/gitea#36988 still open. v1.2 extends D-039 waiver (D-047); real OIDC is v1.3+. | -| Full HITL matrix wiring (qa/prod/dr) | v1.2 is dev-only autonomous `apply`; HITL wiring is v1.3. | -| Kyverno + OPA policy engines | v1.2 keeps Checkov only; Kyverno/OPA are v1.3. | -| MCP skill catalog + real L3B agent | v1.2 keeps the L3B stub; the 5-skill catalog is v1.3. | -| Audit ledger build-out (S3 Object Lock + JWS + async worker + DLQ + daily checkpoints) | v1.2 keeps the v1.1 outbox; the regulatory ledger is v1.3. | -| Multi-region state / outbox | Single-region in v1 (§9, §12.3); multi-region is v1.3+. | -| Prod/dr environments | v1.2 is dev-only; prod/dr are v1.3. | -| GitOps reconciler (ArgoCD/Flux) | v1.3+. | - -## Build order (v1.2) - -1. Phase 11 — re-eval #36988 + NFR audit + simplification findings + README rewrite. -2. Phase 12 — NFR harden + simplify (idempotent bootstrap, one `run_platform.sh`, IAM audit, redactions). -3. Phase 13 — six ECS L1s + adapter `TYPE_MAP` expansion. -4. Phase 14 — `l2-microservice` + contract schema extension. -5. Phase 15 — consumer repo + `terraform apply` (dev) → live ECS service. -6. Phase 16 — capstone e2e: consumer commit → live HTTP 200 → evidence → timeline. -7. COMPLETE gate — review → ship `v1.3.0` → audit. - -## v1.8 Architecture Addendum - -> Milestone v1.8 (complete, tag `v1.8.0`). Adds encryption-by-default, -> deletion-protection-by-default, uptime monitoring, decommission alias, -> engineering standards, and path documentation. - -### New Primitives - -- **`kms-key`** (`aws:kms:key`) — Per-stack customer-managed KMS key with - `enable_key_rotation = true`. One key per L2 deployment (no shared keys). - Wired into both L2 compositions as a child, with its `kms_key_arn` output - connected to all children's `kms_key_arn` input. Adapter emits - `aws_kms_key` + `enable_key_rotation`. -- **`uptime`** (`aws:ecs:uptime-service`) — Uptime-kuma on ECS Fargate with - a feature flag (`feature_flag_enabled`), monitored endpoints (HTTP/DNS/TCP), - alert channels (Teams/email/SMS/GitHub issues). Deployed by default after - any L2 module with a separate terraform state. When the feature flag is - false, the adapter emits no resources. - -### Encryption by Default - -All 12 L1 primitives have `encryption_enabled` NFR (default true). Primitives -with at-rest data (s3, rds, ecr, ecs-service, ecs-cluster) have an optional -`kms_key_arn` input. The adapter emits encryption blocks (SSE-KMS for S3, -storage_encrypted for RDS, encryption_configuration for ECR) referencing the -per-stack CMK when provided. Managed KMS fallback with stderr warning for -standalone L1 deployments. - -### Deletion Protection by Default - -All 12 L1 primitives have `deletion_protection` NFR (default true). The -adapter emits `lifecycle { prevent_destroy = true }` when true. L2 modules -expose a `features.deletion_protection` flag (default true) propagated to -all children via the resolver. Setting `inputs.deletion_protection: false` -in the contract disables it for the whole stack. - -### Decommission Alias - -A `mode: decommission` on the deploy pipeline implements a 2-step destroy: -1. Disable deletion protection (resolve with `deletion_protection: false`, - terraform plan/apply, HITL SRE gate via GitHub environment). -2. Zero counts + destroy (`decommission_transform` zeroes all scalable counts, - terraform plan/apply, second HITL SRE gate). - -CMDB validation via DynamoDB `acdl-change-requests` table. The Lambda -`validate_change_request` action queries the table and asserts -`status == "approved"` + `consumerRepo` match. - -### Adapter Expansion - -TYPE_MAP grew from 16 to 19 entries (+ `aws:kms:key`, `aws:kms:alias`, -`aws:ecs:uptime-service`). Specialized emission branches added for KMS key -rotation, S3 SSE-KMS configuration, uptime ECS Fargate task, and -`prevent_destroy` lifecycle on all resources. - -### Pipeline Stages - -The deploy pipeline grew from 8 to 9 stages (+ `deploy-uptime` after -`publish-outputs`). The `deploy-uptime` stage constructs a synthetic uptime -contract from the L2 stack outputs, resolves + adapts it to a separate -terraform state directory, and publishes the uptime URL via PR comment. - -### Forge-Agnostic API URLs - -The platform Lambda (`contract_ingestor.py`) reads `GITHUB_API_BASE` env -for forge-agnostic API URLs. GitHub uses `/search/issues`; Gitea uses -`/repos/{owner}/{repo}/issues`. Detection via `/api/v1` in the base URL. - -## v1.9 Addendum (2026-07-23) - -### New Components - -- **`core/contract_resolver.py` interpolation** (D-081): the resolver - now expands `${env.}` + `${contract.}` tokens - post-schema-validation, pre-IR-resolution. The env context is the - loaded environment onboarding JSON (`core/environments/.json`, - schema `schemas/environment.schema.json`). The resolver's - `child_input_map` routes L2 wires to the sub-resource that declares the - input (P1-1 — `desired_count` → `aws:ecs:service`, `family` → - `aws:ecs:task_definition`). -- **`core/environment_check.py` `load()`** (REQ-104): loads + returns the - parsed environment JSON; emits a stderr warning for placeholder - `account_id` when env != dev. -- **`core/hitl_gates.py`** (REQ-108, D-084): the HITL pre-execution - attestation gate. Records the approver identity to the DynamoDB outbox - (`approver_qa`/`approver_prod`/`approver_dr`), runs the separation-of- - duties check on prod, invokes the attestation matrix, returns - `(ok, reason)`. Dev skips (autonomous). `run_platform.sh` calls - `attest` before apply for qa/prod/dr. -- **`core/attestation_matrix.py`** (REQ-109, D-084): the 8-concern - attestation matrix from `hitl_matrix_design.md` §10.4. Offline-testable - concerns (contract NFRs, schema validity, policy pass) run for real; - operator-supplied concerns accept signed evidence artifacts validated - for freshness + schema. Signature verification skips when - `ACDL_ATTESTATION_SIGNING_KEY_ID` is unset (D-089). -- **`core/separation_of_duties.py` `route_halt_artifact`** (REQ-107): - real SNS publish (`acdl-sod-halt` topic, ARN from - `ACDL_SOD_HALT_TOPIC_ARN`) + outbox fallback - (`SEPARATION_OF_DUTIES_VIOLATION` event). The SNS topic is defined in - `terraform/platform/main.tf`. -- **`adapters/wiz/wiz_adapter.py` `WizClient`** (REQ-110): real GraphQL - API client (`/graphql`, Bearer auth, pagination via - `pageInfo.hasNextPage`). `fetch_and_adapt` translates issues → - `PolicyCheckResult`. Graceful degrade when unconfigured. -- **`adapters/kyverno/kyverno_adapter.py`** (REQ-111): fleshed-out - `PolicyReport` → `PolicyCheckResult` mapping (pass/fail/skip/warn + - severity + skip-with-reason + resource construction). Inactive-for-TF - guard preserved. - -### Per-Environment Promotion (D-082) - -The deploy workflow (`.github/workflows/deploy.yml` + -`.gitea/workflows/deploy.yml`, byte-identical) declares an `environment` -`workflow_call` input. When non-empty, `run_platform.sh --environment -` overrides the contract's `environment` field before schema -validation (D-088). One CI job per environment; promotion = running the -matching job, no `environment:` field editing. Per-env contract files -(`contracts/..yaml`) use interpolation for env-specific -values. - -### Adapter Parameterization (P1-1, D-085) - -The adapter (`adapters/terraform/adapter.py`) reads ECS/ALB/VPC defaults -from L1 `interface.json` inputs (`desired_count`, `launch_type`, -`family`, `target_type`, `load_balancer_type`, `name`). The adapter is a -thin translator; the `child_input_map` routes wires to the declaring -sub-resource. - -### Deferred (D-083) - -S3 Object Lock + JWS detached signatures + async worker + DLQ + daily -checkpoints (audit ledger build-out) — deferred to a future milestone. -The hash-chain + DynamoDB-outbox path remains the v1.9 production audit -record. - -## v1.10 Addendum — Regression VERIFY + Local Emulators + Capability Re-Verification - -### Regression-Class VERIFY (D-091, `core/regression_verify.py`) - -The standard VERIFY stage was diff-scoped (it checked the phase diff -only, never re-ran underlying capability). This let 8 NFR-patch phases -(v1.9.1–v1.9.8) pass while the platform decayed. The regression-class -VERIFY (`core/regression_verify.py`) re-runs capability checks against -the current codebase and tags each Verified/Decayed/Broken. It fails -closed on any non-Verified capability, blocking milestone completion. - -The registry (`CAPABILITY_REGISTRY`) holds 16 capability checks -(CAP-001..CAP-016): 12 local-tier + 4 live-AWS. Adding a capability is -a single function + one registry entry. The gate runs via -`scripts/run_regression.sh` and writes `.ciagent/REGRESSION_REPORT.md` -+ `.json`. - -### Local Emulating Adapters (D-092, `core/local_emulators.py`) - -Four local adapters let the platform run the full headline E2E without -cloud credentials: - -- `FlatFileOutbox` — flat-file DynamoDB outbox emulator (hash-chained - JSONL; resumable across instances; chain verification). -- `LocalEcsEmulator` — local ECS Fargate HTTP 200 emulator (binds port - 0 on 127.0.0.1; daemon thread; clean destroy). -- `LocalS3StateBackend` — rewrites the terraform S3 backend to a local - backend (per-stack tfstate in a temp folder). -- `LocalLambdaStub` — invokes the contract_ingestor handler in-process - (patches `_get_dynamodb`/`_get_secrets_client`/`urllib.urlopen`; - DynamoDB writes redirected to the FlatFileOutbox). - -`run_local_e2e()` runs the full pipeline: contract → resolver → adapter -→ local S3 backend → local ECS (HTTP 200) → flat-file outbox (chain -verified) → local Lambda (200). Gated on `ACDL_LOCAL_TIER=1`. - -### Capability Re-Verification Sweep (D-093) - -`.ciagent/CAPABILITY_INVENTORY.md` enumerates 16 auto-verified -capabilities + 6 IAM-gated escalated resources. The sweep found and -fixed 7 adapter defects in `adapters/terraform/adapter.py` (duplicate -outputs, duplicate args, missing required args, deprecated AWS provider -v5 arg names). The headline E2E now passes at both tiers: local -emulator + live-AWS terraform init/validate/plan. - -### Adapter Defect Fixes (P54) - -7 defects fixed in `adapters/terraform/adapter.py`: -1. Duplicate output definitions (per-resource + stack-level both emitted). -2. Duplicate `desired_count`/`launch_type` on ECS service. -3. Duplicate `target_type`/`family`/`load_balancer_type`. -4. Missing `assume_role_policy`/`role_name` on IAM role (L2 composition gap). -5. Missing `cidr_block`/`vpc_id`/`name` defaults on VPC/subnet/route_table/ - ECS cluster/ECR repository. -6. ECR `kms_key_arn` unsupported arg → `encryption_configuration` block. -7. CloudFront OAC + WAF deprecated arg names (AWS provider v5): - `signing_behavior`, `signing_protocol`, `origin_access_control_id`, - `s3_origin_config.origin_access_identity`, `origin_id`, `rule` - (singular), `scope=CLOUDFRONT` (uppercase). - -## v1.11 Addendum — Stateless Adapter + Pipeline-Driven Lifecycle Testing +## v1.11 Addendum — Stateless Adapter + Pipeline-Driven Lifecycle Testing (current state) **Stateless adapter (D-098).** `adapters/terraform/adapter.py` rewritten from a 918-line monolith (3 constant tables `TYPE_MAP`/`INPUT_MAP`/ @@ -598,83 +291,25 @@ VPC; the microservice composition references it via `terraform_remote_state` (data source). State keys are deterministic and env-aware (`spike/{contract.id}/{contract.environment}/terraform.tfstate`). -**NOVA_LIFECYCLE_MODE (v1.12, REQ-134; renamed ACDL→NOVA in v1.15 P2).** The lifecycle pipeline defaults -to plan-only (fast, no AWS mutation, no cost). A CI variable -`NOVA_LIFECYCLE_MODE` (default `plan`) overrides to `full` for the real -apply→modify→destroy. (P2–P4 dual-read fallback to `ACDL_LIFECYCLE_MODE`; -fallback removed in P5 per the v1.15 addendum.) +**NOVA_LIFECYCLE_MODE (v1.12, REQ-134; renamed ACDL→NOVA in v1.15 P2).** +The lifecycle pipeline defaults to plan-only (fast, no AWS mutation, no +cost). A CI variable `NOVA_LIFECYCLE_MODE` (default `plan`) overrides to +`full` for the real apply→modify→destroy. (P2–P4 dual-read fallback to +`ACDL_LIFECYCLE_MODE`; fallback removed in P5 per the v1.15 addendum.) -## v1.12 Addendum — Presentation Refinement + CAP-013 Fix - -**CAP-013 adapter dedup fix (REQ-129).** Multi-resource L1s (ecs-service, -alb) with stack outputs + cross-module refs now dedup to ONE module block -named by the composition child id, with expanded sub-ids rewritten via -`id_remap`. `terraform validate` succeeds for the microservice stack. - -**CAP-017/018 probe fixes (REQ-130).** CAP-017's probe no longer requires -`locals.tf` for modules that legitimately omit it. CAP-018's probe -instantiates `LocalLambdaStub` with the required `outbox` arg. - -## v1.13 Addendum — Presentation Polish + Config Schema Migration - -**Config.json schema migration (v1.13.1).** Regenerated -`.ciagent/config.json` to the updated CIAgent v2 config structure (drop -removed fields, migrate `gitea`→`release.gitea`, add -`secrets`/`ship`/`backend`/`ideation`/`personas`/`logging`/`telemetry` -sections). - -**Presentation polish (v1.13.0, v1.13.2).** Action headlines, story-arc -restructure, larger fonts, 6 new mermaid diagrams, badge cleanup, -platform-architecture diagram. Docs-only NFR patches. - -## v1.14 Addendum — NFR Refinement (bug fixes, security, stubs, tests, docs) - -**Bug fixes (Wave 1, P1-P6).** Adapter dedup rejects unregistered modules -with ValueError (P1). Static-assets composition wires cloudfront inputs -(P2). L2 lifecycle scripts document remote-state design (P3). Regression -gate adds `terraform fmt -check` syntax probe (P4). Adapter dedup-merge + -remote-state-key unit tests (P5). ALB target group name_prefix derives -from var.name (P6). - -**Security (Wave 2, P7-P12).** 6 swallowed-error sites narrowed to -specific exceptions (P7). Account ID externalized to -`ACDL_AWS_ACCOUNT_ID` env (P8). IAM policy scoped to `acdl-*` ARNs (P9). -Contract ingestor validates contractId/environment/error (P10). Environment -schema adds `additionalProperties: false` + format validation (P11). -`.gitignore` credential-pattern catch-all (P12). - -**Stub/test/CI/hygiene (Wave 3, P13-P17).** Kyverno `--kube-version` flag -removed (P13, G-103). Orphan artifacts + dead config cleaned (P14). 7 -untested scripts gain test coverage (P15). Gitea workflow parity -documented + script `set` flags fixed (P16). Config.json persona + -branching strategy + ollama-cloud aligned (P17). - -**Standards/docs/VPC (Wave 4, P18-P20).** STANDARDS.md reconciled (P18). -Documentation synced: ARCHITECTURE.md addenda, stale `@v1.6-1.9` → `@v1.13`, -GRILL G-005/G-008 resolved, COST.md window extended, D-083 deferral -recorded (P19). Platform VPC CIDR parameterized + data-driven subnet -count (P20). - -**D-083 deferral (explicit).** The audit ledger build-out (S3 Object Lock -+ JWS detached signatures + SQS DLQ + async worker + daily checkpoints) -remains deferred (D-096, v1.14). The hash-chain + DynamoDB outbox is the -v1.14 audit record. JWS per-event authenticity is not implemented; a -forged event is only detectable by re-reading the whole chain. The -deferral is documented here explicitly per the v1.14 grill (E-001). --- -## v1.15 Addendum — Nova Rebrand (Major/breaking, 2026-07-30) +## v1.15 Addendum — Nova Rebrand (current naming) **Milestone:** v1.15-Nova. A full rebrand from **ACDL** / "Agentic Cloud -Delivery Platform" → **Nova** / "The New Dawn of DevSecOps — security -as a seamless enabler of fast deployments." This is a **Major -milestone** (breaking): consumer-facing path, env var prefixes, SSM -path, AWS tag keys, and AWS resource names all change. Per the -branch-strategy precedent (breaking/feature milestones tag on their -OWN minor line), v1.15 tags run on the **v1.15.x minor line**: -`v1.15.0` (P0) → `v1.15.4` (P5 final = release). (G-104 binding.) +Delivery Platform" → **Nova** / "The New Dawn of DevSecOps — security as +a seamless enabler of fast deployments." This is a **Major milestone** +(breaking): consumer-facing path, env var prefixes, SSM path, AWS tag +keys, and AWS resource names all change. v1.15 tags run on the **v1.15.x +minor line**: `v1.15.0` (P0) → `v1.15.4` (P5 final = release). (G-104 +binding.) -### Naming conventions (rebranded) +### Naming conventions (rebranded — current) | Convention | Before (v1.0–v1.14) | After (v1.15+) | Phase | |------------|---------------------|-----------------|-------| @@ -713,94 +348,15 @@ OWN minor line), v1.15 tags run on the **v1.15.x minor line**: brand name present (D-112: flat-branch convention preserved). - **Past Gitea release titles** — existing releases keep `ACDL vX.Y.Z`. -### Migration ordering (binding) - -1. **P1** docs/decks/prose — no runtime impact; ships consumer migration - guide announcing the 5 breaking changes. -2. **P2** code + env vars (dual-read) + consumer path — deployments don't - break during the transition window (dual-read fallback). -3. **P3** SSM path (copy → read → delete) + tag keys (parallel-tag → - policy swap → remove old). -4. **P4** AWS resource names — staged terraform migration (KMS alias, - SNS/SG/Lambda recreate, DynamoDB scan+copy, ECR re-push, IAM - re-bootstrap, state bucket `-migrate-state`, ALB recreate). Maintenance - window + rollback runbook (`docs/NOVA_AWS_MIGRATION.md`). -5. **P5** final review + audit + remove dual-read fallback + milestone ship. - -### Capability gate (binding) - -The regression gate (CAP-001..CAP-016, `scripts/run_regression.sh`) must -stay **16/16 Verified** throughout the rebrand. P2/P3/P4 update test -fixtures that reference `ACDL`/`acdl` so the gate stays green. No -capability is added, removed, or reclassified in v1.15 — the rebrand is -nomenclature + identifiers, not behavior. +> The full migration ordering (P1–P5), capability gate, and rollback +> runbook are preserved in `.ciagent/archive/ARCHITECTURE-v1.0-v1.24.md` +> §v1.15 Addendum. --- -## v1.16 Addendum — Nova Simplification (NFR, 2026-07-30) +## v1.17 Addendum — Strategic Direction, Leadership Metrics & Unified Story (current telemetry layer) -The v1.16 NFR milestone added 6 new code components + 1 new Terraform -module + 1 new schema, all documented here for the architecture record. - -### New components - -| Component | Path | Purpose | -|-----------|------|---------| -| Onboarding request handler | `core/onboarding.py` | `generate_env_file(request, template_env)` — produces a `.json` from a consumer onboarding request (P19, REQ-183). CLI entry point for self-service env-file generation. | -| Decommission transform | `core/decommission_transform.py` | `decommission_transform(stack)` — zero counts + disable deletion protection (REQ-92). Extracted from contract_resolver (P12, REQ-176). | -| Contract resolver CLI | `core/contract_resolver_cli.py` | `main()` CLI entry point — resolves a contract YAML to a Target Stack JSON. Extracted from contract_resolver (P12, REQ-176). | -| Regression verify CLI | `core/regression_verify_cli.py` | `main()` CLI entry point — runs the regression gate + writes the report. Extracted from regression_verify (P13, REQ-177). | -| Workflow sync generator | `scripts/sync_workflows.py` | `--check`/`--write` — generates the 3 byte-identical Gitea+GitHub workflow pairs from `workflows-src/` (P8, REQ-172). | -| Onboarding Terraform | `terraform/onboarding/` | `aws_iam_role.consumer_deploy` + `aws_iam_role_policy.consumer_invoke` (ABAC `nova:owner` tag). Offline-proven only (P20, REQ-184, D-114). | - -### Modified components - -| Component | Change | Phase | -|-----------|--------|-------| -| `core/contract_resolver.py` | `_load_env` delegates to `environment_check.load()` (dedup); `is_l2` uses registry `kind` field; `_load_schema` caches schemas; `decommission_transform` + CLI re-export shim (P12). | P7, P12, P14 | -| `core/regression_verify.py` | Dedup helpers (`_check_resolver`, `_check_live_terraform_plan`, `_assert_contracts_resolve`); CAP-013..016 `Skipped` on post-teardown (G-111); `passed` accepts Skipped; CLI re-export shim (P13). | P5, P9, P13 | -| `core/lambda/contract_ingestor.py` | Fail closed on missing IAM identity (P10); env enum from `core/environments/` (P10); payload size cap + schema validation (P11); `onboard_consumer` action (P18); `[NOVA-ALERT]` rebrand (P2). | P2, P10, P11, P18 | -| `core/output_publisher.py` | `SAFE_OUTPUT_NAMES` schema-driven from `interface.json`; narrowed excepts; `urllib.error` import (P4, P14). | P4, P14 | -| `core/environment_check.py` | Onboarding message rebranded Nova + self-service request path (P2, P19). | P2, P19 | -| `core/local_emulators.py` | `LocalLambdaStub` sets `NOVA_LAMBDA_LOCAL_BYPASS`; stale dual-read comments + `acdl_*` prefixes removed (P3, P10). | P3, P10 | -| `scripts/run_platform.sh` | `--help` flag; `run_hitl_gate()` fn; `NOVA_CONTRACT_ID`/`NOVA_WORK_DIR` config; decommission + uptime blocks extracted to sourced helpers (P6, P9, P15). | P6, P9, P15 | -| `adapters/terraform/adapter.py` | State bucket `nova-tfstate-*` (P1); module docstring Nova (P2). | P1, P2 | -| `adapters/kyverno/policies/require-resource-labels.yml` | `nova:*` labels (not `acdl:*`) (P1). | P1 | -| `modules/registry.json` | `kind` field (`l1`/`l2`) on all 14 entries (P7). | P7 | - -### New schema - -- `schemas/onboarding.schema.json` — the self-service onboarding request - (consumerRepo, requestedEnvironment, ownerId, billingTag). P18, REQ-182. - -### Onboarding request-path architecture (D-113) - -The no-humans onboarding flow is a 3-step request path (real AWS -provisioning deferred): - -``` -Consumer → POST Lambda (onboard_consumer) → pending CMDB row (P18) - → core/onboarding.py → .json binding file (P19) - → terraform/onboarding/ → cross-account role + ABAC tag (P20, offline) -``` - -The Lambda Function URL (IAM auth) + `consumer_invoke_policy.json` (ABAC -`nova:owner`) are the transport; the request is accepted + a binding -generated + the role Terraform proven offline. No AWS resources are -created by the request path (D-113/D-114). - -### Regression gate (G-111 binding) - -The regression gate (D-091) now treats `Skipped` as acceptable for the -post-v1.11-teardown steady state (D-096): CAP-013..016 (live-AWS tier) -return `Skipped` when the resources are absent (`NoSuchBucket`/ -`ResourceNotFoundException`). `RegressionReport.passed` is -`all(r.status in ("Verified", "Skipped"))`. The gate passes at 18 -Verified + 4 Skipped (0 Decayed/Broken). - -## v1.17 Addendum — Strategic Direction, Leadership Metrics & Unified Story (2026-08-04) - -The v1.17 milestone adds a telemetry/observability layer, a Decision +The v1.17 milestone added a telemetry/observability layer, a Decision Ledger, a metrics export pipeline, a unified narrative deck, and a durable strategic-direction artifact. This addendum documents the architecture; the full research findings are in RESEARCH.md §v1.17. @@ -840,26 +396,26 @@ architecture; the full research findings are in RESEARCH.md §v1.17. │ Nova platform components (existing) │ │ run_platform.sh · confidence_signal · checkov_adapter · │ │ hitl_gates · regression_verify · outbox_writer · contract_ingestor │ -└──────────────────────┬──────────────────────────────────────────────┘ - │ CloudEvents 1.0 envelope (new emitters, P1) - ▼ +└────────────────────┬──────────────────────────────────────────────┘ + │ CloudEvents 1.0 envelope (new emitters, P1) + ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ metrics/events.jsonl (append-only CloudEvents log) │ │ metrics/runs/.json (per-run manifests) │ │ metrics/decision_ledger.db (SQLite hash-chain, D-121) │ │ metrics/test-results.xml (junit, P1) │ -└──────────────────────┬──────────────────────────────────────────────┘ - │ collector reads (P2) - ▼ +└────────────────────┬──────────────────────────────────────────────┘ + │ collector reads (P2) + ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ metrics/nova_metrics.db (SQLite cold store, D-126) │ │ fact_run · fact_capability · fact_policy_check · fact_confidence │ │ fact_test · fact_decision · fact_cost_estimate │ │ dim_capability · dim_milestone │ │ + 8 empty placeholder views (deferred metrics) │ -└──────────────────────┬──────────────────────────────────────────────┘ - │ powerbi_export (P3) - ▼ +└────────────────────┬──────────────────────────────────────────────┘ + │ powerbi_export (P3) + ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ metrics/powerbi/ (CSV/JSON views, folder connector, D-129) │ │ → PowerBI dashboards (external) │ @@ -868,19 +424,20 @@ architecture; the full research findings are in RESEARCH.md §v1.17. **Hot path: deferred (D-126).** No live ops dashboard; SQLite is cold-only (batch/historical). The hot path activates when live AWS is -re-provisioned (D-096 lift). +re-provisioned (D-096 lift — the v1.26 milestone lifts this for the pilot +estate). ### NORTH_STAR integration point (REQ-186) `.ciagent/NORTH_STAR.md` is read by CIAgent in context-loading for all -future milestones. The integration mechanism (to be finalized in P4): -a reference from `PROJECT.md` + `ARCHITECTURE.md` (this section) + a -config entry in `config.json` (`strategic_direction_file: -".ciagent/NORTH_STAR.md"`) that the run workflow reads at SPECIFY. This -ensures the strategic direction survives across milestones without -being overwritten by status updates. +future milestones. The integration mechanism: a reference from +`PROJECT.md` + `ARCHITECTURE.md` (this section) + a config entry in +`config.json` (`strategic_direction_file: ".ciagent/NORTH_STAR.md"`) +that the run workflow reads at SPECIFY. This ensures the strategic +direction survives across milestones without being overwritten by status +updates. -### §12.7 — Policy Engine Registry (v1.25, REQ-291) +### §12.7 — Policy Engine Registry (v1.25, REQ-291 — current) The policy-engine abstraction is first-class: a swappable `PolicyEngine` protocol so the engine may change without touching the confidence @@ -943,3 +500,7 @@ functions without the binary (the "platform functions without AI / deterministic scripts" tenet holds — kyverno-json is deterministic, not AI; the `is_configured()` guard ensures the platform runs even when the binary is not installed). + +> **§12.8 — Pilot Estate** is planned for the v1.26 P4 phase (REQ-321). +> It will document the live-pilot architecture (consumer contract → +> `deploy.yml@v1.25` → apply → attest → record against `581513795199`). \ No newline at end of file diff --git a/.ciagent/PROJECT.md b/.ciagent/PROJECT.md index 3f065ed..66c818a 100644 --- a/.ciagent/PROJECT.md +++ b/.ciagent/PROJECT.md @@ -1,12 +1,15 @@ # 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. +> **Compressed.** The full v1.0–v1.24 milestone-by-milestone narrative is +> preserved verbatim at `.ciagent/archive/PROJECT-v1.0-v1.24.md`. This file +> retains only the durable vision/tenets/scope, the still-load-bearing +> decisions (D-034..D-072, W1.A..BA.F, Q1.3), the capability status, and +> the active milestone (v1.26) + its immediate predecessor (v1.25). +> +> **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." ## Vision / Core Value @@ -39,10 +42,8 @@ traceable to a human attestation and an immutable evidence stream. 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. + explainable confidence signal. +5. **Infrastructure is Consumed, Not Maintained.** 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. @@ -60,17 +61,14 @@ traceable to a human attestation and an immutable evidence stream. ## 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. +> Promoted from Core Tenet #2 + Anti-Goal #1 (v1.18, REQ-216). 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). +enforcement, immutable audit lineage, and the two consumer surfaces. Integration between the PDLC and Nova is **only** through the validated, published contract boundary (`schemas/contract.schema.json` + @@ -78,10 +76,7 @@ published contract boundary (`schemas/contract.schema.json` + 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. +submission-readiness gate, D-133). ``` PDLC (upstream) Nova (downstream) @@ -96,31 +91,23 @@ application business logic → cloud resource lifecycle ## 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. +> Source of truth (v1.18, REQ-215, D-139). ### 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). + and **User Acceptance Testing (UAT)**. The FRs + UAT may originate from + any upstream source — all 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). + **QA** (platform-side quality checks: policy, confidence, schema), and + **Production deployments to cloud**. - **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. + required by the actual release. The platform performs the checks + agentically; the citizen developer authorizes (the human attestation at + the stage gate, D-042, `hitl_gates.py`). ### Matrix @@ -134,26 +121,11 @@ application business logic → cloud resource lifecycle | **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. +**Key: R** = Responsible · **A** = Accountable · **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. +The release is co-owned: 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) @@ -161,15 +133,10 @@ model from the NORTH_STAR. > 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. +**Decay disclosure.** Capabilities marked complete in v1.1–v1.8 were not +reproducible as of 2026-07-27 (7 adapter defects). 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):** @@ -182,699 +149,17 @@ passes at both tiers. | 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 +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). 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//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.}` and - `${contract.}` 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.}` + `${contract.}` 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.}` + `${contract.}` (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). | +auto-verifiable capabilities and fails closed on any non-Verified result. ## Constraints @@ -883,8 +168,8 @@ D-080+ to avoid collision with v1.8 research decisions D-073..D-077): - **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. +- **Engine:** Terraform adapter (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). @@ -906,730 +191,101 @@ D-080+ to avoid collision with v1.8 research decisions D-073..D-077): `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. + vision/architecture sources. - 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. + shape (L1/L2/contract/confidence/evidence/HITL) on stubs. v1.1+ replaces + the stubs with the real platform engine. -## Key Decisions (v1.1) +## Key Decisions (still load-bearing) -Carries forward the still-valid v1.0 decisions (see appendix). New v1.1 -decisions: +> The full decision history (D-001..D-213) is preserved across the v1.0–v1.24 +> archive snapshot + the active-milestone CLARIFY/GRILL files. The decisions +> below remain load-bearing for v1.26 and are retained to avoid +> cross-file pointer-chasing on every read. + +### v1.1 (D-034..D-047) — spike bootstrap, OIDC waiver, confidence inputs | 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. | +| 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 deactivated; the spike uses the rotated `acdl-spike-runner` key per D-039. Key ID redacted in v1.2 Phase 12 (P1-1).** | +| D-036 | Spike picks `l1-s3` + `l2-static-assets` | Simplest real AWS resource; smallest real `terraform plan`; proves the IR + adapter end-to-end | Spike scope fixed | +| D-039 | Spike-only waiver: per-run-rotated long-lived AWS key. OIDC federation deferred (Gitea Actions does NOT support `id-token: write` — go-gitea/gitea#36988). `scripts/rotate_spike_key.sh` rotates after each run. | §12.5 forbids long-lived creds; the waiver satisfies its *intent* (no *persistently* long-lived key). | Spike achieves real `terraform plan` without a persistently long-lived key; real OIDC is a v1.3+ 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. | Architecture §8 locks "six canonical inputs" but does not enumerate them. | Confidence signal has a concrete input enumeration. | +| D-042 | HITL approver identity in Gitea = `gitea.actor` of the `workflow_dispatch` run that sets `approve_{qa,prod,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; `gitea.actor` is the only approval-identity signal. | SoD design is concrete for the Gitea forge. | +| D-047 | v1.2 carries forward the D-039 per-run-rotated-key waiver. Real OIDC federation remains deferred (go-gitea/gitea#36988 still open). | §12.5 forbids long-lived creds; rotation hygiene satisfies the intent. | v1.2 achieves `terraform apply` without a persistently long-lived key. | -## Key Decisions (v1.8) - -Resolved at the CLARIFY stage (full autonomy — all within locked -constraints or user-directed scope). New v1.8 decisions: +### v1.7 (D-048..D-060) — rename, production static-assets, contract ingestion, error reporting, module examples | 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/` 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. | +| D-049 | Production static-assets stack = S3 + CloudFront (OAC) + WAF. | Self-contained, domain-free production edge. Route53/ACM are domain-dependent and deferred. | Authors `cloudfront` + `waf` primitives. | +| D-050 | Deploy outputs: SSM Parameter Store (`SecureString`, KMS-encrypted, `/acdl/{env}/{contractId}/{output_name}`) + GitHub PR comment / job summary. | Two canonical mechanisms: SSM for runtime reads; PR comment for developers. No raw secrets in logs. | 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, PITR). | Enables historical queries, impact analysis, CMDB-style application-state queries. | Defines the table + Lambda. | +| D-053 | Kyverno adapter = K8s-native policy adapter translating `PolicyReport` results → `PolicyCheckResult`. Inactive for Terraform-only stacks. | The platform emits Terraform, not K8s manifests. The adapter activates when the GitOps reconciler emits K8s manifests. | 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). | 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`). Gitea is excluded. | Unifies requirements around one mechanism. The Lambda holds a GitHub token (Secrets Manager) scoped to the platform repo. Idempotent (comments on existing open issue). | Implements the action + wires the `if: failure()` workflow step. | +| D-058 | Module examples = separate validated files in `modules//examples/` (`simple.yaml` + `complex.yaml` + variation files), validated against `schemas/contract.schema.json`. | Examples cannot drift from the schema silently. | Authors the example files; the 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. | Concrete demonstration of multi-engine variation. | Authors the primitive + adapter expansion + examples. | -## Key Decisions (v1.7) - -Resolved at the CLARIFY stage (full autonomy — all within locked constraints -or user-directed scope). New v1.7 decisions: +### v1.8 (D-061..D-072) — P1 remediation, encryption + deletion-protection by default, uptime, decommission | 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//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.) | — | — | +| D-062 | SSM publisher fails loud (`RuntimeError`) when `ACDL_KMS_KEY_ID` unset. `ACDL_ALLOW_DEFAULT_KMS=1` escape hatch for local testing. | Silent AWS-managed-key use is the security gap; callers must set the env. | Implements fail-loud + escape hatch. | +| D-064 | Remove committed `terraform/spike/*.tf` entirely; adapter emits to per-run temp dir. | Cleaner; no stale fixtures. | Removes files + changes `run_platform.sh` target. | +| D-066 | Uptime deployment target: ECS Fargate (reuse existing `ecs-cluster` + `ecs-service` + `alb` primitives). | Most consistent with current platform; ALB gives a stable URL. | Authors uptime primitive on ECS Fargate. | +| D-068 | CMDB = DynamoDB `acdl-change-requests` table (PK `changeRequestId`, SK `submittedAt`). | Consistent with existing platform Lambda + DynamoDB pattern. | 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`). | No shared keys across stacks; 90-day rotation at creation. | 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. | Adds decommission mode + HITL gates. | +| D-072 | Managed KMS fallback for standalone L1 deployments (no L2 CMK): adapter uses `alias/aws/` 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". | Implements fallback + warning. | -### Open-decision resolutions (Phase 07 deliverable — recorded here for traceability) +### Phase 07 open-decision resolutions (still load-bearing for the contract/confidence/HITL substrate) | 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--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 `/` 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 `.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/.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 ` 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 ` - 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 +| W1.A | AI-refinement trigger | 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 | 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 | Tag for dev/qa, SHA for prod. Platform CLI resolves tag→SHA for prod-bound workflows. | +| BA.A | Initial L3B skill catalog | 5 skills: web API, worker, scheduled job, static asset, basic observability bootstrap. **Extended v1.18 (REQ-221/222):** 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`. | +| W3.D | L1/L2 standard versioning | Semver: interface → MAJOR, behavior → MINOR, lifecycle → PATCH. Pin model: L2 contracts pin L1 by `name@semver`; the resolver picks the highest compatible. MAJOR bumps require a new registry entry (immutable publication); old entry enters a 12-month deprecation window. | +| W3.E | Schema mandatory vs optional inputs | 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 optional everywhere. | +| BA.B | Confidence threshold tuning | 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 | 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. | +| BA.D | Cost / capacity governance | 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; override = FinOps + SRE joint sign-off. | +| BA.E | Consumer onboarding | 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. | +| BA.F | Cross-platform evolution | 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. | +| Q1.3 | OpenTofu timing | **Deferred.** Not in v1 or v1.1. The engine abstraction (§12) makes OpenTofu a future adapter, not an architecture change. | + +> **Prior milestone (v1.0 demo) decisions.** D-001..D-033 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` +> and in `.ciagent/archive/PROJECT-v1.0-v1.24.md`. + +> **v1.14–v1.24 decisions.** D-073..D-199 are preserved verbatim in +> `.ciagent/archive/PROJECT-v1.0-v1.24.md`. They remain valid for the +> milestones they governed; the active v1.26 milestone does not +> re-decide them. + +> **v1.25 + v1.26 decisions.** D-200..D-213 (v1.26 CLARIFY) live in +> `.ciagent/CLARIFY.md`; v1.25 binding decisions live in the archive +> snapshot. Both sets are load-bearing for v1.26 execution. + +## v1.25 — kyverno-json Unified Policy Engine (immediate predecessor, complete) + +> Complete. Feature milestone — the primary compliance/policy tool becomes +> kyverno-json, implemented behind a swappable adapter. Tag `v1.24.5` +> (milestone release on the v1.24.x line). Branch `milestone/v1.25-kyverno-json`. +> **Full narrative preserved in `.ciagent/archive/PROJECT-v1.0-v1.24.md`.** + +`kyverno-json` is a runtime from the Kyverno ecosystem that applies Kyverno +policies to **any JSON or YAML payload** — not just Kubernetes manifests. +v1.25 makes it 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 (e.g. OPA) without +touching the confidence signal or the pipeline. + +### What v1.25 delivered (still load-bearing for v1.26) - **Swappable `PolicyEngine` protocol** (`core/policy_engine.py`) — a Python Protocol + registry selected from `config.json` (`policy.engine`, @@ -1639,84 +295,67 @@ on top of, not beside, the scanner findings). 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). + kyverno-json native output to the existing PCR schema. `is_configured()` + guard skips gracefully when the `kyverno-json` binary is absent (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 + `adapters/kyverno-json/policies/`: `contract/`, `stack-ir/`, `plan-json/`, + `meta/`. +- **`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 + input. No change to `core/confidence_signal.py`. +- **Regression-gate-as-policy** — the capability checks in + `core/regression_verify.py` (CAP-013, CAP-023, CAP-024) became declarative kyverno-json policies over the capability-inventory JSON - frontmatter. Capability regression becomes an audit artifact, not - imperative Python. + frontmatter. - **`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). +### v1.25 hard constraints (carried into v1.26) -**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). + 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). - 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. + `block-on-any-critical` meta-policy. +- DO NOT change `core/confidence_signal.py`'s input contract — it already + consumes `list[PolicyCheckResult]`; v1.25 only changed *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). + returns false → `SKIPPED` records → confidence signal proceeds. -### Requirements +### v1.25 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). +New requirements REQ-291..REQ-309 — full text in +`.ciagent/archive/REQUIREMENTS-v1.0-v1.24.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). +> **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 +> **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/`). +> `contract.yaml`. Both projects share the v1.26 milestone; the +> consumer's `.ciagent/` files live in `.ciagent/nova-blockchain-exchange/`. ### Why @@ -1735,41 +374,40 @@ the pilot end-to-end. - **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). + production, T+1 settlement finality = block commit. Equities only. - **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. + 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`. + (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 +### v1.26 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 +New requirements REQ-310..REQ-322 — full text in +`.ciagent/REQUIREMENTS.md` §v1.26 + `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md`. +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). +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 +### v1.26 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. @@ -1782,3 +420,15 @@ build-out; ECS + S3 already exist). - 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. + +### v1.26 phase status (live — see CHECKPOINT.json for the authoritative state) + +- **P0** pre-execution (SPECIFY→CLARIFY→RESEARCH→IDEATE→PLAN→GRILL) — complete, tag `v1.25.0`. +- **P1** blockchain-core (REQ-310,311,312) — complete, tag `v1.25.1`. +- **P2** consumer-contract-and-deploy (REQ-313,314,322) — complete, tag `v1.25.2`. +- **P3** pilot-metrics-and-policies (REQ-315,316,317,318,319,320) — pending. +- **P4** pilot-run-and-docs (REQ-316,321) — pending. +- **P5** final review + audit + milestone ship — pending. Tag `v1.25.5` = the v1.26 release. + +> Phase-by-phase task breakdown, wave ordering, and persona assignments +> live in `.ciagent/PLAN.md` (the active phase plan, retained in full). \ No newline at end of file diff --git a/.ciagent/REQUIREMENTS.md b/.ciagent/REQUIREMENTS.md index 3bcc9b3..c18af90 100644 --- a/.ciagent/REQUIREMENTS.md +++ b/.ciagent/REQUIREMENTS.md @@ -1,2219 +1,32 @@ # Nova — Requirements -## v1 - -### Category: Repos & Org -- **REQ-01:** All demo code lives under the `continuous-intelligence` Gitea org at `https://git.cloudinit.dev`. -- **REQ-09:** Three repos exist: `acdl` (platform + stubs + reusable workflows), `acdl-contracts` (developer surface), `acdl-evidence` (Pages audit timeline). - -### Category: L1 Modules -- **REQ-02:** 8 L1 module folders exist under `acdl/modules/l1/`: `l1-eks-fargate`, `l1-iam-role`, `l1-lambda`, `l1-api-gateway`, `l1-eventbridge`, `l1-sqs`, `l1-s3`, `l1-cloudwatch`. -- **REQ-03:** Each L1 module has a `manifest.yaml` (declaring inputs) and a `mock_apply.sh` that echoes success, sleeps 1s, and exits 0. - -### Category: L2 Modules -- **REQ-04:** 4 L2 modules exist under `acdl/modules/l2/`: `l2-invoice-service`, `l2-commodity-price-feed`, `l2-energy-analytics-api`, `l2-regulatory-reporting`, each composing the specified L1s. -- **REQ-05:** L2 modules compose L1 primitives into deployable shapes with a maximum depth of 5. - -### Category: Core Scripts -- **REQ-06:** `mock_executor.sh` reads an L2 composition, invokes each L1 `mock_apply.sh`, and writes `state.json`. -- **REQ-07:** `policy_checker.py` reads `contract.yaml` and fails with `POLICY_VIOLATION:PUBLIC_INGRESS` on `public-ingress: true`; otherwise passes. -- **REQ-08:** `confidence_signal.py` returns a base score of 0.90 and drops to 0.40 (with reason code) when policy fails; gate threshold is ≥ 0.50. - -### Category: Evidence Stream -- **REQ-11:** `evidence_writer.py` appends events to `audit.json` and links each event to the previous via a SHA-256 hash chain (`prev_hash` + own `hash`). -- **REQ-13:** `acdl-evidence` is Pages-enabled and serves `audit.json` plus `index.html`. - -### Category: Pipeline -- **REQ-10:** The reusable pipeline runs Dev (autonomous), pauses at QA (manual approval), pauses at Prod (manual approval), then finalizes by committing `audit.json` to `acdl-evidence`. -- **REQ-12:** Opening an Issue in `acdl-contracts` runs `l3b_agent_stub.py`, commits a generated `contract.yaml` to a new branch, closes the Issue, and triggers the main pipeline. - -### Category: Demo Acts -- **REQ-14:** `index.html` uses vanilla JS to fetch `audit.json` from the Pages URL and render events as a timeline. -- **REQ-15:** All four demo acts (Friction, Developer Self-Service, Citizen Developer, Safety Net) reproduce deterministically in a dry run. - -## v2 - -(None — v1 covers the complete demo.) - -## v1.1 (Prior milestone — architecture finalization + v1 spike, complete) - -### Category: Architecture Finalization -- **REQ-16:** Architecture reaches v1.0 — all 11 open decisions in `docs/architecture.md` §13 are resolved and recorded in `PROJECT.md` (W1.A, W1.B, W2.A, W3.D, W3.E, BA.A–F, OpenTofu timing). -- **REQ-17:** Target Stack IR is defined as a JSON Schema under `schemas/ir.schema.json`; engine-agnostic (resources, relationships, composition max-depth-5, policy hooks). -- **REQ-18:** `PolicyCheckResult` normalized schema is defined under `schemas/policy_check_result.schema.json`; a Checkov adapter translates Checkov JSON to this schema. -- **REQ-19:** Six-input confidence signal is specified under `platform/confidence_signal.py` with per-env thresholds (dev 0.50 / qa 0.75 / prod 0.90 / dr 0.95) and severity→penalty mapping (critical=hard override, high=-0.2, medium=-0.05, low=-0.01, info=0.0). -- **REQ-20:** Tiered audit ledger design is authored: S3 Object Lock (compliance mode, 7-yr) + DynamoDB outbox (RPO=0, JWS detached signatures, `prev_event_hash` chain, daily checkpoints). -- **REQ-21:** Full 8-concern HITL matrix + separation-of-duties design is authored (CODEOWNERS routing + DynamoDB identity-distinctness check; pre-execution gate model; 1d warn / 2d freeze timeout). -- **REQ-22:** Contract schema (JSON Schema draft 2020-12) is defined under `schemas/contract.schema.json` with per-env mandatory/optional inputs (W3.E) and `profile: agentic` marker for L3B fields. - -### Category: AWS OIDC Bootstrap -- **REQ-23:** AWS auth bootstrap + state backend for the spike: an S3 state bucket + DynamoDB lock/outbox table + an IAM user with a minimal scoped policy (S3 + DynamoDB + plan-only). The temporary long-lived key is used once (waiver D-034) then rotated via `scripts/rotate_spike_key.sh` after each spike run (D-039). **Real OIDC federation is deferred to v1.2** — Gitea Actions does not support `id-token: write` (RESEARCH TARGET 1, conf 0.95), blocked on go-gitea/gitea#36988. - -### Category: v1 Spike — IR, L1, Adapter -- **REQ-24:** One real L1 module `l1-s3` exists under `modules-ir/l1/l1-s3/` with an IR-typed interface (typed inputs/outputs/NFRs) registered in the L1 registry. -- **REQ-25:** One real L2 thin-composition `l2-static-assets` exists under `modules-ir/l2/l2-static-assets/` referencing `l1-s3` only (depth 1, within max-depth-5). -- **REQ-26:** The Terraform adapter (`adapters/terraform/`) compiles the IR-typed L1 interface to Terraform `variable`/`output` blocks and the L2 thin-composition tree to a Terraform root module; it emits a real `terraform plan` against AWS via OIDC; state is stored in S3 + DynamoDB. - -### Category: v1 Spike — End-to-End -- **REQ-27:** One end-to-end contract submission (`contracts/spike.yaml` for `l2-static-assets`) flows through: contract schema validation → contract→IR resolution → `terraform plan` (real AWS) → Checkov `PolicyCheckResult` → confidence signal → evidence event written to the DynamoDB outbox. -- **REQ-28:** Spike verification (`scripts/verify_phase10.sh`) proves the IR-shaped commitments hold: the adapter is the only engine-specific code; no polyglot mess; the L1 content, contract YML, and thin-composition tree are engine-agnostic. - -## Out of Scope (v1.1) - -| Feature | Reason | -|---------|--------| -| Full HITL matrix wiring (qa/prod/dr) | Spike is dev-only (`terraform plan`); HITL wiring is v1.2. | -| Kyverno + OPA policy engines | Spike uses Checkov only; Kyverno/OPA are v1.2. | -| MCP skill catalog + real L3B agent | L3B spike = a single stub contract submission; the 5-skill catalog is v1.2. | -| GitOps reconciler (ArgoCD/Flux) | v1.2. | -| Multi-region state / outbox | Single-region in v1 (§9, §12.3). | -| Prod/dr environments | v1.2. | -| Terraform `apply` (real provisioning) | Spike runs `plan` only; `apply` is gated by HITL in v1.2. | - -## v1.2 (Prior milestone — platform hardening + first real consumer deployment, complete, tag `v1.3.0`) - -### Category: Documentation & Simplification -- **REQ-29:** `README.md` is fully rewritten to reflect the v1.1-complete platform: the actual spike flow (contract → IR → `terraform plan` → Checkov → confidence signal → outbox), how to run it (`scripts/run_platform.sh`), the real repo layout (`acdl_platform/`, `schemas/`, `adapters/`, `terraform/`, `modules-ir/`, `contracts/`, `demo/`), and the v1.2 objective. No stale "v1.1 (active)" framing. -- **REQ-30:** NFR hardening of the v1.1 spike: (a) `terraform/bootstrap/spike_runner_policy.json` audited to least-privilege (S3 + DynamoDB + ECS + ECR + ELB + IAM plan-only, no wildcards beyond the documented exceptions); (b) `create_state_backend.py` and `create_iam_user.py` are idempotent (re-running exits 0 without duplicating resources); (c) `run_spike_plan.sh` + `run_spike_e2e.sh` consolidated into a single `scripts/run_platform.sh` with proper exit codes and error handling; (d) P1-1 carried forward from the v1.1 audit — the two AWS access key IDs in `.ciagent/VERIFY.md` Phase 09 narrative are redacted to placeholders; (e) any remaining stale `platform/` paths in `.ciagent/` are corrected to `acdl_platform/`. - -### Category: L1 Catalog Expansion (ECS Fargate) -- **REQ-31:** Six new IR-typed L1 modules exist under `modules-ir/l1/` and are registered in `modules-ir/registry.json`: `l1-vpc` (VPC + subnets + route tables), `l1-ecs-cluster` (ECS Fargate cluster), `l1-ecs-service` (ECS service + task definition), `l1-iam-role` (task execution + task role), `l1-alb` (application load balancer + listener + target group), `l1-ecr` (ECR repository). Each has an `interface.json` valid against `schemas/ir.schema.json` and produces a valid `terraform plan` fragment via the Terraform adapter. The adapter `TYPE_MAP` is expanded to cover all six IR resource types. - -### Category: L2 Composition & Contract Schema -- **REQ-32:** `l2-microservice` thin-composition exists under `modules-ir/l2/l2-microservice/` referencing the six ECS L1s (depth ≤ 5, within max-depth-5). `schemas/contract.schema.json` is extended with microservice inputs (`image: string`, `port: integer`, `env: map`, `healthcheck: object`) and validates a `contracts/microservice.yaml` submission. Contract→IR resolution (`acdl_platform/contract_resolver.py`) yields a complete target stack for `l2-microservice`. - -### Category: Real Provisioning -- **REQ-33:** The platform runs `terraform apply` (not just `plan`) for the `dev` environment, autonomous per §10 (confidence ≥ 0.50, no HITL). The apply creates real AWS resources (VPC, ECS cluster, ECR repo, ALB, ECS service) and the result is captured in the evidence stream. `apply` for qa/prod/dr remains HITL-gated and out of scope for v1.2. - -### Category: Consumer Repo -- **REQ-34:** A new Gitea repo `acdl-consumer-microservice` exists under the `continuous-intelligence` org, containing: a basic HTTP microservice (e.g., a tiny Python/Go server returning 200), a `Dockerfile`, an ECR push step, and a `contracts/microservice.yaml` submission for `l2-microservice` (dev environment). - -### Category: End-to-End Verification -- **REQ-35:** One end-to-end flow: consumer commit to `acdl-consumer-microservice` → pipeline triggered → contract→IR resolution → `terraform plan` → `terraform apply` (dev) → a live ECS Fargate service serving HTTP 200 on its ALB → evidence event written to the DynamoDB outbox → the event renders on the `acdl-evidence` timeline. `scripts/verify_phase16.sh` proves the full flow green. - -## v1.3 (Prior — module documentation + thin-composition removal, complete) - -### Category: Thin-Composition Removal -- **REQ-36:** The L2 thin-composition layer is removed completely: `composition.json` files, `acdl_platform/contract_resolver.py`, `schemas/contract.schema.json`, `contracts/spike.yaml`, `contracts/microservice.yaml`, and L2 entries in `modules-ir/registry.json` are deleted. The L2 directories are kept as placeholders with READMEs. The downstream pipeline (adapter → checkov → confidence → outbox) is patched to load a pre-existing IR instance instead of resolving a contract. -- **REQ-37:** A `modules-ir/README-TEMPLATE.md` exists that works for both L1 and L2 modules, written in plain language (no jargon), with sections for Overview, Resources, Inputs, Outputs, Usage, Compliance extension points, and Versioning. -- **REQ-38:** Every module has a `README.md`: the 7 L1 modules have full READMEs with Resources/Inputs/Outputs/Usage/Compliance-extension-points/Versioning sections derived from their `interface.json`; the 2 L2 modules have placeholder READMEs noting the composition is under redesign. A `modules-ir/README.md` catalog index lists all modules with one-line descriptions and links. - -### Category: Testing -- **REQ-39:** A pytest test suite exists under `tests/` covering the platform components offline (no AWS, no Checkov, no DynamoDB): the Terraform adapter (`adapters/terraform/adapter.py`), the confidence signal (`acdl_platform/confidence_signal.py`), the Checkov adapter (`adapters/terraform/policy/checkov_adapter.py`), and the outbox writer (`acdl_platform/outbox_writer.py`). The suite validates the IR schema, registry, spike_instance, and adapter output structure. `pyproject.toml` + `requirements-test.txt` pin test dependencies (pytest, jsonschema, pyyaml, boto3-stubs or moto for outbox mocking). - -### Category: Shell Reproducibility -- **REQ-40:** `scripts/run_platform.sh` has a `--check-only` mode that runs offline: loads the pre-existing IR instance, runs the adapter to emit Terraform, validates the JSON structure — without AWS credentials, Checkov, or DynamoDB. The existing `--plan-only` and full modes continue to require AWS. The `--check-only` mode is what CI pipelines run. - -### Category: CI/CD Pipelines -- **REQ-41:** Identical CI/CD pipelines exist for both Gitea Actions (`.gitea/workflows/ci.yml`, dev environment) and GitHub Actions (`.github/workflows/ci.yml`, production). Both run the same three stages: (1) lint — `py_compile` all Python files, (2) test — `pytest`, (3) check-only — `bash scripts/run_platform.sh --check-only`. Both trigger on push to main + pull request. Both use `ubuntu-latest`. Identical outcomes — the only difference is the runner environment. - -- **REQ-42:** `pyproject.toml` exists at the repo root with pytest configuration (testpaths, markers) and the project metadata. `requirements-test.txt` pins test-only dependencies separate from runtime dependencies. - -## v1.4 (Active — central pipeline contract + shell reproducibility + streaming) - -### Category: Central Pipeline Contract -- **REQ-43:** A central pipeline contract exists as `schemas/pipeline.schema.json` (JSON Schema draft 2020-12) + `pipelines/ci.yaml` (YAML instance). The contract declares the pipeline name, triggers (push/PR branches), runner, Python version, and stages (name + command + required + install + description). Both `.gitea/workflows/ci.yml` (Gitea Actions, dev) and `.github/workflows/ci.yml` (GitHub Actions, production) implement the same stages, commands, triggers, and runner as declared in the contract. A test (`tests/test_pipeline_contract.py`) validates the contract against the schema and asserts both workflows conform (same jobs, same commands, same triggers, same runner, byte-identical). - -### Category: Shell Reproducibility -- **REQ-44:** `scripts/run_ci.sh` reproduces the CI pipeline locally — runs the same 3 stages (lint, test, check-only) in sequence with proper exit codes, failing on first error. The script exits 0 with "CI PIPELINE OK" on success. A `--quiet` flag suppresses per-stage banners. The script mirrors the central pipeline contract (`pipelines/ci.yaml`) so the shell and CI environments produce identical outcomes. - -### Category: Pipeline Streaming -- **REQ-45:** `scripts/run_platform.sh` streams output by default: terraform init/validate/plan output is piped to stdout via `tee` (visible to the user and logged), Checkov results are printed in human-readable form, and PolicyCheckResult records are displayed with severity, rule ID, and pass/fail status per record. The `--check-only` mode streams the emitted Terraform file content. A `--quiet` flag suppresses streaming (output to log files only) for backwards compatibility. Both gitea and github workflows are byte-identical (identical outcomes — the only difference is the forge runtime). - -## v1.5 (Prior — consumer happy path + zero-trust docs + reusable deploy workflow, complete) - -### Category: Consumer Happy Path Documentation -- **REQ-46:** `README.md` is rewritten so the consumer model is unambiguous: this repo is the platform source; a consumer never clones it. A consumer repo contains only app code + `contract.yaml` referencing the central pipeline + contract. The platform-flow diagram is a mermaid `flowchart TD` (replacing the ASCII art). "L3A"/"L3B" nomenclature is removed from README (single-surface model). "spike" nomenclature is removed from prose (code paths in bash blocks are kept verbatim). -- **REQ-47:** `docs/CONSUMER_GUIDE.md` (all-caps) replaces `docs/consumer-guide-static-assets.md`. It is generic across all L2 modules (`static-assets` as the worked example), uses mermaid diagrams (model + pipeline flow), documents versioned `uses:` references (floating MAJOR+MINOR tags — bare/`@main` discouraged), scopes prerequisites to consumer-repo bootstrap only (no Terraform/Checkov/boto3/runner-key — those are platform-repo concerns), and documents that the pipeline fetches the ACDL repo at run time via a reusable workflow (consumers never invoke `scripts/run_platform.sh` locally for the happy path). -- **REQ-48:** `README.md` Credentials section is rewritten to express the zero-trust target model: consumer repos use OIDC federation (no long-lived keys) with attribute-based authorization (ABAC) — IAM roles + session policies scoped by repository identity and resource-creation tags so a consumer can only view/update resources it created (blast-radius containment). A documented override allows a static key in GitHub Secrets (consumer repo) or `.env.secrets` (local testing), rotated by a platform-managed scheduled pipeline on a daily cadence; when `.env.secrets` is used locally, rotating out of band is the consumer's responsibility. - -### Category: Reusable Deploy Workflow -- **REQ-49:** A reusable deploy workflow exists as byte-identical `.gitea/workflows/deploy.yml` (Gitea, dev) and `.github/workflows/deploy.yml` (GitHub, production), implementing the central deployment pipeline contract (`pipelines/deploy.yaml` validated against `schemas/deploy-pipeline.schema.json`). It is invoked by consumer repos via `uses: acdl/.gitea/workflows/deploy.yml@vMAJOR.MINOR` (versioned tag). The workflow checks out the consumer repo, checks out the ACDL platform repo into the runner workspace, installs runtime deps (Python, Terraform, Checkov), and invokes `scripts/run_platform.sh` against the consumer's contract path (passed as a workflow input). OIDC is the default auth (`permissions: id-token: write`); a static-key override reads from repository secrets. -- **REQ-50:** `contracts/static-assets.yaml` uses a versioned `uses:` reference (`@v1.4`, MAJOR+MINOR) — not bare `@v1` or `@main` — as the canonical example the consumer guide points at. -- **REQ-51:** `tests/test_pipeline_contract.py` is extended to validate the new deploy workflows: both files exist, are byte-identical, and conform to `schemas/deploy-pipeline.schema.json` (stages present, names match `pipelines/deploy.yaml` stage names). The existing CI-workflow conformance tests continue to pass unchanged. - -## v1.6 (Active — consumer-facing docs restructure + terminology normalization + environments concept) - -### Category: Internal-surface scrub -- **REQ-52:** No consumer-facing documentation (README.md, docs/**, modules/**/README.md, contracts/**) references `.ciagent/` — it is local CIAgent metadata, never visible to platform engineers or consumers. The README repository-layout table has no `.ciagent/` row. No `.gitea/` references appear in consumer-facing docs (consumers use GitHub only); the README repository-layout table has no `.gitea/workflows/` row. -- **REQ-53:** `acdl_platform/` is renamed to `core/` across the directory, all imports in tests/scripts/pipelines/workflows, and all doc references. (`platform/` was the original target but shadows Python's stdlib `platform` module — `core/` was chosen to stay importable.) `grep -R "acdl_platform" .` (excluding `.ciagent/`, `demo/`, `.git/`) returns 0 hits. The test suite passes after the rename. - -### Category: Docs site restructure -- **REQ-54:** `docs/` is restructured into a Jekyll-style GitHub Pages site: `docs/_config.yml`, `docs/index.md` (landing), `docs/modules/` (catalog + per-module Pages-friendly copies), `docs/contracts/index.md`, `docs/pipeline/index.md` + `docs/pipeline/versioning.md`, `docs/environments/index.md`, `docs/consumer-guide.md`, `docs/architecture.md` (consolidated from architecture.md + architecture-v1.0.md, current-architecture only), `docs/vision.md`. No `.ciagent/` links anywhere in `docs/`. Consumer-facing content (modules, contracts, pipeline, versioning) lives in Pages. - -### Category: Terminology normalization -- **REQ-55:** Consumer-facing docs drop the "L2" nomenclature — L2 modules are referred to as "modules". "L1" label is dropped in consumer-facing docs — L1 primitives are referred to as "primitives". The "composition" terminology is changed to "pattern" for modules in prose (the on-disk `composition.json` files and code references are unchanged this phase). A roadmap entry records that "composition" will later describe the thin orchestration where consumers dynamically create a module directly from the contract file (future implementation, not implemented now). -- **REQ-56:** The term "forge" is replaced in consumer-facing docs with "platform runners" / "platform-managed" as appropriate. The term "forge" remains only in internal architecture docs. - -### Category: README rewrite -- **REQ-57:** README.md repository-roles section is restated to match reality: a consumer repo contains (a) its application code, (b) one or more contracts (`.acdl/contract.yaml`), and (c) one or more CI definitions (a thin `.github/workflows/deploy.yml` that `uses:` the central reusable workflow, pointing at the appropriate environment + contract). The platform repo (this one) owns modules/adapters/schemas/pipelines/scripts/workflows. A consumer never clones the platform repo. -- **REQ-58:** README.md Status section is replaced with a Features list (referenceable by consumers and platform engineers) and a Roadmap subsection listing only planned future features (no internal CIAgent status, no version-by-version changelog). -- **REQ-59:** README.md "How the platform works" mermaid diagram is revised so all node text is visible (no overflow): labels are split with `
`, boxes widened as needed. A security-checks stage is added before the policy-checks stage. Specific tools (Checkov, Terraform) are not named — they are "security checks (adapter)", "policy checks (adapter)", "infrastructure plan". An "infrastructure apply" stage is added at the appropriate level (dev only, after confidence). -- **REQ-60:** README.md Credentials & zero-trust section removes the "go-gitea/gitea#36988 blocked" mention and the "waivers D-039/D-047" language (not consumer/platform-engineer facing). It states: default OIDC + ABAC; alternative is a static AWS key (GitHub Secrets for platform-runner runs, or `.env.secrets` locally) with the expectation of daily rotation (platform-managed for runner runs) or out-of-band rotation (consumer-managed for local `.env.secrets`). - -### Category: Environments concept + onboarding -- **REQ-61:** The concept of platform-managed environments is introduced: consumers are not required to provide an AWS account, VPC, subnet, S3 state bucket, or runner key. `docs/environments/index.md` documents that a named environment is a platform-owned AWS account + network + state backend + IAM role surfaced to the consumer via ABAC, selected by name in the contract. The old README environments table (dev/qa/prod/dr) is removed completely. A minimal onboarding scaffold exists: `platform/environments/` with a sample `dev.json` + README, `platform/environment_check.py`, a wire-in at the top of `scripts/run_platform.sh`, a friendly first-run onboarding message when no environment is defined for the repo, and `tests/test_environment_check.py` covering the missing-env and present-env cases. - -## v1.7 (Active — production platform + contract ingestion + pipeline maturation) - -### Category: Rename + production-ready stack -- **REQ-62:** `static-assets` is renamed to `static-assets` everywhere (D-048 — including `.ciagent/` historical narrative: verbatim phase descriptions, REQ-25/27/50 text, D-036, RESEARCH.md). `grep -R "static-assets[^s]" .` (excluding `.git/`) returns 0 hits. The module dir `modules/l2/static-assets/` → `modules/l2/static-assets/`; `contracts/static-assets.yaml` → `contracts/static-assets.yaml`; the registry key is renamed; all scripts, tests, docs, and `.ciagent/` files use `static-assets`. The reconstruction test is updated to expect `static-assets` throughout. -- **REQ-63:** Two new primitives exist: `cloudfront` (distribution + OAC, stack types `aws:cloudfront:distribution` + `aws:cloudfront:originaccesscontrol`) and `waf` (WAFv2 web ACL, stack type `aws:wafv2:webacl`), each with an `interface.json` valid against `schemas/stack.schema.json` and a full README (Resources/Inputs/Outputs/Usage/Compliance/Versioning). Both are registered in `modules/registry.json`. The Terraform adapter `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` covers the new stack types. -- **REQ-64:** The `static-assets` module is augmented to a production-ready stack referencing s3 + cloudfront + waf (depth 1, D-049). `composition.json` wires the s3 bucket regional domain name to the CloudFront origin, and the WAF web ACL ARN to the CloudFront distribution. `schemas/contract.schema.json` is extended for the new module inputs (`price_class`, `viewer_protocol_policy`, `waf_enabled`, `default_ttl`, `max_ttl`). The `uses:`/`ref:` tag advances from `@v1.4` to `@v1.6` (D-056/D-057); floating git tags `v1.6` + `v1` are created pointing at `v1.6.0`. - -### Category: Tagging standards + security adapters -- **REQ-65:** A required-tag set is defined in `schemas/tagging-standard.json` (`acdl:owner`, `acdl:contract`, `acdl:environment`, `acdl:cost-center`). A Checkov custom YAML rule at `adapters/terraform/policy/custom_rules/acdl_tagging.yaml` fails (severity `medium`) when required tags are missing on taggable resources. `checkov_adapter.py` removes the `_emit_tag_naming_skipped()` placeholder (D-043 closure) and maps `ACDL_TAG_NAMING` as a real rule. `scripts/run_platform.sh` Step 5 passes `--external-checks-dir` to load the custom rule. -- **REQ-66:** A Wiz adapter stub exists at `adapters/wiz/wiz_adapter.py` translating Wiz API issues → `PolicyCheckResult` records (`engine: "wiz"`, D-052). It degrades gracefully when unconfigured (emits a single `SKIPPED` `WIZ_NOT_CONFIGURED` record). `tests/test_wiz_adapter.py` passes offline with a fixture response. The pipeline invokes it optionally (Step 5b) when `WIZ_API_TOKEN` is set. -- **REQ-67:** A Kyverno K8s-native adapter exists at `adapters/kyverno/kyverno_adapter.py` translating Kyverno `PolicyReport` results → `PolicyCheckResult` records (`engine: "kyverno"`, D-053). Sample policies exist at `adapters/kyverno/policies/` (disallow-privileged, require-labels, require-image-digests). `tests/test_kyverno_adapter.py` passes offline. The adapter is inactive for Terraform-only stacks (the platform emits Terraform, not K8s manifests); it is ready for the GitOps reconciler roadmap item. `schemas/policy_check_result.schema.json` engine enum includes `checkov | kyverno | opa | wiz`. - -### Category: Platform Lambda + contract ingestion -- **REQ-68:** A platform Lambda (`core/lambda/contract_ingestor.py`) is invoked via a Function URL (IAM auth) and accepts `{ consumerRepo, contractId, contract, environment, action }`. It writes contracts to a DynamoDB table `acdl-contracts` (PK `consumerRepo`, SK `contractId#submittedAt`, SSE via a customer-managed CMK, point-in-time recovery) (D-051). `terraform/platform/main.tf` defines the table, Lambda, Function URL, KMS key, Secrets Manager secret (`acdl/github-token`), and Lambda execution role. `terraform/platform/consumer_invoke_policy.json` grants the consumer's deploy role `lambda:InvokeFunctionUrl` on the Lambda ARN, scoped via ABAC (cross-account). Onboarding grants the Lambda-invoke permission; `docs/environments/index.md` documents this. `tests/test_contract_ingestor.py` passes offline (moto-mocked DynamoDB). - -### Category: Deploy outputs + error reporting + stage comments -- **REQ-69:** `scripts/run_platform.sh` has a `publish-outputs` step (after apply) that writes deploy outputs to SSM Parameter Store as `SecureString` (KMS-encrypted, namespaced `/acdl/{env}/{contractId}/{output_name}`) for runtime-injectable values, and a `comment-outputs` step that posts a structured GitHub PR comment / job summary with human-readable connection strings (D-050). `core/output_publisher.py` implements the SSM write + GitHub comment formatting. `tests/test_output_publisher.py` passes offline (moto + mocked GitHub API). `pipelines/deploy.yaml` + both deploy workflow YAMLs declare the new stages (byte-identical). -- **REQ-70:** The Lambda `report_error` action (`core/lambda/contract_ingestor.py`) creates a GitHub issue on the platform repo (`acdl/acdl`) via the GitHub API using a token from Secrets Manager (D-055). Idempotent (comments on an existing open issue rather than duplicating). `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` (byte-identical) have an `if: failure()` error-report step invoking the Lambda via `aws lambda invoke-function-url` (SigV4-signed). Gitea is excluded (only the CIAgent uses it; platform engineers and consumers use GitHub). -- **REQ-71:** `.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml` (byte-identical) post a PR comment after every successful pipeline stage (validate-contract, resolve-stack, plan, checkov, confidence, apply, publish-outputs) via `scripts/post_stage_comment.sh` (uses `GITHUB_TOKEN` + `gh api`; no-op when not in a PR context). The comment includes the stage name, status (pass), and key metrics (plan counts, confidence score, outputs published). - -### Category: Platform pipelines + release automation -- **REQ-72:** Three platform pipelines exist: (1) `.github/workflows/platform-test.yml` (PR, stages: lint, unit-test, integration-test — runs `run_platform.sh --check-only` for every sample contract, schema-validation — validates all `schemas/*.json` + `modules/**/interface.json` + `modules/**/composition.json` + `modules//examples/*.yaml` against their schemas); (2) `.github/workflows/primitives-plan.yml` (PR, plan-only for all L1 primitives via matrix, `scripts/run_primitive_plan.sh`); (3) `.github/workflows/patterns-plan.yml` (PR, plan-only for all L2 modules via matrix, `scripts/run_pattern_plan.sh`). -- **REQ-73:** `.github/workflows/release.yml` runs on merge to `main`, computes the next semver (PATCH per phase, MINOR on milestone COMPLETE), creates the MAJOR.MINOR.PATCH tag, force-moves the MAJOR.MINOR + MAJOR floating tags, and creates a GitHub release with an auto-generated body (D-057). `tests/test_release_logic.py` passes (unit test the semver computation + tag-update logic with a mocked `git describe`). - -### Category: Remove legacy consumer-repos + module examples + RDS primitive -- **REQ-74:** The legacy consumer-repos directory is deleted entirely (a v1.2 artifact removed in v1.7; references in `.ciagent/` historical narrative are rewritten per D-048). A recursive grep for the legacy directory name (excluding `.git/`) returns 0 hits. -- **REQ-75:** A new RDS primitive (`modules/l1/rds/`) with an `engine` input (enum: postgres, mysql, etc.) demonstrates multi-engine variation (D-059). Every module (primitives + patterns) has a `modules//examples/` directory with `simple.yaml` + `complex.yaml` (+ variation files) validated against `schemas/contract.schema.json` in the platform-test pipeline schema-validation stage (D-058). Each module's `README.md` `## Examples` section references + excerpts the validated files. `docs/modules/index.md` + `docs/consumer-guide.md` + `docs/contracts/index.md` are updated with the new module names + examples. - -## v1.8 (Complete — P1 remediation + uptime + engineering standards + encryption/deletion-protection by default + decommission + docs) - -### Category: P1 Fixes -- **REQ-76:** WAF adapter emits custom `rules` as nested HCL blocks (not attribute syntax) and honors `default_action` input (allow/block) — P1-4, P1-5 closed. -- **REQ-77:** L2 composition `outputs[]` array is resolved by `contract_resolver.py` into `stack.outputs`; the adapter emits corresponding `output` blocks — P1-7 closed. -- **REQ-78:** SSM publisher fails loud when `ACDL_KMS_KEY_ID` is unset (no silent AWS-managed-key fallback); `ACDL_ALLOW_DEFAULT_KMS=1` escape hatch for local testing — P1-3 closed. -- **REQ-79:** `consumer_invoke_policy` is rendered via Terraform with the caller's live account ID (no `000000000000` placeholder) — P1-6 closed. -- **REQ-80:** `run_platform.sh` emits adapter output to a per-run temp dir, not committed `terraform/spike/*.tf`; the committed files are removed — P1-8 closed. -- **REQ-81:** `contract_ingestor.py` reads `GITHUB_API_BASE` env for forge-agnostic API URLs (GitHub + Gitea) — P1-9 closed. -- **REQ-82:** Deploy workflow static-key override is wired to `configure-aws-credentials` inputs (`access-key`/`secret-key`), not inert env vars — S1 closed. - -### Category: Encryption by Default -- **REQ-83:** A per-stack CMK primitive (`kms-key`) exists with 90-day rotation enabled at creation; one key per L2 deployment; no shared keys across stacks. -- **REQ-84:** All primitives have encryption by default (`encryption_enabled` NFR, default true) + optional `kms_key_arn` input. CMK is prioritized; managed KMS is the fallback when no CMK is provided. -- **REQ-85:** L2 modules wire a per-stack CMK child + connect its `kms_key_arn` output to each child's `kms_key_arn` input. - -### Category: Deletion Protection by Default -- **REQ-86:** `deletion_protection` NFR (boolean, default true) on every L1 primitive; the adapter emits `prevent_destroy` lifecycle meta-arg when true. -- **REQ-87:** L2 modules expose a `features.deletion_protection` flag (default true); consumers can disable via contract `inputs.deletion_protection: false`. - -### Category: Uptime Monitoring -- **REQ-88:** An uptime-kuma L1 primitive exists (ECS Fargate) with: `feature_flag_enabled` (boolean, default true), `monitored_endpoints` (array of HTTP/DNS/TCP checks), `static_checks` (pre-defined health checks), `alert_channels` (Teams webhook, email, SMS, GitHub issues). -- **REQ-89:** Uptime is deployed by default after any L2 module deploy (separate terraform state, separate terraform run); L2 module outputs (endpoints) are passed to the uptime deployment as `monitored_endpoints`. The uptime URL is published to the consumer via PR comment. -- **REQ-90:** The `feature_flag_enabled` input (set from consumer contract `inputs.uptime_enabled`, default true) disables the uptime deployment entirely (no resources emitted). -- **REQ-91:** A `deploy-uptime` pipeline stage is declared in `pipelines/deploy.yaml` + both deploy workflow YAMLs (byte-identical). - -### Category: Decommission + CMDB -- **REQ-92:** A decommission mode on the deploy pipeline (`mode: decommission`) implements a 2-step pipeline: (1) plan/apply to disable deletion protection with an HITL SRE gate, (2) plan/apply with all counts set to 0 with a second HITL SRE gate. Uses the existing deploy pipeline with different behavior. -- **REQ-93:** A DynamoDB `acdl-change-requests` table serves as the CMDB. The decommission alias accepts a `changeRequestId` input validated via a `validate_change_request` Lambda action (CR status must be `approved`). -- **REQ-94:** The decommission flow is documented in `docs/CONSUMER_GUIDE.md` (how to request a CR, trigger decommission, HITL gates, what happens). - -### Category: Engineering Standards -- **REQ-95:** `modules/STANDARDS.md` exists with comprehensive L1 + L2 authoring + code review standards (scanned from current modules): required files, interface schema, input/output/NFR conventions, encryption + deletion protection as mandatory NFRs, naming, adapter extension pattern, code review checklist. -- **REQ-96:** `modules/README.md` catalog index includes all primitives (rds + uptime + kms-key added); `modules/README-TEMPLATE.md` updated with `## NFRs` section. - -### Category: Path Documentation -- **REQ-97:** `schemas/README.md` documents how to write a schema, wire it into the platform, test it in CI, where to write tests, dependencies, and the existing schema catalog. -- **REQ-98:** `pipelines/README.md` documents how to write a pipeline contract, wire it into workflows, test it, dependencies, and the existing pipeline catalog. -- **REQ-99:** `adapters/README.md` documents how to write an adapter, wire it into the platform, test it, dependencies, and the existing adapter catalog. - -## Out of Scope (v1.2) - -| REQ | Original criterion | Clarified criterion (effective) | Decision | -|-----|--------------------|----------------------------------|----------| -| REQ-09 | Three repos exist | Three repos exist (`acdl`, `acdl-contracts`, `acdl-evidence`) under `continuous-intelligence`; new repos use `default_branch: "main"`, `auto_init: true` | D-015 | -| REQ-10 | "Pages returns 200 with placeholder `index.html`" on `acdl-evidence` | Gitea has no Pages; substitute: an HTTP GET against the raw file URL `https://git.cloudinit.dev/continuous-intelligence/acdl-evidence/raw/branch/main/index.html` returns 200 with the placeholder HTML body | D-012, D-016 | -| REQ-10 | "`qa` and `prod` environments exist on `acdl-contracts`" | Gitea has no environments API and ignores `environment:` blocks; substitute: the reusable workflow defines `qa-gate` and `prod-gate` jobs gated by `workflow_dispatch` approval inputs (D-004 fallback); a `qa` and `prod` branch may be created on `acdl-contracts` as a visible stand-in for environments | D-013 | - -## Out of Scope (v1.0 demo — retained for history) - -| Feature | Reason | -|---------|--------| -| Real cloud provisioning (AWS/GCP/Azure) | Demo explicitly stubs all infrastructure; no cloud access available. | -| Real LLM inference / external AI APIs | Spec forbids external AI; L3B is a keyword parser. | -| Production-grade infrastructure | Demo target is a 30-minute executive show, not a production system. | -| Adversarial tamper-proofing of evidence | Hash chain is demonstrative; not cryptographically secure against a determined attacker. | -| Multi-tenant isolation | Out of demo scope. | - -## v1.9 (complete — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation, tag `v1.9.0`) - -### Category: Design Doc Refresh -- **REQ-100:** `core/hitl_matrix_design.md` is up to date: the "dev-only spike" framing is replaced with the v1.9 wired-gates reality (qa/prod/dr `workflow_dispatch` approval gates + CODEOWNERS routing + outbox-based SoD); the 8-concern attestation matrix is marked implemented (offline-testable subset) with operator-supplied concerns noted; the spike-scope note is updated. No stale "v1.2 wires the gates" language remains. -- **REQ-101:** `core/audit_ledger_design.md` is up to date: the hash-chain + DynamoDB-outbox path is marked shipped + production (since v1.8); the S3 Object Lock + JWS + async worker + DLQ + daily checkpoints build-out is clearly labeled "Deferred to a future milestone" (D-083); the RPO/RTO table reflects the v1.9 state. - -### Category: P1-1 Remediation -- **REQ-102:** The adapter (`adapters/terraform/adapter.py`) contains no resource-type-specific hardcoded defaults for ECS/ALB/VPC resources — `desired_count`, `launch_type`, `target_type`, `load_balancer_type`, `family`, and `Name` tag values are read from L1 `interface.json` inputs (with defaults declared in the interface). The adapter is a thin translator. An L1 with an overridden `desired_count: 3` emits `desired_count = 3`; the default emits `desired_count = 1` via the interface default, not an adapter hardcode (P1-1 closed). - -### Category: Contract Interpolation -- **REQ-103:** The contract resolver (`core/contract_resolver.py`) expands `${env.}` and `${contract.}` tokens in contract string values (including dotted paths like `${env.state_backend.bucket}`) after schema validation and before IR resolution. The `env` context is the loaded `core/environments/.json`; the `contract` context is the contract dict. Unresolved tokens raise `ValueError` (fail loud). Sample contracts use naming patterns that include region, account id, and environment (e.g. `acdl-${env.environment}-${contract.module}-${env.account_id}-${env.region}`). -- **REQ-104:** An environment JSON schema `schemas/environment.schema.json` (draft 2020-12) defines the environment file shape (`name`, `account_id`, `region`, `state_backend`, `network`, `runner_role_arn`, `autonomy`, `confidence_threshold`). `core/environments/dev.json` validates against it. `qa.json`, `prod.json`, `dr.json` placeholder bindings exist (autonomy `attested`, thresholds 0.75/0.90/0.95). - -### Category: Per-Environment CI Jobs -- **REQ-105:** Per-environment contract files exist for each sample module (`contracts/static-assets.{dev,qa,prod,dr}.yaml` and `contracts/microservice.{dev,qa,prod,dr}.yaml`), each setting `environment:` to its own name and using interpolation for env-specific values. The existing `contracts/static-assets.yaml` + `contracts/microservice.yaml` remain as the dev default for backwards compatibility. -- **REQ-106:** The reusable deploy workflow (`.github/workflows/deploy.yml` + `.gitea/workflows/deploy.yml`, byte-identical) declares an `environment` `workflow_call` input (enum dev/qa/prod/dr, default empty). When non-empty, `scripts/run_platform.sh --environment ` overrides the contract's `environment` field at load time (before interpolation). A consumer repo's caller workflow has one job per environment, each pointing at its respective contract (or the same contract + the env input). Promotion = running the matching job; no `environment:` field editing. `docs/CONSUMER_GUIDE.md` documents the per-env caller workflow pattern. - -### Category: Stub Implementation -- **REQ-107:** `core/separation_of_duties.py` `route_halt_artifact` is a real implementation: publishes to an SNS topic `acdl-sod-halt` (ARN from `ACDL_SOD_HALT_TOPIC_ARN`); when unset, falls back to a structured stderr emission + a `SEPARATION_OF_DUTIES_VIOLATION` event write to the DynamoDB outbox via `outbox_writer.write_event`. No silent print-only stub. The SNS topic is defined in `terraform/platform/main.tf`. -- **REQ-108:** HITL qa/prod/dr pre-execution attestation gates are wired via `core/hitl_gates.py` (`attest(contract_id, env, approver, evidence)`). The gate records the approver (`gitea.actor` / `github.actor`) to the outbox (`approver_qa` / `approver_prod` / `approver_dr` attributes per `audit_ledger_design.md`), runs the separation-of-duties check on prod, and returns `(ok, reason)`. `scripts/run_platform.sh` calls `hitl_gates.attest` before apply for qa/prod/dr (dev skips). The workflow's `workflow_dispatch` approval input is the trigger. -- **REQ-109:** The full 8-concern attestation matrix from `hitl_matrix_design.md` §10.4 is implemented in `core/attestation_matrix.py`. Offline-testable concerns (contract NFRs, schema validity, policy pass) run for real; operator-supplied concerns (k6 load test, DR drill, FinOps forecast) accept an uploaded signed evidence artifact validated for freshness + schema, failing loud if missing/expired for prod/dr. `hitl_gates.attest` invokes the matrix for the target env and blocks on any failing concern. -- **REQ-110:** The Wiz adapter (`adapters/wiz/wiz_adapter.py`) is a real API client: a `WizClient` queries the Wiz GraphQL API (`WIZ_API_TOKEN` + `WIZ_API_URL`) and translates issues → `PolicyCheckResult` records. It degrades gracefully (existing `WIZ_NOT_CONFIGURED` SKIPPED record) when env unset. Offline tests use a recorded GraphQL fixture. -- **REQ-111:** The Kyverno adapter (`adapters/kyverno/kyverno_adapter.py`) translator is fleshed out: full `PolicyReport` → `PolicyCheckResult` mapping with severity + skip handling. It remains inactive for Terraform-only stacks (guard preserved); a `--kube-version` stub is added for future GitOps. Sample policies already exist. - -## v1.10 (active — pipeline regression fix + capability re-verification + verified-reality rewrite, tag `v1.10.0`) - -### Category: Pipeline Regression Fix -- **REQ-112:** The CIAgent VERIFY stage supports a `regression` mode that re-runs capability checks (not just diff checks), triggered at minimum on milestone completion. The regression run executes the local-emulator tier (REQ-113) for every capability marked Verified in prior milestones; any capability that fails the regression run blocks milestone completion. Regression results are recorded in `---ci---` blocks as `regression: { capability: , status: Verified|Decayed|Broken }`. Existing diff-scoped VERIFY behavior is preserved for non-regression invocations. A regression run against the current codebase surfaces at least one Decayed/Broken capability (proving the gate catches decay, not just passes). `tests/test_verify_regression_mode.py` passes. - -### Category: Local Emulating Adapters -- **REQ-113:** Local emulating adapters exist so the platform is fully locally testable without cloud credentials: (a) a flat-file DynamoDB outbox adapter that writes evidence events to flat files in a temp folder with a valid hash chain, same write/read interface as the live DynamoDB outbox adapter; (b) a local ECS Fargate emulator that records the service definition and returns a synthetic HTTP 200 from a local shell process, same interface as the live ECS adapter; (c) a local S3 state backend (flat-file tfstate in a temp folder); (d) a local Lambda stub that invokes the handler in-process with no AWS Lambda call. The headline E2E (contract submission → service live → evidence event) runs end-to-end against the local tier with no cloud credentials. `tests/test_local_emulating_adapters.py` passes. `run_platform.sh --local` (or equivalent) runs the full pipeline locally. - -### Category: Capability Re-Verification Sweep -- **REQ-114:** Every capability advertised in v1.1→v1.8 PROJECT/ROADMAP is enumerated in `.ciagent/CAPABILITY_INVENTORY.md` with a unique ID per capability (v1.0 demo excluded as archived/superseded). Each capability is re-verified: the headline E2E (contract → ECS Fargate → evidence event) runs both live-AWS and local-emulator tiers, both must pass; all other capabilities run the local tier via emulating adapters (REQ-113). Each capability is tagged Verified / Decayed / Broken in `CAPABILITY_INVENTORY.md`. Every Decayed/Broken capability is fixed in-sweep (D-090: no cap) until Verified, with per-capability commits `verify(P54): ` and `fix(P54): `. All v1.1→v1.8 advertised capabilities end Verified. The regression run (REQ-112) is clean against the re-verified state. - -### Category: Verified-Reality Rewrite -- **REQ-115:** PROJECT.md, ROADMAP.md, and both leadership decks are rewritten to match `CAPABILITY_INVENTORY.md` exactly. PROJECT.md gains a "Capability Status (Re-Verified 2026-07-27)" section listing every v1.1→v1.8 capability with its Verified tag and the tier(s) tested, plus a decay disclosure: capabilities marked complete in v1.1–v1.8 ran at the time of tagging; as of 2026-07-27 they were not reproducible and were re-verified in v1.10. ROADMAP.md v1.9.x entries note deck-freeze and superseded-by-reverification status. Both leadership decks reflect the re-verified status; any claim that cannot be demonstrated live is removed. HTML is re-rendered; PPTX is uploaded to the v1.10.0 release. Decks are unfrozen only after this lands. `ci-doc-verifier` confirms no stale capability claims remain. v1.10.0 is tagged; the Gitea release is published. - -## Out of Scope (v1.9) - -| Feature | Reason | -|---------|--------| -| S3 Object Lock + JWS + async worker + DLQ + daily checkpoints (audit ledger build-out) | Requires non-offline-testable AWS infra (Object Lock bucket, KMS signing key, SQS DLQ, Lambda worker). Deferred to a future milestone (D-083). The hash-chain + DynamoDB-outbox path remains the v1.9 production audit record. | -| Live k6/Gatling load test execution, live DR drill, live FinOps forecast | Operator-supplied evidence artifacts (signed blobs) are accepted + validated; the platform does not run these inline. | -| Self-service environment provisioning | Adding an environment remains a platform-team action (per `core/environments/README.md`). v1.9 adds the env files + schema, not self-service provisioning. | - -## Traceability - -### v1.0 (prior — demo) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-01 | 1 | complete (v1.0.1) | -| REQ-02 | 2 | complete (v1.0.2) | -| REQ-03 | 2 | complete (v1.0.2) | -| REQ-04 | 3 | complete (v1.0.3) | -| REQ-05 | 3 | complete (v1.0.3) | -| REQ-06 | 3 | complete (v1.0.3) | -| REQ-07 | 3 | complete (v1.0.3) | -| REQ-08 | 3 | complete (v1.0.3) | -| REQ-09 | 1 | complete (v1.0.1) | -| REQ-10 | 4 | complete (v1.0.4) | -| REQ-11 | 3 | complete (v1.0.3) | -| REQ-12 | 4 | complete (v1.0.4) | -| REQ-13 | 5 | complete (v1.0.5) | -| REQ-14 | 5 | complete (v1.0.5) | -| REQ-15 | 5 | complete (v1.0.5) | - -### v1.1 (prior — architecture finalization + v1 spike, complete) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-16 | 07 | complete (v1.1.2) | -| REQ-17 | 07 | complete (v1.1.2) | -| REQ-18 | 07 | complete (v1.1.2) | -| REQ-19 | 07 | complete (v1.1.2) | -| REQ-20 | 07 | complete (v1.1.2) | -| REQ-21 | 07 | complete (v1.1.2) | -| REQ-22 | 07 | complete (v1.1.2) | -| REQ-23 | 08 | complete (v1.1.3) | -| REQ-24 | 09 | complete (v1.1.4) | -| REQ-25 | 10 | complete (v1.1.5) | -| REQ-26 | 09 | complete (v1.1.4) | -| REQ-27 | 10 | complete (v1.1.5) | -| REQ-28 | 10 | complete (v1.1.5) | - -### v1.2 (prior — platform hardening + first real consumer deployment, complete) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-29 | 11 | complete (v1.2.1) | -| REQ-30 | 12 | complete (v1.2.2) | -| REQ-31 | 13 | complete (v1.2.3) | -| REQ-32 | 14 | complete (v1.2.4) | -| REQ-33 | 15 | partial (v1.2.5, IAM-blocked) | -| REQ-34 | 15 | complete (v1.2.5) | -| REQ-35 | 16 | partial (v1.2.6, IAM-blocked) | - -### v1.3 (prior — module documentation + thin-composition removal, complete) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-36 | 17 | complete (v1.3.1) | -| REQ-37 | 17 | complete (v1.3.1) | -| REQ-38 | 17 | complete (v1.3.1) | -| REQ-39 | 18 | complete (v1.3.2) | -| REQ-40 | 18 | complete (v1.3.2) | -| REQ-41 | 18 | complete (v1.3.2) | -| REQ-42 | 18 | complete (v1.3.2) | - -### v1.4 (prior — central pipeline contract + shell reproducibility + streaming) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-43 | 19 | complete (v1.4.1) | -| REQ-44 | 19 | complete (v1.4.1) | -| REQ-45 | 19 | complete (v1.4.1) | - -### v1.5 (prior — consumer happy path + zero-trust docs + reusable deploy workflow, complete) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-46 | 20 | complete (v1.5.0) | -| REQ-47 | 20 | complete (v1.5.0) | -| REQ-48 | 20 | complete (v1.5.0) | -| REQ-49 | 20 | complete (v1.5.0) | -| REQ-50 | 20 | complete (v1.5.0) | -| REQ-51 | 20 | complete (v1.5.0) | - -### v1.6 (complete — consumer-facing docs restructure + terminology normalization + environments concept, tag `v1.6.0`) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-52 | 21 | complete (v1.6.0) | -| REQ-53 | 21 | complete (v1.6.0) | -| REQ-54 | 21 | complete (v1.6.0) | -| REQ-55 | 21 | complete (v1.6.0) | -| REQ-56 | 21 | complete (v1.6.0) | -| REQ-57 | 21 | complete (v1.6.0) | -| REQ-58 | 21 | complete (v1.6.0) | -| REQ-59 | 21 | complete (v1.6.0) | -| REQ-60 | 21 | complete (v1.6.0) | -| REQ-61 | 21 | complete (v1.6.0) | - -### v1.7 (complete — production platform + contract ingestion + pipeline maturation, tag `v1.7.0`) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-62 | 22 | complete (v1.7.0) | -| REQ-63 | 22 | complete (v1.7.0) | -| REQ-64 | 22 | complete (v1.7.0) | -| REQ-65 | 23 | complete (v1.7.0) | -| REQ-66 | 23 | complete (v1.7.0) | -| REQ-67 | 23 | complete (v1.7.0) | -| REQ-68 | 24 | complete (v1.7.0) | -| REQ-69 | 25 | complete (v1.7.0) | -| REQ-70 | 25 | complete (v1.7.0) | -| REQ-71 | 25 | complete (v1.7.0) | -| REQ-72 | 26 | complete (v1.7.0) | -| REQ-73 | 26 | complete (v1.7.0) | -| REQ-74 | 27 | complete (v1.7.0) | -| REQ-75 | 27 | complete (v1.7.0) | - -### v1.8 (complete — P1 remediation + uptime + standards + encryption/deletion-protection by default + decommission + docs, tag `v1.8.0`) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-76 | 28 | complete (v1.8.0) | -| REQ-77 | 28 | complete (v1.8.0) | -| REQ-78 | 29 | complete (v1.8.0) | -| REQ-79 | 29 | complete (v1.8.0) | -| REQ-80 | 30 | complete (v1.8.0) | -| REQ-81 | 30 | complete (v1.8.0) | -| REQ-82 | 30 | complete (v1.8.0) | -| REQ-83 | 31 | complete (v1.8.0) | -| REQ-84 | 31 | complete (v1.8.0) | -| REQ-85 | 31 | complete (v1.8.0) | -| REQ-86 | 32 | complete (v1.8.0) | -| REQ-87 | 32 | complete (v1.8.0) | -| REQ-88 | 33 | complete (v1.8.0) | -| REQ-89 | 33 | complete (v1.8.0) | -| REQ-90 | 33 | complete (v1.8.0) | -| REQ-91 | 33 | complete (v1.8.0) | -| REQ-92 | 34 | complete (v1.8.0) | -| REQ-93 | 34 | complete (v1.8.0) | -| REQ-94 | 34 | complete (v1.8.0) | -| REQ-95 | 35 | complete (v1.8.0) | -| REQ-96 | 35 | complete (v1.8.0) | -| REQ-97 | 36 | complete (v1.8.0) | -| REQ-98 | 36 | complete (v1.8.0) | -| REQ-99 | 36 | complete (v1.8.0) | -### v1.9 (complete — design doc refresh + contract interpolation + per-env CI jobs + stub implementation + P1-1 remediation, tag `v1.9.0`) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-100 | 39 | complete (v1.9.0) | -| REQ-101 | 39 | complete (v1.9.0) | -| REQ-102 | 39 | complete (v1.9.0) | -| REQ-103 | 40 | complete (v1.9.0) | -| REQ-104 | 40 | complete (v1.9.0) | -| REQ-105 | 41 | complete (v1.9.0) | -| REQ-106 | 41 | complete (v1.9.0) | -| REQ-107 | 42 | complete (v1.9.0) | -| REQ-108 | 42 | complete (v1.9.0) | -| REQ-109 | 42 | complete (v1.9.0) | -| REQ-110 | 42 | complete (v1.9.0) | -| REQ-111 | 42 | complete (v1.9.0) | -### v1.10 (active — pipeline regression fix + capability re-verification + verified-reality rewrite, tag `v1.10.0`) - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-112 | 52 | complete (v1.9.9) | -| REQ-113 | 53 | complete (v1.9.10) | -| REQ-114 | 54 | complete (v1.9.11) | -| REQ-115 | 55 | complete (v1.9.12) | - -## v1.11 (active — RESTART: stateless adapter + pipeline-driven module lifecycle testing, tag `v1.11.0`) - -The v1.11 milestone closes G-005 (CAP-017..022 deploy-unverified) and G-008 -(no cost docs) via a corrected architecture. The first v1.11 attempt is -abandoned (branches `phase/56-iam-re-bootstrap` + `phase/57-live-deploy-microservice`); -the restart branches off `v1.10.2`. - -### Category: Stateless Adapter -- **REQ-123** — The terraform adapter (`adapters/terraform/adapter.py`) is rewritten from a 918-line monolith (3 constant tables `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` + 39 type-specific branches) to a ~80-line stateless assembler. Each L1 module ships a real `terraform/` module dir owning its resource shape, nested blocks, and defaults. The adapter reads the registry and emits `module "x" { source = ... }` blocks. No type-specific logic in the adapter. (Phase P56a) - -### Category: Per-Module Terraform -- **REQ-124** — All 12 L1 modules have a `terraform/` subdir (`versions.tf`/`variables.tf`/`locals.tf`/`main.tf`/`outputs.tf`) with defaults centralized in `locals.tf` (heavy interpolation of vars against sensible defaults). `interface.json` stays engine-agnostic. The registry has a `terraform_dir` field per entry. (Phase P56b) - -### Category: Shell Lifecycle Modes -- **REQ-125** — `scripts/run_platform.sh` gains `--apply` and `--destroy` modes; the shell owns all terraform lifecycle. Python never runs terraform. `scripts/verify_deploy_microservice.py` is deleted. (Phase P57) - -### Category: Single Platform VPC + Deterministic State -- **REQ-126** — `terraform/platform/main.tf` owns ONE VPC; the microservice composition references it via `data` source (no inline VPC). State keys are deterministic and env-aware (`spike/{id}/{env}/terraform.tfstate`), stable across apply/modify/destroy. (Phase P58) - -### Category: L1 Lifecycle Pipeline -- **REQ-127** — A `modules-lifecycle` pipeline (Gitea + GitHub, byte-identical) matrix-runs each L1 module's `examples/{simple,complex}.yml` contracts through apply→modify→destroy against live AWS. No per-module Python. The "test" = the pipeline cell going green. (Phases P59–P60) - -### Category: L2 Lifecycle Pipeline -- **REQ-128** — The lifecycle pipeline extends to L2 modules (static-assets, microservice). L2 = composition only (no L2 terraform files); the composition is deterministic (same contract → same stack → same state key). (Phases P61–P62) - -### Category: Operating Model + G-005/G-008 Closure -- **REQ-116** — CAP-017..022 marked Verified in CAPABILITY_INVENTORY + PROJECT + decks with "Verified live-aws via lifecycle pipeline; torn down to zero-cost" note. (Phase P65) -- **REQ-118** — Both leadership decks rewritten to reflect verified-then-torn-down status; no stale "deploy-unverified" claims. (Phase P65) -- **REQ-119** — `.ciagent/COST.md` documents the v1.0→v1.10 AWS spend window (Cost Explorer query). (Phase P63) -- **REQ-120** — `.ciagent/PRE_MORTEM.md` documents the v1.10 decay root cause + forward pre-mortem. (Phase P64) -- **REQ-121** — CAP-017..022 added to the regression registry (evidence = lifecycle pipeline green). (Phase P63) -- **REQ-122** — All deployed stacks torn down via `--decommission` (D-070 two-step, CR CHG0680001); zero live ACDL resources remain. (Phase P64) - -### v1.11 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-123 | P56a | complete | -| REQ-124 | P56b | complete | -| REQ-125 | P57 | complete | -| REQ-126 | P58 | complete | -| REQ-127 | P59, P60 | complete | -| REQ-128 | P61, P62 | complete | -| REQ-116 | P65 | complete | -| REQ-118 | P65 | complete | -| REQ-119 | P63 | complete | -| REQ-120 | P64 | complete | -| REQ-121 | P63 | complete | -| REQ-122 | P64 | complete | - -### Out of Scope (v1.11) -- OIDC act_runner adoption (pending go-gitea/gitea#36988). -- Per-phase regression (G-007: milestone-level regression gate is correct). -- Audit ledger build-out (D-083). -- Operator-supplied evidence. -- Pilot onboarding (G-001). -- Boto3 post-deploy verification probes (CAP-017..022 live-verify via boto3) — deferred to a future QA milestone. The lifecycle pipeline apply→destroy IS the verification for v1.11. - ---- - -## Milestone v1.12 — Presentation Refinement (REQ-129..REQ-133) - -**Objective:** Refine the leadership presentation decks to reflect the -verified reality after v1.11 — the stateless adapter, pipeline-driven -lifecycle testing, the cost operating model, the pre-mortem, and the -teardown to zero-cost. The v1.11 P65 deck-rewrite task did not fully land -on the deck artifacts: the rendered HTML still claims 6 cloud -capabilities are "deploy-unverified (IAM drift)", the road-to-north-star -diagram still shows v1.10 as "NEXT", and the v1.11 architecture stories -are absent. The v1.10 decay lesson (PRE_MORTEM.md FM-3) requires decks -to match verified reality exactly, not outrun it. The v1.12 regression -gate run (Phase 66) surfaced 3 Broken capabilities — one real adapter -defect (CAP-013) and two regression-probe bugs (CAP-017, CAP-018) — that -must be fixed before the decks can honestly claim 22/22 Verified. - -**Surface:** leadership decks only (`docs/presentations/`) — both decks -across all four layers (source markdown, Marp deck, rendered HTML, -talking points) + diagrams + README. Plus the one real adapter fix and -two probe fixes required to make the deck claims true. - -### Requirements - -- **REQ-129** — The adapter's module-call dedup logic - (`adapters/terraform/adapter.py`) is fixed so multi-resource L1s with - stack outputs (e.g. `ecs-service`, `alb`) produce valid Terraform: - `terraform validate` succeeds for the microservice stack (CAP-013 - Verified live-aws). The regression gate re-runs and confirms 22/22 - Verified. (Phase 67) -- **REQ-130** — The two regression-probe bugs are fixed: CAP-017's - probe no longer requires `locals.tf` for modules that legitimately - omit it (`core/regression_verify.py`); CAP-018's probe instantiates - `LocalLambdaStub` with the required `outbox` arg. The regression gate - re-runs clean (19 Verified + 3 fixed → 22/22 Verified). (Phase 67) -- **REQ-131** — Both leadership decks' capability claims match - `CAPABILITY_INVENTORY.md` exactly: 22/22 Verified, no - "deploy-unverified" / "IAM drift" / "design-verified" framing. The - decks reflect "Verified live-aws via lifecycle pipeline; torn down to - zero-cost." A grep-based doc verification (successor to the planned - `ci-doc-verifier`) confirms zero stale claims across - `docs/presentations/`. (Phase 68, Phase 70) -- **REQ-132** — Both decks reflect v1.11's architecture as - leadership-relevant stories: (a) the stateless adapter - (918→~80 lines, defaults centralized in per-module `terraform/` - dirs, the adapter is an assembler); (b) pipeline-driven lifecycle - testing (a `modules-lifecycle` pipeline matrix-runs each module - apply→modify→destroy against live AWS — the green cell IS the - verification). The `road-to-north-star` diagram + both decks' roadmap - appendix slides reflect v1.11 complete (v1.10 no longer "NEXT"). - Version refs in deck examples bump from `@v1.10` → `@v1.11` (and - `@v1.12` at Phase 70 complete after the tag exists). (Phase 68) -- **REQ-133** — Both decks' "Operating Model & Cost" appendix slide - carries the real `COST.md` figures ($0.001883 / 8 days, ~$0.007/mo, - S3-dominated, zero BAU compute) + the zero-cost-steady-state / - D-096 teardown claim, and references the pre-mortem - (`PRE_MORTEM.md`: v1.10 decay root cause + four forward failure modes - + structural mitigations). Both rendered HTML decks re-rendered and - committed; both talking-points files re-distilled to match the updated - Marp structure (including the A6 Operating Model & Cost section that - was missing from the talking points). PPTX exported to the v1.12.0 - release. (Phase 69, Phase 70) -- **REQ-134** — The `modules-lifecycle` pipeline defaults to **plan-only** - (fast, no AWS mutation) so it runs on every PR without cost or AWS - credentials. A CI variable `ACDL_LIFECYCLE_MODE` (workflow input - `lifecycle_mode`, default `plan`) overrides to `full` for the real - apply→modify→destroy against live AWS. The four lifecycle scripts - (`run_lifecycle_test.sh`, `run_lifecycle_destroy.sh`, - `run_l2_lifecycle_test.sh`, `run_l2_lifecycle_destroy.sh`) read the - flag and dispatch to `--plan-only` (plan mode) or `--apply`/`--destroy` - (full mode). Both forge workflows (`.github` + `.gitea`, byte-identical) - expose `lifecycle_mode` as a `workflow_dispatch` input and pass it via - `env:` to every lifecycle step; the CI VPC apply/destroy jobs are - skipped in plan mode. `pipelines/modules-lifecycle.yml` + the schema - document the `default_mode: plan` field. Tests assert the plan-only - default, the override path, the byte-identity of both workflows, and - the CI VPC skip in plan mode. (Phase 67b) - -### v1.12 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-129 | P67 | complete | -| REQ-130 | P67 | complete | -| REQ-134 | P67b | complete | -| REQ-131 | P68, P70 | complete | -| REQ-132 | P68 | complete | -| REQ-133 | P69, P70 | complete | - -### Out of Scope (v1.12) -- docs/ site, README.md, consumer-guide, module READMEs (decks only). -- Structural deck rework (re-ordering, adding/removing main slides) — - v1.12 keeps the 10 main + 6 appendix structure to avoid the - backwards-sequencing failure mode (PRE_MORTEM.md FM-3). -- New capability claims beyond what v1.11 verified. -- Per-phase regression hardening (G-007, unchanged). - ---- - -## Milestone v1.14 — NFR Refinement (REQ-135..REQ-154) - -**Objective:** Bug fixes, security posture improvements, stub/missing- -functionality identification + implementation, and documentation + NFR -refinement across the entire codebase. **No new features.** NFR milestone -— the final phase's patch IS the deliverable. - -The v1.11 multi-persona review left 5 P1 + 4 P2 findings open; the -codebase has 6+ swallowed-error sites, 15+ hardcoded account-ID -references, 7 untested scripts, an offline-proxy regression gate, -ARCHITECTURE.md with no v1.11–v1.13 addendum, and consumer-facing docs -referencing stale `@v1.6`–`@v1.9` workflow tags. v1.14 clears all of it -in a 20-phase sweep. - -### Requirements - -- **REQ-135** — The adapter dedup loop raises `ValueError` for - unregistered-module resources instead of silently dropping them (P1-1). - (Phase P1) -- **REQ-136** — The static-assets L2 composition wires `default_ttl`/ - `max_ttl`/`price_class`/`viewer_protocol_policy` and makes WAF - conditional via `waf_enabled`, so `complex.yml` is a real modify (P1-2). - (Phase P2) -- **REQ-137** — The L2 lifecycle scripts' usage strings no longer - advertise the vestigial `[ci-vpc-outputs.json]` arg, or document the - remote-state design (P1-3). (Phase P3) -- **REQ-138** — The regression gate's CAP-017..022 checks run - `terraform validate` (not just file-existence + resolver); the - offline-proxy caveat is documented honestly (P1-5). (Phase P4) -- **REQ-139** — Unit tests for adapter dedup merge behavior + - `ACDL_REMOTE_STATE_KEY` override exist and pass (P2-2). (Phase P5) -- **REQ-140** — The ALB target group `name_prefix` derives from `var.name` - (P2-1). (Phase P6) -- **REQ-141** — 6 over-broad `except ...: pass` sites narrowed to specific - exceptions; errors logged with context. (Phase P7) -- **REQ-142** — The hardcoded account ID `581513795199` is externalized to - `ACDL_AWS_ACCOUNT_ID` env / `data.aws_caller_identity` across 15+ sites. - (Phase P8) -- **REQ-143** — 6 `Resource: "*"` IAM statements scoped to `acdl-*` ARNs; - regression test asserts the scoping. (Phase P9) -- **REQ-144** — The contract ingestor validates `contractId`/`environment`/ - `error`; ABAC reliance documented; spoofing-resistance test passes. - (Phase P10) -- **REQ-145** — `contract.schema.json` + `environment.schema.json` reject - undocumented fields (`additionalProperties: false`); format validation - for bucket/ARN/CIDR. (Phase P11) -- **REQ-146** — `.gitignore` has a credential-pattern catch-all; - `test_no_secrets_tracked.py` passes. (Phase P12) -- **REQ-147** — The Kyverno `--kube-version` flag is either implemented or - removed with a documented deferral rationale. (Phase P13) -- **REQ-148** — Orphan bytecode + dead config cleaned (orphan `.pyc`, - stale coverage source, stale version, dead JS allowlist). (Phase P14) -- **REQ-149** — 7 untested scripts have unit test coverage (≥1 test each). - (Phase P15) -- **REQ-150** — Gitea workflow parity resolved; `rotate_spike_key.sh` + - `sync_to_gl.sh` have `set -euo pipefail`. (Phase P16) -- **REQ-151** — `config.json` persona block + branching strategy + - ollama-cloud backend aligned with PERSONAS.md + actual runtime. - (Phase P17) -- **REQ-152** — `modules/STANDARDS.md` internally consistent; no stale - `TYPE_MAP` reference. (Phase P18) -- **REQ-153** — ARCHITECTURE.md has v1.11–v1.14 addenda; stale `@v1.6–1.9` - → `@v1.13`; GRILL G-005/G-008 resolved; COST.md window covers v1.11–v1.14; - D-083 deferral recorded. (Phase P19) -- **REQ-154** — Platform VPC CIDR is a variable; subnet count is - data-driven; `0.0.0.0/0` ingress documented. (Phase P20) - -### v1.14 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-135 | P1 | complete | -| REQ-136 | P2 | complete | -| REQ-137 | P3 | complete | -| REQ-138 | P4 | complete | -| REQ-139 | P5 | complete | -| REQ-140 | P6 | complete | -| REQ-141 | P7 | complete | -| REQ-142 | P8 | complete | -| REQ-143 | P9 | complete | -| REQ-144 | P10 | complete | -| REQ-145 | P11 | complete | -| REQ-146 | P12 | complete | -| REQ-147 | P13 | complete | -| REQ-148 | P14 | complete | -| REQ-149 | P15 | complete | -| REQ-150 | P16 | complete | -| REQ-151 | P17 | complete | -| REQ-152 | P18 | complete | -| REQ-153 | P19 | complete | -| REQ-154 | P20 | complete | - -### 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). - ---- - -## v1.15 — Nova (Rebrand) - -**Milestone type:** Major (breaking — consumer-facing path, env var -prefixes, SSM path, AWS tag keys, and AWS resource names all change). -Per the branch-strategy precedent (breaking/feature milestones tag on -their OWN minor line), v1.15 tags run on the **v1.15.x minor line**: -`v1.15.0` (P0) → `v1.15.1..v1.15.4` (P1–P4) → `v1.15.4` (P5 final = -milestone release). (G-104 binding: the v1.14.x patch line is the NFR -convention; a Major milestone ships on its own minor.) - -A full rebrand 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; the S&P Global Energy -visual theme (`sp-theme.json`) is a client brand and is **not** touched. -The rebrand applies across docs, decks, code, configs, CI, env vars, -consumer conventions, SSM paths, AWS tag keys, and AWS resource names — -with a staged infrastructure migration to avoid breakage. - -Ideation source: `--ideate` flag (user-directed scope; the survey found -1,465 occurrences of `ACDL`/`acdl` across 205 files and zero existing -`nova` references — no collision risk). Accepted ideas become -IDEATE-01..IDEATE-10, mapped to REQ-155..REQ-164. - -### Requirements - -- **REQ-155** — (IDEATE-01) All prose, titles, headers, and comments - across `README.md`, `docs/**`, `.ciagent/*.md`, deck markdown sources, - `pyproject.toml` name/description, and `release.yml` release-title - prefix are rebranded `ACDL`/`Agentic Cloud Delivery Platform` → `Nova`. - Illustrative URLs in docs (`github.com/acdl/...`, - `git.cloudinit.dev/continuous-intelligence/acdl*`) are updated to - `nova` for prose consistency. Gitea release titles going forward read - `Nova vX.Y.Z` (past releases keep their names). (Phase P1) -- **REQ-156** — (IDEATE-02) All Marp deck markdown sources - (`docs/presentations/*-marp.md`, `*.md`, `*-talking-points.md`) and - mermaid source `.mmd` files are rebranded `ACDL` → `Nova`; the deck - title-slide subtitle becomes `Nova — The New Dawn of DevSecOps`. The - `.mmd` sources are edited and the rendered PNG diagrams are - re-exported so the committed PNGs match the new labels. The S&P visual - theme (`sp-theme.json`) is unchanged. HTML decks are re-rendered. - (Phase P1) -- **REQ-157** — (IDEATE-03) The Nova tagline ("The New Dawn of DevSecOps - — security as a seamless enabler of fast deployments") is added to the - README header, both deck title slides, and `docs/vision.md` — - alongside (not replacing) the existing "North Star" / "consumers - declare intent" framing. (Phase P1) -- **REQ-158** — (IDEATE-04) `adapters/terraform/policy/custom_rules/acdl_tagging.py` - is renamed `nova_tagging.py` with its Checkov custom-rule registration - updated (`schemas/tagging-standard.json` line 5 + adapter config). The - Checkov rule enforces `nova:*` tag keys. (Phase P2) -- **REQ-159** — (IDEATE-05) All 21 `ACDL_*` env var prefixes are renamed - to `NOVA_*` across `scripts/`, `core/`, `adapters/`, `tests/`, - workflows (`.gitea/`, `.github/`), `.env`, `.env.secrets` (key names - only — values/secret material stay), and consumer docs. A **dual-read - fallback** (`NOVA_X` preferred, fall back to `ACDL_X`) is implemented - in the config/env loader so deployments do not break during the - transition window; the fallback is removed in the final phase once all - consumers are migrated. Gitea repo secrets are rotated via API. - (Phase P2) -- **REQ-160** — (IDEATE-06) The consumer on-disk contract path - `.acdl/contract.yml` (and `.acdl/static-assets.*.yml`, - `.acdl/contract.yaml`) becomes `.nova/contract.yml` across the - contract resolver, deploy workflow checkout path, consumer docs, and - the contract schema description. A consumer migration guide is shipped - with P1 docs. (Phase P2) -- **REQ-161** — (IDEATE-07) The SSM parameter path prefix - `/acdl/{env}/{contractId}/{output}` becomes - `/nova/{env}/{contractId}/{output}` across `core/output_publisher`, - the contract resolver, and consumer docs. A migration script copies - existing `/acdl/...` parameters → `/nova/...`, readers are updated, - then old parameters are deleted. (Phase P3) -- **REQ-162** — (IDEATE-08) AWS tag keys `acdl:owner`, - `acdl:environment`, `acdl:contract`, `acdl:cost-center`, `acdl:ref` - become `nova:owner`, `nova:environment`, `nova:contract`, - `nova:cost-center`, `nova:ref` across terraform tagging, the Checkov - custom rule (`nova_tagging.py`), and ABAC session policies. A - **parallel-tag period** adds `nova:*` tags to all resources first, - updates the ABAC session policies to match `nova:*`, then removes the - `acdl:*` tags once consumers are verified. (Phase P3) -- **REQ-163** — (IDEATE-09) All `acdl-*` AWS resource names are renamed - to `nova-*` via terraform: KMS alias `alias/acdl-platform` → - `alias/nova-platform`, SNS `acdl-sod-halt` → `nova-sod-halt`, SG - `acdl-ecs-sg` → `nova-ecs-sg`, Lambda `acdl-contract-ingestor` → - `nova-contract-ingestor`, DynamoDB `acdl-contracts`/`acdl-change-requests` - → `nova-contracts`/`nova-change-requests` (scan+copy data migration, - verify row counts, keep old tables until verified), ECR - `acdl-microservice` → `nova-microservice` (re-push images), IAM - user/policy `acdl-spike-runner` → `nova-spike-runner` (re-bootstrap - with new key), state bucket `acdl-tfstate-...` → `nova-tfstate-...` - (`terraform init -migrate-state` to new backend, state JSON backed up - first), ALB name prefix `acdl-alb` → `nova-alb` (recreate, brief - downtime). A maintenance window + rollback runbook is published with - the migration. (Phase P4) -- **REQ-164** — (IDEATE-10) The dual-read env var fallback - (`ACDL_*`→`NOVA_*`) and any `ACDL_*`-only references are removed once - all consumers are migrated; the consumer migration guide is finalized; - `nova_tagging.py` no longer accepts `acdl:*` tag keys. (Phase P5) - -### v1.15 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-155 | P1 | complete | -| REQ-156 | P1 | complete | -| REQ-157 | P1 | complete | -| REQ-158 | P2 | complete | -| REQ-159 | P2 | complete | -| REQ-160 | P2 | complete | -| REQ-161 | P3 | complete | -| REQ-162 | P3 | complete | -| REQ-163 | P4 | complete | -| REQ-164 | P5 | complete | - -### Out of Scope (v1.15) -- Renaming the real Gitea org/repo (`continuous-intelligence/acdl`) or - GitHub org `acdl` — config.json `release.gitea.repo` stays `acdl`; - URLs in docs are illustrative and updated to `nova` for prose only. -- Renaming the S&P Global Energy visual theme (`sp-theme.json`, - deck CSS) — that is client branding, not the Nova product brand. -- Past Gitea release titles — existing releases keep their `ACDL vX.Y.Z` - names; only future releases use `Nova vX.Y.Z`. -- Git branch/tag naming — branches use `milestone/v*` / `phase/*` and - tags use `v*` semver; no brand name present, no change needed. - ---- - -## v1.16 — Nova Simplification (NFR) - -**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). - -**Objective:** A 20-phase NFR sweep (no new features) themed around five -user-directed axes: Simplify without regressions, Security, -Maintainability, User/Developer Experience, and No Humans Onboarding -Flow. The v1.15 rebrand left a fresh debt layer (stale brand strings, a -state-bucket drift, a Kyverno policy contradicting the Nova tagging -standard, dead code) that this milestone clears, alongside genuine -simplification and the first self-service onboarding request path. - -### Requirements - -- **REQ-165** — The adapter-emitted terraform backend references - `nova-tfstate-*` (not `acdl-tfstate-*`); the Kyverno - `require-resource-labels.yml` policy enforces `nova:*` labels (not - `acdl:*`). Correctness regression fix from the v1.15 rebrand. (Phase P1) -- **REQ-166** — All user-facing "ACDL" strings rebranded to Nova: - onboarding message, Lambda alert title/body, PR-stage comments, CI - banner, module docstrings (contract_resolver/confidence_signal/adapter/ - kyverno/wiz + adapters README). (Phase P2) -- **REQ-167** — Dead `ACDL_ENVIRONMENT_OVERRIDE` export removed; stale - dual-read comments dropped; `acdl_*` temp-dir prefixes → `nova_*`. (Phase P3) -- **REQ-168** — `migrate_ssm_paths.py` `except Exception: pass` narrowed - to `ParameterNotFound` + structured log. (Phase P4) -- **REQ-169** — `regression_verify.py` duplicated live-plan/resolver/ - lifecycle-resolve blocks extracted into shared helpers (~70 lines - saved). (Phase P5) -- **REQ-170** — `run_platform.sh` dead export removed; HITL attestation - block extracted to a shell function; hardcoded UUID/`v18` work-dir - stamp replaced with config. (Phase P6) -- **REQ-171** — `contract_resolver.py` imports the env loader from - `environment_check` (dedup); registry entries carry a `kind` field; - fragile `is_l2` path-string heuristic replaced. (Phase P7) -- **REQ-172** — `scripts/sync_workflows.py` generates the 3 - byte-identical workflow pairs from one source; the byte-identity test - is replaced with a generator-output test. (Phase P8) -- **REQ-173** — `run_platform.sh` decommission + uptime blocks extracted - into `scripts/run_decommission.sh` + `scripts/run_uptime.sh`. (Phase P9) -- **REQ-174** — `contract_ingestor.py` fails closed (not silent `pass`) - when IAM identity is absent; the env enum is derived from - `core/environments/` (not hardcoded). (Phase P10) -- **REQ-175** — The contract blob payload is size-capped + schema- - validated before the DynamoDB write; error/stackTrace caps are - consistent. (Phase P11) -- **REQ-176** — `contract_resolver.py` (638 lines) split into resolve / - decommission-transform / cli modules. (Phase P12) -- **REQ-177** — `regression_verify.py` (670 lines) split into capability - checks / live-plan helpers / cli modules. (Phase P13) -- **REQ-178** — `SAFE_OUTPUT_NAMES` is schema-driven (from - interface.json `sensitive` annotations); loaded schemas are cached in - the resolver. (Phase P14) -- **REQ-179** — `run_platform.sh` has a real `--help`; `--deploy-uptime` - is documented; `--local` is surfaced in the README. (Phase P15) -- **REQ-180** — `.github/workflows/README.md` catalogs all 7 workflows' - triggers, inputs, required secrets, and reusable-workflow contracts. (Phase P16) -- **REQ-181** — A single getting-started section in the README: - offline happy path (`run_ci.sh` + `run_platform.sh --check-only`/ - `--local`) first, AWS path second. (Phase P17) -- **REQ-182** — `schemas/onboarding.schema.json` defines the onboarding - request; `contract_ingestor.py` gains an `onboard_consumer` action that - writes a `pending` CMDB row. (Phase P18) -- **REQ-183** — `core/onboarding.py` generates a `.json` from a - consumer request + emits a PR; the onboarding message is rebranded to - Nova and no longer routes to "contact the platform team" for the - request step. (Phase P19) -- **REQ-184** — Terraform for the consumer deploy-role + `nova:owner` - ABAC tag grant, offline-proven (`terraform validate` + `--check-only` - only; no live apply). (Phase P20) - -### v1.16 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-165 | P1 | complete | -| REQ-166 | P2 | complete | -| REQ-167 | P3 | complete | -| REQ-168 | P4 | complete | -| REQ-169 | P5 | complete | -| REQ-170 | P6 | complete | -| REQ-171 | P7 | complete | -| REQ-172 | P8 | complete | -| REQ-173 | P9 | complete | -| REQ-174 | P10 | complete | -| REQ-175 | P11 | complete | -| REQ-176 | P12 | complete | -| REQ-177 | P13 | complete | -| REQ-178 | P14 | complete | -| REQ-179 | P15 | complete | -| REQ-180 | P16 | complete | -| REQ-181 | P17 | complete | -| REQ-182 | P18 | complete | -| REQ-183 | P19 | complete | -| REQ-184 | P20 | complete | - -### Out of Scope (v1.16) -- New features (feat phases). v1.16 is NFR-only. -- Real AWS account/network/state provisioning (self-service) — the - onboarding request path is implemented (D-113); actual cloud resource - creation stays a future feature milestone. -- Live apply of the cross-account role Terraform (D-114) — offline-proven - only; live apply deferred. -- D-083 audit ledger build-out (carries forward; unchanged). -- Real OIDC federation (carries forward; blocked on go-gitea/gitea#36988). -- Re-proposing v1.14 NFR categories already closed (D-117): 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.17 — Strategic Direction, Leadership Metrics & Unified Story - -**Milestone type:** Feature (P1–P3 feat; P4 docs; P5 docs+test; P6 test; -P7 review+audit+ship). Progressive patches; the final phase's patch IS -the milestone release. Tags run 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). - -**Objective:** Three pillars. (A) Encode the PO's strategic direction in -a durable `NORTH_STAR.md` read by CIAgent in every future `/ci-run`. -(B) Instrument Nova to collect, aggregate, and surface leadership-grade -metrics that prove the "no-humans" autonomous-infrastructure value -proposition — grounded in signals Nova actually emits, derived via -documented formulas, or explicitly deferred with a decision ID — flowing -into PowerBI-ready views. (C) Merge the two existing decks into one -unified narrative deck with the "tell them x3" arc at deck + slide level, -per-slide benefit callouts, and fluid transitions. - -**Hard constraint:** DO NOT make anything up. Every metric carries a -`grounded` / `derived` / `deferred` status with a source file or -decision ID. Deferred metrics ship as empty PowerBI placeholder views -with documented schemas. - -### Requirements - -**Pillar A — Strategic Direction** - -- **REQ-185** — `.ciagent/NORTH_STAR.md` is PO-authored with Vision, - Strategic Objectives (4), Anti-Goals (5), Non-Goals (v1.17 scope), - 12–18mo Targets (with grounding column), and Success Criteria. The - attestation clarification is reflected: human attestation required at - stage gates (QA for production, SRE for operational readiness); - autonomy in operations, not in accountability. (Phase P0) -- **REQ-186** — CIAgent reads `NORTH_STAR.md` in context-loading for all - future milestones; the file is referenced from PROJECT.md and - ARCHITECTURE.md so the strategic direction survives across milestones. - (Phase P4) - -**Pillar B — Leadership Metrics + PowerBI** - -- **REQ-187** — Event emitters: a CloudEvents 1.0 envelope is adopted; - a per-run manifest writer emits structured events (run_id, contractId, - env, stages×durations, exit, confidence, HITL block count) to - `metrics/runs/`; existing ephemeral `$WORK/*.json` (pcr, signal, - event, outbox, stack) are persisted as durable artifacts; pytest - `addopts` gains `--junitxml`+`--json-report`; Infracost runs as a - plan post-processor emitting `cost.estimated{delta_usd}` (offline). - (Phase P1) -- **REQ-188** — Decision Ledger: `outbox_writer.py` is extended to emit - to a SQLite append-only table with hash chain; `ai.decision.made` - events are modeled from Nova's real decision points (decision_id=run_id, - chosen_action=band outcome, confidence=score, alternatives=perInput - breakdown, human_override=HITL block) with outcome backfill from - apply.completed; `attestation.recorded` events capture qa/prod/dr - sign-offs (approver, env, concerns, result). Honors D-083 (no S3 Object - Lock/JWS). (Phase P1) -- **REQ-189** — Metrics collector: `core/metrics/collector.py` + - `schemas/metrics_*.schema.json` read all grounded signals - (REGRESSION_REPORT.json, per-run manifests, junit XML, pcr.json, - signal.json, COST.md, decision ledger) → normalized SQLite cold store - at `metrics/nova_metrics.db`; idempotent re-runs. (Phase P2) -- **REQ-190** — PowerBI export: `core/metrics/powerbi_export.py` emits - CSV/JSON views to `metrics/powerbi/` (fact_run, fact_capability, - fact_policy_check, fact_confidence, fact_test, fact_decision, - fact_cost_estimate, dim_capability, dim_milestone + 8 empty - placeholder views for deferred metrics with documented schemas) + - `docs/METRICS_VIEWS.md` schema doc. (Phase P3) -- **REQ-191** — Zero-touch efficiency metrics: Autonomous Resolution - Rate (runs without operational HITL block ÷ total; attestation gates - excluded), Human Escalation Frequency (operational HITL blocks only), - AI Decision Accuracy (decisions not followed by apply.failed/incident - within 5min), MTTD/MTTR (platform-run: apply.failed → successful - retry). (Attestation Coverage is owned by REQ-194, not here.) - (Phase P4) -- **REQ-192** — Velocity metrics: Provisioning Lead Time - (apply.completed.time − intent.received.time), Deployment Frequency - (count(apply.completed) per day). Self-Healing Velocity deferred (no - auto-remediator). (Phase P4) -- **REQ-193** — Financial & cost-ROI metrics: FTE Hours Saved (derived: - run count × manual baseline), Cost Savings via Infracost estimates - (grounded), Cost Efficiency Ratio (derived), Platform ROI (derived - formula). Live CUR reconciliation deferred (D-096). (Phase P4) -- **REQ-194** — Reliability, security & compliance metrics: Zero-Trust - Policy Compliance Rate (from pcr.json), Attestation Coverage (prod/dr - promotions attested by a human ÷ total prod/dr promotions; grounded in - hitl_gates.py + outbox approver_* attributes; canonical owner of this - metric). Uptime, Patch Remediation, SLA/downtime deferred (D-096). - (Phase P4) -- **REQ-195** — Metrics catalog doc: `docs/METRICS.md` catalogs every - executive KPI with `grounded`/`derived`/`deferred` status, source - file or decision ID, and a per-KPI definition-of-success doc in - `docs/metrics/.md`. (Phase P4) - -**Pillar C — Unified Narrative Deck** - -- **REQ-196** — The two existing decks (`how-the-platform-works` + - `the-developer-experience`) are merged 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 x3 structure ("tell them what you're - going to tell them → tell them → tell them what you told them") applies - at deck level (opening = arc; body = tell them; closing = recap + ask). - Both old decks are retired (all derived artifacts deleted). (Phase P5) -- **REQ-197** — Each slide has the x3 structure (opens with what it - covers, delivers, closes with an explicit "benefit of this stage" - callout) + fluid transitions between slides (no disjointed jumps). - The 4-step deck process (source `.md` → Marp → HTML → talking-points) - is re-run for the unified deck. (Phase P5) - -**Cross-cutting** - -- **REQ-198** — Regression capability: CAP-023 (metrics collector runs, - emits expected schema) + CAP-024 (deck structure: slide count, x3 - present, per-slide benefit present) added to `core/regression_verify.py`. - (Phase P6) - -**Ideation enhancements (REQ-199..213 — additive, within D-120..D-132)** - -- **REQ-199** — Metrics schema validation in CI: `run_ci.sh` validates - `metrics/powerbi/*.json` + a sample `metrics/events.jsonl` against - their schemas; exits 0. (Phase P3) -- **REQ-200** — Idempotent collector re-run test: `test_metrics_collector_idempotent` - passes (two runs → identical row counts + chain verified). (Phase P2) -- **REQ-201** — Metrics store backup/restore doc: `metrics/README.md` - documents regenerable vs append-only artifacts + restore procedure. - (Phase P2) -- **REQ-202** — Metrics glossary appendix slide: the unified deck has a - "Metrics Glossary" appendix slide with one-line KPI definitions + - grounding badges. (Phase P5) -- **REQ-203** — "What's Deferred — and Why" slide: the unified deck has - a slide pairing each of 8 deferred metrics with its blocking decision - ID. (Phase P5) -- **REQ-204** — NORTH_STAR diff-check in CI: `run_ci.sh` includes - `check_north_star_diff` that fails when Vision/Objectives/Anti-Goals/ - Targets sections change without a `NORTH_STAR-CHANGE:` commit trailer. - (Phase P4) -- **REQ-205** — Per-module lifecycle success-rate report: each lifecycle - run writes `metrics/lifecycle/-.json`; collector projects - into `fact_lifecycle`; PowerBI "Module Lifecycle Health" view. (Phase - P1 emitter + P2 collector + P3 view) -- **REQ-206** — Code coverage trend emission: `pyproject.toml` addopts - gains `--cov=core --cov=adapters --cov-report=json:metrics/coverage.json`; - collector ingests; `fact_test` carries a coverage column. (Phase P1 + - P2) -- **REQ-207** — Decision Ledger CLI: `core/metrics/decision_ledger_cli.py` - supports `query`, `verify-chain`, `stats`, `export`, `replay`; - `verify-chain` detects broken hashes; `replay` prints ordered events; - tests pass offline. (Phase P2) -- **REQ-208** — PowerBI starter dashboard README: `metrics/powerbi/NOVA_DASHBOARD_README.md` - documents folder-connector import + starter visual model + reference - screenshot. (Phase P3) -- **REQ-209** — PowerBI column-level data dictionary: `docs/METRICS_VIEWS.md` - has a per-column data-dictionary table (column, type, source/formula, - unit, grounded/derived/deferred status). (Phase P3/P4) -- **REQ-210** — Deferred-metrics activation roadmap: `docs/METRICS_DEFERRED_ROADMAP.md` - lists 8 deferred metrics + onboarding-grant half with {blocking - decision, unblock requirement, candidate milestone} + a "Hot-Path - Activation (post-D-096)" section (Nova-native only, D-120) + - "Re-evaluation Triggers" section. (Phase P4) -- **REQ-211** — Trust-snapshot report: `core/metrics/trust_snapshot.py` - emits `metrics/TRUST_SNAPSHOT.md` with 5 trust metrics (Decision Ledger - Coverage, Attestation Coverage, Capability Health, AI Decision - Accuracy, Confidence-Gate Halt Rate) + chain-integrity verdict + - snapshot hash; runs offline. (Phase P4) -- **REQ-212** — Confidence-Gate Halt Rate metric: `docs/METRICS.md` + - trust snapshot include "Confidence-Gate Halt Rate" (signal.json - band=halt ÷ total runs); PowerBI view includes it. (Phase P4) -- **REQ-213** — "No-humans" thesis defensibility brief: `docs/NO_HUMANS_THESIS.md` - defines the thesis, grounded proof metrics, deferred proof metrics, - and explicit anti-claims (incl. D-122 honesty); the unified deck's - Vision act cites it. (Phase P4/P5) - -### v1.17 Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| REQ-185 | P0 | complete | -| REQ-186 | P4 | complete | -| REQ-187 | P1 | complete | -| REQ-188 | P1 | complete | -| REQ-189 | P2 | complete | -| REQ-190 | P3 | complete | -| REQ-191 | P4 | complete | -| REQ-192 | P4 | complete | -| REQ-193 | P4 | complete | -| REQ-194 | P4 | complete | -| REQ-195 | P4 | complete | -| REQ-196 | P5 | complete | -| REQ-197 | P5 | complete | -| REQ-198 | P6 | complete | -| REQ-199 | P3 | complete | -| REQ-200 | P2 | complete | -| REQ-201 | P2 | complete | -| REQ-202 | P5 | complete | -| REQ-203 | P5 | complete | -| REQ-204 | P4 | complete | -| REQ-205 | P1+P2+P3 | complete | -| REQ-206 | P1+P2 | complete | -| REQ-207 | P2 | complete | -| REQ-208 | P3 | complete | -| REQ-209 | P3/P4 | complete | -| REQ-210 | P4 | complete | -| REQ-211 | P4 | complete | -| REQ-212 | P4 | complete | -| REQ-213 | P4/P5 | complete | - -### Out of Scope (v1.17) - -- Live AWS re-provisioning (D-096) — metrics requiring live - infrastructure ship as placeholder views. -- Onboarding auto-grant (D-113/D-114/D-119) — only the request-path - metric is grounded. -- ML anomaly-forecasting / predictive remediation — no emitter today; - Predictive-vs-Reactive metric ships as a placeholder. -- Drift detection scheduled job (D-096 + no scheduler) — drift metrics - ship as placeholders. -- Live cost CUR reconciliation (D-096) — Infracost pre-apply estimates - are grounded; actuals are not. -- S3 Object Lock / JWS tamper-evident ledger (D-083) — Decision Ledger - uses a local SQLite hash-chain this milestone. -- Multi-cloud support (Azure/GCP/K8s) — Nova is AWS-only this milestone. -- A third deck — the two existing decks merge into one; no new - standalone metrics deck. -- A Nova web UI — dashboards are PowerBI, not a Nova-built frontend. - ---- - -## v1.18 — Citizen Developer & Production-Grade Guidance - -> **Milestone type:** Feature. 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). -> **Active milestone:** v1.18. **Branch:** -> `milestone/v1.18-citizen-developer-guidance`. - -### Requirements - -- **REQ-214** — S&P Global Energy Marp theme restored in the unified deck - (`docs/presentations/nova-no-humans-platform-marp.md`). The `style:` block - from commit `ae0cb58` (v1.9.2 / P45) is ported: H1/H2 `#D6002A` - (S&P red-core), title-slide bg `#1B1B1B` (grey-90) with 8px `#D6002A` top - accent bar, body text `#1B1B1B`, blockquote border `#D6002A`, - table headers `#F0F0F0`, font `'Akkurat Pro'` with web-safe fallbacks. The - current Nova header/footer text is preserved (rebrand is not touched — - only the visual theme is restored). HTML re-rendered with the S&P theme. - -- **REQ-215** — RACI matrix authored in `PROJECT.md` (new `## RACI Matrix` - section) and `docs/raci.md` (citizen-developer-facing copy). Three roles: - **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). Rendered as a table: rows = work categories (FRs, UAT, - NFRs, Infra, QA, Prod deploy, Release attestation), columns = R/A/C/I per - role. Includes the compliance-standard-equivalence note. - -- **REQ-216** — PDLC-upstream scope statement made explicit in `PROJECT.md` - (new `## Scope: Nova is Downstream of PDLC` subsection under Domain - Boundaries) and `docs/scope.md`. States that 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. Promotes Core Tenet #2 + Anti-Goal #1 from buried - tenets to a dedicated, unmissable scope statement. - -- **REQ-217** — `schemas/submission-readiness.schema.json` (JSON Schema - draft 2020-12) defines what is acceptable to start — a superset gate - *above* `contract.schema.json` validity. Required fields: `contractId` - (non-empty), `environment` (dev/qa/prod/dr) with the W3.E per-env mandatory - table enforced (dev: stack+environment; qa: +validation.e2eSuite - +validation.loadTest; prod: +runbook+dashboard+oncall; dr: +drDrillRef), - `tags` (the 5 required Nova tags per D-054: `nova:owner`, `nova:contract`, - `nova:environment`, `nova:cost-center`, `nova:ref`), `policyPreconditions` - (declared policy expectations the platform will enforce, e.g., - `public-ingress: false`), `profile` (`developer` or `agentic`; if - `agentic`, requires `naturalLanguageIntent`, `confidenceAtSubmission`, - `agentTrace` per REQ-22 / W3.E), `appSource` (repo + ref pointer for - runtime fetch). - -- **REQ-218** — `core/submission_readiness.py` validator, invoked as - `contract_ingestor.py --check-readiness` subcommand (decision D-133). Returns - a structured `ReadinessResult` (pass/fail per check, with reason codes). - On fail → the ingestor rejects with a citizen-developer-facing error - (not a stack trace). On pass → proceeds to existing contract ingestion. - Calls `contract.schema.json` validation first, then the readiness checks. - Reason codes: `MISSING_TAGS`, `ENV_MISSING_MANDATORY::`, - `AGENTIC_MISSING_INTENT`, `MISSING_APP_SOURCE`, `POLICY_PRECONDITION_MISSING`. - -- **REQ-219** — `docs/submission-readiness.md` citizen-developer-facing doc - explaining what is acceptable to start, with good + rejected examples and - the reason-code catalog. References `schemas/submission-readiness.schema.json` - as the source of truth. - -- **REQ-220** — `tests/test_submission_readiness.py` covers: good contract - passes; missing tags fail with `MISSING_TAGS`; missing env mandatory fails - with `ENV_MISSING_MANDATORY::`; agentic profile missing intent - fails with `AGENTIC_MISSING_INTENT`; missing appSource fails with - `MISSING_APP_SOURCE`. - -- **REQ-221** — `skills/` directory with 9 Atelier-derived skill files mapped - to the BA.A citizen-developer catalog: `skills/api.md` (domains/api/), - `skills/security.md` (domains/security/), `skills/data.md` (domains/data/), - `skills/testing.md` (domains/testing/), `skills/observability.md` - (domains/observability/), `skills/errors.md` (domains/errors/), - `skills/devops.md` (domains/devops/), `skills/infrastructure-as-code.md` - (domains/infrastructure-as-code/), `skills/compliance.md` - (domains/compliance/). Each names the Atelier source path, distills the - first-principles to the citizen-developer-relevant subset, links to - agent-checklist triggers, and maps to the BA.A 5-skill catalog (web API, - worker, scheduled job, static asset, basic observability bootstrap). - -- **REQ-222** — `docs/skills.md` index page listing the skill catalog, the - Atelier provenance, and how the citizen developer's AI agent consumes them - (read before completing a task; run `review/agent-checklist.md` before - finishing). `PROJECT.md` BA.A decision extended with the Atelier-derived - skill catalog reference. - -- **REQ-223** — `mcp/atelier/server.py` MCP server (stdio transport, - decision D-135) with a **plugin-registry architecture** (decision D-140): - `plugins/.py` modules each expose `register(mcp: MCPServer) -> None` - and call `@mcp.tool()` for their tools; `server.py` scans `plugins/` and - calls `register` on each. Initial plugins: `principles.py` - (`atelier.lookup_principle`, `atelier.list_domains`, `atelier.matrix_lookup`) - and `validation.py` (`atelier.validate_against_principles` — agentic - validation against the Atelier agent-checklist, beyond Wiz/Checkmarx/Mend). - Uses the MCP Python SDK v2 (`modelcontextprotocol/python-sdk`). - -- **REQ-224** — `mcp/atelier/vendor/` vendored Atelier snapshot (pinned tag, - decision D-136) for audit reproducibility. `mcp/atelier/vendor/VERSION.md` - records the pinned tag + a `scripts/update_atelier_vendor.sh` helper for - intentional upgrades. `mcp/atelier/README.md` documents the server: how to - run, transport, tool catalog, plugin-authoring guide, vendoring policy. - -- **REQ-225** — `tests/test_atelier_mcp.py` covers: tool registration (all 4 - tools discoverable via `tools/list`), `atelier.lookup_principle` returns - the principle text + core C-rule, `atelier.validate_against_principles` - catches a planted C1 (correctness) + C7 (observability) violation in a - known-bad snippet and passes a known-good snippet, `atelier.matrix_lookup` - returns the domain→core mapping, plugin discovery loads all plugins in - `plugins/`. - -- **REQ-226** — 3 new deck slides added to the unified deck - (`docs/presentations/nova-no-humans-platform-marp.md`) → 21 slides total: - Slide 19 "Scope: Downstream of PDLC", Slide 20 "RACI: Who Owns What", - Slide 21 "Production-Grade Guidance via Atelier". Arc Preview slide - updated to reflect 21-slide count. Talking points - (`nova-no-humans-platform-talking-points.md`) synced for the 3 new slides. - S&P theme preserved (regression check vs P1). CAP-024 deck structure - regression passes. - -- **REQ-227** — `docs/presentations/README.md` slide count + deck table - updated to reflect 21 slides + the 3 new slide titles. - -- **REQ-228** — `scripts/render_deck.sh` (renders HTML + PPTX from a Marp - deck, commits both to git) and `scripts/attach_release_asset.py` (uploads - a file to a Gitea release via the API). Any phase modifying - `docs/presentations/*-marp.md` or `docs/presentations/assets/` MUST - re-render HTML + PPTX, commit the PPTX binary to `docs/presentations/`, - and attach it to the phase's Gitea release. PPTX is stored as a committed - binary (no LFS, decision D-141). - -### Out of Scope (v1.18) - -- **Streamable HTTP transport for the MCP server** — stdio ships now; HTTP - is a future milestone (the SDK supports it on the same server object, so - adding it later is a transport-only change, not a rewrite). -- **A Nova-built frontend / dashboard** — observability stays PowerBI / - external; no Nova web UI. -- **Replacing the existing BA.A 5-skill catalog** — the Atelier-derived - skills extend it, not replace it. -- **Live AWS re-provisioning** (D-096, still deferred) — submission-readiness - validates the contract shape, not a live AWS deployment. -- **A second forge adapter** (GitLab) — BA.F cross-platform evolution is - future work. -- **Atelier live-fetch mode** — vendoring is the only mode this milestone; - live-fetch (with its reproducibility trade-offs) is not implemented. - -### v1.18 Traceability - -| REQ | Phase | Status | -|-----|-------|--------| -| REQ-214 | P1 | complete | -| REQ-215 | P2 | complete | -| REQ-216 | P2 | complete | -| REQ-217 | P3 | complete | -| REQ-218 | P3 | complete | -| REQ-219 | P3 | complete | -| REQ-220 | P3 | complete | -| REQ-221 | P4 | complete | -| REQ-222 | P4 | complete | -| REQ-223 | P5 | complete | -| REQ-224 | P5 | complete | -| REQ-225 | P5 | complete | -| REQ-226 | P6 | complete | -| REQ-227 | P6 | complete | -| REQ-228 | P1/P2/P6 | complete | - -## v1.19 — Nova 2nd-Release Sync (GitLab consumer mirror) - -> **NFR-only chore milestone.** A single execution phase shipping a patch on -> the v1.18.x line (tag `v1.18.0`). Establishes the manual-only "2nd release" -> pipeline from `~/acdl` (CIAgent-managed source of truth) into `~/nova` -> (GitLab `jonathanchery/nova` — a separate repo, separate history, consumer / -> platform-team audience). `~/acdl` retains the full CIAgent audit trail; -> `~/nova` receives only the consumer subset, committed with real -> conventional commits per domain (no kitchen-sink "sync from source mirror"). - -- **REQ-229** — `scripts/sync_to_nova.sh` replaces `scripts/sync_to_gl.sh`. - The script: (1) refuses to run without `--release` / `RELEASE_CONFIRMED=1` - (manual-only — never triggerable by CI); (2) rsyncs the consumer subset of - `~/acdl` into `~/nova`, excluding `.ciagent/`, `.gitea/`, `.env*`, `terraform/`, - `demo/`, runtime metrics artifacts, and internal-only scripts (full list in - `EXCLUDE_SCRIPTS`), while protecting `~/nova/.git` history via rsync - `--filter=P .git`; (3) commits changes domain-by-domain in a fixed order - (config → core → adapters → modules → contracts → schemas → pipelines → - mcp → skills → scripts → tests → docs → workflows) using one - conventional-commit message per changed domain passed via repeated `-m` - flags (positional mapping over changed domains only — no kitchen-sink - commit); (4) validates conventional-commit format (`feat|fix|docs|chore|…`) - unless `--no-verify-format`; (5) pushes to the branch upstream unless - `--no-push`. `--list-domains`, `--dry-run`, `-v` supported. The old - `sync_to_gl.sh` is removed. (Phase P1) - -### Out of Scope (v1.19) - -- **coreci / Atelier review gate on the synced tree** — deferred; the sync - ships consumer contents as-is. 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 ` later. -- **Deleting `~/gl`** — the old GitLab `acdl` mirror is left on disk; only the - sync script targeting it is removed. - -### v1.19 Traceability - -| REQ | Phase | Status | -|-----|-------|--------| -| REQ-229 | P1 | complete | - -## v1.20 — Consumer Cleanup + Transparent Terraform + Slide Pipeline - -> **Multi-concern milestone.** Four user-directed inputs spanning consumer -> cleanup, infrastructure transparency, and presentation automation. Tags -> run on the v1.19.x line (milestone v1.20 → tags v1.19.0, v1.19.1, …). +> **Compressed.** The full v1.0–v1.25 requirement history (REQ-01..REQ-309) +> is preserved verbatim at `.ciagent/archive/REQUIREMENTS-v1.0-v1.24.md`. +> This file retains only the v1.25 requirement set (the immediate +> predecessor milestone whose policy-engine substrate is load-bearing for +> v1.26) + a pointer to the active v1.26 requirements, which live in the +> consumer subproject at `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` +> (multi-project mode per `config.json`). > -> **Input 1 — Gitea/GitLab removal:** Remove all mentions of `gitea` / `gitlab` -> (case-insensitive) from every file synced to `~/nova`. The platform team -> (consumer of `~/nova`) must never know about the dev forge or the GitLab -> mirror. Genericize forge-detection code to `forge` / `generic_forge`. -> -> **Input 2 — Documentation simplification:** Radically simplify all synced -> documentation. Anything the CIAgent needs to reference for itself lives in -> `.ciagent/`. Everything else is tailored to the Platform Team audience. -> Strip ciagent-internal provenance (REQ-/D-/P-/CAP- IDs, milestone headers, -> `.ciagent/PROJECT.md` citations) from synced docs. Delete completed -> migration guides. Move internal artifacts to `.ciagent/`. -> -> **Input 3 — Transparent terraform:** Move terraform `init` / `validate` / -> `plan` / `apply` / `output` into native workflow steps (transparent, visible -> in CI logs). Split `run_platform.sh` into `run_codegen.sh` (pre-TF) + -> `run_postapply.sh` (post-TF). Add `var.enabled` feature flags to every L1 -> module + L2 composition toggles. Wire forge repo variables as per-client -> feature flags — different clients test different functionality without -> version upgrades. -> -> **Input 4 — Slide pipeline + product roadmap:** The slides have not adopted -> the S&P Global theme fully. Create a dedicated render pipeline that builds -> the slides (mermaid PNGs + Marp HTML/PPTX) with the S&P theme applied to all -> slide chrome. Add a 12-month product roadmap (high-level, product-oriented -> vs the technical roadmap in `.ciagent/ROADMAP.md`) to the deck. +> Earlier requirement sets (v1.0–v1.24, REQ-01..REQ-290) remain valid for +> the milestones they governed. They are not re-decided by v1.26. Full +> text in the archive snapshot + git history. -- **REQ-230** — No `gitea` / `gitlab` string literal (case-insensitive) appears - in any file synced to `~/nova`. Verified by - `tests/test_no_forge_mentions.py` which scans the synced subset (same - path rules as `sync_to_nova.sh`'s `DOMAINS` / `EXCLUDES`). Forge-detection - code (`contract_ingestor.py`, `hitl_gates.py`, `run_platform.sh`) is - genericized: `gitea` → `forge` / `generic_forge`, `GITEA_ACTOR` → - `FORGE_ACTOR` (with `GITHUB_ACTOR` primary). (Phase P1) +## v1.25 — kyverno-json Unified Policy Engine (immediate predecessor, complete) -- **REQ-231** — Synced documentation is tailored to the Platform Team - audience. Ciagent-internal provenance (`v1.XX — Strategic Direction` headers, - `REQ-NNN` / `D-NNN` / `P-NNN` / `CAP-NNN` IDs, `.ciagent/PROJECT.md` - "source of truth" citations) is stripped from synced docs. (Phase P1) - -- **REQ-232** — Completed/historical migration docs - (`docs/NOVA_MIGRATION.md`, `docs/NOVA_AWS_MIGRATION.md`) removed from the - synced tree. `docs/NO_HUMANS_THESIS.md` moved to `.ciagent/` (internal - thesis-defense artifact). (Phase P1) - -- **REQ-233** — Terraform `init` / `validate` / `plan` / `apply` / `output` - run as native workflow steps in `deploy.yml` (transparent, named steps - visible in CI logs), not buried inside `run_platform.sh`. (Phase P4) - -- **REQ-234** — `run_platform.sh` is split: `run_codegen.sh` (pre-TF: env - check, validate, resolve, adapt) + `run_postapply.sh` (post-TF: Checkov, - confidence, HITL, outbox, SSM, comment, uptime). A thin `run_platform.sh` - shim preserves backward compat for local-dev usage. (Phase P4) - -- **REQ-235** — Every L1 module has `variable "enabled" { type = bool, - default = true }` + `count = var.enabled ? 1 : 0` on its primary - resource(s); declared in `interface.json`. The `uptime` module's - `feature_flag_enabled` is renamed to `enabled` (with backward-compat alias). - (Phase P4) - -- **REQ-236** — L2 `composition.json` supports per-child `enabled` toggles - driven by contract `inputs.enable_`. The resolver skips children - with `enabled: false`. (Phase P4) - -- **REQ-237** — `deploy.yml` reads feature flags from forge repository - variables (`vars.ENABLE_*`) and passes them as `-var` flags to terraform, - enabling per-client feature toggles without version upgrades. (Phase P4) - -- **REQ-238** — Stale artifact path `/tmp/acdl_platform_run_v18` in - `deploy.yml` fixed to use `NOVA_WORK_DIR`. (Phase P4) - -- **REQ-239** — A dedicated S&P Global theme CSS file - (`docs/presentations/assets/nova-sp-theme.css`) is the Marp theme for all - Nova presentation decks. The theme applies the S&P Red/Black/White palette - (`#D6002A`, `#1B1B1B`, `#FFFFFF`) to all slide chrome (background, - header/footer, pagination, tables, blockquotes), not just headings. (Phase P2) - -- **REQ-240** — A dedicated render pipeline (`scripts/render_slides.sh`) - builds the presentation deck end-to-end: (1) renders all - `assets/mmd/*.mmd` → `assets/png/*.png` via `mermaid-cli --configFile - sp-theme.json`; (2) renders the Marp deck → HTML + PPTX via `marp-cli`; - (3) stages all rendered artifacts to git. Supersedes `render_deck.sh`. - (Phase P2) - -- **REQ-241** — A CI workflow (`workflows-src/slides.yml` + - `.github/workflows/slides.yml`) runs `render_slides.sh` on any change to - `docs/presentations/**` and commits the rendered HTML/PPTX/PNGs back. No - manual re-render step; no artifact drift. (Phase P2) - -- **REQ-242** — `tests/test_slides_pipeline.py` validates: (1) the Marp - deck frontmatter references `nova-sp-theme.css`; (2) the CSS contains the - S&P colors; (3) every `.mmd` has a corresponding `.png`; (4) the HTML - exists and is newer than the Marp `.md`. (Phase P2) - -- **REQ-243** — `docs/presentations/README.md` directory layout is updated - to remove retired decks (`how-the-platform-works-*`, - `the-developer-experience-*`) and document the render pipeline + theme CSS. - (Phase P2) - -- **REQ-244** — A 12-month product roadmap (4 quarters, product-outcome - oriented, grounded in NORTH_STAR strategic objectives + deferred-metric - candidate milestones) is added to the presentation deck as Slide 20 + - Slide 21. The roadmap is distinct from Slide 15's deferred-metric unblock - paths. A matching talking-points section is added. (Phase P3) - -### Out of Scope (v1.20) - -- **Multi-cloud (Azure/GCP) implementation** — deferred; only the product - roadmap references it as a Q4 aspiration. -- **ML anomaly-forecasting service** — deferred; only the product roadmap - references it as a Q4 aspiration. -- **Actual pilot estate activation** — deferred (requires live AWS - re-provisioning, D-096 lift); the product roadmap references it as Q1. -- **Token rotation for `NOVA_GITEA_TOKEN`** — out of scope; the `.env` files - are correctly excluded from sync. Flagged for awareness only. - -### v1.20 Traceability - -| REQ | Phase | Status | -|-----|-------|--------| -| REQ-230 | P1 | complete | -| REQ-231 | P1 | complete | -| REQ-232 | P1 | complete | -| REQ-233 | P4 | complete | -| REQ-234 | P4 | complete | -| REQ-235 | P4 | complete | -| REQ-236 | P4 | complete | -| REQ-237 | P4 | complete | -| REQ-238 | P4 | complete | -| REQ-239 | P2 | complete | -| REQ-240 | P2 | complete | -| REQ-241 | P2 | complete | -| REQ-242 | P2 | complete | -| REQ-243 | P2 | complete | -| REQ-244 | P3 | complete | - -## v1.21 — Nova Deck Refinement & Pipeline Hardening - -> Leadership-deck refinement based on 33 review notes on the v1.20 deck -> (v1.20 shipped as `nova-no-humans-platform*`). This milestone renames the -> deck to the professional "Autonomous Cloud Delivery Platform" framing, -> restructures the narrative (Problem → Solution → Proof → Roadmap + Ask), -> removes internal provenance from audience-facing slides, hardens the -> policy pipeline (Checkov before plan, Wiz-or-Checkov on plan), and moves -> the strategic integration objective into the North Star. -> -> Tags run on the v1.20.x line (milestone v1.21 → tags v1.20.0, v1.20.1, …). - -### REQ-245 — Deck rename + restructure - -The deck files are renamed from `nova-no-humans-platform*` to -`nova-autonomous-cloud-delivery*` across all five artifacts -(source `.md`, `-marp.md`, `.html`, `.pptx`, `-talking-points.md`). -The in-deck title becomes "Nova — The Autonomous Cloud Delivery Platform" -(professional, conveys autonomy without the provocative "no-humans" -wording). The narrative restructures to 18 main + 1 appendix slides: - -1. The Problem (merged old 1+2; broader problem framing; no "arc"; no - "18 capabilities verified"; not "humans are the problem"; add tribal - knowledge / rockstar-operator framing) -2. Nova's Vision -3. Strategic Objectives + Anti-Goals -4. Scope: Downstream of PDLC (moved up) -5. RACI: Who Owns What (moved up) -6. The Platform Pipeline -7. The Decision Ledger -8. The Attestation Matrix -9. Telemetry & Live Ops -10. Decision Ledger + Attestation Coverage -11. Cost & ROI -12. What's Deferred — and Why -13. Roadmap to the North Star -14. 12-Month Product Roadmap -15. Quarter-by-Quarter Outcomes -16. Production-Grade Guidance via Atelier (1/2) -17. Production-Grade Guidance via Atelier (2/2) -18. Recap + Ask -A1. Metrics Glossary - -Removed: old Slide 10 (Capability Health), old Slide 12 (Zero-Touch -Efficiency), old Appendix A2 (Operating Model & Cost). Slide 5's first -table removed. - -### REQ-246 — Thesis rename + reframe - -`.ciagent/NO_HUMANS_THESIS.md` is renamed (git mv) to -`.ciagent/AUTONOMY_THESIS.md`. Content reframes from "removing humans" to -"autonomy in operations, human at stage gates" — professional, not -provocative. The operator-bottleneck framing is softened; the attestation -model + provable trust are emphasized. Anti-claims are retained and -reworded for a tech-leadership audience. All references across the repo -are updated to the new filename + framing. - -### REQ-247 — Strategic-docs sync (NORTH_STAR + PROJECT) - -`NORTH_STAR.md` is updated: -- Vision polished for a technical audience concerned about security, - security remediation velocity, and reliability; "infrastructure - operations become visible" is preserved as a recurring theme. -- Strategic Objective #2 (provable trust) is reworded: trust is - established by deterministic scripts that calculate a score, not by - AI. The platform functions without AI. "AI decisions" are really - automated decisions. -- Strategic Objective #3 (ROI) is reworded with four CTO-grade metrics: - Lead Time (PR → Production), Infrastructure Vulnerability Count - (downward trend), MTTR, Cloud Spend Reduction. All flow into PowerBI - views and are captured by the telemetry pipeline. -- Strategic Objective #4 is replaced: integrate with externally owned - PDLC, SDLC, Agentic, and Citizen Developer platforms regardless of - source; Nova provides skills + MCP endpoints to make applications - production-grade; all intents to deploy to production go through the - same rigorous controls and quality gates. -- Anti-goals #1 (hyperscaler competitor), #4 (legacy untagged), and #5 - (sold to operators) are removed. Two new anti-goals added: not an - upstream development platform; not a replacement for the Product - Lifecycle (PDLC). -- Anti-goal #3 reworded to remove the "removes humans" framing. - -`PROJECT.md` mission statement + scope are synchronized with the -integration objective and the reworded strategic objectives. - -### REQ-248 — RACI restructure (Quality Engineering + SRE) - -The RACI matrix (slide + `docs/raci.md`) is restructured: -- A **Quality Engineering** column is added. -- The Platform column no longer holds the **A** for release attestation; - accountability is reassigned to QA or SRE as appropriate. -- "Release Management" is renamed to **SRE**. -- "Release attestation" is split into two rows: the SRE part is - **Production Readiness** (operational readiness sign-off). -- The slide is sized to fit (text shrunk / low-impact rows dropped). - -### REQ-249 — Atelier split (2 slides) - -Slide 19 (Production-Grade Guidance via Atelier) is split into two slides: -- **16 (1/2):** Skills + MCP server overview (the 9 skills, the 4 MCP - tools, the plugin-registry + stdio surface). -- **17 (2/2):** Agentic validation beyond deterministic scanners + - vendored Atelier for audit reproducibility. -The benefit wording is improved; the same spirit is retained. - -### REQ-250 — Pipeline hardening (Checkov before plan; Wiz-or-Checkov on plan) - -`scripts/run_platform.sh` (and `scripts/run_postapply.sh` where -relevant) implement the two-stage policy scan: -1. **Checkov runs on static code** (the generated `main.tf` / TF - directory) **before** `terraform plan` — fail-fast, quick developer - feedback on policy violations in the authored code. -2. **After `terraform plan`:** if `WIZ_API_TOKEN` + `WIZ_API_URL` are - set, run **Wiz against the plan**; otherwise run **Checkov against - the plan** as a drop-in replacement. **Wiz and Checkov are never - both run on the plan.** -`adapters/wiz/wiz_adapter.py` is updated if needed for plan-mode -input. Slide 6 + `docs/scope.md` reflect the new flow. Tests -(`tests/test_pipeline.py`, `tests/test_pipeline_contract.py`, and -any checkov/wiz tests) are updated and pass. - -### REQ-251 — Theme CSS fix (Appendix A1) + footer cleanup - -`docs/presentations/assets/nova-sp-theme.css` is fixed so the Appendix -A1 Metrics Glossary table is readable (the table background color is -corrected). The Marp footer no longer shows the version (`v1.20`) or -the `Act %{page}/5` artifact. The title-slide subtitle no longer shows -`v1.18 — Citizen Developer & Production-Grade Guidance`; it becomes -"Product Development & Citizen Developer Overview" (or similar) to -convey the audience for the platform. - -### REQ-252 — Global citation + badge + version removal - -Across all audience-facing slides (the Marp deck, the source-of-truth -markdown, and the talking points): -- All internal citations are removed: `D-###` decision IDs, - `REQ-###` requirement IDs, and internal file paths - (e.g. `outbox_writer.py`, `confidence_signal.py`). -- All `Planned` badges are removed. -- The version is removed from the footer and the title slide. -Every benefit callout is rewritten for a tech-leadership audience -(security, remediation velocity, reliability, lead time). A "less is -more / no fluff" final prose pass is applied; the story stays clear. - -### REQ-253 — Render + verify + ship - -Changed/new mermaid diagrams are re-rendered (slide 1 new diagram, slide -9 expand, Atelier split). HTML + PPTX are re-rendered via -`scripts/render_slides.sh`. `tests/test_slides_pipeline.py` passes: -asserts 18 main + 1 appendix slides, no badge spans, no version in the -footer, no `D-###`/`REQ-###`/`.py` paths in audience-facing slides, and -filename refs updated in render scripts + CI workflow + README. -`tests/test_no_forge_mentions.py` passes. Full `pytest` passes -(pipeline-hardening tests green). `run_platform.sh --check-only` passes. -Milestone ship: tag the final phase on the v1.20.x line; create a -release; attach the PPTX. - -### Out of Scope (v1.21) - -- **Live pilot estate activation** — still deferred (D-096). -- **ML anomaly-forecasting service** — still deferred. -- **Multi-cloud (Azure/GCP) implementation** — still deferred. -- **Tamper-evident ledger (S3 Object Lock + JWS)** — still deferred - (D-083); the deck describes it as a roadmap item without citing the - decision ID in the audience-facing slides. - -### v1.21 Traceability - -| REQ | Phase | Status | -|-----|-------|--------| -| REQ-245 | P2 | complete | -| REQ-246 | P1 | complete | -| REQ-247 | P1 | complete | -| REQ-248 | P2 | complete | -| REQ-249 | P2 | complete | -| REQ-250 | P4 | complete | -| REQ-251 | P3 | complete | -| REQ-252 | P2 | complete | -| REQ-253 | P5 | complete | - -## v1.22 — Nova Deck Layout Fix - -> 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. Root cause (per investigation): `nova-sp-theme.css` has zero -> `section` padding (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 is NOT a P5 regression — -> the theme CSS is byte-identical between P3 and P5; P5's denser content -> made the pre-existing theme flaws visible. -> -> Comprehensive fix across four layers: theme CSS, render scripts, mermaid -> diagrams, deck content. Adds the layout/aspect-ratio/theme-structural -> tests that were missing (the gap that let this through). -> -> Tags run on the v1.21.x line (milestone v1.22 → tags v1.21.0, v1.21.1, …). - -### REQ-254 — Theme CSS: section padding + overflow handling - -`docs/presentations/assets/nova-sp-theme.css` adds a `section` padding -rule so content is not jammed against the slide edges. The padding -reserves space for the header (top) and footer (bottom) chrome: e.g. -`section { padding: 48px 56px 40px; }`. The theme also adds explicit -overflow handling on `section` so dense content is not silently clipped -by the marpit base `overflow:hidden` — either `overflow: auto` as an -authoring-time signal, or a documented shrink-to-fit rule. The fix does -NOT re-introduce Marp's default theme via `@import` (the theme remains -standalone); it explicitly sets the padding the default would have -provided. - -### REQ-255 — Theme CSS: aspect-ratio-aware image rules - -The blunt `img { max-height: 320px }` rule is replaced with an -aspect-ratio-aware rule that does not break the Marp `w:`/`h:` directives: -`img { max-width: 100%; max-height: 380px; object-fit: contain; }`. A -`.wide` / `.tall` class convention is added for diagrams (wide diagrams: -`max-height: 280px`; tall diagrams: `max-height: 480px`) so authors can -opt into the right bound per diagram instead of fighting a single blunt -rule. The `w:900` directive on a tall image (slide 9) no longer gets -silently overridden by `max-height`. - -### REQ-256 — Theme CSS: title-slide chrome + spacing tightening - -- `section.title header, section.title footer { display: none; }` — the - title slide and appendix slide no longer render header/footer chrome - that collides with content (the `` + - `` directives only suppress the page number, - not the chrome). -- `section h2 + p { margin-top: 0.2em; }` — tightens the spacing between - the `## Slide N — Title` heading and the bold lead paragraph that - follows it on every content slide (reclaims ~22px per slide). -- `section p { margin: 0.4em 0; }` — reduces default `

` margins - (~1em top/bottom) that waste vertical space on dense slides. -- `ol` styling added (matches `ul`/`li`). -- Table cell padding reduced to `4px 8px` for tables with ≥8 rows (via - a `table.dense` class or a `:nth-child` heuristic) so 10-13 row tables - (slides 8, 12, A1) fit. -- `@media print` overrides added for PPTX export fidelity. - -### REQ-257 — Render scripts: delete render_deck.sh + pin CLI versions - -`scripts/render_deck.sh` is **deleted** (it omits `--theme`, relying on -the frontmatter `theme: nova-sp` which Marp cannot resolve as a custom -theme without `--theme-set` — it falls back to the default theme, -producing unthemed output). The README already documents -`render_slides.sh` as the canonical script. Both `render_slides.sh` and -the deleted `render_deck.sh` references are removed from any docs/tests. -`render_slides.sh` pins marp-cli and mermaid-cli to specific versions -(replace `@latest` with pinned versions) to prevent uncontrolled -boilerplate-CSS drift like the P3→P5 HTML diff. - -### REQ-258 — render_slides.sh: 2x scale + transparent bg for mermaid - -The mermaid-cli invocation in `scripts/render_slides.sh` (lines 51-55) -adds `-s 2 -b transparent` to match the README spec (line 193). This -produces crisp 2x PNGs with transparent backgrounds instead of the -current 1x renders (e.g. `platform-pipeline.png` is only 1568px wide -instead of the 3136px a 2x render would produce). - -### REQ-259 — Re-layout telemetry-live-ops.mmd to LR - -`docs/presentations/assets/mmd/telemetry-live-ops.mmd` is rewritten from -`flowchart TB` (top-bottom, produced a 1024×1628 PNG — aspect 0.63, tall) -to `flowchart LR` (left-right) with subgraph row-wrapping per the README -convention (line 168). The re-rendered PNG (at 2x transparent, per -REQ-258) has an aspect ratio in [1.2, 2.5] suitable for a 16:9 slide. -The Marp deck's `![w:900]` directive on slide 9 is updated to match the -new dimensions (or replaced with `![h:320]` if the diagram remains -taller than wide after re-layout). - -### REQ-260 — Re-layout platform-pipeline.mmd to 2-row wrap - -`docs/presentations/assets/mmd/platform-pipeline.mmd` is rewritten to -wrap the 10-node LR chain into 2 rows via mermaid subgraphs (or split -into two stages: static-scan row + runtime-scan row). The current -1568×116 PNG (aspect 13.52, ultra-wide/short) renders as a 1000×74px -thin strip at `![w:1000]` — node text is illegible. The re-rendered -PNG (at 2x transparent) has an aspect ratio in [1.2, 2.5] suitable for -a 16:9 slide. - -### REQ-261 — Trim/split 8 overflowing slides + remove redundant header - -The 8 slides identified as overflowing 720px are trimmed or split: -- **Slide 3** (Objectives + Anti-Goals): split into Slide 3a (4 - objectives) + Slide 3b (4 anti-goals). Main slide count 18 → 19. -- **Slide 5** (RACI): apply `table.dense` class (from REQ-256) to - reduce cell padding; keep 8 rows. -- **Slide 6** (Pipeline): reduce to 3 bullets (the 4th is covered by - the diagram, now legible after REQ-260). -- **Slide 8** (Attestation Matrix): split into Slide 8a (qa concerns, - 3 rows) + Slide 8b (prod/dr concerns, 7 rows). Main slide count - 19 → 20. -- **Slide 9** (Telemetry): reduce to 3 bullets; image now legible - after REQ-259. -- **Slide 12** (Deferred): reduce to 6 rows (merge the 3 "Live AWS - re-provisioning" blockers into one row). -- **Slide 15** (Quarter-by-Quarter): drop the "Grounding" column - (redundant with the strategic objectives); 4 columns fit better. -- **Appendix A1** (Glossary): apply `table.dense` class (16px font); - keep 13 rows. - -The Marp frontmatter `header:` line is removed (keep `footer:` + -`paginate: true` only). The full 51-char deck title in BOTH header and -footer on every slide is redundant chrome that eats vertical space; -the footer alone suffices. The title slide and appendix already use -`` which (after REQ-256) suppresses chrome. - -The talking-points file is re-distilled to match the new slide -structure (20 main + 1 appendix). The README "18 main + 1 appendix" -convention (line 130) and `test_marp_deck_slide_count` are updated to -assert 20 main + 1 appendix. - -### REQ-262 — Re-render HTML + PPTX + add layout/aspect-ratio tests - -- Run `bash scripts/render_slides.sh nova-autonomous-cloud-delivery` → - re-render all mermaid PNGs (2x transparent) + HTML + PPTX. Verify - slide count (20 main + 1 appendix = 21) and media embedding. -- Add tests to `tests/test_slides_pipeline.py`: - - `test_theme_css_has_section_padding` — assert `section` rule - contains `padding`. - - `test_theme_css_suppresses_title_chrome` — assert - `section.title header` / `section.title footer` `display: none`. - - `test_png_aspect_ratios_sane` — for every PNG in `assets/png/`, - assert aspect ratio ∈ [1.2, 2.5] (catches the 13.52× and 0.63× - outliers). - - `test_render_slides_has_2x_scale` — assert `render_slides.sh` - contains `-s 2` and `-b transparent`. - - `test_render_deck_removed` — assert `render_deck.sh` does not - exist. - - `test_html_embeds_theme` — assert committed HTML contains - `--sp-red` and `padding` in the inline `