# 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` ✓ complete (P2, v1.25.2) The consumer repo declares its infrastructure via a `contract.yaml` at the repo root, validated against `schemas/contract.schema.json`. The 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 (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-CONSUMER-BUMP — Consumer deploy.yml `@v1.25` → `@v1.29` (v1.29 P5) The consumer repo's deploy workflow invocation (REQ-314, originally `@v1.25`) is bumped to `@v1.29` to track the v1.29 platform release (Reposplit + Identity Layer Bring-Live). The v1.29 platform publishes Lambda zip + layer wheel + Python wheel + ECR container image to GitHub Releases (REQ-354); the consumer's smoke test runs against these artifacts. **Must-haves:** - `.github/workflows/deploy.yml` — `uses: acdl/.github/workflows/deploy.yml@v1.29` with `with: { contract: contract.yaml, mode: full, environment: dev }`. - `.gitea/workflows/deploy.yml` — updated to `@v1.29` (the consumer's `.gitea/` is out of scope for the acdl REQ-367 Gitea scrub — that scrub is `acdl/acdl` only; the consumer may keep its Gitea mirror or follow suit — this is a consumer-repo decision). - `tests/test_v1.29_smoke.py` — sign-up → sign-in → token-vend → apply → audit chain against the v1.29 publish artifacts (the consumer's contract → `deploy.yml@v1.29` mode=full → apply → attest → record against `581513795199`). Uses the existing CAP-025 round-trip assertion (v1.26). **Status:** The consumer repo is not checked out in this environment. The deploy.yml bump + smoke test are documented here; the actual bump requires a consumer repo checkout. The smoke test runs against the v1.29.0 intermediate tag artifacts (produced by P1, grill CF-3/G-3). ### 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. ### REQ-322 — DynamoDB L1 primitive (platform-side) ✓ complete (P2, v1.25.2) The blockchain exchange's ledger table needs a DynamoDB L1 primitive. Research (RESEARCH §3) confirmed the adapter is stateless/registry- 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 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; 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).