From a0a658bc9a8d2bccaf3a12ccfac3c7285e236745 Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 21:11:51 +0000 Subject: [PATCH 1/6] =?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 2/6] =?UTF-8?q?docs(P00):=20clarify=20=E2=80=94=20v1.26=20?= =?UTF-8?q?ambiguities=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 3/6] =?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 4/6] =?UTF-8?q?docs(P00):=20ideate=20=E2=80=94=20v1.26=20(?= =?UTF-8?q?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 5/6] =?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 6/6] =?UTF-8?q?docs(P00):=20grill=20=E2=80=94=20v1.26=20ad?= =?UTF-8?q?versarial=20review=20(9=20challenges,=20PROCEED=200.84,=202=20r?= =?UTF-8?q?evisions)?= 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