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