---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---
12 KiB
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/<name>/ 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/<name>/, (2) drop ValidatingPolicy
YAML/JSON files, (3) wire a caller. No engine code change needed.
Test pattern: one test file per subdir (tests/test_<name>_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-<AWS_ACCOUNT_ID>-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).