6a3d47e482
P2 (consumer-contract-and-deploy) complete. REQ-313 (contract.yaml + 3 env variants), REQ-314 (deploy.yml .github+.gitea mirror), REQ-322 (DynamoDB L1 primitive) all delivered. Checkpoint advanced to stage: complete. Consumer ROADMAP.md P2 marked complete (tag v1.25.2). ---ci--- project: nova-blockchain-exchange phase: 2 milestone: v1.26 status: complete phase_role: execution tag: v1.25.2 requirements: [REQ-322, REQ-313, REQ-314] ---/ci---
221 lines
10 KiB
Markdown
221 lines
10 KiB
Markdown
# 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-314 — Consumer deploy workflow invocation ✓ complete (P2, v1.25.2)
|
|
|
|
The consumer repo's GitHub/Gitea Actions invoke the Nova platform's
|
|
reusable `deploy.yml@v1.25` workflow with `mode: full` for the pilot.
|
|
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-<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). |