# Nova — v1.26 Research Findings > Phase: research (pre-execution). Milestone: v1.26 (Live Pilot Estate > Activation). Status: research. Researcher: ci-researcher. > Autonomy: full. --- ## 1. Domain — Homegrown PoA Blockchain for Securities Settlement ### 1.1 Why a homegrown chain (not Ethereum/Solana/Hyperledger) 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. 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. ### 1.2 PoA consensus — single validator (pilot) 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). ### 1.3 T+1 settlement finality 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). ### 1.4 Equities-only scope (D-200) 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. --- ## 2. Nova Consumer Deploy Model ### 2.1 The reusable `deploy.yml@v1.25` workflow 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). 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.2 `run_platform.sh --apply` path (confirmed) `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). **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). ### 2.3 Contract schema — multi-module manifest `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. --- ## 3. Platform Module Readiness (the critical finding) ### 3.1 The adapter is stateless (v1.11 rewrite) `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. ### 3.2 ECS — ready `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. ### 3.3 S3 — ready `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`. ### 3.4 DynamoDB — GAP (REQ-322) **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.5 Stale doc (not a blocker) `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. --- ## 4. Metric Pipeline Grounding (Post-Pilot targets) ### 4.1 AI Decision Accuracy — outcome backfill (REQ-317) `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). ### 4.2 Human Escalation Frequency — `reason='confidence'` tag (REQ-318) `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. ### 4.3 Touchless Resolution Rate — denominator activates post-pilot `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. --- ## 5. kyverno-json Policy Extensibility `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`). 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. --- ## 6. Env-JSON Wiring Reconciliation (REQ-319) `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`. --- ## 7. Risk Analysis | Risk | Likelihood | Impact | Mitigation | |---|---|---|---| | `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. | --- ## 8. Persona Assessment 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).