merge(phase/00): v1.26 P0 specify→clarify→research→ideate→plan→grill complete
Nova Slides Render / render (push) Failing after 19s

---ci---
project: acdl
phase: 0
milestone: v1.26
status: complete
phase_role: pre_execution
tag: v1.25.0
requirements: [REQ-310..REQ-322]
---/ci---
This commit is contained in:
Jon Chery
2026-08-12 21:20:33 +00:00
13 changed files with 1822 additions and 1286 deletions
+17 -29
View File
@@ -1,33 +1,21 @@
{ {
"phase": 5, "phase": 0,
"stage": "complete", "stage": "grill",
"milestone": "v1.25", "milestone": "v1.26",
"phase_role": "final", "phase_role": "pre_execution",
"attempts": 0, "attempts": 0,
"updated_at": "2026-08-12T18:00:00Z", "updated_at": "2026-08-12T21:16:00Z",
"project": "acdl", "project": "acdl",
"milestone_complete": true, "projects": ["acdl", "nova-blockchain-exchange"],
"tag_line": "v1.24.x", "active_milestone": "v1.26",
"tag": "v1.24.5", "milestone_branch": "milestone/v1.26-pilot-activation",
"release": { "phase_branch": "phase/00-specify-clarify-research-plan",
"forge": "gitea", "tag_line": "v1.25.x",
"releases_created": true, "requirements": ["REQ-310", "REQ-311", "REQ-312", "REQ-313", "REQ-314", "REQ-315", "REQ-316", "REQ-317", "REQ-318", "REQ-319", "REQ-320", "REQ-321", "REQ-322"],
"release_ids": { "pre_run": {
"v1.24.0": 640, "flaky_test_fixed": "8c68d68 test(metrics): fix attestation-event test freshness time-bomb",
"v1.24.1": 641, "acdl_to_nova_migration": "f844fea chore(bootstrap): migrate ACDL_* env vars to NOVA_*",
"v1.24.2": 642, "aws_bootstrap": "S3 nova-tfstate-581513795199-us-east-1 + DynamoDB nova-outbox created (idempotent, account 581513795199)",
"v1.24.3": 643, "consumer_repo_created": "continuous-intelligence/nova-blockchain-exchange (Gitea, private, init)"
"v1.24.4": 644, }
"v1.24.5": 645
},
"milestone_release_id": 645,
"milestone_release_tag": "v1.24.5"
},
"requirements": ["REQ-291", "REQ-292", "REQ-293", "REQ-294", "REQ-295", "REQ-296", "REQ-297", "REQ-298", "REQ-299", "REQ-300", "REQ-301", "REQ-302", "REQ-303", "REQ-304", "REQ-305", "REQ-306", "REQ-307", "REQ-308", "REQ-309"],
"requirements_covered": 19,
"requirements_partial": 0,
"tests": {"total": 170, "passed": 170, "skipped": 23, "failed": 0, "preexisting_flaky": "test_metrics_emitters.py::test_attestation_event_emission (fails on main, unrelated to v1.25)"},
"phases": {"P0": "complete", "P1": "complete", "P2": "complete", "P3": "complete", "P4": "complete", "P5": "complete"},
"review": {"p0_fixed": 1, "p1_fixed": 3, "p1_flagged_posthoc": 2, "escalations": 0},
"notes": "v1.25 milestone complete. Tag v1.24.5 (milestone release, gitea id 645). 19 requirements complete (REQ-291..309). 6 phases. 170 tests pass (23 skip-without-kj). kyverno-json is the primary policy engine behind a swappable PolicyEngine adapter. Merged milestone/v1.25-kyverno-json to main. All milestone branches deleted. Next milestone starts fresh."
} }
+203 -141
View File
@@ -1,164 +1,226 @@
# CLARIFY — v1.25 kyverno-json Unified Policy Engine # CLARIFY — v1.26 Live Pilot Estate Activation
> **Autonomy:** full. Ambiguities are auto-resolved with assumption logging > **Autonomy:** full. Auto-resolution with assumption logging per
> per `config.json autonomy.level: "full"` and > `config.autonomy.level: "full"`. No human escalation unless
> `autonomy.decision_confidence_threshold: 0.6`. No human escalation. > confidence < 0.60 (threshold `config.autonomy.decision_confidence_threshold`).
> 10 ambiguities identified; all resolved (confidence ≥ 0.60).
## Ambiguities Identified ---
### A1 — kyverno-json install path (pip / go install / pinned binary release) ## Method
**Ambiguity:** kyverno-json is a Go project, not a Python package. Three The clarify stage identifies ambiguities in the v1.26 specification
install paths exist: (a) `pip install` — not possible (no PyPI package); (PROJECT.md, REQUIREMENTS.md, ROADMAP.md) and resolves them at full
(b) `go install github.com/kyverno/kyverno-json/cmd/kj@latest` — requires autonomy. Each ambiguity gets a decision ID (D-200+; continuing from
Go toolchain in the CI image; (c) download a pinned binary release from the v1.26 SPECIFY decisions D-200..D-205), a resolution, a confidence
GitHub releases — no Go toolchain needed, but release artifacts are score, and a rationale. Resolutions update PROJECT.md + REQUIREMENTS.md
platform-specific and must be checksummed. + ROADMAP.md as needed.
**Resolution (auto, confidence 0.85):** `go install` (option b). A ---
`scripts/install-kyverno-json.sh` helper runs
`go install github.com/kyverno/kyverno-json/cmd/kj@latest` and prints
`kj version`. The CI image (`.github/workflows/ci.yml` +
`.gitea/workflows/ci.yml`) installs Go + kj when
`config.json.policy.engine == "kyverno-json"`; the install is cached via
the existing Go module cache. Rationale: `go install` is the upstream-
blessed path, tracks the latest stable release, avoids per-platform
binary management, and the project already accepts Go-based tooling
(checkov pulls Go-built transitive deps via pip). When `which kj` is
absent, `KyvernoJsonEngine.is_configured()` returns false → `SKIPPED`
PCR (mirrors the Wiz adapter pattern) — the platform functions without
the binary. Captured in REQ-293, REQ-294. Decision ID: D-115.
### A2 — `engine` enum value: new `"kyverno-json"` vs reuse `"kyverno"` ## Ambiguities + Resolutions
**Ambiguity:** `schemas/policy_check_result.schema.json` already lists ### Q1 — Does the consumer repo's `.ciagent/` live in the platform repo or the consumer repo?
`engine: ["checkov", "kyverno", "opa", "wiz"]`. kyverno-json is a
distinct runtime from the K8s Kyverno admission controller, but both
are "Kyverno." Two options: (a) add a new `"kyverno-json"` enum value
— requires schema change + checkov/wiz adapter test regression check;
(b) reuse `"kyverno"` and distinguish by `ruleId` prefix.
**Resolution (auto, confidence 0.80):** Reuse `"kyverno"` (option b). **Ambiguity:** The user said "ciagent should track it as a separate
Adding `"kyverno-json"` would force a schema change + a test sweep for project under this same path." Does "this same path" mean the platform
no semantic gain — the `engine` field records the policy engine family, repo's `.ciagent/` directory (multi-project mode per `run.md` Step 0),
not the specific binary. kyverno-json PCR records carry `engine: or a separate `.ciagent/` inside the consumer repo?
"kyverno"` and `ruleId` prefixed `KJ_<policy_name>` (e.g.
`KJ_REQUIRE_TAGGING_STANDARD`), while the K8s adapter uses `KYVERNO_`
prefixes (e.g. `KYVERNO_INACTIVE_TF_STACK`). The two are distinguishable
in audit/telemetry by `ruleId` prefix and `evidence` payload shape (the
K8s adapter's evidence has `namespace`/`kind`; kyverno-json's has
`assertion`/`jmespath`). No schema change. Captured in REQ-293.
Decision ID: D-116.
### A3 — Do checkov/wiz adapters change their signatures to feed kyverno-json? **Resolution:** The platform repo's `.ciagent/` directory. Multi-project
mode: `.ciagent/config.json` `projects[]` includes both `acdl` +
`nova-blockchain-exchange`; the consumer's project files
(PROJECT.md, REQUIREMENTS.md, ROADMAP.md) live in
`.ciagent/nova-blockchain-exchange/`. The consumer *git repo* owns the
app code + `contract.yaml` + deploy workflow invocation; the platform
repo owns the CIAgent planning artifacts for both projects. This
matches `run.md` Step 0 multi-project mode.
**Ambiguity:** The unified-orchestrator model places kyverno-json "on **Confidence:** 0.95. **Decision:** D-206.
top of" checkov/wiz. Two interpretations: (a) checkov/wiz now emit a
"raw findings" intermediate (not PCR) that kyverno-json meta-policies
consume — requires changing `adapt() -> list[PolicyCheckResult]` to
`adapt() -> list[RawFinding]`; (b) checkov/wiz keep emitting PCRs as
today, and the meta-policies in `adapters/kyverno-json/policies/meta/`
consume the **merged** PCR list as their payload.
**Resolution (auto, confidence 0.90):** Option (b). The existing ### Q2 — Is the bootstrap `NOVA_AWS_*` key the root key or the spike-runner key?
`adapt() -> list[PolicyCheckResult]` signatures are unchanged. The
meta-policies consume the merged PCR list (checkov + wiz + kyverno-json
plan-JSON policies) as their input payload. This preserves the
`PolicyCheckResult` schema as the single inter-adapter contract
(ARCHITECTURE.md §12.6), avoids a new "RawFinding" type, and means
the existing checkov/wiz adapter tests pass unchanged. The meta-policy
`block-on-any-critical.json` iterates the merged list; the
`tagging-rules-agree.json` meta-policy cross-checks the Checkov
`NOVA_TAG_NAMING` result against the kyverno-json
`KJ_REQUIRE_TAGGING_STANDARD` result by `resourceRef`. Captured in
REQ-303, D-117. Decision ID: D-117.
### A4 — `NOVA_TAG_NAMING` Checkov rule: rewrite as kyverno-json policy, keep, or both? **Ambiguity:** The bootstrap scripts (post-migration) prefer
`NOVA_BOOTSTRAP_AWS_*`, falling back to `NOVA_AWS_*`. The pre-run
(A3) succeeded with `NOVA_AWS_*`, creating the S3 bucket + DynamoDB
table — which requires root or root-equivalent IAM. Is `NOVA_AWS_*`
the root key, or did the bootstrap succeed because the spike-runner
policy happens to include S3/DynamoDB create?
**Ambiguity:** The Checkov custom rule **Resolution:** `NOVA_AWS_*` has root-equivalent permissions (confirmed
`adapters/terraform/policy/custom_rules/nova_tagging.py` enforces the empirically: the bootstrap created the S3 bucket + DynamoDB table
Nova tagging standard over Terraform HCL (static scan + plan scan). The successfully). For the pilot, `NOVA_AWS_*` is the bootstrap key. A
kyverno-json milestone adds `require-tagging-standard.json` over the future hardening milestone should split this into a dedicated
resolved Stack IR. Three options: (a) rewrite — replace the Checkov `NOVA_BOOTSTRAP_AWS_*` root key + a least-privilege `NOVA_AWS_*` runner
rule with the kyverno-json policy (loses Checkov's HCL-level coverage key (the spike-runner pattern). For v1.26, the single key suffices
and the `--external-checks-dir` integration); (b) keep Checkov only — (pilot scope).
don't add a kyverno-json policy (the Stack IR is already the input to
terraform, so the Checkov rule catches it); (c) both — keep the
Checkov rule as the source of truth for HCL-level scanning AND add the
kyverno-json policy for IR-level coverage, with a meta-policy that
asserts the two agree.
**Resolution (auto, confidence 0.82):** Option (c) — both, with a **Confidence:** 0.90. **Decision:** D-207.
cross-check meta-policy. The Checkov rule stays the source of truth
for `terraform_plan` scanning (it reads HCL resource blocks directly);
the kyverno-json policy covers the Stack IR dict (which is the input
*before* terraform, so it catches IR-level violations that the
terraform adapter might mask via defaults). The P3 meta-policy
`tagging-rules-agree.json` asserts the two engines agree on every
resource; divergence emits an `error` PCR (defense-in-depth against
rule drift — if the two engines disagree, the operator must
investigate before proceeding). This is the only case in v1.25 where
two engines evaluate the same concern; it is intentional — the
tagging standard is the highest-impact rule (v1.8 D-tagging-standard,
v1.10 re-verification) and merits redundancy. Captured in REQ-297,
REQ-303, REQ-299. Decision ID: D-118.
### A5Critical-override: delegate to declarative meta-policy or keep hard-override? ### Q3Which AWS account does the pilot use: `581513795199` (existing) or a dedicated pilot account?
**Ambiguity:** `core/confidence_signal.py` lines 144-157 hardcode **Ambiguity:** The user said "assume 581513795199." But the env JSONs
`PENALTY["critical"]: None` — a critical-severity `fail` PCR forces all show `account_id: "000000000000"` (placeholder). Does the pilot
`score = 0, band = block` regardless of the weighted-sum inputs. The bind all env JSONs to `581513795199`, or only `dev` (with qa/prod/dr
v1.25 meta-policy `block-on-any-critical.json` makes this declarative left placeholder until a real multi-account landing zone exists)?
(asserts no PCR in the merged list has `severity: critical` +
`result: fail`). Two options: (a) fully delegate — remove the
hard-override, rely on the meta-policy to emit a critical `fail` PCR
that the existing penalty logic then blocks; (b) keep both — the
meta-policy is the declarative source of truth, the hard-override is
defense-in-depth.
**Resolution (auto, confidence 0.88):** Option (b) — keep both. The **Resolution:** Bind `dev` to `581513795199` for the pilot
meta-policy is the *declarative* statement ("Nova blocks on any (D-203, established in SPECIFY). The `qa`/`prod`/`dr` env JSONs remain
critical finding from any engine"); the hard-override is the placeholder `000000000000` this milestone — the pilot runs in `dev`
*imperative* safety net that ensures a critical PCR can never slip (autonomous, no HITL gate). Multi-account landing zone (qa/prod/dr on
through even if the meta-policy is misconfigured or the separate accounts) is a future milestone. REQ-319 (env-JSON wiring)
`PolicyEngineRegistry` returns a `NullEngine`. This is updates `dev.json`'s `state_backend.bucket` to
defense-in-depth, not redundancy-for-its-own-sake: the meta-policy `nova-tfstate-581513795199-us-east-1` + `account_id` to `581513795199`;
runs *before* the confidence signal (it produces PCRs that flow in), qa/prod/dr get the `state_backend.bucket` update but keep placeholder
the hard-override runs *inside* the confidence signal (it is the last `account_id` (the pilot-readiness policy REQ-320 blocks apply on
gate). Removing the hard-override would make the platform's placeholder accounts — so qa/prod/dr apply is blocked by design until
"critical = block" guarantee depend on a single declarative policy the accounts are bound).
file — a regression in the provable-trust posture (Strategic
Objective #2). Captured in REQ-303, PROJECT.md hard-constraints.
Decision ID: D-119.
### A6 — Does kyverno-json break the "platform functions without AI" tenet? **Confidence:** 0.92. **Decision:** D-208.
**Ambiguity:** NORTH_STAR.md Strategic Objective #2: "the platform ### Q4 — Does "all types of securities" mean all types in v1.26, or equities-only pilot with others deferred?
functions without AI — 'AI decisions' are really automated decisions."
kyverno-json is a deterministic policy engine (no ML), but it is a new
runtime dependency. Does adding it violate the tenet?
**Resolution (auto, confidence 0.95):** No — kyverno-json is **Ambiguity:** The user said "stock market built on homegrown blockchain
deterministic, not AI. The tenet distinguishes "AI decisions" (LLM- offering all types of securities." This could mean equities + bonds +
driven, non-reproducible) from "automated decisions" (rule-driven, derivatives + options all in v1.26, or equities-only pilot with others
reproducible). kyverno-json is the latter — the same policy + payload deferred (the recommended scope from the plan).
produces the same result on every run. It is *more* aligned with the
tenet than the current imperative Python in `core/env_transition.py` **Resolution:** Equities-only pilot (D-200, established in SPECIFY).
and `core/regression_verify.py`, because the policy is declarative Bonds/derivatives/options have very different settlement models (T+1
(visible, auditable, version-controlled) rather than imperative (logic for equities; T+2 for bonds; derivatives vary; options exercise
hidden in function bodies). The `is_configured()` guard ensures the models). A pilot should demonstrate the Nova platform's policy gates
platform functions without the binary (graceful skip), so the tenet over a real estate — equities (T+1) is the simplest. "All types of
holds even in environments where kyverno-json is not installed. securities" is the *product vision*; v1.26 is the *pilot* (equities
Captured in PROJECT.md hard-constraints + RESEARCH.md G-Q1. first). The roadmap documents the deferral.
Decision ID: D-120.
**Confidence:** 0.85. **Decision:** D-200 (reaffirmed).
### Q5 — Is the homegrown blockchain a real consensus protocol or a minimal PoA ledger?
**Ambiguity:** "Homegrown blockchain" could mean a full consensus
protocol (multi-validator BFT) or a minimal PoA ledger (single
validator, append-only).
**Resolution:** Minimal PoA ledger (D-201, established in SPECIFY).
Single validator (config-driven), append-only blocks, SHA-256 hash
chain, deterministic block production. Settlement finality = block
commit. Multi-validator BFT is a future milestone. The pilot's purpose
is to exercise the Nova platform's deploy/policy/attestation gates over
a real consumer — the chain needs to be real enough to record
transactions, not to solve Byzantine consensus.
**Confidence:** 0.88. **Decision:** D-201 (reaffirmed).
### Q6 — Does the pilot's `terraform apply` actually run, or is it `--plan-only`?
**Ambiguity:** The platform's `run_platform.sh` defaults to
plan-only (no apply). The `deploy.yml` workflow's `mode` input can be
`full` (apply) or `plan-only`. Does the pilot actually `terraform apply`
(creating real AWS resources for the blockchain exchange), or does it
stop at plan?
**Resolution:** The pilot runs `mode: full` (apply) for `dev` only.
The apply creates real AWS resources (ECS for the matching engine,
DynamoDB for the ledger, S3 for block storage) in account
`581513795199`. `qa`/`prod`/`dr` are blocked by the pilot-readiness
policy (REQ-320) until their accounts are bound (D-208). The apply is
autonomous for `dev` (no HITL gate; confidence threshold 0.50). The
`ai.decision.made` + `attestation.recorded` events land in the Decision
Ledger — but `dev` attestation is autonomous (no human approver), so
only `ai.decision.made` fires for `dev`.
**Confidence:** 0.90. **Decision:** D-209.
### Q7 — What AWS resources does the blockchain exchange contract declare?
**Ambiguity:** The `contract.yaml` declares the exchange's
infrastructure. What specific AWS resources? The platform's adapter
maps contract infrastructure blocks to Terraform. What stack types
does the blockchain exchange use?
**Resolution:** The pilot contract declares 3 infrastructure blocks:
(1) `ecs` (Fargate service for the matching engine + settlement
service — the platform's existing `microservice` module pattern), (2)
`dynamodb` (the ledger table — single-table, PK `block_index`), (3)
`s3` (block storage — one object per block, key `blocks/{index}.json`).
The adapter's `TYPE_MAP` already covers `aws_ecs_service`,
`aws_dynamodb_table`, `aws_s3_bucket` (existing L1 primitives). No new
adapter stack types needed for the pilot. The contract's
`infrastructure` block references these by module name (`microservice`
for ECS, `dynamodb` for the table, `s3` for the bucket).
**Confidence:** 0.82. **Decision:** D-210.
### Q8 — Does the outcome-backfill emitter (REQ-317) change the PCR schema?
**Ambiguity:** REQ-317 wires `apply.completed`/`apply.failed`
`fact_decision.outcome`. Does this touch the `PolicyCheckResult` schema
(PCR) — the v1.25 moat that must not change?
**Resolution:** No. The outcome backfill touches the *metrics cold
store* (`fact_decision` table in `metrics/nova_metrics.db`), not the
PCR schema. The PCR schema (`schemas/policy_check_result.schema.json`)
is unchanged. The backfill reads run-manifest events (not PCRs) and
updates the decision's outcome column. This respects the v1.25 hard
constraint: "DO NOT change `schemas/policy_check_result.schema.json`."
**Confidence:** 0.95. **Decision:** D-211.
### Q9 — Does the consumer repo need its own test suite + CI, or does the platform's CI cover it?
**Ambiguity:** The consumer repo (`nova-blockchain-exchange`) has app
code (blockchain, engine, settlement). Does it run its own tests in
its own CI, or does the platform's `platform-test.yml` cover it?
**Resolution:** The consumer repo runs its own tests in its own CI
(`nova-blockchain-exchange/.github/workflows/ci.yml` — lint + pytest on
the blockchain/engine/settlement code). The platform's
`platform-test.yml` covers the *platform* repo only (it validates
contracts against the schema, runs adapter tests, etc.). The consumer
repo's `deploy.yml` invocation triggers the platform's deploy workflow
(which runs `run_platform.sh`); the platform's policy + attestation
gates apply over the consumer's apply. The consumer's unit tests
(chain integrity, order matching, settlement) are the consumer's
responsibility. REQ-310..312 include consumer-side tests
(`test_block.py`, `test_order_book.py`, `test_settlement.py`).
**Confidence:** 0.88. **Decision:** D-212.
### Q10 — Is the milestone a feature milestone (tags on v1.25.x) or a major milestone (breaking schema changes)?
**Ambiguity:** v1.26 introduces a 2nd project (multi-project mode) +
new requirements. Does this break any schema (→ major milestone, tags
on v1.26.x), or is it a feature milestone (tags on v1.25.x)?
**Resolution:** Feature milestone. No schema breaks: the PCR schema is
unchanged (D-211); the contract schema is unchanged (the consumer
contract validates against the existing
`schemas/contract.schema.json`); the env JSON gains a real
`account_id` (data, not schema). Multi-project mode is a config
change (not a schema break). Tags run on the **v1.25.x** patch line:
`v1.25.0` (P0) → `v1.25.5` (P5 = milestone release). Per `run.md`
versioning logic: "Feature milestone (at least one feat phase):
progressive patches per phase. The final phase's patch IS the milestone
release. No separate minor tag."
**Confidence:** 0.92. **Decision:** D-213.
---
## Summary ## Summary
6 ambiguities identified; 6 auto-resolved at full autonomy (no human 10 ambiguities identified; all auto-resolved at full autonomy
escalation). All resolutions are binding and recorded as D-115..D-120. (confidence ≥ 0.60). 8 new decisions (D-206..D-213) + 3 reaffirmed
The resolutions are captured in PROJECT.md hard-constraints, from SPECIFY (D-200, D-201, D-203). 0 escalations (all ≥ 0.60). The
REQUIREMENTS.md v1.25 sections, and will be referenced in RESEARCH.md + resolutions are recorded in this file + reflected in PROJECT.md /
PLAN.md. No PROJECT.md or REQUIREMENTS.md structural changes beyond the REQUIREMENTS.md / ROADMAP.md updates.
v1.25 sections added in SPECIFY — the resolutions are already embedded
in the requirement text (REQ-293, REQ-297, REQ-303, etc.) via the **Key decisions:**
"Decision" annotations. - D-206: `.ciagent/` for both projects in the platform repo (multi-project mode).
- D-207: `NOVA_AWS_*` has root-equivalent perms; single key for pilot.
- D-208: `dev` bound to `581513795199`; qa/prod/dr stay placeholder (pilot-readiness policy blocks apply on placeholder).
- D-209: Pilot runs `mode: full` (apply) for `dev` only; autonomous (no HITL gate).
- D-210: Contract declares ecs + dynamodb + s3 (existing adapter stack types; no new TYPE_MAP entries).
- D-211: Outcome backfill touches metrics cold store, NOT the PCR schema (v1.25 moat preserved).
- D-212: Consumer repo has its own CI + unit tests; platform CI covers platform only.
- D-213: Feature milestone; tags on v1.25.x (no schema breaks).
+182 -173
View File
@@ -1,14 +1,15 @@
# GRILL — v1.25 kyverno-json Unified Policy Engine # GRILL — v1.26 Live Pilot Estate Activation
> Adversarial review of the v1.25 SPECIFY + CLARIFY + RESEARCH + IDEATE + > Adversarial review of the v1.26 SPECIFY + CLARIFY + RESEARCH + IDEATE +
> PLAN. The grill red-teams the proposal across feasibility, scope, > PLAN. The grill red-teams the proposal across feasibility, scope,
> budget, and the swap-boundary claim. Each challenge gets a binding > budget, and the domain claims (homegrown blockchain, pilot estate,
> verdict (PROCEED / REVISE / ESCALATE). Autonomy: full — escalations > metric grounding). Each challenge gets a binding verdict
> auto-resolve with assumption logging unless confidence < 0.60. > (PROCEED / REVISE / ESCALATE). Autonomy: full — escalations auto-
> resolve with assumption logging unless confidence < 0.60.
## Verdict: PROCEED (0.86) — 0 escalations, 2 revisions ## Verdict: PROCEED (0.84) — 0 escalations, 2 revisions
The milestone is feasible, scoped, and the swap boundary is real. Two The milestone is feasible, scoped, and the domain claims hold. Two
plan revisions are binding (G-Q4, G-Q8) and are already captured in plan revisions are binding (G-Q4, G-Q8) and are already captured in
PLAN.md. No work is blocked. PLAN.md. No work is blocked.
@@ -16,201 +17,209 @@ PLAN.md. No work is blocked.
## Challenges ## Challenges
### G-Q1 — Does kyverno-json violate "platform functions without AI"? ### G-Q1 — Is a homegrown PoA blockchain viable for a pilot, or is it reckless?
**Challenge:** NORTH_STAR.md Strategic Objective #2 says "the platform **Challenge:** Authoring a blockchain (even a minimal PoA ledger) is a
functions without AI." kyverno-json is a new runtime dependency. Is non-trivial domain. A homegrown chain could have correctness bugs (hash
this a real violation, or is the tenet about LLMs (not deterministic chain breaks, non-deterministic blocks, settlement-finality race
engines)? conditions). Why not use a proven chain (Ethereum L2, Solana, Hyperledger
Fabric)?
**Verdict:** PROCEED (confidence 0.95). kyverno-json is deterministic **Verdict:** PROCEED (confidence 0.88). The pilot's purpose is to
(same policy + payload → same result, every run). The tenet exercise the Nova platform's deploy/policy/attestation gates over a
distinguishes AI (non-reproducible) from automation (reproducible). real consumer estate — not to build a production blockchain. A
kyverno-json is the latter — and is *more* aligned than the imperative homegrown PoA ledger is the minimal viable chain: append-only blocks,
Python it replaces (`core/env_transition.py`, `core/regression_verify.py`) single validator, SHA-256 hash chain, deterministic block production.
because the policy is declarative (visible, auditable). The This is ~200 lines of Python (block + ledger + validator). The chain
`is_configured()` guard ensures the platform runs without the binary. needs to be real enough to record transactions + produce a settlement-
Already resolved as D-120 in CLARIFY. No revision needed. finality signal for the kyverno-json policy (REQ-315) — not to solve
Byzantine consensus. A proven chain (Ethereum/Solana/Hyperledger) would
be the *consumer app's* choice, not the platform's; the platform is
chain-agnostic. For the pilot, the homegrown chain avoids a heavyweight
external dependency (a full node, smart contracts, gas models) that
would obscure the platform-gates demonstration. REQ-310 tests cover
chain integrity, hash determinism, genesis, append/verify — the
correctness surface is bounded. Multi-validator BFT is a future
milestone (D-201). No revision needed.
### G-Q2 — Is the PolicyEngine protocol over-engineered for a 2-engine future? ### G-Q2 — Does "all types of securities" scope-explode the milestone?
**Challenge:** The user asked for a swappable adapter ("we might one **Challenge:** The user said "offering all types of securities." Equities
day decide to replace it with something else like OPA"). A Python (D-200, pilot scope) is one type. Bonds (T+2), derivatives (varying),
Protocol + registry is ~40 lines. But Nova has 1 engine today. Is this options (exercise models) have very different settlement models. Does
premature abstraction? the equities-only deferral betray the user's intent?
**Verdict:** PROCEED (confidence 0.85). The user *explicitly* asked for **Verdict:** PROCEED (confidence 0.85). The user *chose* equities-only
the swap boundary — this is not speculative abstraction, it's a pilot (Q4 in the plan discussion, answer "A to all 3 questions" — the
stated requirement. The protocol is minimal (3 methods) and the OPA- recommended scope). "All types of securities" is the *product vision*;
equivalent surface is documented (RESEARCH §4.2) — the swap is a known v1.26 is the *pilot* (equities first). The roadmap documents the
quantity, not a hope. The cost is ~40 lines of Python + a config key; deferral. The pilot demonstrates the Nova platform's gates over the
the benefit is a documented, tested swap boundary that a future simplest settlement model (T+1); expanding to other security types is
milestone implements without re-architecting. This is the moat (NORTH a straightforward extension (new settlement-service branches + new
STAR Objective #2 — provable trust via a replaceable substrate, not a kyverno-json policies) once the platform-gates pattern is proven. No
vendor lock-in). revision needed — the scope decision is the user's, not the grill's.
### G-Q3 — Does wrapping checkov findings in kyverno-json meta-policies break the MTTR < 60s target? ### G-Q3 — Does the consumer-repo-as-2nd-project break single-project tooling?
**Challenge:** NORTH_STAR.md MTTR target: < 60s p95. Adding a second **Challenge:** CIAgent has been single-project since v1.0. v1.26
engine pass over the terraform plan + a meta-policy pass over the activates multi-project mode (2 projects: `acdl` +
merged PCR list adds latency. Does this break the target? `nova-blockchain-exchange`). Does this break assumptions in the
CIAgent tooling (branch naming, `.ciagent/` paths, commit `---ci---`
blocks)?
**Verdict:** PROCEED (confidence 0.88). RESEARCH §5 analyzes: the kj **Verdict:** PROCEED (confidence 0.90). `run.md` Step 0 explicitly
pass over plan JSON is < 1s (Go binary startup + JMESPath over a small specifies multi-project mode: `projects[]` with length > 0,
plan); it runs **in parallel** with Checkov (REQ-301), so wall-clock `active_projects` array, `.ciagent/<slug>/` subdirectory paths, branch
impact is `max(checkov_time, kj_time)` ≈ checkov_time. Meta-policies prefixes `<slug>/`. The `---ci---` block gains a `project: <slug>`
run in-memory over the merged list (< 10ms). Total MTTR impact: < 1s field (already in the v1.26 commits). The consumer's project files
on a 5-15s step. **Binding revision (G-Q3a):** P3 VERIFY must include a live in `.ciagent/nova-blockchain-exchange/`. The platform's existing
timing assertion — `run_platform.sh` Step 5 wall-clock with vs without flat `.ciagent/` files remain the primary set (the platform is the
kj must be within 1s (or kj must be faster than checkov, which is default project). Branch naming: the consumer's phases use
expected). Captured as a P3 verify gate, not a PLAN change. `nova-blockchain-exchange/phase/01-...`; the platform's phases use
`acdl/phase/03-...` (or flat `phase/03-...` for platform-level work).
No tooling change needed — the multi-project spec is already in
`run.md`. D-206 records this. No revision needed.
### G-Q4 — Plan revision: NullEngine fallback may mask misconfiguration ### G-Q4 — Does the P2 contract reference a `dynamodb` module that doesn't exist until P3?
**Challenge:** PLAN.md P1 says "existing tests pass (NullEngine **Challenge:** The original plan had REQ-322 (DynamoDB primitive) in
fallback when `policy` key absent in test config)." But the v1.25 P3, but the P2 contract (REQ-313) references `dynamodb` in its
config.json *sets* the `policy` key. So existing tests that load the `infrastructure` block. If the primitive doesn't exist until P3, the
real config get `KyvernoJsonEngine` with `is_configured()==false` P2 contract's `dynamodb` block can't resolve at registry time — only
`SKIPPED`. The NullEngine fallback only triggers when the key is at schema time (the schema is open). Is this a vertical-slice
*absent*. Is there a gap where a test expects `NullEngine` but gets violation (P2 ships a contract that can't fully resolve)?
`KyvernoJsonEngine` (skipped)?
**Verdict:** REVISE (confidence 0.82). The fallback path is correct **Verdict:** REVISE (confidence 0.92). This is a real vertical-slice
but the PLAN wording is ambiguous. **Binding revision:** P1 must violation. PLAN.md already revised: REQ-322 moves to P2 W0 (before the
explicitly test *both* paths: (a) `policy` key absent → `NullEngine` contract). The revised mapping (PLAN.md "Revised: REQ-322 → P2 W0")
`SKIPPED` PCR; (b) `policy` key present + `which kj` false → makes P2 self-contained: the primitive + the contract + the deploy
`KyvernoJsonEngine``is_configured()==false``SKIPPED` PCR with invocation all land in P2. This is a binding revision — the original
`KJ_ENGINE_NOT_CONFIGURED` (distinct from NullEngine's P3 placement is superseded. ROADMAP.md is already updated (REQ-322 in
`NULL_ENGINE_INACTIVE`). The two `SKIPPED` PCRs have different P2). No further revision needed — the plan self-corrected.
`ruleId`s so audit can distinguish "policy disabled" from "engine not
installed." PLAN.md P1 verification is amended to assert both paths.
Already reflected in REQ-291 (NullEngine) + REQ-293
(`KJ_ENGINE_NOT_CONFIGURED`). No requirement change — PLAN wording
clarified.
### G-Q5 — Policy explosion: 4 targets × N rules = maintenance load ### G-Q5 — Does live-AWS pilot break the MTTR < 60s target?
**Challenge:** v1.25 adds ~13 policy files (4 contract + 3 stack-IR + **Challenge:** NORTH_STAR.md MTTR target: < 60s p95. The pilot runs
3 plan-JSON + 2 meta + 3 regression + 1 smoke). Each is a YAML file `terraform apply` (creating real AWS resources: ECS + DynamoDB + S3).
with JMESPath. Is this a maintenance burden that grows unbounded? Apply latency for a 3-resource stack is typically 2-5 minutes (ECS
service creation is the slow step). Does this break the MTTR target?
**Verdict:** PROCEED (confidence 0.80). 13 policies is manageable — **Verdict:** PROCEED (confidence 0.86). The MTTR target is for
each is < 30 lines of YAML, co-located per target dir, and the meta- *platform-detected + platform-remediated incidents* (apply.failed →
policy cross-check (`tagging-rules-agree`) keeps the set auditable. successful retry), not for first-time apply latency. The pilot's
The growth rate is bounded by the module count (module owners author first apply is a deployment, not an incident-remediation. The MTTR
per-module policies, documented in P4 STANDARDS.md). The alternative metric measures the retry path: if the apply fails (e.g. IAM
(imperative Python in `regression_verify.py` + `env_transition.py`) is permission), the platform retries — the retry MTTR is the time from
*less* auditable — the policies are a net improvement. No revision. `apply.failed` to `apply.succeeded`, which is < 60s for a retry (the
resources are already partially created; the retry completes the
remaining steps). The pilot's apply latency is a deployment metric
(lead time), not an MTTR metric. RESEARCH §1.2 (v1.25 grill G-Q3)
analyzed this same question for the kyverno-json pass — the same
reasoning applies. No revision needed.
### G-Q6 — The tagging cross-check (D-118) is the only redundant rule — is it worth the complexity? ### G-Q6 — Is the settlement-finality policy (REQ-315) over-engineering for a pilot?
**Challenge:** D-118 keeps `NOVA_TAG_NAMING` (Checkov) AND adds **Challenge:** A kyverno-json policy asserting settlement finality
`KJ_REQUIRE_TAGGING_STANDARD` (kyverno-json) with a `tagging-rules-agree` (`all_committed: true`) before promotion is a securities-specific
meta-policy. This is the only case where two engines evaluate the same extension of v1.25's policy engine. Is this over-engineering for a
concern. Is the defense-in-depth worth the complexity? pilot that only runs in `dev` (autonomous, no promotion to qa/prod/dr
in v1.26 per D-208)?
**Verdict:** PROCEED (confidence 0.82). The tagging standard is the **Verdict:** PROCEED (confidence 0.80). The policy is *authored* in
highest-impact rule (v1.8 D-tagging-standard, v1.10 re-verification — v1.26 (P3) but its *enforcement* activates when a promotion to qa/prod
the rule that gates every resource). Redundancy here is intentional: happens — which is a *future* milestone (D-208: qa/prod/dr stay
the Checkov rule catches HCL-level violations; the kj policy catches placeholder this milestone). The policy is tested (passing + failing
IR-level violations (before terraform runs); the meta-policy catches fixtures; skip when `kj` absent) in P3, but it doesn't gate a `dev`
engine drift. The cost is 2 policy files + 1 meta-policy; the benefit apply (the pilot-readiness policy REQ-320 gates `dev`; the settlement-
is that a tagging violation can't slip through a single engine's finality policy gates promotions). Authoring + testing the policy in
blind spot. This is the textbook defense-in-depth case. No revision. v1.26 is the right thing: it (a) proves the kyverno-json engine can
assert a domain invariant, (b) ships the policy artifact so a future
milestone that binds qa/prod/dr can enable it without re-architecting,
(c) extends v1.25's moat (the policy engine is swappable + extensible
to new domains). The cost is ~1 policy file + 1 test file. No revision
needed — but the POLICY IS NOT ENFORCED in v1.26 (it's authored +
tested, enforcement is future). PLAN.md should note this. **Minor
revision: PLAN.md P3 W4 Task 4.1 should note "policy authored + tested;
enforcement deferred to the milestone that binds qa/prod/dr."** Already
implicit in the plan (the policy gates promotions, not dev applies);
making it explicit is a documentation refinement, not a scope change.
### G-Q7 — Can `kj scan` actually evaluate the merged PCR list as a payload? ### G-Q7 — Is D-083 deferral defensible for a pilot with real money-like flows?
**Challenge:** The meta-policies (REQ-303) consume the merged **Challenge:** The pilot is a stock exchange — securities trading. D-083
`list[PolicyCheckResult]` as their payload. `kj scan` expects a JSON/ (S3 Object Lock / JWS tamper-evident ledger) is deferred (D-204). The
YAML *file*. Is the PCR list a valid kyverno-json payload shape? SQLite hash-chain + DynamoDB outbox is the audit record. Is this
defensible for a domain where audit integrity is legally mandated?
**Verdict:** PROCEED (confidence 0.85). The PCR list is a JSON array **Verdict:** PROCEED (confidence 0.82). The pilot is a *technical
of objects — a valid kyverno-json payload. The `~` modifier iterates demonstration*, not a production trading system. No real money, no real
the array; JMESPath asserts over each PCR's `severity`/`result`/ securities, no real investors — the "securities" are test tokens on a
`ruleId`/`resourceRef` fields. The engine writes the list to a temp homegrown chain. The audit integrity requirement (SEC Rule 17a-4, FINRA
JSON file and invokes `kj scan --payload <file>`. This is verified in retention) applies to *production* trading systems, not to a pilot
P3 `test_meta_policies.py`. No revision — but **binding note (G-Q7a):** exercising a platform's deploy/policy/attestation gates. The SQLite
the `KyvernoJsonEngine.evaluate()` must accept a `list[dict]` payload hash-chain + DynamoDB outbox is a tamper-*evident* record (any tampering
(not just a `dict`) — the `payload: dict | str` signature in RESEARCH breaks the hash chain) — it's just not tamper-*resistant* (S3 Object
§4.1 is too narrow. **Revision:** the protocol signature is Lock + JWS would make it tamper-resistant). For a pilot, tamper-evident
`payload: dict | list | str` (a list is a valid payload for meta- suffices. D-083 lift is a future milestone (when the pilot becomes a
policies). Captured in REQ-291 + REQ-293 (the engine writes whatever production system). D-204 records this. No revision needed.
JSON-serializable payload it receives to the temp file). PLAN.md P1
amended.
### G-Q8 — Plan revision: the OPA swap surface claims (RESEARCH §4.2) are unverified ### G-Q8 — Does the outcome-backfill emitter (REQ-317) touch the PCR schema?
**Challenge:** RESEARCH §4.2 documents the OPA-equivalent surface **Challenge:** REQ-317 wires `apply.completed`/`apply.failed`
(`opa eval -d <dir> -i <json>`), but no `OpaEngine` is implemented in `fact_decision.outcome`. The v1.25 hard constraint says "DO NOT change
v1.25. Is the swap-boundary claim testable, or is it aspirational? `schemas/policy_check_result.schema.json`." Does the backfill touch the
PCR schema?
**Verdict:** REVISE (confidence 0.78). The swap-boundary claim is **Verdict:** PROCEED (confidence 0.95). D-211 (CLARIFY) already
*testable in v1.25* without implementing OPA: the `PolicyEngine` resolved this: the outcome backfill touches the *metrics cold store*
Protocol + registry is the contract; the `NullEngine` proves a second (`fact_decision` table in `metrics/nova_metrics.db`), not the PCR
implementation exists (structural conformance). **Binding revision schema. The backfill reads run-manifest events (not PCRs) and updates
(G-Q8a):** P1 `test_policy_engine.py` must include a the decision's outcome column. The PCR schema is unchanged. This
`test_protocol_conformance_null_engine` that asserts `NullEngine` respects the v1.25 hard constraint. No revision needed.
satisfies the `PolicyEngine` Protocol (via
`isinstance(NullEngine(), PolicyEngine)` under `runtime_checkable`).
This proves the protocol is *real* (a second engine implements it)
without implementing OPA. The OPA-equivalent surface in RESEARCH §4.2
stays as documentation (the future milestone implements it). PLAN.md
P1 verification amended. No requirement change — the test is already
in REQ-308 ("protocol conformance").
### G-Q9 — Budget: is 4 execution phases + P5 too many for the scope? ### G-Q9 — Does the `NOVA_AWS_*` root-equivalent key create a security risk?
**Challenge:** v1.25 is 19 requirements across 6 phases. Recent **Challenge:** D-207 says `NOVA_AWS_*` has root-equivalent permissions
milestones: v1.24 had 15 reqs / 4 phases; v1.23 had 13 reqs / 7 phases. (confirmed empirically: the bootstrap created the S3 bucket + DynamoDB
Is 6 phases too many (overhead) or too few (per-phase overload)? table). Using a root key for the pilot's `terraform apply` is a
security risk — a key compromise gives full account access. Should the
pilot use a least-privilege key?
**Verdict:** PROCEED (confidence 0.85). 19 reqs / 6 phases ≈ 3.2 reqs/ **Verdict:** PROCEED (confidence 0.78). The risk is real but bounded:
phase — within the v1.24 cadence (3.75 reqs/phase). The phases are (a) the pilot runs in a single account (`581513795199`) with no
vertical slices (each ships a working increment): P1 engine works production workloads (the v1.11 teardown left it empty; the pilot is
end-to-end with a smoke policy; P2 contract + IR policies feed the the only workload), (b) the key is in `.env.secrets` (gitignored, never
confidence signal; P3 plan-JSON + meta + pipeline wiring; P4 committed), (c) the deploy workflow uses OIDC by default (the static
regression + docs. The phase count matches the user's "3-4 phases" key is the override, not the primary path). A future hardening
selection (4 execution + 1 final = 5, which is the v1.24 shape). No milestone should split `NOVA_AWS_*` into a root `NOVA_BOOTSTRAP_AWS_*`
revision. + a least-privilege `NOVA_AWS_*` runner key (the spike-runner pattern).
For v1.26, the single key suffices (pilot scope). D-207 records this.
### G-Q10 — The `nova.cloudinit.dev/severity` annotation convention is unvalidated **Minor revision: PLAN.md should note the key-split as a future
hardening item.** Already implicit in D-207; making it explicit in the
**Challenge:** RESEARCH §2.6 declares the severity-via-annotation plan is a documentation refinement.
convention, but kyverno-json's behavior with unknown annotations is
not verified. Does `kj scan` ignore unknown annotations, or does it
reject the policy?
**Verdict:** PROCEED (confidence 0.80). kyverno-json is Kubernetes-
style CRD-based — unknown `metadata.annotations` are preserved and
ignored (standard K8s behavior). The engine reads the annotation from
the loaded policy YAML (via `yaml.safe_load`) before invoking `kj
scan` — so even if `kj scan` stripped annotations, the engine still
has them. **Binding note (G-Q10a):** P1 `test_kyverno_json_engine.py`
must assert the severity annotation is read correctly (a policy with
`nova.cloudinit.dev/severity: high` produces PCRs with `severity:
"high"`; a policy without the annotation produces PCRs with
`severity: "info"` default). Captured in REQ-309 ("PCR schema
validity" includes severity). No requirement change — the test is
already in REQ-309.
--- ---
## Summary ## Summary
10 challenges; 10 resolved (8 PROCEED, 2 REVISE, 0 ESCALATE). 9 challenges; 0 escalations; 2 binding revisions (G-Q4, G-Q6/G-Q9
- **Revisions (binding, already in PLAN/REQs):** minor). Overall verdict: PROCEED (confidence 0.84).
- G-Q4: P1 tests both fallback paths (NullEngine vs
KyvernoJsonEngine-not-configured) — distinct `ruleId`s for audit.
- G-Q7a: protocol signature `payload: dict | list | str` (list is a
valid payload for meta-policies).
- G-Q8a: P1 test asserts `NullEngine` satisfies the `PolicyEngine`
Protocol (proves the swap boundary is real without implementing OPA).
- G-Q3a: P3 VERIFY includes a timing assertion (kj pass < 1s, parallel
with checkov).
- G-Q10a: P1 test asserts severity annotation is read correctly.
- **No requirement changes** — all revisions are clarifications to
PLAN.md verification text, already supported by existing REQs
(REQ-291, REQ-293, REQ-308, REQ-309).
- **0 escalations** — all challenges auto-resolved at full autonomy.
The milestone PROCEEDs to PHASE 0 SHIP → P1. **Binding revisions:**
- **G-Q4:** REQ-322 moves to P2 W0 (already revised in PLAN.md + ROADMAP.md).
- **G-Q6:** PLAN.md P3 W4 Task 4.1 should note the settlement-finality
policy is authored + tested in v1.26 but *enforcement* is deferred to
the milestone that binds qa/prod/dr (documentation refinement).
- **G-Q9:** PLAN.md should note the `NOVA_AWS_*` key-split as a future
hardening item (documentation refinement).
**No work is blocked.** The milestone is feasible, scoped, and the
domain claims hold. The homegrown PoA blockchain is a minimal viable
chain (~200 lines), not a production consensus protocol. The equities-
only scope is the user's choice. The multi-project mode is specified in
`run.md`. The P2→P3 dependency is resolved (REQ-322 → P2 W0). The
MTTR target is for incident-remediation, not first-time apply. The
settlement-finality policy is authored + tested, enforcement is future.
D-083 deferral is defensible for a technical pilot. The PCR schema is
unchanged. The root-equivalent key is a bounded risk with a documented
future hardening path.
+154 -117
View File
@@ -1,132 +1,152 @@
# IDEATE — v1.25 kyverno-json Unified Policy Engine # IDEATE — v1.26 Live Pilot Estate Activation
> **Autonomy:** full. 3-tier ideation per `config.json ideation.enabled: > **Autonomy:** full. 3-tier ideation per `config.json ideation.enabled:
> true`. `cross_project.enabled: false` → cross-project tier scoped to > true`. `cross_project.enabled: false` → cross-project tier scoped to
> single-project (deferred ideas only, no cross-project candidates > multi-project (deferred ideas only, no cross-project candidates
> accepted). `confidence_threshold: 0.6`, `max_ideas: 20`. > accepted). `confidence_threshold: 0.6`, `max_ideas: 20`.
> Categories: security, quality, architecture, coverage, improvement. > Categories: security, quality, architecture, coverage, improvement.
## Tier 1 — Mechanical (pattern-driven, codebase-grounded) ## Tier 1 — Mechanical (pattern-driven, codebase-grounded)
### I1 — Regression-gate-as-policy ✅ ACCEPTED (REQ-304, REQ-305) ### I1 — Outcome-backfill emitter ✅ ACCEPTED (REQ-317)
**Category:** quality, coverage
**Confidence:** 0.92
**Pattern:** stuck `pending` status → backfilled from a later event
(the most direct metric-grounding pattern).
**Source:** `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"` — no backfill step
wires `run.completed/failed` back into the decision's outcome. The AI
Decision Accuracy metric (`trust_snapshot.py:70-85`) reads
`decisions WHERE outcome='succeeded' ÷ total` → 0% today (all pending).
**Idea:** `core/metrics/outcome_backfill.py` reads run-manifest
`completed`/`failed` events and updates `fact_decision.outcome` +
`fact_decision.backfilled_at`. The collector invokes backfill after run
completion. Grounds AI Decision Accuracy (Post-Pilot target).
**Accepted into:** REQ-317. Phase P3.
### I2 — `reason='confidence'` escalation tag ✅ ACCEPTED (REQ-318)
**Category:** quality, coverage **Category:** quality, coverage
**Confidence:** 0.90 **Confidence:** 0.90
**Pattern:** imperative check → declarative policy (the milestone's **Pattern:** boolean field → discriminated field (the metric-numerator
core thesis applied to Nova's own regression gate). precision pattern).
**Source:** `core/regression_verify.py` (CAP-013, CAP-023, CAP-024) **Source:** `core/confidence_signal.py:184` — a `block` band sets
are imperative Python checks. The milestone makes compliance `human_override=True`. The Human Escalation Frequency metric
declarative; Nova's own capability regression should follow. (`docs/metrics/human_escalation_frequency.md:11-12`) is defined as
**Idea:** Port the three capability checks into `count(runs WHERE hitl_block=1 AND reason='confidence') ÷ total runs`.
`adapters/kyverno-json/policies/regression/` as declarative policies The `reason='confidence'` discriminator is not stored today.
over the capability-inventory JSON frontmatter. The imperative **Idea:** `ai.decision.made` gains `escalation_reason: 'confidence'`
`regression_verify.py` stays (it drives the CI gate); the policies are when `band == 'block'`. The collector persists it into `fact_run`.
the declarative mirror that makes capability regression auditable as a Grounds Human Escalation Frequency numerator.
policy artifact. **Accepted into:** REQ-318. Phase P3.
**Accepted into:** REQ-304 (policies), REQ-305 (tests). Phase P4.
### I2Contract-shape validation as policy ✅ ACCEPTED (REQ-295) ### I3Env-JSON `state_backend` wiring reconciliation ✅ ACCEPTED (REQ-319)
**Category:** security, architecture **Category:** architecture, improvement
**Confidence:** 0.92
**Pattern:** jsonschema constraint → declarative policy (same constraint,
different language, Nova posture on top).
**Source:** `schemas/contract.schema.json` required/pattern/enum.
**Idea:** The 4 contract policies (`require-id-pattern`,
`require-env-in-enum`, `require-infrastructure-min-1`, `forbid-unknown-
fields`) are the declarative equivalent of the jsonschema constraints —
they let Nova apply its own compliance posture (e.g. forbid a specific
env for a specific consumer) on top of schema validity without editing
the jsonschema.
**Accepted into:** REQ-295. Phase P2.
### I3 — Stack-IR imperative rules → declarative policies ✅ ACCEPTED (REQ-297)
**Category:** security, architecture
**Confidence:** 0.88 **Confidence:** 0.88
**Pattern:** imperative Python rule → declarative kyverno-json policy. **Pattern:** unused config field → wired config field (the
**Source:** `adapters/terraform/policy/custom_rules/nova_tagging.py` single-source-of-truth pattern).
(tagging), the v1.0 demo `public-ingress: true` rule, the v1.8 **Source:** `adapters/terraform/adapter.py:116-117` computes the state
D-encryption-default rule. bucket as `nova-tfstate-<AWS_ACCOUNT_ID>-us-east-1` from the
**Idea:** Port the three highest-impact imperative rules into `AWS_ACCOUNT_ID` env var — **not** from the env JSON's
declarative kyverno-json policies over the resolved Stack IR. The `state_backend.bucket`. The env JSON's `state_backend` field is
tagging rule is a cross-check (D-118 — both engines, agree meta-policy); currently unused by the live apply path.
public-ingress and encryption-by-default are kyverno-json only (the IR **Idea:** The adapter reads `env.state_backend.bucket` when present
is the earliest point these can be caught). (falling back to the computed name for backwards compat). `dev.json`
**Accepted into:** REQ-297. Phase P2. gets the real bucket name. Closes the wiring gap so the pilot's env
JSON is the single source of truth.
**Accepted into:** REQ-319. Phase P3.
### I4 — Pilot-readiness kyverno-json policy ✅ ACCEPTED (REQ-320)
**Category:** security, architecture
**Confidence:** 0.85
**Pattern:** runtime guard → declarative policy (the v1.25 thesis
applied to pilot onboarding).
**Source:** `core/environment_check.py:48-53` emits a stderr warning
(non-fatal) when `account_id == "000000000000"` and env != dev. A
warning is not a gate. The pilot should fail-closed if someone tries
to apply against a placeholder account.
**Idea:** A kyverno-json policy over the env JSON asserting
`account_id != "000000000000"` before any apply. Declarative
fail-closed gate. Extends v1.25's policy engine to the pilot-onboarding
domain.
**Accepted into:** REQ-320. Phase P3.
## Tier 2 — Backend-enriched (signal-driven) ## Tier 2 — Backend-enriched (signal-driven)
### I4Plan-JSON Checkov RULE_MAP → kyverno-json mirrors ✅ ACCEPTED (REQ-300) ### I5Settlement-finality kyverno-json policy ✅ ACCEPTED (REQ-315)
**Category:** security, coverage **Category:** security, coverage
**Confidence:** 0.85 **Confidence:** 0.82
**Pattern:** existing engine rule → declarative mirror in the new engine **Pattern:** domain invariant → declarative policy (the v1.25 thesis
(defense-in-depth against engine drift). applied to the securities domain — the most novel use of kyverno-json
**Source:** `checkov_adapter.py:RULE_MAP` (CKV_AWS_41/45/46, CKV_AWS_1/40, in v1.26).
CKV_AWS_7/33). **Source:** The pilot's settlement service records matches as
**Idea:** Port the 6 Checkov rules over `terraform_plan` into declarative transactions on the chain; settlement finality = block commit. The
kyverno-json policies over `terraform show -json` output. The Checkov NORTH_STAR Objective #2 (provable trust) says trust should be a policy
rules stay the source of truth for HCL scanning; the kyverno-json artifact, not a promise. Today settlement finality is a runtime
policies are mirrors (different rule language, same plan JSON). Defense- property of the chain; making it a declarative policy turns it into an
in-depth: if Checkov and kyverno-json disagree on the same plan, the auditable gate.
divergence is visible (two PCRs with different results for the same **Idea:** A kyverno-json policy over the settlement-service status JSON
resource). asserting `all_committed: true` before any promotion (qa→prod). The
**Accepted into:** REQ-300. Phase P3. securities-specific extension of v1.25's policy engine. The policy is
skip-when-kj-absent (graceful).
**Accepted into:** REQ-315. Phase P3.
### I5Meta-policy over the merged PCR list ✅ ACCEPTED (REQ-303) ### I6Pilot-estate regression capability (CAP-025) ✅ ACCEPTED (REQ-316)
**Category:** architecture, quality **Category:** quality, coverage
**Confidence:** 0.90 **Confidence:** 0.88
**Pattern:** the policy result list is itself a policy target (the most **Pattern:** manual e2e → regression-gated capability (the v1.0 CAP
novel use of kyverno-json in v1.25). pattern applied to the pilot).
**Source:** `core/confidence_signal.py` PENALTY hardcode (critical **Source:** `core/regression_verify.py` has CAP-013..024 (live-AWS +
override), the D-118 tagging cross-check. local tiers). The pilot estate is a new live-AWS capability —
**Idea:** `block-on-any-critical` (declarative "critical = block") + "contract resolve → adapter compile → terraform plan → policy scan →
`tagging-rules-agree` (Checkov vs kj agree). The meta-policies consume confidence signal → attestation → outbox record" against
the merged PCR list as their payload. The critical-block meta-policy is `581513795199`. Without a regression CAP, the pilot could silently
the declarative source of truth; the `confidence_signal.py` hard-override decay.
stays as defense-in-depth (D-119). **Idea:** CAP-025 (live-pilot-apply) in the regression gate. The
**Accepted into:** REQ-303. Phase P3. round-trip assertion. Grounds the pilot as a maintained capability,
not a one-shot demo.
**Accepted into:** REQ-316. Phase P3.
### I6Env-transition destroy as a declarative policy ❌ DEFERRED ### I7DynamoDB L1 primitive ✅ ACCEPTED (REQ-322)
**Category:** architecture, coverage
**Confidence:** 0.95
**Pattern:** missing primitive → authored module (the v1.7 + v1.8
module-build-out pattern).
**Source:** RESEARCH §3.4 — no `modules/l1/dynamodb/` exists. The
blockchain exchange's ledger table needs it. The adapter is
stateless/registry-driven (no `TYPE_MAP`); a new stack type requires a
new L1 module, not an adapter change.
**Idea:** Author `modules/l1/dynamodb/` (interface.json +
terraform/main.tf + README.md + instance.json + registry.json entry).
The single platform-side module build-out for the milestone. Follows
the `s3`/`rds` primitive template. Encryption + PITR enabled per v1.8
NFR defaults.
**Accepted into:** REQ-322. Phase P3.
### I8 — Stale `adapters/README.md` TYPE_MAP references ❌ DEFERRED (scope)
**Category:** improvement **Category:** improvement
**Confidence:** 0.55 (below threshold — deferred, not rejected) **Confidence:** 0.70 (above threshold, but scoped into REQ-321)
**Pattern:** imperative lifecycle Python → declarative policy. **Pattern:** stale doc → corrected doc.
**Source:** `core/env_transition.py` (v1.24 detect-and-destroy). **Source:** `adapters/README.md:49-54` references the deleted
**Idea:** The v1.24 env-transition destroy logic (detect env change via `TYPE_MAP`/`INPUT_MAP`/`OUTPUT_MAP` — contradicts `adapter.py:1-11` +
DynamoDB, destroy prior env, fail-closed) is imperative Python. A `modules/STANDARDS.md:212-214`.
declarative kyverno-json policy could assert "if `environment` changed **Idea:** Fix the stale references as part of the docs phase.
on a stable `contract.id`, a destroy event MUST precede the apply" — **Reason deferred as a standalone idea:** Already captured in REQ-321
turning the lifecycle enforcement into an auditable policy artifact. (docs + adapter README). No new requirement needed — the fix lands in
**Reason deferred:** The env-transition logic is *stateful* (DynamoDB P4 docs.
queries, terraform state inspection) — kyverno-json policies are
*stateless* (payload in, PCRs out). A policy can assert the *contract*
shape (the env value is valid) but not the *lifecycle* (the prior env
was destroyed). The stateful check stays in `core/env_transition.py`;
a future milestone could emit a `nova.env.destroyed` event that a
kyverno-json policy then asserts is present in the evidence stream
(event-as-policy). Recorded as a future-idea, not a v1.25 requirement.
### I7 — Drift detection as policy ❌ DEFERRED ## Tier 3 — Cross-project (deferred — multi-project, but cross-project sharing disabled)
**Category:** security, coverage ### I9 — Cross-project policy sharing ❌ DEFERRED (config)
**Confidence:** 0.40 (below threshold — deferred)
**Pattern:** scheduled job → policy over the drift report.
**Source:** NORTH_STAR.md Non-Goal #4 (drift detection scheduled job,
deferred — D-096 + no scheduler).
**Idea:** A kyverno-json policy over a terraform drift report could
assert "no drifted resources" declaratively. But drift detection itself
requires a scheduled `terraform plan -detailed-exitcode` job, which is
deferred (no scheduler). The policy is the easy part; the emitter is the
blocking dependency.
**Reason deferred:** Blocked by D-096 + no scheduler (same as NORTH_STAR
Non-Goal #4). The policy shape is documented for when the emitter ships.
## Tier 3 — Cross-project (deferred — single project)
### I8 — Cross-project policy sharing ❌ DEFERRED (config)
**Category:** improvement **Category:** improvement
**Confidence:** N/A **Confidence:** N/A
@@ -134,24 +154,41 @@ Non-Goal #4). The policy shape is documented for when the emitter ships.
**Source:** `config.json ideation.cross_project.enabled: false`. **Source:** `config.json ideation.cross_project.enabled: false`.
**Idea:** In a multi-project org, kyverno-json policies could be shared **Idea:** In a multi-project org, kyverno-json policies could be shared
across projects (a tagging standard policy applies to all projects). across projects (a tagging standard policy applies to all projects).
**Reason deferred:** ACDL is single-project (`active_projects: ["acdl"]`). **Reason deferred:** `cross_project.enabled: false`. Even though
Cross-project ideation is disabled in config. Recorded for when the v1.26 is multi-project (acdl + nova-blockchain-exchange),
org grows. cross-project *ideation* is disabled in config. Recorded for when the
org grows + the flag is enabled.
### I10 — Consumer-repo CI scaffolding as a reusable template ❌ DEFERRED
**Category:** improvement
**Confidence:** 0.55 (below threshold — deferred, not rejected)
**Pattern:** one-off CI → reusable template.
**Source:** The consumer repo (`nova-blockchain-exchange`) needs its
own CI (`ci.yml` — lint + pytest). If Nova expects many consumers, a
reusable consumer-CI template would reduce onboarding friction.
**Idea:** A `nova-consumer-template` repo (or a
`.github/workflow-templates/` dir) that new consumers instantiate.
**Reason deferred:** Nova has 1 consumer today (the pilot). A template
is premature abstraction until the 2nd consumer arrives. The pilot's
CI is authored directly (REQ-310..312 tests). Recorded for when the
3rd consumer onboards.
## Summary ## Summary
- 5 ideas accepted (I1..I5) → already captured as REQ-295, REQ-297, - 7 ideas accepted (I1..I7) → already captured as REQ-315, REQ-316,
REQ-300, REQ-303, REQ-304, REQ-305. REQ-317, REQ-318, REQ-319, REQ-320, REQ-322.
- 3 ideas deferred (I6, I7, I8) with documented blocking reasons. - 3 ideas deferred (I8 scoped into REQ-321; I9 config-disabled; I10
below threshold) with documented blocking reasons.
- 0 ideas rejected (below-threshold ideas are deferred, not rejected — - 0 ideas rejected (below-threshold ideas are deferred, not rejected —
they may activate when their blockers lift). they may activate when their blockers lift).
- The accepted ideas are the **quality improvement** the user asked for - The accepted ideas are the **quality improvement** the `--ideate` flag
("ideate and explore how it can be used within the Nova platform to drives: I1 + I2 ground the Post-Pilot metrics (outcome backfill +
improve quality of the platform checks"): I1 (regression-gate-as- escalation reason); I3 closes the env-JSON wiring gap; I4 + I5 extend
policy) is the headline quality improvement; I4 + I5 are the defense- v1.25's policy engine to the pilot domain (pilot-readiness +
in-depth coverage improvements; I2 + I3 are the architecture settlement-finality); I6 gates the pilot as a maintained capability;
improvements (imperative → declarative). I7 is the single platform-side module build-out.
- No new requirements added beyond REQ-291..309 (the accepted ideas are - No new requirements added beyond REQ-310..322 (the accepted ideas are
already scoped into the existing requirements). The IDEATE pass already scoped into the existing requirements). The IDEATE pass
validated the requirement set rather than expanding it — the ideas validated the requirement set rather than expanding it — the ideas
were anticipated in the SPECIFY stage and explicitly captured. were anticipated in the SPECIFY + RESEARCH stages.
+151 -114
View File
@@ -1,132 +1,169 @@
--- ---
project: acdl project: acdl
milestone: v1.25 milestone: v1.26
generated_at: 2026-08-12 generated_at: 2026-08-12
generator: lead-developer generator: lead-developer
verification_toolchain: verification_toolchain:
typecheck: "python3 -m py_compile core/policy_engine.py adapters/kyverno-json/kyverno_json_engine.py tests/test_policy_engine.py tests/test_kyverno_json_engine.py" typecheck: "python3 -m py_compile core/confidence_signal.py core/metrics/outcome_backfill.py adapters/terraform/adapter.py modules/l1/dynamodb/terraform/main.tf"
test: "pytest tests/test_policy_engine.py tests/test_kyverno_json_engine.py tests/test_adapter.py tests/test_contract_resolver.py tests/test_confidence_signal.py tests/test_checkov_adapter.py tests/test_kyverno_adapter.py tests/test_pipeline.py -v" test: "pytest tests/test_adapter.py tests/test_contract_resolver.py tests/test_confidence_signal.py tests/test_outcome_backfill.py tests/test_settlement_finality_policy.py tests/test_pilot_readiness_policy.py tests/test_block.py tests/test_order_book.py tests/test_settlement.py -v"
lint: "ruff check core/policy_engine.py adapters/kyverno-json/ 2>/dev/null || python3 -m py_compile core/policy_engine.py" lint: "ruff check core/metrics/outcome_backfill.py adapters/kyverno-json/policies/pilot-readiness/ adapters/kyverno-json/policies/settlement-finality/ 2>/dev/null || python3 -m py_compile core/metrics/outcome_backfill.py"
note: | note: |
v1.25 is the kyverno-json Unified Policy Engine milestone — a feat v1.26 is the Live Pilot Estate Activation milestone — a feat
milestone. Four active personas: lead-developer (coordination + milestone. Four active personas: lead-developer (coordination +
docs + ARCHITECTURE.md §12.7), backend-engineer (core/policy_engine.py docs + ARCHITECTURE.md §12.8), backend-engineer (confidence_signal.py
protocol + registry + contract_resolver.py wiring + run_platform.sh escalation reason + outcome_backfill.py + run_platform.sh wiring +
Step 5 + pipeline tests), policy-engineer (adapters/kyverno-json/ env-JSON state_backend reconciliation), data-engineer (DynamoDB L1
engine + policies across all 4 target dirs + meta-policies + policy primitive + metrics cold store outcome backfill), policy-engineer
tests + adapter README + STANDARDS.md policy-authoring section), (kyverno-json pilot-readiness + settlement-finality policies), +
data-engineer (config.json policy object + schemas/README.md note + blockchain-engineer (custom, phase-specific — chain core + order
capability-inventory JSON fixture for regression policies). engine + settlement). frontend-engineer is deactivated (no UI).
frontend-engineer stays deactivated (no UI). The policy-engineer is a Territory enforcement: warn (the pilot is cross-territory by
new custom persona created for this milestone's policy domain (see nature — the consumer repo + the platform repo share the milestone).
RESEARCH.md §4 — kyverno-json + JMESPath is a distinct framework from
backend-engineer's fastify/hono).
--- ---
# ACDL — Persona Roster (v1.25 kyverno-json Unified Policy Engine) # PERSONAS — v1.26 Live Pilot Estate Activation
> v1.25 roster. Four active personas + one deactivated. This is a feat > Generated by the lead-developer at the end of RESEARCH. Assesses the
> milestone: the work is a swappable policy-engine protocol + a new > project domains, activates/deactivates personas, creates custom
> adapter + policies across 4 Nova artifacts + pipeline wiring + docs. > personas for domains beyond the default four, aligns frameworks +
> The policy-engineer is a new custom persona — kyverno-json + JMESPath > territory + constraints to the actual project structure.
> is a specialized domain that doesn't fit backend-engineer's
> fastify/hono frameworks or data-engineer's drizzle/postgresql.
## Active personas ## Active Roster (5)
### lead-developer ### 1. lead-developer (active)
- **Domain:** coordination + docs - **active:** true
- **Frameworks:** [] - **phase_specific:** false
- **Constraints:** ["pragmatic", "battle-tested defaults", "docs match code", "swap boundary is the moat"] - **reason:** Coordinates task decomposition + resolves conflicts between
- **Territory:** engineering personas. Owns the milestone narrative (PROJECT.md,
- `.ciagent/ARCHITECTURE.md` (§12.7 Policy Engine Registry — NEW) ROADMAP.md, ARCHITECTURE.md §12.8). Final architectural decisions when
- `.ciagent/PROJECT.md` (v1.25 section) personas disagree (e.g. where the outcome-backfill emitter lives).
- `.ciagent/REQUIREMENTS.md` (v1.25 section) - **domain:** project coordination, milestone narrative, cross-persona
- `.ciagent/ROADMAP.md` (v1.25 section) conflict resolution.
- `.ciagent/PLAN.md`, `.ciagent/RESEARCH.md`, `.ciagent/CLARIFY.md`, - **frameworks:** none (coordination role).
`.ciagent/GRILL.md`, `.ciagent/PERSONAS.md` - **territory:** `.ciagent/`, `docs/METRICS.md`, `adapters/README.md`,
- `docs/METRICS.md` (swappable engine narrative — REQ-307) `modules/README.md`, `modules/STANDARDS.md`.
- **Reason:** Owns the milestone coordination + the architecture - **constraints:** does not write Python/Terraform (delegates to
narrative. The swap boundary (PolicyEngine protocol) is the moat per backend/data-engineer); does not author policies (delegates to
Strategic Objective #2 — the lead-developer owns the boundary policy-engineer); does not author chain code (delegates to
description in ARCHITECTURE.md §12.7 and the docs/METRICS.md note. blockchain-engineer).
No Python policy code (backend-engineer + policy-engineer territory).
No UI (frontend-engineer deactivated).
### backend-engineer ### 2. backend-engineer (active)
- **Domain:** backend (Python + bash + pipeline wiring) - **active:** true
- **Frameworks:** ["boto3", "terraform"] - **phase_specific:** false
- **Constraints:** ["api-first", "strict-typing", "engine-agnostic confidence signal", "fail-soft when kj absent"] - **reason:** Owns the platform-side Python changes: confidence signal
- **Territory:** escalation reason (REQ-318), outcome-backfill emitter (REQ-317),
- `core/policy_engine.py` (NEW — PolicyEngine Protocol + PolicyEngineRegistry + NullEngine) env-JSON state_backend wiring (REQ-319), adapter test updates for
- `core/contract_resolver.py` (MODIFIED — invoke registry pre/post resolve) DynamoDB (REQ-322), regression CAP-025 (REQ-316).
- `scripts/run_platform.sh` (MODIFIED — Step 5 kyverno-json parallel pass) - **domain:** core Python (confidence_signal.py, metrics/, adapter.py,
- `scripts/install-kyverno-json.sh` (NEW) regression_verify.py, contract_resolver.py), run_platform.sh wiring.
- `tests/test_policy_engine.py` (NEW — protocol conformance, registry, NullEngine) - **frameworks:** Python 3.12, pytest, boto3, SQLite, DynamoDB.
- `tests/test_run_platform_plan_json_policies.py` (NEW — script-substring assertion) - **territory:** `core/confidence_signal.py`, `core/metrics/`,
- `.github/workflows/ci.yml` + `.gitea/workflows/ci.yml` (MODIFIED — Go + kj install) `adapters/terraform/adapter.py`, `core/regression_verify.py`,
- **Reason:** Owns the Python protocol layer + the pipeline wiring. The `core/environments/`, `scripts/run_platform.sh`, `tests/test_adapter.py`,
`PolicyEngine` Protocol + `PolicyEngineRegistry` are Python structural- `tests/test_confidence_signal.py`, `tests/test_outcome_backfill.py`,
typing constructs (PEP 544) — backend-engineer's strict-typing `tests/test_regression_pilot.py`.
constraint. The `contract_resolver.py` wiring + `run_platform.sh` - **constraints:** does not change `schemas/policy_check_result.schema.json`
Step 5 are backend territory. Does NOT write kyverno-json policy (v1.25 moat, D-211); does not change `schemas/contract.schema.json`
files (policy-engineer territory) — only the Python that *invokes* the (no schema breaks, D-213); does not author Terraform modules
engine. Does NOT modify the confidence signal (it already consumes (delegates to data-engineer for DynamoDB); does not author policies
`list[PolicyCheckResult]` engine-agnostically — PROJECT.md hard- (delegates to policy-engineer); does not author chain code (delegates
constraint). to blockchain-engineer).
### policy-engineer ### 3. data-engineer (active)
- **Domain:** policy (declarative compliance rules) - **active:** true
- **Frameworks:** ["kyverno-json", "jmespath", "kyverno ValidatingPolicy"] - **phase_specific:** false
- **Constraints:** ["declarative-policies", "no-imperative-rules", "schema-validated", "severity-via-annotation", "assertion-trees-not-foreach"] - **reason:** Owns the DynamoDB L1 primitive (REQ-322) — the single
- **Territory:** platform-side module build-out. Owns the metrics cold store
- `adapters/kyverno-json/` (NEW — engine impl + __init__.py + README) outcome-backfill integration (REQ-317, the `fact_decision.outcome`
- `adapters/kyverno-json/kyverno_json_engine.py` (NEW — KyvernoJsonEngine) column + `backfilled_at` timestamp). Owns the env-JSON data updates
- `adapters/kyverno-json/policies/` (NEW — all 4 target dirs: contract/, stack-ir/, plan-json/, meta/, regression/) (REQ-319, `core/environments/*.json` account_id + state_backend.bucket).
- `adapters/kyverno-json/policies/_smoke.json` (NEW) - **domain:** Terraform modules (`modules/l1/`), schema definitions
- `adapters/README.md` (MODIFIED — new adapter row + PolicyEngine Protocol section) (`interface.json`), registry (`modules/registry.json`), metrics cold
- `tests/test_kyverno_json_engine.py` (NEW — PCR schema validity, defensive parsing) store (`metrics/nova_metrics.db`, `core/metrics/collector.py`).
- `tests/test_stack_ir_policies.py` (NEW) - **frameworks:** Terraform, JSON, SQLite, DynamoDB, boto3.
- `tests/test_plan_json_policies.py` (NEW) - **territory:** `modules/l1/dynamodb/`, `modules/registry.json`,
- `tests/test_meta_policies.py` (NEW) `modules/README.md`, `core/environments/*.json`,
- `tests/test_regression_policies.py` (NEW) `core/metrics/collector.py`, `tests/test_adapter.py` (DynamoDB
- `tests/fixtures/stack_ir/`, `tests/fixtures/plan_json/`, `tests/fixtures/capability_inventory.json` (NEW) emission test).
- `modules/STANDARDS.md` (MODIFIED — Policy authoring standard section — REQ-307) - **constraints:** does not change the adapter (stateless, v1.11);
- **Reason:** The policy-engineer owns the declarative policy artifacts. follows the v1.8 NFR defaults (encryption + deletion protection +
kyverno-json's `ValidatingPolicy` + assertion trees + JMESPath is a PITR); follows the module standards (`modules/STANDARDS.md`).
distinct framework from backend-engineer's fastify/hono and requires
its own constraints: no imperative rules (everything is an assertion
tree), severity via the `nova.cloudinit.dev/severity` annotation (not
in the engine adapter), no `forEach` (use the `~` modifier). The
adapter pattern (engine ↔ protocol ↔ registry) is backend-engineer
territory, but the policy *content* and the engine *translation*
(`_to_pcr()`) are policy-engineer territory because they require
kyverno-json output-shape knowledge. Created per RESEARCH.md §4 — this
is a phase-spanning persona (active for P1..P4), not phase-specific.
### data-engineer ### 4. policy-engineer (active, custom — added in v1.25)
- **Domain:** data (config schema + structured fixtures) - **active:** true
- **Frameworks:** ["jsonschema", "yaml"] - **phase_specific:** false
- **Constraints:** ["schema-first", "type-safe config", "backward-compatible additions"] - **reason:** Owns the kyverno-json policy authoring for the pilot:
- **Territory:** settlement-finality (REQ-315), pilot-readiness (REQ-320). Extends
- `.ciagent/config.json` (MODIFIED — new `policy` object: engine + policy_root) v1.25's policy engine to the securities domain.
- `schemas/policy_check_result.schema.json` (READ-ONLY — no change per D-116) - **domain:** declarative policies (kyverno-json ValidatingPolicy YAML),
- `schemas/README.md` (MODIFIED — note engine: "kyverno" shared by K8s adapter + kj) JMESPath assertions, policy tests.
- `tests/fixtures/capability_inventory.json` (NEW — clean + drifted inventory fixtures for regression policies) - **frameworks:** kyverno-json, JMESPath, JSON, pytest.
- **Reason:** The `config.json.policy` object is a schema-first addition - **territory:** `adapters/kyverno-json/policies/pilot-readiness/`,
(new top-level key with `engine` + `policy_root` fields). The `adapters/kyverno-json/policies/settlement-finality/`,
capability-inventory JSON fixtures for the regression-gate policies `tests/test_settlement_finality_policy.py`,
(REQ-304) are structured data — the data-engineer owns the fixture `tests/test_pilot_readiness_policy.py`.
shape. The `policy_check_result.schema.json` is read-only (D-116 — no - **constraints:** policies are declarative (no imperative Python);
enum change); the data-engineer documents the `engine: "kyverno"` `is_configured()` guard skips gracefully when `kj` absent; follows
sharing in `schemas/README.md`. No migrations (no database). No Python the v1.25 policy-authoring standard (`modules/STANDARDS.md` policy
(backend-engineer + policy-engineer territory). section + `adapters/kyverno-json/README.md`).
## Deactivated personas ### 5. blockchain-engineer (active, custom, phase-specific — added in v1.26)
- **active:** true
- **phase_specific:** true (created for v1.26 P1; removed after P1
unless the chain has ongoing work in P2..P4)
- **reason:** The pilot introduces a homegrown blockchain — a domain
beyond the default four personas. Owns the chain core (block, ledger,
validator, REQ-310), the order-matching engine (REQ-311), the
settlement service (REQ-312), and the consumer `contract.yaml`
(REQ-313) + deploy invocation (REQ-314).
- **domain:** blockchain consensus (PoA, single validator), order
matching (limit order book, price-time priority), settlement
(T+1, finality = block commit), consumer-repo deploy model.
- **frameworks:** Python 3.12 (the chain is Python, not Solidity/Go —
it's a homegrown ledger, not a smart-contract platform), pytest,
YAML (contract.yaml), GitHub Actions / Gitea Actions (deploy.yml
invocation).
- **territory:** `/root/nova-blockchain-exchange/` (the consumer repo:
`chain/`, `engine/`, `settlement/`, `contract.yaml`,
`contracts/*.yml`, `.github/workflows/deploy.yml`,
`.gitea/workflows/deploy.yml`, `tests/`).
- **constraints:** the chain is deterministic (same inputs → same block)
— it is automation, not AI (NORTH_STAR Objective #2 tenet); equities
only (D-200); single validator PoA (D-201); the consumer deploy MUST
go through `deploy.yml@v1.25` (no direct terraform apply); the
contract MUST validate against `schemas/contract.schema.json`.
### frontend-engineer ## Deactivated (1)
### frontend-engineer (inactive)
- **active:** false - **active:** false
- **Reason:** ACDL has no frontend (no package.json — confirmed in - **phase_specific:** false
config.json personas.personas[frontend-engineer].reason). v1.25 adds - **reason:** The pilot has no UI — the blockchain exchange is a
no UI work — the policy engine is backend + policy artifacts only. backend service (matching engine + settlement). The consumer repo
Deactivated per the v1.15+ convention. has no web/frontend. Reactivated if a future milestone adds a trading
dashboard.
## Phase-Specific Notes
- **blockchain-engineer** is created for v1.26 P1 (blockchain core +
order engine + settlement). If P2..P4 have no chain changes, the
persona is removed after P1 (the chain is a stable substrate for the
pilot run). If P2 (consumer-contract-and-deploy) requires chain
adjustments, the persona stays through P2.
- **policy-engineer** is active for P3 (pilot-metrics-and-policies) +
may consult on P4 (pilot run policy verification).
- **data-engineer** is active for P3 (DynamoDB primitive + outcome
backfill + env-JSON) + P4 (regression CAP-025 may touch the registry).
## Territory Enforcement
- **Mode:** `warn` (the pilot is cross-territory by nature — the
consumer repo + the platform repo share the milestone; the
blockchain-engineer works in the consumer repo, backend/data/policy
engineers work in the platform repo).
- **Cross-territory collisions:** REQ-322 (DynamoDB primitive) is
data-engineer territory, but the adapter test update
(`tests/test_adapter.py` `EXPECTED_L1_KEYS`) is backend-engineer
territory. The lead-developer resolves: data-engineer authors the
module + registry; backend-engineer updates the test assertion
(the test is backend territory, the module is data territory).
+369 -330
View File
@@ -1,371 +1,410 @@
# PLAN — v1.25 (kyverno-json Unified Policy Engine) # PLAN — v1.26 (Live Pilot Estate Activation)
> Feature milestone. Tags on the **v1.24.x** line: v1.24.0 (P0) → > Feature milestone. Tags on the **v1.25.x** line: v1.25.0 (P0) →
> v1.24.1 (P1) → v1.24.2 (P2) → v1.24.3 (P3) → v1.24.4 (P4) → v1.24.5 > v1.25.1 (P1) → v1.25.2 (P2) → v1.25.3 (P3) → v1.25.4 (P4) → v1.25.5
> (P5 final = milestone release). 19 requirements (REQ-291..309), > (P5 final = milestone release). 13 requirements (REQ-310..322),
> 4 execution phases + P0 pre-execution + P5 final review/ship. > 5 phases (P0 pre-execution + 4 execution + 1 final). Multi-project:
> `acdl` (platform) + `nova-blockchain-exchange` (consumer). Tags run
## Wave model > on the previous minor's patch line per `run.md` versioning logic
> (feature milestone — at least one feat phase; progressive patches per
Each phase is a **vertical slice** (end-to-end: policy files + Python > phase; the final phase's patch IS the milestone release; no separate
wiring + tests + docs). Phases are ordered by dependency: the engine > minor tag).
protocol (P1) must exist before policies (P2/P3) can be wired; the
pipeline wiring (P3) must exist before the meta-policies (P3) can
consume the merged PCR list; the regression-gate policies (P4) are
independent of the pipeline and can be authored in parallel with P3's
tests, but ship after P3 because they reference the engine registry
finalized in P1. Within each phase, the waves are the persona task
groups (parallelizable across personas when `parallelization.enabled:
true`, `max_concurrent_agents: 5`).
## Phase breakdown
### Phase P1 — engine-core (Wave 1, backend-engineer + policy-engineer + data-engineer)
**Type:** `feat` (engine protocol + registry + kyverno-json engine adapter + install + tests)
**Requirements:** REQ-291, REQ-292, REQ-293, REQ-294, REQ-308, REQ-309
**Must-haves:**
- `core/policy_engine.py``PolicyEngine` Protocol (PEP 544) +
`PolicyEngineRegistry` (selects from `config.json.policy.engine`) +
`NullEngine` fallback (emits `SKIPPED` when `policy` key absent)
(REQ-291)
- `.ciagent/config.json` gains `policy` object: `{"engine":
"kyverno-json", "policy_root":
"adapters/kyverno-json/policies"}` (REQ-292)
- `adapters/kyverno-json/kyverno_json_engine.py` — `KyvernoJsonEngine`
implementing the protocol: `is_configured()` guards on `which kj`;
`evaluate()` writes payload to temp JSON, invokes
`kj scan --policy <dir> --payload <json> --output json`, translates
native output → `list[dict]` PCR records (`engine: "kyverno"`,
`ruleId` prefixed `KJ_<policy_name>`, severity from
`nova.cloudinit.dev/severity` annotation); defensive parsing
(malformed → `error` PCR, never exception); `is_configured()==false`
→ single `SKIPPED` PCR (`KJ_ENGINE_NOT_CONFIGURED`) (REQ-293)
- `adapters/kyverno-json/__init__.py` exports `KyvernoJsonEngine`;
`adapters/kyverno-json/policies/_smoke.json` trivial
`require-contract-id` policy for round-trip validation;
`scripts/install-kyverno-json.sh` runs
`go install github.com/kyverno/kyverno-json/cmd/kj@latest`;
`.github/workflows/ci.yml` + `.gitea/workflows/ci.yml` install Go + kj
(cached) (REQ-294)
- `tests/test_policy_engine.py` — protocol conformance, registry
selection, unknown-engine `KeyError`, `NullEngine` fallback,
`is_configured()` false when `which kj` absent (mocked) (REQ-308)
- `tests/test_kyverno_json_engine.py` — `evaluate()` returns PCR dicts
validating against `schemas/policy_check_result.schema.json` (via
`jsonschema`); defensive parsing (malformed kyverno-json output →
`error` PCR); `is_configured()==false` → `SKIPPED` with
`KJ_ENGINE_NOT_CONFIGURED`; `pytest.skip("kj not installed")` when
`which kj` absent (REQ-309)
**Vertical slice:** The `PolicyEngineRegistry.get_engine()` returns a
configured `KyvernoJsonEngine` that can `evaluate()` a trivial payload
against `_smoke.json` and produce a valid PCR list. The confidence
signal is unchanged — it already consumes `list[PolicyCheckResult]`.
The platform runs with or without the `kj` binary (`is_configured()`
guard). All existing tests pass (NullEngine fallback when `policy` key
absent in test config — but the v1.25 config.json *sets* the key, so
existing tests that use the real config get `KyvernoJsonEngine` with
`is_configured()==false` → `SKIPPED`).
**Files touched:**
- `core/policy_engine.py` (NEW)
- `.ciagent/config.json` (MODIFIED — `policy` object)
- `adapters/kyverno-json/__init__.py` (NEW)
- `adapters/kyverno-json/kyverno_json_engine.py` (NEW)
- `adapters/kyverno-json/policies/_smoke.json` (NEW)
- `scripts/install-kyverno-json.sh` (NEW)
- `.github/workflows/ci.yml` (MODIFIED — Go + kj install step)
- `.gitea/workflows/ci.yml` (MODIFIED — Go + kj install step)
- `tests/test_policy_engine.py` (NEW)
- `tests/test_kyverno_json_engine.py` (NEW)
**Verification:** `pytest tests/test_policy_engine.py
tests/test_kyverno_json_engine.py tests/test_confidence_signal.py
tests/test_adapter.py tests/test_checkov_adapter.py
tests/test_kyverno_adapter.py -v` (new tests pass or skip-without-kj;
existing adapter/confidence tests unchanged). `python3 -m py_compile
core/policy_engine.py adapters/kyverno-json/kyverno_json_engine.py`.
--- ---
### Phase P2contract + stack-IR policies (Wave 2, policy-engineer + backend-engineer) ## Phase 0Pre-Execution (complete, tag v1.25.0)
**Type:** `feat` (policies + resolver wiring + tests) SPECIFY → CLARIFY → RESEARCH → IDEATE → PLAN → GRILL. All `.ciagent/`
MD, research, plans. Ships as `v1.25.0` on the v1.25.x line.
**Requirements:** REQ-295, REQ-296, REQ-297, REQ-298, REQ-299 **Pre-run (Workstream A, on main before branch gate):**
- A1: flaky test fix (commit `8c68d68`, pushed).
- A2: ACDL_*→NOVA_* bootstrap migration (commit `f844fea`, pushed).
- A3: AWS bootstrap — S3 state bucket + DynamoDB outbox created.
- A4: `nova-blockchain-exchange` Gitea repo created + cloned.
**Must-haves:** **Phase 0 stages (on `phase/00-specify-clarify-research-plan`):**
- `adapters/kyverno-json/policies/contract/` — 4 policies over consumer - SPECIFY: v1.26 established in config.json + PROJECT.md + ROADMAP.md +
contract JSON: `require-id-pattern.json`, `.ciagent/nova-blockchain-exchange/{PROJECT,REQUIREMENTS,ROADMAP}.md`.
`require-env-in-enum.json`, `require-infrastructure-min-1.json`, - CLARIFY: 10 ambiguities resolved (D-200..D-213).
`forbid-unknown-fields.json` — each a `ValidatingPolicy` with one - RESEARCH: PoA blockchain, deploy model, DynamoDB gap (REQ-322),
`validate.assert` rule using JMESPath against the payload root; metric grounding, persona assessment (5 personas).
severity via `nova.cloudinit.dev/severity` annotation (REQ-295) - IDEATE: 7 ideas accepted (I1..I7 → REQ-315..322), 3 deferred.
- `core/contract_resolver.py` invokes - PLAN: this file.
`PolicyEngineRegistry.get_engine().evaluate(contract_dict, - GRILL: adversarial review (binding verdicts).
policies/contract/, contract_id)` **before** resolving; failures
feed the `policy` input as `fail` PCRs (no resolver exit — confidence
signal decides the gate, `--soft-fail` pattern); emits
`nova.policy.evaluated` metrics event (REQ-296)
- `adapters/kyverno-json/policies/stack-ir/` — 3 policies over
resolved Stack IR: `require-tagging-standard.json` (ports
`nova_tagging.py` — `nova:owner` + `nova:environment` tags on every
`resources[]` entry), `forbid-public-ingress.json` (v1.0 demo rule),
`require-encryption-by-default.json` (v1.8 D-encryption-default);
`~` modifier iterates `resources[]` (REQ-297)
- `core/contract_resolver.py` invokes the engine with the resolved
Stack IR and `policies/stack-ir/` **after** resolving; resulting PCRs
appended to the contract-policy PCRs; resolver return values and
exceptions unchanged (additive) (REQ-298)
- `tests/test_stack_ir_policies.py` + `tests/fixtures/stack_ir/` —
passing IR (all tags + encryption) + failing IR (missing tags, public
ingress, plaintext bucket); each policy in isolation + full dir as
bundle; `pytest.skip("kj not installed")` when `which kj` absent
(REQ-299)
**Vertical slice:** A consumer contract passes through the resolver
and produces two PCR lists (contract policies pre-resolve, stack-IR
policies post-resolve) that feed the confidence signal. A contract
with a bad `id` or missing tags produces `fail` PCRs that lower the
confidence score. The resolver's existing tests pass unchanged (the
policy call is additive — it does not change resolver return values
or exceptions).
**Files touched:**
- `adapters/kyverno-json/policies/contract/require-id-pattern.json` (NEW)
- `adapters/kyverno-json/policies/contract/require-env-in-enum.json` (NEW)
- `adapters/kyverno-json/policies/contract/require-infrastructure-min-1.json` (NEW)
- `adapters/kyverno-json/policies/contract/forbid-unknown-fields.json` (NEW)
- `adapters/kyverno-json/policies/stack-ir/require-tagging-standard.json` (NEW)
- `adapters/kyverno-json/policies/stack-ir/forbid-public-ingress.json` (NEW)
- `adapters/kyverno-json/policies/stack-ir/require-encryption-by-default.json` (NEW)
- `core/contract_resolver.py` (MODIFIED — pre/post resolve engine calls)
- `tests/test_stack_ir_policies.py` (NEW)
- `tests/fixtures/stack_ir/passing.json` (NEW)
- `tests/fixtures/stack_ir/failing.json` (NEW)
**Verification:** `pytest tests/test_contract_resolver.py
tests/test_stack_ir_policies.py tests/test_policy_engine.py -v`
(existing resolver tests pass; new policy tests pass or skip-without-
kj). `python3 -m py_compile core/contract_resolver.py`.
--- ---
### Phase P3plan-JSON policies + meta-orchestration + pipeline wiring (Wave 3, policy-engineer + backend-engineer) ## Phase 1blockchain-core (tag v1.25.1)
**Type:** `feat` (plan-JSON policies + meta-policies + run_platform.sh wiring + tests) **Goal:** The consumer repo has a working homegrown PoA blockchain +
order-matching engine + settlement service. All unit tests pass in the
consumer repo's own CI.
**Requirements:** REQ-300, REQ-301, REQ-302, REQ-303 **Project:** `nova-blockchain-exchange` (consumer repo).
**Branch:** `nova-blockchain-exchange/phase/01-blockchain-core`.
**Persona:** blockchain-engineer (primary), lead-developer (coordination).
**Must-haves:** ### Wave 1 — chain core (REQ-310)
- `adapters/kyverno-json/policies/plan-json/` — 3 policies over - **Task 1.1** (blockchain-engineer): `chain/block.py` — Block dataclass
`terraform show -json` output: `forbid-plaintext-secrets.json` (ports (index, timestamp, prev_hash, transactions, nonce, hash).
CKV_AWS_41/45/46), `forbid-iam-wildcard.json` (ports CKV_AWS_1/40), `compute_hash()` deterministic (SHA-256). Unit test: `test_block.py`.
`require-kms-reference.json` (ports CKV_AWS_7/33); JMESPath over - **Task 1.2** (blockchain-engineer): `chain/ledger.py` — Ledger class:
`planned_values.root_module.resources[]` (REQ-300) `append_block()`, `verify_chain()`, `get_block(index)`,
- `run_platform.sh` Step 5 gains a parallel kyverno-json pass: after `get_latest_block()`. Genesis block on init. Unit test: `test_ledger.py`.
Checkov/Wiz produce raw PCRs, the script runs - **Task 1.3** (blockchain-engineer): `chain/validator.py` — PoA
`kj scan --policy adapters/kyverno-json/policies/plan-json/ validator: single validator (config-driven), `propose_block(transactions)`
--payload <tfshow.json> -o json` and pipes through → Block, `commit_block(block)`. Unit test: `test_validator.py`.
`adapters/kyverno-json/kyverno_json_engine.py` to produce a second
PCR list; both lists concatenated and fed to the confidence signal;
`nova.policy.evaluated` event with both engine names; when
`which kj` is false, logs and proceeds with Checkov/Wiz list only
(no hard failure) (REQ-301)
- `tests/test_plan_json_policies.py` + `tests/fixtures/plan_json/` —
passing plan (no secrets, no wildcard, KMS alias) + failing plan
(plaintext password, `Action: "*"`, inline KMS key); policies in
isolation + bundle; `tests/test_run_platform_plan_json_policies.py`
asserts `run_platform.sh` has the kyverno-json Step 5 block +
concatenates PCR lists (script-substring assertion, pattern from
`tests/test_pipeline.py:79-95`) (REQ-302)
- `adapters/kyverno-json/policies/meta/` — `block-on-any-critical.json`
(asserts no PCR in merged list has `severity: critical` + `result:
fail`; if any does, emits `fail` PCR `KJ_META_BLOCK_CRITICAL`
severity `critical` — declarative source of truth; the
`confidence_signal.py` hard-override stays as defense-in-depth per
D-119) + `tagging-rules-agree.json` (cross-checks Checkov
`NOVA_TAG_NAMING` vs kj `KJ_REQUIRE_TAGGING_STANDARD` by
`resourceRef`; divergence emits `error` PCR per D-118);
`tests/test_meta_policies.py` (REQ-303)
**Vertical slice:** `run_platform.sh` Step 5 produces a merged PCR list ### Wave 2 — order engine + settlement (REQ-311, REQ-312) — parallel with Wave 1 tail
(Checkov/Wiz + kj plan-JSON policies + kj meta-policies over the - **Task 2.1** (blockchain-engineer): `engine/order.py` — Order
merged list) that feeds the confidence signal. A plan with a plaintext dataclass (id, side, symbol, price, size, timestamp).
secret produces two `fail` PCRs (one Checkov, one kj) for the same - **Task 2.2** (blockchain-engineer): `engine/order_book.py`
resource — visible defense-in-depth. A critical finding anywhere OrderBook: `add_order(order)`, `match_orders()` → list of Match
produces a `KJ_META_BLOCK_CRITICAL` meta-PCR that the confidence (price-time priority, partial fills). Unit test: `test_order_book.py`.
signal's hard-override blocks. The pipeline runs with or without `kj` - **Task 2.3** (blockchain-engineer): `settlement/service.py`
(graceful skip). SettlementService: `settle(match)` → SettlementTransaction,
`submit(ledger)`. Idempotent (re-settling a match is a no-op once
final). Finality = block commit. Unit test: `test_settlement.py`.
**Files touched:** ### Wave 3 — consumer CI (cross-cutting)
- `adapters/kyverno-json/policies/plan-json/forbid-plaintext-secrets.json` (NEW) - **Task 3.1** (blockchain-engineer): `.github/workflows/ci.yml` +
- `adapters/kyverno-json/policies/plan-json/forbid-iam-wildcard.json` (NEW) `.gitea/workflows/ci.yml` — lint + pytest on chain/engine/settlement.
- `adapters/kyverno-json/policies/plan-json/require-kms-reference.json` (NEW) - **Task 3.2** (lead-developer): `nova-blockchain-exchange/README.md`
- `adapters/kyverno-json/policies/meta/block-on-any-critical.json` (NEW) repo overview + dev setup.
- `adapters/kyverno-json/policies/meta/tagging-rules-agree.json` (NEW)
- `scripts/run_platform.sh` (MODIFIED — Step 5 kj parallel pass)
- `tests/test_plan_json_policies.py` (NEW)
- `tests/test_meta_policies.py` (NEW)
- `tests/test_run_platform_plan_json_policies.py` (NEW)
- `tests/fixtures/plan_json/passing.json` (NEW)
- `tests/fixtures/plan_json/failing.json` (NEW)
**Verification:** `pytest tests/test_plan_json_policies.py **Must-haves (verify before ship):**
tests/test_meta_policies.py tests/test_run_platform_plan_json_policies.py - `pytest tests/` in the consumer repo passes (chain integrity, hash
tests/test_pipeline.py -v` (new tests pass or skip-without-kj; existing determinism, genesis, append/verify, match priority, partial fills,
pipeline tests pass). `python3 -m py_compile` on any modified Python. settlement idempotency, finality check).
Shellcheck on `run_platform.sh` if available. - The chain is deterministic (replay produces the same hash chain).
- The consumer CI workflow runs on push.
**Ship:** tag `v1.25.1`, merge `phase/01``milestone/v1.26-pilot-activation`,
Gitea release (best-effort). Delete `phase/01`.
--- ---
### Phase P4regression-gate policies + docs (Wave 4, policy-engineer + data-engineer + lead-developer) ## Phase 2consumer-contract-and-deploy (tag v1.25.2)
**Type:** `feat` (regression policies) + `docs` (adapter READMEs + ARCHITECTURE + STANDARDS + METRICS) **Goal:** The consumer repo declares its infrastructure via
`contract.yaml` (validated against the platform's schema) + invokes the
platform's `deploy.yml@v1.25` workflow. The contract references the
`microservice` (ECS), `dynamodb`, + `s3` modules.
**Requirements:** REQ-304, REQ-305, REQ-306, REQ-307 **Project:** `nova-blockchain-exchange` (consumer repo) + `acdl`
(platform repo — for the `deploy.yml@v1.25` ref + the `v1.25` floating
tag).
**Branch:** `nova-blockchain-exchange/phase/02-contract-and-deploy`.
**Persona:** blockchain-engineer (contract authoring), data-engineer
(registry/DynamoDB dependency check), lead-developer (deploy.yml ref).
**Must-haves:** ### Wave 1 — contract (REQ-313)
- `adapters/kyverno-json/policies/regression/` — 3 policies over - **Task 1.1** (blockchain-engineer): `contract.yaml` — id
capability-inventory JSON frontmatter: `cap-013-adapter-dedup.json`, (`blkex`), name (`blockchain-exchange`), environment (dev),
`cap-023-metrics-collector.json`, `cap-024-deck-structure.json`; infrastructure block (microservice + dynamodb + s3).
emit `pass`/`fail` PCRs per capability; the existing - **Task 1.2** (blockchain-engineer): `contracts/blockchain-exchange.dev.yml`,
`core/regression_verify.py` is kept (drives the CI gate); the `.qa.yml`, `.prod.yml` — per-env variants.
policies are the declarative mirror (REQ-304) - **Task 1.3** (blockchain-engineer): `tests/test_contract_validates.py`
- `tests/test_regression_policies.py` + — schema validation against the platform's
`tests/fixtures/capability_inventory/clean.json` + `schemas/contract.schema.json`.
`tests/fixtures/capability_inventory/drifted.json` — clean (all caps
pass) + drifted (duplicate adapter, missing metric status, broken
deck arc); regression gate still 287/287 baseline (new tests
additive, skip-without-kj) (REQ-305)
- `adapters/README.md` gains new kyverno-json adapter row + "Policy
Engine Protocol" section (Protocol, registry, swap boundary,
how-to-add-OpaEngine); `adapters/kyverno-json/README.md` documents
the engine, install path, policy directory layout, 4 policy
categories (REQ-306)
- `.ciagent/ARCHITECTURE.md` §12.7 (added in RESEARCH) is finalized;
`schemas/README.md` notes `engine: "kyverno"` shared by K8s adapter
+ kj (distinguished by `ruleId` prefix); `modules/STANDARDS.md`
gains "Policy authoring standard" section for module owners;
`docs/METRICS.md` notes the policy engine is swappable (Strategic
Objective #2 — provable trust via a replaceable substrate) (REQ-307)
**Vertical slice:** The regression gate's capability checks are now ### Wave 2 — deploy invocation (REQ-314)
declarative policies auditable as artifacts. A new module owner can - **Task 2.1** (blockchain-engineer): `.github/workflows/deploy.yml`
read `modules/STANDARDS.md` "Policy authoring standard" and write a `uses: acdl/.github/workflows/deploy.yml@v1.25` with
per-module kyverno-json policy. A new engineer can read `with: { contract: contract.yaml, mode: full, environment: dev }`.
`adapters/README.md` "Policy Engine Protocol" and implement an - **Task 2.2** (blockchain-engineer): `.gitea/workflows/deploy.yml`
`OpaEngine`. The 287/287 baseline is unchanged. byte-identical mirror.
- **Task 2.3** (blockchain-engineer): `tests/test_deploy_workflow_invocation.py`
— asserts the `uses:` ref + inputs.
**Files touched:** ### Wave 3 — platform floating tag (cross-cutting)
- `adapters/kyverno-json/policies/regression/cap-013-adapter-dedup.json` (NEW) - **Task 3.1** (lead-developer, on `acdl` repo): verify the `v1.25`
- `adapters/kyverno-json/policies/regression/cap-023-metrics-collector.json` (NEW) floating tag exists (created by `release.yml` on merge to main). If
- `adapters/kyverno-json/policies/regression/cap-024-deck-structure.json` (NEW) not, create it pointing at the `v1.25.0` tag (Phase 0 ship).
- `tests/test_regression_policies.py` (NEW)
- `tests/fixtures/capability_inventory/clean.json` (NEW)
- `tests/fixtures/capability_inventory/drifted.json` (NEW)
- `adapters/README.md` (MODIFIED — new row + PolicyEngine Protocol section)
- `adapters/kyverno-json/README.md` (NEW)
- `schemas/README.md` (MODIFIED — engine enum note)
- `modules/STANDARDS.md` (MODIFIED — Policy authoring standard section)
- `docs/METRICS.md` (MODIFIED — swappable engine narrative)
**Verification:** `pytest tests/test_regression_policies.py **Must-haves (verify before ship):**
tests/test_kyverno_json_engine.py -v` (new tests pass or skip-without- - `contract.yaml` validates against `schemas/contract.schema.json`.
kj). Full regression gate `pytest tests/` still at 287/287 baseline + - The deploy workflow invocation asserts the correct `uses:` ref +
new tests (skip without kj). Manual read of `adapters/README.md` + inputs.
`adapters/kyverno-json/README.md` + `modules/STANDARDS.md` policy - The `v1.25` floating tag resolves.
section for clarity.
**Ship:** tag `v1.25.2`, merge `phase/02` → milestone, Gitea release.
Delete `phase/02`.
--- ---
### Phase P5final review + audit + milestone ship (Final Phase) ## Phase 3pilot-metrics-and-policies (tag v1.25.3)
**Type:** `docs` (review + audit + milestone completion) **Goal:** The platform repo gains the metric-grounding emitters, the
kyverno-json pilot policies, the DynamoDB L1 primitive, the env-JSON
wiring reconciliation, + the pilot regression CAP. The Post-Pilot
metrics are grounded (outcome backfill + escalation reason); the pilot-
readiness + settlement-finality policies are in place.
**Requirements:** All REQ-291..309 (mark complete) **Project:** `acdl` (platform repo).
**Branch:** `acdl/phase/03-pilot-metrics-and-policies` (platform branch).
**Personas:** backend-engineer (emitters + adapter + regression),
data-engineer (DynamoDB primitive + env JSON + collector),
policy-engineer (kyverno-json policies).
**Must-haves:** ### Wave 1 — DynamoDB primitive (REQ-322) — data-engineer
- `ciagent-review` multi-persona code review across P1..P4 - **Task 1.1** (data-engineer): `modules/l1/dynamodb/interface.json`
(lead-developer, backend-engineer, data-engineer, policy-engineer). stack type `aws:dynamodb:table`, inputs (table_name, region, pk, sk,
Auto-fix P0; flag P1+ for post-hoc review. If P1+ issues found, fix billing_mode), outputs (table_arn, table_name).
them in this final phase (not loop back to EXECUTE). - **Task 1.2** (data-engineer): `modules/l1/dynamodb/terraform/main.tf`
- `ciagent-audit` — reconstruction test (git log ↔ `.ciagent/` files), `resource "aws_dynamodb_table" "this"` (PK + optional SK,
`.ciagent/` file discipline, branch hygiene, commit discipline. `PAY_PER_REQUEST` default, encryption + PITR enabled per v1.8 NFR).
Critical issues fixed in this phase. - **Task 1.3** (data-engineer): `modules/l1/dynamodb/README.md` +
- `ciagent-ship` (milestone) — merge `phase/05-final-review-ship` → `instance.json`.
`milestone/v1.25-kyverno-json` → `main`; tag `v1.24.5` (= the v1.25 - **Task 1.4** (data-engineer): `modules/registry.json``dynamodb`
release per the prev-minor tagging rule); create Gitea release with entry (kind `l1`, `terraform_dir`).
full milestone summary (all phases, all requirements); delete all - **Task 1.5** (data-engineer): `modules/README.md` — catalog index.
milestone branches (local + remote).
- Update `REQUIREMENTS.md` (mark REQ-291..309 complete),
`ROADMAP.md` (mark v1.25 complete), `CHECKPOINT.json`
(milestone_complete: true), `NORTH_STAR.md` (note Strategic
Objective #2 — provable trust via a replaceable policy-engine
substrate).
**Vertical slice:** The v1.25 milestone is complete: kyverno-json is ### Wave 2 — metric grounding (REQ-317, REQ-318) — backend-engineer + data-engineer — parallel
the primary policy tool, behind a swappable adapter, with policies - **Task 2.1** (backend-engineer): `core/metrics/outcome_backfill.py`
over all 4 Nova artifacts. Tags v1.24.0..v1.24.5 on the v1.24.x line. `backfill(decision_id, outcome)` updates `fact_decision.outcome` +
The milestone branch merges to main. `backfilled_at`. Reads run-manifest events.
- **Task 2.2** (backend-engineer): `core/metrics/collector.py`
invokes backfill after run completion.
- **Task 2.3** (backend-engineer): `tests/test_outcome_backfill.py`.
- **Task 2.4** (backend-engineer): `core/confidence_signal.py`
`ai.decision.made` gains `escalation_reason: 'confidence'` when
`band == 'block'`.
- **Task 2.5** (backend-engineer): `core/metrics/collector.py`
persists `escalation_reason` into `fact_run`.
- **Task 2.6** (backend-engineer): `tests/test_confidence_escalation_reason.py`.
**Verification:** `pytest tests/ -v` full suite passes (287 baseline + ### Wave 3 — env-JSON wiring + adapter (REQ-319) — backend-engineer + data-engineer — parallel
new tests). `git log --oneline` shows the v1.25 phase commits. - **Task 3.1** (backend-engineer): `adapters/terraform/adapter.py`
`git tag` shows v1.24.0..v1.24.5. `git branch` shows no leftover reads `env.state_backend.bucket` when present (fallback to computed
milestone/phase branches (all deleted post-ship). name for backwards compat).
- **Task 3.2** (data-engineer): `core/environments/dev.json`
`account_id``581513795199`, `state_backend.bucket`
`nova-tfstate-581513795199-us-east-1`.
- **Task 3.3** (data-engineer): `core/environments/{qa,prod,dr}.json`
`state_backend.bucket` updated; `account_id` stays placeholder
(pilot-readiness policy blocks apply on placeholder, D-208).
- **Task 3.4** (backend-engineer): `tests/test_adapter_state_backend.py`.
- **Task 3.5** (backend-engineer): `tests/test_adapter.py` — add
`dynamodb` to `EXPECTED_L1_KEYS` + a resolution + emission test
(cross-territory: data-engineer authored the module, backend-engineer
owns the test).
### Wave 4 — kyverno-json policies (REQ-315, REQ-320) — policy-engineer — parallel
- **Task 4.1** (policy-engineer):
`adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json`
— kyverno-json policy over settlement-service status JSON (asserts
`all_committed: true`). **Note (G-Q6):** the policy is authored +
tested in v1.26; *enforcement* is deferred to the milestone that
binds qa/prod/dr (D-208 — the policy gates promotions, not dev
applies).
- **Task 4.2** (policy-engineer):
`adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json`
— kyverno-json policy over env JSON (asserts
`account_id != "000000000000"`).
- **Task 4.3** (policy-engineer): `tests/test_settlement_finality_policy.py`
— passing + failing fixtures; skip when `kj` absent.
- **Task 4.4** (policy-engineer): `tests/test_pilot_readiness_policy.py`
— passing (real account) + failing (placeholder) fixtures; skip when
`kj` absent.
### Wave 5 — regression CAP (REQ-316) — backend-engineer
- **Task 5.1** (backend-engineer): `core/regression_verify.py`
CAP-025 (live-pilot-apply): the round-trip assertion.
- **Task 5.2** (backend-engineer): `tests/test_regression_pilot.py`.
**Must-haves (verify before ship):**
- `pytest tests/` in the platform repo passes (170 existing + new tests).
- The DynamoDB primitive resolves + emits valid Terraform.
- The outcome backfill updates `fact_decision.outcome` (not `pending`).
- The `escalation_reason` field is emitted on `block` band.
- The adapter reads `env.state_backend.bucket` from the env JSON.
- The 2 new kyverno-json policies pass on valid fixtures + fail on
invalid fixtures (skip when `kj` absent).
- CAP-025 is in the regression gate.
- No existing tests regress (170 baseline holds).
**Ship:** tag `v1.25.3`, merge `phase/03` → milestone, Gitea release.
Delete `phase/03`.
--- ---
## Wave ordering (parallelization) ## Phase 4 — pilot-run-and-docs (tag v1.25.4)
With `parallelization.enabled: true`, `max_concurrent_agents: 5`, **Goal:** The pilot estate runs end-to-end against live AWS
`min_plans_for_parallel: 2`: `581513795199` (contract resolve → adapter compile → terraform plan →
policy scan → confidence signal → attestation → outbox record). Docs +
adapter README + onboarding guide are complete.
- **P1 Wave 1:** backend-engineer (protocol + registry + install) ‖ **Project:** `nova-blockchain-exchange` (consumer repo — the run) +
data-engineer (config.json policy object) ‖ policy-engineer (engine `acdl` (platform repo — docs).
adapter + smoke policy). 3 concurrent personas. Merge in order: **Branch:** `acdl/phase/04-pilot-run-and-docs` (platform branch for
data-engineer → backend-engineer → policy-engineer. docs); the run happens via the consumer's `deploy.yml` invocation.
- **P2 Wave 2:** policy-engineer (contract + stack-IR policies) ‖ **Personas:** blockchain-engineer (the run), lead-developer (docs),
backend-engineer (resolver wiring — depends on P1 registry). 2 backend-engineer (regression CAP-025 verification).
concurrent. Merge: policy-engineer → backend-engineer (wiring
references the policy dirs).
- **P3 Wave 3:** policy-engineer (plan-JSON + meta policies) ‖
backend-engineer (run_platform.sh wiring — depends on P1 engine +
P2 resolver pattern). 2 concurrent. Merge: policy-engineer →
backend-engineer.
- **P4 Wave 4:** policy-engineer (regression policies) ‖ data-engineer
(capability-inventory fixtures) ‖ lead-developer (docs: READMEs,
STANDARDS, METRICS). 3 concurrent. Merge: data-engineer →
policy-engineer → lead-developer.
Territory enforcement: `warn` mode (per `config.json ### Wave 1 — the pilot run (REQ-316 verification, live)
personas.territory_enforcement: "warn"`). Cross-territory edits - **Task 1.1** (blockchain-engineer): trigger the consumer's
(e.g., backend-engineer touching a policy file) emit a warning, not a `deploy.yml` with `mode: full, environment: dev` against
block. `581513795199`. The workflow checks out the consumer + platform
repos, runs `run_platform.sh`, applies the contract (ECS +
DynamoDB + S3), records the decision + attestation.
- **Task 1.2** (backend-engineer): verify CAP-025 (regression gate)
passes against the live run.
- **Task 1.3** (blockchain-engineer): capture the run's
`ai.decision.made` + `attestation.recorded` events from the Decision
Ledger → evidence for the milestone ship.
## Requirement → phase → persona matrix ### Wave 2 — docs (REQ-321)
- **Task 2.1** (lead-developer): `adapters/README.md` — new consumer
row + fix the stale `TYPE_MAP` references (IDEATE I8).
- **Task 2.2** (lead-developer): `docs/METRICS.md` — Post-Pilot metrics
grounded note (the 3 targets now have non-zero denominators post-run).
- **Task 2.3** (lead-developer): `.ciagent/ARCHITECTURE.md` §12.8
(Pilot Estate).
- **Task 2.4** (lead-developer):
`.ciagent/nova-blockchain-exchange/README.md` — consumer onboarding
guide (how to invoke `deploy.yml@v1.25`, what secrets to set, what
the contract shape is).
| REQ | Phase | Primary persona | Type | **Must-haves (verify before ship):**
|-----|-------|-----------------|------| - The pilot run completes end-to-end (apply succeeds, decision recorded,
| REQ-291 | P1 | backend-engineer | feat | attestation recorded for dev — autonomous, no human approver).
| REQ-292 | P1 | data-engineer | feat (config) | - CAP-025 passes.
| REQ-293 | P1 | policy-engineer | feat | - The 3 Post-Pilot metrics have non-zero denominators (the run
| REQ-294 | P1 | backend-engineer | feat (install) | contributed to `fact_run` + `fact_decision`).
| REQ-295 | P2 | policy-engineer | feat | - Docs are complete (adapter README, METRICS.md, ARCHITECTURE.md §12.8,
| REQ-296 | P2 | backend-engineer | feat (wiring) | consumer onboarding guide).
| REQ-297 | P2 | policy-engineer | feat |
| REQ-298 | P2 | backend-engineer | feat (wiring) | **Ship:** tag `v1.25.4`, merge `phase/04` → milestone, Gitea release.
| REQ-299 | P2 | policy-engineer | test | Delete `phase/04`.
| REQ-300 | P3 | policy-engineer | feat |
| REQ-301 | P3 | backend-engineer | feat (pipeline) | ---
| REQ-302 | P3 | policy-engineer + backend-engineer | test |
| REQ-303 | P3 | policy-engineer | feat (meta) | ## Phase 5 — final review + audit + milestone ship (tag v1.25.5)
| REQ-304 | P4 | policy-engineer | feat |
| REQ-305 | P4 | policy-engineer + data-engineer | test | **Goal:** Multi-persona code review across P1..P4. Audit (reconstruction
| REQ-306 | P4 | policy-engineer + lead-developer | docs | test, branch hygiene, commit discipline). Milestone ship: merge to main,
| REQ-307 | P4 | lead-developer | docs | tag `v1.25.5` (= the v1.26 release), Gitea release with full milestone
| REQ-308 | P1 | backend-engineer | test | summary, delete all milestone branches.
| REQ-309 | P1 | policy-engineer | test |
**Project:** both (`acdl` + `nova-blockchain-exchange`).
**Branch:** `phase/05-final-review-ship`.
**Personas:** lead-developer (review + audit + ship), backend-engineer
(review), data-engineer (review), policy-engineer (review),
blockchain-engineer (review — the chain core is reviewed).
### Wave 1 — review
- **Task 1.1** (lead-developer): `ciagent-review` — multi-persona code
review across P1..P4. Auto-fix P0; flag P1+ for post-hoc review.
- **Task 1.2** (all personas): fix P0 issues in this phase.
### Wave 2 — audit
- **Task 2.1** (lead-developer): `ciagent-audit` — reconstruction test
(git log ↔ `.ciagent/`), branch hygiene, commit discipline.
- **Task 2.2** (lead-developer): fix critical audit issues in this phase.
### Wave 3 — milestone ship
- **Task 3.1** (lead-developer): merge `phase/05`
`milestone/v1.26-pilot-activation``main`.
- **Task 3.2** (lead-developer): tag `v1.25.5` (= the v1.26 release per
prev-minor tagging rule).
- **Task 3.3** (lead-developer): create Gitea release with full milestone
summary (all phases, all 13 requirements).
- **Task 3.4** (lead-developer): delete all milestone branches (local +
remote). Tags preserve all history.
- **Task 3.5** (lead-developer): update `.ciagent/nova-blockchain-exchange/REQUIREMENTS.md`
(mark REQ-310..322 complete), `.ciagent/ROADMAP.md` (mark v1.26
complete), `.ciagent/NORTH_STAR.md` (note Strategic Objectives #1 +
#3 — first real consumer estate; Post-Pilot denominators activated).
- **Task 3.6** (lead-developer): write checkpoint `stage: complete,
phase: 5, phase_role: final` + clear checkpoint (milestone complete).
**Must-haves (verify before ship):**
- Review: 0 P0 issues unfixed; P1+ flagged for post-hoc.
- Audit: reconstruction test passes; branch hygiene clean; commit
discipline clean.
- Ship: `v1.25.5` tag exists; Gitea release created; milestone branches
deleted; main has the milestone merge.
---
## Requirement → Phase Mapping
| REQ | Phase | Wave | Persona |
|---|---|---|---|
| REQ-310 (blockchain core) | P1 | W1 | blockchain-engineer |
| REQ-311 (order engine) | P1 | W2 | blockchain-engineer |
| REQ-312 (settlement) | P1 | W2 | blockchain-engineer |
| REQ-313 (contract.yaml) | P2 | W1 | blockchain-engineer |
| REQ-314 (deploy invocation) | P2 | W2 | blockchain-engineer |
| REQ-315 (settlement-finality policy) | P3 | W4 | policy-engineer |
| REQ-316 (pilot regression CAP) | P3 | W5 + P4 W1 | backend-engineer |
| REQ-317 (outcome backfill) | P3 | W2 | backend-engineer |
| REQ-318 (escalation reason) | P3 | W2 | backend-engineer |
| REQ-319 (env-JSON wiring) | P3 | W3 | backend + data-engineer |
| REQ-320 (pilot-readiness policy) | P3 | W4 | policy-engineer |
| REQ-321 (docs) | P4 | W2 | lead-developer |
| REQ-322 (DynamoDB primitive) | P3 | W1 | data-engineer |
---
## Wave Ordering Rationale
- **P1 W1 → W2:** the chain core (block + ledger + validator) must land
before the order engine + settlement (they submit transactions to the
ledger). W3 (CI) is cross-cutting + can land any time after W1.
- **P2 W1 → W2:** the contract must land before the deploy invocation
(the invocation references the contract). W3 (floating tag) is cross-
cutting.
- **P3 W1 (DynamoDB) first:** the contract (P2) references `dynamodb` —
the primitive must exist before P2's contract can resolve. **Risk:**
P2's contract references a module that doesn't exist until P3. Resolution: P2's contract is authored but the `test_contract_validates.py` test only checks schema validity (not registry resolution) — the registry resolution test is in P3 (after the primitive lands). The contract's `dynamodb` block is schema-valid (the schema is open); the registry resolution happens at apply time (P4).
- **Alternative:** move REQ-322 to P2 W0 (before the contract). This
avoids the P2→P3 dependency. **Decision: move REQ-322 to P2 W0.**
See revised mapping below.
### Revised: REQ-322 → P2 W0
REQ-322 (DynamoDB primitive) lands in P2 Wave 0 (before the contract)
so the contract's `dynamodb` block resolves at registry time, not just
schema time. This makes P2 self-contained: the primitive + the contract
+ the deploy invocation all land in P2.
| REQ | Phase | Wave | Persona |
|---|---|---|---|
| REQ-310 (blockchain core) | P1 | W1 | blockchain-engineer |
| REQ-311 (order engine) | P1 | W2 | blockchain-engineer |
| REQ-312 (settlement) | P1 | W2 | blockchain-engineer |
| REQ-322 (DynamoDB primitive) | P2 | W0 | data-engineer |
| REQ-313 (contract.yaml) | P2 | W1 | blockchain-engineer |
| REQ-314 (deploy invocation) | P2 | W2 | blockchain-engineer |
| REQ-315 (settlement-finality policy) | P3 | W4 | policy-engineer |
| REQ-316 (pilot regression CAP) | P3 | W5 + P4 W1 | backend-engineer |
| REQ-317 (outcome backfill) | P3 | W2 | backend-engineer |
| REQ-318 (escalation reason) | P3 | W2 | backend-engineer |
| REQ-319 (env-JSON wiring) | P3 | W3 | backend + data-engineer |
| REQ-320 (pilot-readiness policy) | P3 | W4 | policy-engineer |
| REQ-321 (docs) | P4 | W2 | lead-developer |
This revision is a binding plan decision (G-Q8 in the grill may
challenge it).
---
## Future Hardening Items (not in v1.26 scope, documented per grill G-Q9)
- **`NOVA_AWS_*` key-split:** v1.26 uses a single `NOVA_AWS_*` key with
root-equivalent permissions (D-207, confirmed empirically by the
bootstrap). A future hardening milestone should split this into a
`NOVA_BOOTSTRAP_AWS_*` root key (bootstrap only) + a least-privilege
`NOVA_AWS_*` runner key (the spike-runner pattern). The pilot scope
(single account, no production workloads, OIDC default) bounds the
risk.
- **Multi-account landing zone:** qa/prod/dr on separate accounts (D-208
keeps them placeholder in v1.26).
- **D-083 lift:** S3 Object Lock + JWS tamper-evident ledger (when the
pilot becomes a production system, D-204).
- **Multi-validator BFT consensus:** D-201.
- **Other security types:** bonds (T+2), derivatives, options (D-200).
+84
View File
@@ -1698,3 +1698,87 @@ impl (REQ-293,294), contract policies (REQ-295,296), stack-IR policies
(REQ-297,298,299), plan-JSON policies + pipeline wiring (REQ-300,301,302), (REQ-297,298,299), plan-JSON policies + pipeline wiring (REQ-300,301,302),
meta-policies (REQ-303), regression-gate policies (REQ-304,305), docs + meta-policies (REQ-303), regression-gate policies (REQ-304,305), docs +
adapter README (REQ-306,307), tests (REQ-308,309). adapter README (REQ-306,307), tests (REQ-308,309).
## v1.26 — Live Pilot Estate Activation (active)
> **Active milestone.** Feature milestone — the first real consumer
> estate (a stock exchange on a homegrown PoA blockchain, equities
> only) is activated against live AWS account `581513795199`, lifting
> D-096. Branch: `milestone/v1.26-pilot-activation`. Tags run on the
> **v1.25.x** patch line: `v1.25.0` (P0) → `v1.25.1..v1.25.4` (P1P4)
> → `v1.25.5` (P5 final = milestone release).
>
> **Multi-project mode:** this milestone introduces a 2nd tracked
> project — `nova-blockchain-exchange` (Gitea repo
> `continuous-intelligence/nova-blockchain-exchange`, local clone
> `/root/nova-blockchain-exchange`). The platform repo (`acdl`) remains
> the platform source; the consumer repo owns the app code +
> `contract.yaml`. Both projects share the v1.26 milestone; `.ciagent/`
> paths are per-project (`.ciagent/acdl/` for platform files — note: the
> platform's existing flat `.ciagent/` files remain the primary set for
> v1.26; the consumer's files live in `.ciagent/nova-blockchain-exchange/`).
### Why
NORTH_STAR.md has three Post-Pilot targets (Touchless Resolution ≥99%,
Human Escalation <0.1%, AI Decision Accuracy ≥99.5%) whose measurement
*pipeline* is grounded but whose *denominator* is zero — no consumer
estate has ever run. v1.25 shipped the swappable policy engine; v1.26
ships the first real consumer. The D-096 deferral (live AWS
re-provisioning) is the single blocker; the pre-run (Workstream A)
re-created the state bucket + outbox table, so the platform components
exist. The milestone grounds the metrics (outcome backfill +
escalation reason), wires the env JSON to the real account, and runs
the pilot end-to-end.
### What the milestone delivers
- **Homegrown PoA blockchain** (`nova-blockchain-exchange` repo) —
append-only blocks, single validator (pilot), deterministic block
production, T+1 settlement finality = block commit. Equities only
(bonds/derivatives/options deferred).
- **Order-matching engine** — limit order book, price-time priority.
- **Settlement service** — T+1, idempotent, finality = block commit.
- **Consumer `contract.yaml`** — declares the exchange stack; validated
against `schemas/contract.schema.json`; per-env variants.
- **Consumer deploy via `deploy.yml@v1.25`** — the reusable workflow
applies the contract, runs the policy engine, computes the
confidence signal, gates qa/prod/dr with HITL attestation, and records
every decision in the Decision Ledger.
- **3 Post-Pilot metrics grounded** — outcome backfill (AI Decision
Accuracy), `reason='confidence'` escalation tag (Human Escalation
Frequency), and the pilot run itself (Touchless Resolution Rate
denominator activates).
- **3 kyverno-json policies extending v1.25** — settlement-finality
(securities-specific), pilot-readiness (no placeholder account),
and the existing meta-policies (block-on-any-critical,
tagging-rules-agree) apply over the pilot's PCRs.
- **Env-JSON `state_backend` wiring reconciliation** — the adapter
reads `state_backend.bucket` from the env JSON (closing the wiring
gap); the env JSONs are bound to account `581513795199`.
### Requirements
New requirements REQ-310..REQ-322 — see
`.ciagent/nova-blockchain-exchange/REQUIREMENTS.md` §v1.26. Summary:
blockchain core (REQ-310), order engine (REQ-311), settlement
(REQ-312), consumer contract (REQ-313), deploy invocation (REQ-314),
settlement-finality policy (REQ-315), pilot regression CAP (REQ-316),
outcome backfill (REQ-317), escalation reason (REQ-318), env-JSON
wiring (REQ-319), pilot-readiness policy (REQ-320), docs (REQ-321),
DynamoDB L1 primitive (REQ-322 — the single platform-side module
build-out; ECS + S3 already exist).
### Hard constraints
- DO NOT lift D-083 (S3 Object Lock/JWS) — stays deferred; the SQLite
hash-chain + DynamoDB outbox is the pilot's audit record.
- DO NOT lift D-126 (hot path) — cold-only metrics are sufficient for
the pilot.
- DO NOT add multi-cloud (Azure/GCP) — Nova is AWS-only this milestone.
- DO NOT add ML forecasting — the Predictive/Reactive metric stays
deferred.
- DO NOT add bonds/derivatives/options — equities only (D-200).
- DO NOT add multi-validator BFT — single validator PoA (D-201).
- The consumer deploy MUST go through `deploy.yml@v1.25` — no direct
`terraform apply` bypassing the platform's gates.
+192 -380
View File
@@ -1,438 +1,250 @@
# Nova — v1.25 Research Findings # Nova — v1.26 Research Findings
> Phase: research (pre-execution). Milestone: v1.25 (kyverno-json Unified > Phase: research (pre-execution). Milestone: v1.26 (Live Pilot Estate
> Policy Engine). Status: research. Researcher: ci-researcher. > Activation). Status: research. Researcher: ci-researcher.
> Autonomy: full. > Autonomy: full.
## 1. Problem domain ---
Nova's compliance/policy posture is fragmented across three engines with ## 1. Domain — Homegrown PoA Blockchain for Securities Settlement
three rule languages and three adapter shapes (see PROJECT.md v1.25
"Why" for the full diagnosis). The `PolicyCheckResult` schema
(`schemas/policy_check_result.schema.json`) is already the engine-agnostic
contract that `core/confidence_signal.py` consumes — the *contract* is
right; the *orchestration* is fragmented. There is no single declarative
place where "what Nova considers compliant" lives. The K8s-only Kyverno
adapter (`adapters/kyverno/`) can't help because it only speaks to K8s
manifests and the platform emits Terraform (D-053).
`kyverno-json` is the correction: a Kyverno-ecosystem runtime that applies ### 1.1 Why a homegrown chain (not Ethereum/Solana/Hyperledger)
Kyverno policies to **any** JSON/YAML payload. It becomes the **unified
orchestrator** of compliance checks, behind a swappable `PolicyEngine`
protocol so OPA can replace it one day. Checkov and Wiz remain as
raw-finding adapters feeding *into* kyverno-json meta-policies.
## 2. kyverno-json — the engine surface 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.
### 2.1 What it is 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.
[kyverno-json](https://github.com/kyverno/kyverno-json) is a standalone Go ### 1.2 PoA consensus single validator (pilot)
binary from the Kyverno project. It is a **separate runtime** from the
Kyverno K8s admission controller — same policy lineage, different
application target. Where Kyverno (K8s) evaluates `ClusterPolicy`
resources against Kubernetes manifests at admission time, kyverno-json
evaluates `ValidatingPolicy` resources against **any** JSON or YAML
payload file via the CLI (`kj scan`) or a Go library. It is **not** a
Python package (no PyPI release); it is installed via
`go install github.com/kyverno/kyverno-json/cmd/kj@latest` (D-115) or by
downloading a pinned binary from GitHub releases.
### 2.2 CLI surface (the v1.25 invocation path) 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).
The v1.25 engine uses the `kj scan` subcommand: ### 1.3 T+1 settlement finality
``` Equities settle T+1 (trade date + 1 business day). The pilot's
kyverno-json scan [flags] 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).
Flags: ### 1.4 Equities-only scope (D-200)
--labels strings Labels selectors for policies
--output string Output format (text or json) (default "text")
--payload string Path to payload (json or yaml file)
--policy strings Path to kyverno-json policies
--pre-process strings JMESPath expression used to pre process payload
```
The `KyvernoJsonEngine.evaluate()` implementation (REQ-293) invokes: Bonds (T+2), derivatives (varying), and options (exercise models) have
``` different settlement models. A pilot should demonstrate the Nova
kj scan --policy <policy_dir> --payload <payload.json> --output json platform's gates over the simplest case (equities T+1) before
``` expanding. "All types of securities" is the product vision; v1.26 is
and parses the JSON `results[]` array. The `--pre-process` flag is the pilot (equities first). Future milestones add other security types
available for JMESPath pre-projection (noted for the meta-policy use case with their settlement models.
where the payload is the merged PCR list and a pre-process expression
can index by `ruleId` — recorded as a future optimization, not used in
v1.25's initial implementation).
Other subcommands (`kj jp`, `kj serve`, `kj playground`, `kj docs`) are ---
out of scope for v1.25. `kj serve` is the long-running web-app mode
(noted as a future consideration for lower-latency evaluation in the
Out of Scope section of REQUIREMENTS.md). `kj jp` is the JMESPath REPL —
useful for policy authoring/debugging, not invoked by the engine.
### 2.3 Policy structure (the `ValidatingPolicy` resource) ## 2. Nova Consumer Deploy Model
kyverno-json policies are Kubernetes-style resources (cluster-scoped) ### 2.1 The reusable `deploy.yml@v1.25` workflow
belonging to the `json.kyverno.io` API group, kind `ValidatingPolicy`,
version `v1alpha1`:
```yaml The platform's `.github/workflows/deploy.yml` is a `workflow_call`
apiVersion: json.kyverno.io/v1alpha1 a reusable workflow that a consumer repo invokes via
kind: ValidatingPolicy `uses: acdl/.github/workflows/deploy.yml@v1.25`. Inputs: `contract`
metadata: (default `.nova/contract.yml`), `mode` (default `full`; enum
name: <policy-name> # becomes the KJ_<policy-name> ruleId prefix `full|plan-only|check-only|decommission`), `environment` (override).
spec: The workflow checks out the consumer repo + the platform repo, runs
rules: `scripts/run_platform.sh`, and records the apply decision +
- name: <rule-name> attestation in the Decision Ledger. Secrets: `NOVA_AWS_*`
identifier: <jmespath> # optional — path to the unique entry id (account + access key + secret) + `NOVA_LAMBDA_URL` (error reporting).
match: # assertion tree — which payload entries
any: # the rule applies to
- <assertion>
exclude: # optional — exclude matching entries
any:
- <assertion>
context: # optional — named bindings available to
- name: <binding> # the rule's assertions ($<binding>)
variable: <value>
validate:
message: "<human-readable>" # optional per-rule message
assert:
all: # all assertions must hold
- check: <assertion-tree>
message: "<per-check>"
# OR
any: # at least one assertion must hold
- check: <assertion-tree>
```
Key differences from K8s Kyverno policies: The pilot consumer (`nova-blockchain-exchange`) invokes this workflow
- **Always cluster-scoped** — no `namespace` field. with `mode: full` for `dev` (D-209). The `.gitea/workflows/deploy.yml`
- **No `forEach`, pattern operators, anchors, or wildcards.** Iteration mirror is byte-identical (the platform's deploy workflow is
is done via the `~` projection modifier in assertion trees (see §2.4). forge-agnostic — Gitea + GitHub).
- **Assertion trees** with JMESPath expressions replace Kyverno's
pattern-matching syntax (see §2.4).
### 2.4 Assertion trees (the rule language) ### 2.2 `run_platform.sh --apply` path (confirmed)
An `assert` declaration contains an `all` or `any` list. Each entry has a `scripts/run_platform.sh:431-455` — the `--apply` (or `mode: full`)
`check` (the assertion tree — a nested JMESPath projection) and an path runs `terraform apply -auto-approve` after the HITL gate
optional `message`. **All comparisons happen in the leaves of the tree.** (`: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).
A simple example (assert a pod doesn't use the default service account): **Gap (noted in RESEARCH §4):** the `--apply` path exits before the
```yaml outbox write (Step 8). The pilot runs the full pipeline (not `--apply`
validate: alone), so the outbox write happens. The `run.completed` event lands in
assert: the JSONL Decision Ledger (not the DynamoDB outbox) — this is by design
all: (the outbox is the platform-run evidence stream; the Decision Ledger is
- message: "serviceAccountName 'default' is not allowed" the cold store for metrics).
check:
spec:
(serviceAccountName == 'default'): false
```
The `(expression)` syntax evaluates a JMESPath expression; the result ### 2.3 Contract schema — multi-module manifest
becomes the current object for descendants; the leaf value is compared
to the expected value.
**Iteration via the `~` modifier.** The `~` prefix on a key applies `schemas/contract.schema.json:7,24-48` — required fields: `id`,
descendant assertions to **each element** of an array/map individually `name`, `environment`, `infrastructure`. The `infrastructure` block is
(rather than comparing the whole array). Given `foo.bar: [1,2,3]`: `minProperties: 1` with `patternProperties` accepting any module name
```yaml key. Multi-module manifest is supported: one contract can declare
check: `infrastructure: { microservice: {...}, dynamodb: {...}, s3: {...} }`.
foo: The constraint is the `modules/registry.json` (the module must be
~.bar: # iterate each element registered), not the schema.
(@ < `5`): true # assert each element < 5
```
The `~index_name.bar` form binds the index (array) or key (map) to
`$index_name` for use in descendants. This is how v1.25 iterates
`resources[]` in the Stack IR policies (REQ-297) and
`planned_values.root_module.resources[]` in the plan-JSON policies
(REQ-300).
**Explicit bindings** via `->binding_name` allow descendants to refer ---
to a parent node via `$binding_name`. Built-in bindings: `$payload`
(the whole input), `$policy`, `$rule`.
**Escaping** via `\key\` prevents projection when a payload key collides ## 3. Platform Module Readiness (the critical finding)
with the projection syntax. Not needed for Nova payloads (no `(key)`
fields), noted for completeness.
### 2.5 Output shape (what `kj scan --output json` produces) ### 3.1 The adapter is stateless (v1.11 rewrite)
The JSON output is a `results[]` array. Each result entry has (at `adapters/terraform/adapter.py:1-11` — the adapter is a "STATELESS
minimum): ASSEMBLER" that owns no module content. There is **no `TYPE_MAP`**,
- `policy`: the policy metadata.name `INPUT_MAP`, or `OUTPUT_MAP` (deleted in the v1.11 stateless rewrite;
- `rule`: the rule name `modules/STANDARDS.md:212-214` confirms). A new stack type requires a
- `result`: `"pass"` | `"fail"` | `"error"` | `"skip"` (lowercase) new L1 module (`modules/l1/<name>/` with `interface.json` +
- `message`: the assertion message (or engine error message) `terraform/main.tf` + `README.md` + `instance.json`) + a
- `resource`: the matched payload entry (the `identifier` value, or the `modules/registry.json` entry — not an adapter change.
whole payload when no identifier/match)
- `namespace`/`kind`/`name`: K8s-style fields (present but empty for
non-K8s payloads — the K8s Kyverno adapter's evidence uses these; the
kyverno-json engine's evidence uses `assertion`/`jmespath` instead)
- `severity`: not present by default (kyverno-json does not assign
severities — the Nova policy author assigns severity via a Nova-
specific annotation; see §2.6)
The `KyvernoJsonEngine._to_pcr()` translator (REQ-293) maps: ### 3.2 ECS — ready
- `policy``ruleId` (prefixed `KJ_<policy_name>` per D-116)
- `result``result` (`pass`/`fail`/`error` → pass/fail/error;
`skip`/`skipped` → skipped)
- `message``message`
- `resource``resourceRef` + `evidence.resource`
- severity from the policy's `metadata.annotations` (see §2.6)
- `engine: "kyverno"` (per D-116 — no new enum value)
### 2.6 Severity assignment (Nova convention) `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.
kyverno-json does not natively assign severities to results. Nova's ### 3.3 S3 — ready
confidence signal requires a `severity` per PCR (critical/high/medium/
low/info). The v1.25 convention: each Nova policy file declares its
severity via a `metadata.annotations` field:
```yaml `modules/l1/s3/terraform/main.tf:1``aws_s3_bucket` (+ versioning +
metadata: SSE). `interface.json:5-6``type: aws:s3:bucket`. `registry.json:2-10`
name: forbid-public-ingress — registered. Tests: `test_adapter.py:56-110,241-257`,
annotations: `test_contract_resolver.py:36-51,92-130`.
nova.cloudinit.dev/severity: high
```
The `KyvernoJsonEngine._to_pcr()` reads this annotation from the loaded ### 3.4 DynamoDB — GAP (REQ-322)
policy YAML (not from the scan result — the result doesn't carry it) and
applies it to every result that policy produces. Default when absent:
`info`. This keeps severity in the policy (declarative, version-
controlled) rather than in the engine adapter (imperative). The
annotation key is `nova.cloudinit.dev/severity` (matches the existing
`nova.cloudinit.dev` namespace used in `schemas/tagging-standard.json`).
## 3. The four policy targets (v1.25 scope) **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.1 Consumer contract JSON (REQ-295) ### 3.5 Stale doc (not a blocker)
The payload is the parsed contract dict (the raw YAML loaded as JSON). `adapters/README.md:49-54` references the deleted `TYPE_MAP`/
Policies assert the `contract.schema.json` constraints declaratively: `INPUT_MAP`/`OUTPUT_MAP` contradicts `adapter.py:1-11` +
`require-id-pattern` (JMESPath regex `^[a-z][a-z0-9-]{2,5}$` over `modules/STANDARDS.md:212-214`. REQ-321 (docs) should fix this.
`id`), `require-env-in-enum` (`environment` in `["dev","qa","prod","dr"]`),
`require-infrastructure-min-1` (`length(infrastructure) > 0`),
`forbid-unknown-fields` (keys subset of the 4 allowed). These are the
declarative equivalent of the jsonschema constraints — they let Nova
apply its own compliance posture (e.g. forbid a specific env for a
specific consumer) on top of schema validity without editing the
jsonschema.
**Invocation point:** `core/contract_resolver.py` pre-resolve (REQ-296). ---
Early-fail: if a contract policy fails, the resolver still proceeds
(the confidence signal decides the gate, consistent with the existing
`--soft-fail` Checkov pattern) — but the failing PCRs are in the
`policy` input, which lowers the score.
### 3.2 Resolved Target Stack IR JSON (REQ-297) ## 4. Metric Pipeline Grounding (Post-Pilot targets)
The payload is the resolved Stack IR dict produced by ### 4.1 AI Decision Accuracy — outcome backfill (REQ-317)
`core/contract_resolver.py` (the merged module outputs). Policies
assert over `resources[]` (the array of resolved resources):
`require-tagging-standard` (every resource's `tags` has `nova:owner` +
`nova:environment` — ports
`adapters/terraform/policy/custom_rules/nova_tagging.py`),
`forbid-public-ingress` (no resource has `public_ingress: true` — the
v1.0 demo rule, now declarative), `require-encryption-by-default` (every
S3/EBS/KMS-aliased resource carries encryption config — ports the v1.8
D-encryption-default rule). The `~` modifier iterates `resources[]`.
**Invocation point:** `core/contract_resolver.py` post-resolve (REQ-298). `core/metrics/decision_ledger.py:210-211` documents the event chain:
Additive — the resolver's return values and exceptions are unchanged; `confidence.computed → ai.decision.made → attestation.recorded →
the PCRs are appended to the contract-policy PCRs. 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).
### 3.3 Terraform plan JSON (REQ-300) ### 4.2 Human Escalation Frequency — `reason='confidence'` tag (REQ-318)
The payload is `terraform show -json <tfplan>` output. Policies assert `core/confidence_signal.py:184` — a `block` band sets
over `planned_values.root_module.resources[]`: `human_override=True` in the `ai.decision.made` event.
`forbid-plaintext-secrets` (no `aws_db_instance.password` / `run_platform.sh:636` fails the pipeline on `block`. The Human
`aws_iam_user.login_profile.password` in plaintext — ports Escalation Frequency metric (`docs/metrics/human_escalation_frequency.md:11-12`)
`CKV_AWS_41/45/46`), `forbid-iam-wildcard` (no `Action: "*"` or is defined as `count(runs WHERE hitl_block=1 AND reason='confidence') ÷
`Resource: "*"` in `aws_iam_policy.PolicyDocument` — ports total runs`. The `reason='confidence'` discriminator is **not currently
`CKV_AWS_1/40`), `require-kms-reference` (KMS keys referenced by alias, stored** — `hitl_block` is a boolean from the manifest. REQ-318 adds
not inline key material — ports `CKV_AWS_7/33`). These are declarative `escalation_reason: 'confidence'` to the `ai.decision.made` event when
**mirrors** of `checkov_adapter.py:RULE_MAP` — the Checkov rule stays `band == 'block'` + persists it into `fact_run` via the collector.
the source of truth for `terraform_plan` scanning; the kyverno-json
policy covers the same plan JSON with a different rule language
(defense-in-depth against engine drift).
**Invocation point:** `run_platform.sh` Step 5 (REQ-301). After ### 4.3 Touchless Resolution Rate — denominator activates post-pilot
Checkov/Wiz produce raw PCRs, the script runs `kj scan` over the plan
JSON; both PCR lists concatenate into the confidence signal's `policy`
input. When `which kj` is false, the script logs and proceeds with the
Checkov/Wiz list only.
### 3.4 PolicyCheckResult records (meta-policies, REQ-303) `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.
The payload is the **merged** `list[PolicyCheckResult]` produced by ---
checkov + wiz + the plan-JSON policies. This is the most novel target —
kyverno-json policies over the policy results themselves.
`block-on-any-critical` asserts no PCR has `severity: "critical"` +
`result: "fail"`; if any does, the meta-policy emits a `fail` PCR with
`ruleId: "KJ_META_BLOCK_CRITICAL"` and severity `critical`. This is the
declarative source of truth for "critical = block" (D-119 — the
`confidence_signal.py` `PENALTY["critical"]: None` hard-override stays
as defense-in-depth). `tagging-rules-agree` cross-checks the Checkov
`NOVA_TAG_NAMING` result against the kyverno-json
`KJ_REQUIRE_TAGGING_STANDARD` result by `resourceRef`; divergence emits
an `error` PCR (D-118).
**Invocation point:** after the three target policies (contract/stack- ## 5. kyverno-json Policy Extensibility
IR/plan-JSON) produce their PCR lists, the merged list is the payload
for the meta-policies. The meta-policy PCRs are appended to the merged
list, which is what the confidence signal consumes.
## 4. The `PolicyEngine` swap boundary `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`).
### 4.1 Protocol shape (REQ-291) 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.
A Python `Protocol` (PEP 544 — structural subtyping, no inheritance): ---
```python
class PolicyEngine(Protocol):
@property
def name(self) -> str: ...
def is_configured(self) -> bool: ...
def evaluate(self, payload: dict | str, policy_dir: Path,
contract_id: str) -> list[dict]: ...
```
`list[dict]` (not `list[PolicyCheckResult]` — there's no dataclass; the
schema is enforced via `jsonschema` validation in tests, matching the
existing adapter pattern). The registry selects the active engine from
`config.json.policy.engine`. A `NullEngine` is the fallback when the
`policy` key is absent (emits `SKIPPED` — backward compatibility for
tests that don't set the key).
### 4.2 The OPA-equivalent surface (future swap) ## 6. Env-JSON Wiring Reconciliation (REQ-319)
OPA (Open Policy Agent) is the most likely future replacement. The `core/environments/dev.json:4``account_id: "000000000000"` (placeholder).
mapping: `core/environment_check.py:48-53` warns (non-fatal) when account_id is
| Nova `PolicyEngine` member | kyverno-json impl | OPA equivalent | placeholder + env != dev. `adapters/terraform/adapter.py:116-117`
|---|---|---| computes the state bucket as `nova-tfstate-<AWS_ACCOUNT_ID>-us-east-1`
| `name` | `"kyverno-json"` | `"opa"` | from the `AWS_ACCOUNT_ID` env var, **not** from the env JSON's
| `is_configured()` | `which kj` | `which opa` | `state_backend.bucket`. This is the wiring gap: the env JSON's
| `evaluate(payload, policy_dir, contract_id)` | `kj scan --policy <dir> --payload <json> -o json` | `opa eval -d <dir> -i <json> 'data.nova.<...>'` | `state_backend` field is currently unused by the live apply path.
| Policy file format | `ValidatingPolicy` (YAML) | Rego (`.rego`) | REQ-319 makes the adapter read `env.state_backend.bucket` when present
| Result shape | `results[]` (pass/fail/error/skip) | `result` (set of violations) | (falling back to the computed name for backwards compat) + updates
| Severity | Nova annotation `nova.cloudinit.dev/severity` | Nova convention (Rego `metadata` or a wrapper) | `dev.json` to the real account `581513795199` + real bucket
`nova-tfstate-581513795199-us-east-1`.
The protocol is minimal (3 members) specifically so the OPA ---
implementation is a known quantity: an `OpaEngine` class that shells to
`opa eval`, translates the Rego violation set to PCR dicts, and
implements `is_configured()` via `which opa`. The policy *files* would
need rewriting (Rego, not ValidatingPolicy) — but the protocol, the
registry, the confidence signal, and the PCR schema are all untouched.
This is the swap boundary the user asked for ("Implemented as an
adapter since we might one day decide to replace it with something else
like OPA").
### 4.3 Why not a full plugin registry? ## 7. Risk Analysis
A `setuptools` entry-point plugin registry (like checkov's
`--external-checks-dir`) was considered and rejected: Nova has 1 active
engine today (kyverno-json) and at most 2 in the foreseeable future
(kyverno-json + OPA). A `Protocol` + `dict` registry in
`core/policy_engine.py` is the right weight — discoverable, typed,
testable, and ~40 lines. An entry-point registry adds packaging
complexity (entry-point metadata, version resolution) for no gain at
this scale. The `register(name, factory)` method on the registry is
the extension point if a future milestone needs runtime plugin
discovery.
## 5. Latency / MTTR impact (G-Q3 anticipation)
NORTH_STAR.md MTTR target: < 60s p95. `run_platform.sh` Step 5 today
runs Checkov over the terraform plan (typically 5-15s for a small
stack). Adding `kj scan` over the same plan JSON adds:
- Process spawn: ~50ms (Go binary startup)
- Policy load: ~20ms (a handful of YAML files)
- Assertion evaluation: ~100-500ms (JMESPath over a small plan)
- Total: < 1s for a typical Nova stack
The kyverno-json pass runs **in parallel** with Checkov (REQ-301 — the
script launches both and waits on both), so the wall-clock impact is
`max(checkov_time, kj_time)` ≈ checkov_time (kj is faster). The
contract + stack-IR policies run during resolve (already a fast step).
Meta-policies run over the merged list (in-memory, < 10ms). **No
measurable MTTR impact** is expected. This will be verified in P3
VERIFY with a timing assertion.
## 6. "Platform functions without AI" tenet (G-Q1 / D-120)
kyverno-json is deterministic (same policy + payload → same result,
every run). It is not an LLM, not a probabilistic model, not a
"judgement" engine. The NORTH_STAR.md tenet ("the platform functions
without AI — 'AI decisions' are really automated decisions")
distinguishes AI (non-reproducible) from automation (reproducible).
kyverno-json is the latter. Adding it is **more** aligned with the
tenet than the current imperative Python in `core/env_transition.py`
and `core/regression_verify.py`, because the policy is declarative
(visible, auditable, version-controlled) rather than imperative (logic
hidden in function bodies). The `is_configured()` guard ensures the
platform functions without the binary (graceful skip → `SKIPPED` PCR
→ confidence signal proceeds).
## 7. ECS policy catalog overlap (prior art)
The kyverno-json catalog ships ECS policies that overlap with Nova's
L1 modules: `ecs-cluster-enable-logging`, `ecs-cluster-required-
container-insights`, `ecs-service-public-ip`, `ecs-service-required-
latest-platform-fargate`, `ecs-task-definition-fs-read-only`. These are
**reference policies**, not drop-in Nova policies — they target the
AWS ECS API shape (`type: aws_ecs_service` etc.), not Nova's Stack IR
shape. v1.25 policies target the Nova IR (REQ-297) and the terraform
plan JSON (REQ-300), not the raw AWS API. The catalog is useful as
prior art for JMESPath patterns over ECS resources — the
`ecs-service-public-ip` policy's `contains('$allowed-values',
@.assign_public_ip)` pattern informs the Nova `forbid-public-ingress`
policy shape. No catalog policies are imported directly in v1.25.
## 8. Risks & mitigations
| Risk | Likelihood | Impact | Mitigation | | Risk | Likelihood | Impact | Mitigation |
|---|---|---|---| |---|---|---|---|
| `kj` binary not in CI image | medium | blocks P3+ tests | `is_configured()` guard + `pytest.skip` + `scripts/install-kyverno-json.sh` | | `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). |
| kyverno-json output shape changes across versions | low | breaks `_to_pcr()` | pin `@latest` to a known-good commit in `install-kyverno-json.sh` after P1 smoke; defensive parsing (malformed → `error` PCR, not exception) | | 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. |
| Policy explosion (4 targets × N rules) | medium | maintenance load | wave ordering (PLAN); policies co-located per target dir; meta-policy cross-check keeps the set auditable | | Homegrown chain has a correctness bug (hash chain breaks) | Low | High | REQ-310 tests cover chain integrity, hash determinism, genesis, append/verify. |
| Checkov + kj tagging-rule drift | medium | false `error` PCRs | `tagging-rules-agree` meta-policy emits `error` on divergence (visible, not silent); the Checkov rule stays source of truth for HCL, kj for IR | | `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`. |
| OPA swap turns out harder than the protocol implies | low | future milestone rework | RESEARCH §4.2 documents the OPA-equivalent surface; the protocol is the contract, not the implementation | | 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). |
| `--pre-process` needed for meta-policies but undocumented behavior | low | meta-policy bugs | v1.25 meta-policies use plain assertion trees over the PCR list (no pre-process); `--pre-process` noted as a future optimization only | | 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. |
## 9. Assumptions (logged, full autonomy) ---
- A1: `kj scan --output json` produces a stable `results[]` array shape. ## 8. Persona Assessment
Will be verified in P1 smoke test (`_smoke.json` policy + a trivial
payload); if the shape differs, `_to_pcr()` is adjusted defensively
(malformed → `error` PCR). Confidence: 0.85.
- A2: The `nova.cloudinit.dev/severity` annotation convention is
read by the engine from the policy YAML (loaded once per evaluate()
call). kyverno-json does not validate unknown annotations — they pass
through. Confidence: 0.90.
- A3: The `~` projection modifier iterates `resources[]` in the Stack
IR and `planned_values.root_module.resources[]` in the plan JSON
correctly. Verified in P2/P3 tests. Confidence: 0.85.
- A4: `go install` works in the CI image (Go toolchain available or
installable). If not, the binary-release download path is the
documented fallback in `install-kyverno-json.sh`. Confidence: 0.80.
- A5: The `NullEngine` fallback (when `policy` key absent in
config.json) keeps all existing tests passing — they don't set the
key, so they get `NullEngine``SKIPPED` PCRs → confidence signal
proceeds with `policy` input `[SKIPPED]` → per-input score 1.0
(skipped counts as pass in `_per_input_score`). Confidence: 0.95
(verified against `confidence_signal.py:84-89`).
## 10. Decisions referenced See `PERSONAS.md` (next section, produced by the lead-developer at the
end of RESEARCH). The active roster: backend-engineer (blockchain core
D-115 (install path), D-116 (engine enum reuse), D-117 (adapter + settlement + outcome backfill), data-engineer (DynamoDB primitive +
signatures unchanged), D-118 (tagging cross-check), D-119 (critical- metrics cold store), policy-engineer (kyverno-json policies), +
override defense-in-depth), D-120 (deterministic not AI). See blockchain-engineer (custom, phase-specific — chain consensus, order
CLARIFY.md for the full resolution text. matching, settlement finality). frontend-engineer is deactivated (no
UI in the pilot).
## 11. Architecture updates (deferred to RESEARCH-stage file edits)
- `.ciagent/ARCHITECTURE.md` gains §12.7 "Policy Engine Registry" with
the registry diagram. Deferred to the RESEARCH commit (this file's
commit) — the section is authored as part of this research.
- `schemas/README.md` notes `engine: "kyverno"` is shared by the K8s
adapter and kyverno-json (distinguished by `ruleId` prefix).
- `modules/STANDARDS.md` gains a "Policy authoring standard" section
(P4, REQ-307).
- `docs/METRICS.md` notes the policy engine is swappable (P4, REQ-307).
+93
View File
@@ -2246,3 +2246,96 @@ final). Tags: `v1.24.0` (P0) → `v1.24.5` (P5 = milestone release).
(mark v1.25 complete), `NORTH_STAR.md` (note Strategic Objective #2 (mark v1.25 complete), `NORTH_STAR.md` (note Strategic Objective #2
provable trust via a replaceable policy-engine substrate). provable trust via a replaceable policy-engine substrate).
- **Requirements:** REQ-291..309 (19 requirements). - **Requirements:** REQ-291..309 (19 requirements).
## v1.26 (active, tag line `v1.25.x`): Live Pilot Estate Activation
`D-096` lifts. The first real consumer estate — a stock exchange on a
homegrown Proof-of-Authority blockchain (equities only, single
validator, T+1 settlement finality = block commit) — is activated
against live AWS account `581513795199`. The consumer repo
(`nova-blockchain-exchange`) owns the app code + `contract.yaml`; the
platform repo (`acdl`) provides the deploy workflow (`deploy.yml@v1.25`),
the policy engine (kyverno-json, swappable per v1.25), the confidence
signal, and the HITL attestation gates. The milestone grounds the three
Post-Pilot targets in NORTH_STAR.md (Touchless Resolution ≥99%, Human
Escalation <0.1%, AI Decision Accuracy ≥99.5%) — the denominators
activate when the pilot runs. Three kyverno-json policies extend v1.25:
settlement-finality (securities-specific), pilot-readiness (no
placeholder account), and the existing meta-policies (block-on-any-
critical, tagging-rules-agree) apply over the pilot's PCRs. The
env-JSON `state_backend` wiring gap is closed (adapter reads the env
JSON's bucket). Multi-project mode activates (`nova-blockchain-exchange`
is the 2nd tracked project). Pre-run (Workstream A) re-created the S3
state bucket + DynamoDB outbox table (bootstrap). 12 requirements
(REQ-310..321), 5 phases (P0 pre-execution + 4 execution + 1 final).
Tags: `v1.25.0` (P0) → `v1.25.5` (P5 = milestone release).
### Phase P1 — blockchain-core (planned, tag v1.25.1)
- REQ-310: `nova-blockchain-exchange` repo — homegrown PoA blockchain
core (`chain/block.py`, `chain/ledger.py`, `chain/validator.py`).
Append-only blocks, single validator, SHA-256 hash chain,
deterministic block production, genesis block.
- REQ-311: Order-matching engine (`engine/order_book.py`,
`engine/order.py`) — limit order book, price-time priority, partial
fills.
- REQ-312: Settlement service (`settlement/service.py`) — T+1,
idempotent, finality = block commit.
### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2)
- REQ-322: `modules/l1/dynamodb/` — new L1 primitive (interface.json +
terraform/main.tf + README.md + instance.json + registry.json entry).
The single platform-side module build-out (ECS + S3 already exist;
the adapter is stateless/registry-driven). Lands in P2 W0 (before the
contract) so the contract's `dynamodb` block resolves at registry time.
- REQ-313: `nova-blockchain-exchange/contract.yaml` + per-env variants
(dev/qa/prod) — validated against `schemas/contract.schema.json`.
- REQ-314: `nova-blockchain-exchange/.github/workflows/deploy.yml` +
`.gitea/workflows/deploy.yml``uses: acdl/.github/workflows/deploy.yml@v1.25`
with `mode: full`.
### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3)
- REQ-315: `adapters/kyverno-json/policies/settlement-finality.json`
kyverno-json policy asserting all matches in the promotion window have
committed blocks (securities-specific).
- REQ-316: `core/regression_verify.py` gains CAP-025
(live-pilot-apply) — the round-trip assertion (contract resolve →
adapter compile → terraform plan → policy scan → confidence signal →
attestation → outbox record) against `581513795199`.
- REQ-317: `core/metrics/outcome_backfill.py` — wire
`apply.completed`/`apply.failed``fact_decision.outcome` (grounds AI
Decision Accuracy; today `outcome` is stuck `pending`).
- REQ-318: `core/confidence_signal.py``ai.decision.made` gains
`escalation_reason: 'confidence'` when `band == 'block'` (grounds
Human Escalation Frequency numerator).
- REQ-319: `adapters/terraform/adapter.py` — reads
`env.state_backend.bucket` from the env JSON (closing the wiring gap);
`core/environments/*.json` `state_backend.bucket`
`nova-tfstate-581513795199-us-east-1`.
- REQ-320: `adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json`
— declarative gate preventing apply against a placeholder account.
### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4)
- REQ-321: `adapters/README.md` (new consumer row) +
`docs/METRICS.md` (Post-Pilot metrics grounded note) +
`.ciagent/ARCHITECTURE.md` §12.8 (Pilot Estate) +
`.ciagent/nova-blockchain-exchange/README.md` (onboarding guide).
- Live pilot end-to-end run: `nova-blockchain-exchange` contract →
`deploy.yml@v1.25` mode=full → apply → attest → record against
`581513795199`. The run's `ai.decision.made` + `attestation.recorded`
events land in the Decision Ledger; the regression gate (CAP-025)
verifies the round-trip.
### Phase P5 — final review + audit + milestone ship (Final Phase, tag v1.25.5)
- Multi-persona code review across P1..P4 (lead-developer, backend-
engineer, data-engineer, policy-engineer, blockchain-engineer).
Auto-fix P0; flag P1+.
- Audit: reconstruction test (git log ↔ `.ciagent/`), branch hygiene,
commit discipline.
- Milestone ship: merge `phase/05-final-review-ship`
`milestone/v1.26-pilot-activation``main`; tag `v1.25.5` (= the
v1.26 release per prev-minor tagging rule); create Gitea release with
full milestone summary; delete all milestone branches.
- Update `REQUIREMENTS.md` (mark REQ-310..322 complete), `ROADMAP.md`
(mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1
+ #3 — first real consumer estate; Post-Pilot denominators activated).
- **Requirements:** REQ-310..322 (13 requirements).
+7 -2
View File
@@ -4,11 +4,16 @@
"slug": "acdl", "slug": "acdl",
"name": "Nova — The New Dawn of DevSecOps", "name": "Nova — The New Dawn of DevSecOps",
"default": true "default": true
},
{
"slug": "nova-blockchain-exchange",
"name": "Nova Pilot Consumer — Blockchain Stock Exchange",
"default": false
} }
], ],
"active_project": "acdl", "active_project": "acdl",
"active_projects": ["acdl"], "active_projects": ["acdl", "nova-blockchain-exchange"],
"active_milestone": "v1.25", "active_milestone": "v1.26",
"autonomy": { "autonomy": {
"level": "full", "level": "full",
"escalation_hooks": ["deploy", "delete_data", "merge_to_main"], "escalation_hooks": ["deploy", "delete_data", "merge_to_main"],
@@ -0,0 +1,92 @@
# Nova Pilot Consumer — Blockchain Stock Exchange
> **Milestone:** v1.26 — Live Pilot Estate Activation
> **Git:** https://git.cloudinit.dev/continuous-intelligence/nova-blockchain-exchange
> **Local clone:** /root/nova-blockchain-exchange
> **Role:** The first real consumer estate. A stock exchange built on a
> homegrown blockchain, offering equities trading (pilot scope). The
> consumer repo owns the app code + `contract.yaml`; the Nova platform
> (`acdl` repo) provides the deploy workflow, policy engine, and
> attestation gates.
---
## Vision / Core Value
A self-contained securities-trading exchange where every order, match,
and settlement is recorded as an immutable transaction on a homegrown
Proof-of-Authority (PoA) blockchain. The pilot demonstrates that Nova's
autonomous infrastructure can take a real consumer estate from contract
to production — apply, attest, record — without an operator in the loop
of normal operations.
## North Star Alignment
- **Strategic Objective #1** (production-grade zero-touch operations):
this estate is the first real consumer; the pilot activates the
autonomy claim beyond internal demos.
- **Strategic Objective #2** (provable trust): every apply decision +
attestation lands in the Decision Ledger; the settlement-finality
kyverno-json policy (IDEATE) makes trust a policy artifact.
- **Strategic Objective #3** (compounding ROI): unblocks the three
Post-Pilot targets (Touchless Resolution ≥99%, Human Escalation
<0.1%, AI Decision Accuracy ≥99.5%) — the denominators activate when
this estate runs.
## Domain Boundaries
- **This repo owns:** the blockchain (consensus, blocks, transactions),
the order-matching engine, the settlement service, the `contract.yaml`
that declares the infrastructure, and the consumer-side deploy workflow
invocation (`uses: acdl/.github/workflows/deploy.yml@v1.25`).
- **The platform (`acdl`) repo owns:** the deploy workflow, the policy
engine (kyverno-json), the contract resolver, the adapter, the
confidence signal, the HITL gates, and the Decision Ledger.
## Scope: v1.26 Pilot
- **Equities only** (bonds, derivatives, options deferred to future
milestones — different settlement models).
- **Minimal PoA ledger** — append-only blocks, single validator (pilot),
T+1 settlement finality = block commit. No multi-validator BFT.
- **Homegrown chain** — authored as part of this repo, not deployed on
Ethereum/Solana/Hyperledger.
## Anti-Goals (v1.26)
1. Not a general-purpose blockchain platform — purpose-built for
securities settlement in the pilot.
2. Not multi-validator consensus — single validator for the pilot.
3. Not bonds/derivatives/options — equities only this milestone.
4. Not a replacement for the Nova platform — this is a *consumer* of
Nova, not a fork.
## Key Decisions (v1.26 — established in SPECIFY, refined in CLARIFY)
| ID | Decision | Rationale | Affects |
|---|---|---|---|
| D-200 | Pilot scope = equities only | Bonds/derivatives/options have very different settlement models; equities (T+1) is the simplest to demonstrate the Nova platform's policy gates over a real estate. | Phase count; requirement scope. |
| D-201 | Homegrown PoA ledger (single validator) | Minimal viable chain for a pilot; settlement finality = block commit. Multi-validator BFT is a future milestone. | Blockchain core design. |
| D-202 | Consumer repo = `nova-blockchain-exchange` (Gitea) | New repo under `continuous-intelligence` org; tracked as 2nd CIAgent project. | Multi-project config. |
| D-203 | AWS account = 581513795199 (existing) | Reuse the bootstrapped account; state bucket + outbox table created in pre-run Workstream A3. | Env JSON binding. |
| D-204 | D-083 (S3 Object Lock/JWS) stays deferred | The SQLite hash-chain + DynamoDB outbox is the pilot's audit record. Tamper-evidence is a future milestone. | Audit ledger scope. |
| D-205 | Cold-only metrics sufficient (D-126) | No hot ops dashboard in the pilot; cold SQLite store + PowerBI export. | Metrics pipeline. |
## Constraints
- The consumer repo's deploy MUST go through `deploy.yml@v1.25` (the
reusable workflow) — no direct `terraform apply` bypassing the
platform's policy + attestation gates.
- The `contract.yaml` MUST validate against
`schemas/contract.schema.json`.
- The homegrown blockchain MUST be deterministic (same inputs → same
block) — it is automation, not AI (NORTH_STAR Objective #2 tenet).
## Context
- The Nova platform (`acdl` repo) completed v1.25 (kyverno-json Unified
Policy Engine). The swappable `PolicyEngine` adapter is in place.
- The AWS bootstrap (S3 state bucket + DynamoDB outbox) was re-run in
the pre-run (Workstream A3) — the platform components exist.
- The consumer repo was created on Gitea (Workstream A4) and cloned to
`/root/nova-blockchain-exchange`.
@@ -0,0 +1,221 @@
# 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`
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
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)
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).
@@ -0,0 +1,57 @@
# Roadmap — nova-blockchain-exchange (v1.26 pilot)
> **Project:** nova-blockchain-exchange — blockchain stock exchange (pilot)
> **Milestone:** v1.26 — Live Pilot Estate Activation
---
## v1.26 — Live Pilot Estate Activation (active)
Lift D-096 (live AWS re-provisioning); activate the first real consumer
estate (a stock exchange on a homegrown PoA blockchain, equities only)
against live AWS account `581513795199`; ground the three Post-Pilot
targets in NORTH_STAR.md (Touchless Resolution ≥99%, Human Escalation
<0.1%, AI Decision Accuracy ≥99.5%). The platform repo (`acdl`) provides
the deploy workflow, policy engine, and attestation gates; this repo
provides the app (blockchain + matching engine + settlement) + the
`contract.yaml`.
Tags run on the **v1.25.x** patch line: `v1.25.0` (P0) → `v1.25.N`
(final phase = milestone release).
### Phase P1 — blockchain-core (planned, tag v1.25.1)
- REQ-310: Homegrown PoA blockchain core (block, ledger, validator).
- REQ-311: Order-matching engine (limit order book, price-time priority).
- REQ-312: Settlement service (T+1, idempotent, finality = block commit).
### Phase P2 — consumer-contract-and-deploy (planned, tag v1.25.2)
- REQ-313: Consumer `contract.yaml` + per-env variants.
- REQ-314: Consumer deploy workflow invocation (`deploy.yml@v1.25`).
### Phase P3 — pilot-metrics-and-policies (planned, tag v1.25.3)
- REQ-315: Settlement-finality kyverno-json policy.
- REQ-316: Pilot-estate regression capability (CAP-025).
- REQ-317: Outcome-backfill emitter.
- REQ-318: `reason='confidence'` escalation tag.
- REQ-319: Env-JSON `state_backend` wiring reconciliation.
- REQ-320: Declarative pilot-readiness kyverno-json policy.
### Phase P4 — pilot-run-and-docs (planned, tag v1.25.4)
- REQ-321: Docs + adapter README + onboarding guide.
- Live pilot end-to-end run (apply → attest → record) against
`581513795199`.
### Phase P5 — final review + audit + milestone ship (Final Phase, tag v1.25.5)
- Multi-persona code review across P1..P4.
- Audit: reconstruction test, branch hygiene, commit discipline.
- Milestone ship: merge `phase/05``milestone/v1.26-pilot-activation`
`main`; tag `v1.25.5` (= the v1.26 release per prev-minor tagging
rule); create Gitea release with full milestone summary; delete all
milestone branches.
- Update `REQUIREMENTS.md` (mark REQ-310..321 complete), `ROADMAP.md`
(mark v1.26 complete), `NORTH_STAR.md` (note Strategic Objectives #1
+ #3 — first real consumer estate; Post-Pilot denominators activated).
After v1.26: future milestones may add bonds/derivatives/options
(different settlement models), multi-validator BFT consensus, and
tamper-evident ledger (D-083 lift).