The v1.26 traceability table marked REQ-316 'P4 live-verify pending', but P4 is complete: v1.25.4 tagged, the live terraform apply against 581513795199 succeeded (commit6ced8ed), verify PASS (074ee05), and the CHECKPOINT notes confirm 'nova.outcome.backfilled (pending->succeeded)'. Corrected to 'v1.25.4 — live-verify complete'. 0 P0 issues remain after this fix. ---ci--- project: acdl phase: 5 milestone: v1.26 status: execute wave: review-audit ---
16 KiB
Nova — Requirements
Compressed. The full v1.0–v1.25 requirement history (REQ-01..REQ-309) is preserved verbatim at
.ciagent/archive/REQUIREMENTS-v1.0-v1.24.md. This file retains only the v1.25 requirement set (the immediate predecessor milestone whose policy-engine substrate is load-bearing for v1.26) + a pointer to the active v1.26 requirements, which live in the consumer subproject at.ciagent/nova-blockchain-exchange/REQUIREMENTS.md(multi-project mode perconfig.json).Earlier requirement sets (v1.0–v1.24, REQ-01..REQ-290) remain valid for the milestones they governed. They are not re-decided by v1.26. Full text in the archive snapshot + git history.
v1.25 — kyverno-json Unified Policy Engine (immediate predecessor, complete)
Feature milestone — complete.
kyverno-jsonbecomes the primary compliance / policy tool, implemented behind a swappablePolicyEngineadapter so OPA (or any other engine) can replace it one day. Tags run on the v1.24.x line (milestone v1.25 → tags v1.24.0..v1.24.5). Tagv1.24.5= the milestone release.One problem, one architectural correction:
- Fragmented policy posture. Nova's compliance rules were split across Checkov (imperative YAML + a Python custom rule for tagging), Wiz (API findings), the K8s-only Kyverno adapter (inactive for Terraform stacks — D-053), and imperative Python in
core/env_transition.py+core/regression_verify.py. There was no single declarative place where "what Nova considers compliant" lived.The correction:
kyverno-json(a Kyverno-ecosystem runtime that applies Kyverno policies to any JSON/YAML payload) becomes the unified orchestrator of compliance checks. Checkov and Wiz remain as raw-finding adapters feeding into kyverno-json meta-policies. The engine is behind aPolicyEngineprotocol so it is replaceable. The confidence signal is untouched — it already consumeslist[PolicyCheckResult]engine-agnostically.
Decisions (locked in CLARIFY, full autonomy — load-bearing for v1.26)
- D-115 (C-1):
kyverno-jsonis a runtime dependency installed viago install github.com/kyverno/kyverno-json/cmd/kj@latest(pinned in ascripts/install-kyverno-json.shhelper; the CI image installs it). Not a Python package — kyverno-json is a Go binary. TheKyvernoJsonEngine.is_configured()checkswhich kjand skips gracefully when absent (emitsSKIPPEDPCR, mirroring the Wiz adapter). - D-116 (C-2): kyverno-json PCR records carry
engine: "kyverno"(no new enum value). The existingengineenum inschemas/policy_check_result.schema.jsonalready includes"kyverno"; adding"kyverno-json"would force a schema change + checkov_adapter test regression for no semantic gain. TheruleIdprefixKJ_distinguishes kyverno-json rules from the K8s Kyverno adapter'sKYVERNO_prefix where they overlap. - D-117 (C-3): Checkov and Wiz adapters keep their current
adapt() -> list[PolicyCheckResult]signatures. They emit PCRs as today. The meta-policies inadapters/kyverno-json/policies/meta/consume the merged PCR list (checkov + wiz + kyverno-json) as their input payload, applying Nova-specific posture rules on top. No adapter signature changes. - D-118 (C-4):
NOVA_TAG_NAMING(the Checkov custom rule inadapters/terraform/policy/custom_rules/nova_tagging.py) is kept. A kyverno-json mirror policyrequire-tagging-standard.jsonis added inadapters/kyverno-json/policies/stack-ir/. The P3 meta-policytagging-rules-agree.jsonasserts the two engines agree on every resource; divergence emits anerrorPCR (defense-in-depth against rule drift). The Checkov rule stays the source of truth for Terraform-static scanning; the kyverno-json policy covers Stack IR.
Category: Policy Engine Core (feat)
- REQ-291:
core/policy_engine.pydefines aPolicyEnginePythonProtocol(PEP 544) with three members:name -> str,is_configured() -> bool, andevaluate(payload: dict | str, policy_dir: Path, contract_id: str) -> list[dict](where each dict conforms toschemas/policy_check_result.schema.json). APolicyEngineRegistrysingleton selects the active engine fromconfig.json's newpolicy.enginekey (default"kyverno-json"); raisesKeyErroron an unknown engine name. The registry exposesget_engine()andregister(name, factory). Pure stdlib, no engine imports at the protocol layer. - REQ-292:
.ciagent/config.jsongains a new top-levelpolicyobject:{"engine": "kyverno-json", "policy_root": "adapters/kyverno-json/policies"}. The registry readspolicy.engineto select the active engine andpolicy.policy_rootas the default policy directory. Backward-compatible: if thepolicykey is absent, the registry returns aNullEnginethat emits onlySKIPPEDrecords (so existing tests that don't set the key still pass).
Category: kyverno-json Engine Adapter (feat)
- REQ-293:
adapters/kyverno-json/kyverno_json_engine.pyimplementsKyvernoJsonEnginesatisfying thePolicyEngineprotocol.is_configured()returnsTruewhenwhich kjsucceeds.evaluate()writes the payload to a temp JSON file, invokeskj scan --policy <policy_dir> --payload <payload.json> -o json, parses the native result list, and translates each entry to a PCR dict (engine: "kyverno",ruleIdprefixedKJ_<policy_name>, severity mapped,resultmapped pass/fail/skip → pass/fail/skipped). Whenis_configured()is false,evaluate()returns a singleSKIPPEDPCR withruleId: "KJ_ENGINE_NOT_CONFIGURED". Native output parsing is defensive: any kyverno-json output that doesn't match the expected shape produces anerrorPCR, never an exception. - REQ-294:
adapters/kyverno-json/__init__.pyexportsKyvernoJsonEngine.adapters/kyverno-json/policies/_smoke.jsonis a single trivial policy (require-contract-id) used to validate the engine round-trip end-to-end in tests.scripts/install-kyverno-json.shrunsgo install github.com/kyverno/kyverno-json/cmd/kj@latestand printskj version; documented inadapters/kyverno-json/README.md. The CI image installs Go + kj whenpolicy.engine == "kyverno-json"; the install is cached.
Category: Contract Policies (feat)
- REQ-295:
adapters/kyverno-json/policies/contract/holds kyverno-json policies over consumer contract JSON. Four policies mirroringschemas/contract.schema.jsonconstraints:require-id-pattern.json,require-env-in-enum.json,require-infrastructure-min-1.json,forbid-unknown-fields.json. Each policy is a single KyvernoPolicyresource with onevalidate.assertrule using JMESPath against the payload root. - REQ-296:
core/contract_resolver.pyinvokes thePolicyEngineRegistry.get_engine().evaluate()with the contract dict andpolicies/contract/before resolving (early-fail on contract violations) and emits anova.policy.evaluatedmetrics event. Failures feed the confidence signal'spolicyinput asfailPCRs; the resolver does not exit — the confidence signal decides the gate (consistent with the existing--soft-failCheckov pattern).
Category: Stack-IR Policies (feat)
- REQ-297:
adapters/kyverno-json/policies/stack-ir/holds policies over the resolved Target Stack IR dict.require-tagging-standard.json(every resource carriesnova:owner+nova:environmenttags — portsnova_tagging.pyinto a declarative Kyverno policy).forbid-public-ingress.json(no resource haspublic_ingress: true).require-encryption-by-default.json(every S3 bucket + EBS volume + KMS-aliased resource carries encryption config — ports the v1.8 D-encryption-default rule). - REQ-298:
core/contract_resolver.pyinvokes the engine with the resolved Stack IR andpolicies/stack-ir/after resolving. The resulting PCRs are appended to the contract-policy PCRs and fed to the confidence signal. The resolver's existingtests/test_contract_resolver.pycontinues to pass (the policy call is additive — it does not change resolver return values or exceptions). - REQ-299:
tests/test_stack_ir_policies.py+ fixturetests/fixtures/stack_ir/— a passing IR + a failing IR. Tests run theKyvernoJsonEngineagainst realkjwhenwhich kjsucceeds, andpytest.skip("kj not installed")when absent.
Category: Plan-JSON Policies + Pipeline Wiring (feat)
- REQ-300:
adapters/kyverno-json/policies/plan-json/holds policies overterraform show -jsonoutput.forbid-plaintext-secrets.json(portsCKV_AWS_41/45/46).forbid-iam-wildcard.json(portsCKV_AWS_1/40).require-kms-reference.json(portsCKV_AWS_7/33). The CheckovRULE_MAPincheckov_adapter.pyis unchanged — these are declarative mirrors, not replacements. - REQ-301:
run_platform.shStep 5 ("runtime policy scan") gains a parallel kyverno-json pass: after Checkov/Wiz produce raw PCRs, the script runskj scanand pipes throughadapters/kyverno-json/kyverno_json_engine.pyto produce a second PCR list. Both lists are concatenated and fed to the confidence signal'spolicyinput. Whenwhich kjis false, the script logs and proceeds with the Checkov/Wiz list only (no hard failure). - REQ-302:
tests/test_plan_json_policies.py+ fixturetests/fixtures/plan_json/— a passing + failing plan JSON.tests/test_run_platform_plan_json_policies.pyassertsrun_platform.shhas the kyverno-json Step 5 block and that it concatenates PCR lists.
Category: Meta-Policies (feat)
- REQ-303:
adapters/kyverno-json/policies/meta/holds policies whose payload is the mergedlist[PolicyCheckResult]itself.block-on-any-critical.json— asserts no PCR in the list hasseverity: "critical"+result: "fail"; if any does, the meta-policy emits afailPCR withruleId: "KJ_META_BLOCK_CRITICAL"and severitycritical. This is the declarative source of truth for "critical = block"; theconfidence_signal.pyPENALTY["critical"]: Nonehard-override stays as defense-in-depth.tagging-rules-agree.json— for every resource in the Stack IR, asserts the CheckovNOVA_TAG_NAMINGresult and the kyverno-jsonKJ_REQUIRE_TAGGING_STANDARDresult agree; divergence emits anerrorPCR.tests/test_meta_policies.pycovers both.
Category: Regression-Gate Policies (feat, quality improvement from IDEATE)
- REQ-304:
adapters/kyverno-json/policies/regression/holds policies over the capability-inventory JSON frontmatter. Three policies port the imperative checks incore/regression_verify.py:cap-013-adapter-dedup.json,cap-023-metrics-collector.json,cap-024-deck-structure.json. The existingcore/regression_verify.pyis kept (it drives the CI gate); the policies are the declarative mirror that makes capability regression auditable as a policy artifact, not imperative Python. Future milestones may switch the gate to the policy version. - REQ-305:
tests/test_regression_policies.py+ fixturetests/fixtures/capability_inventory.json— a clean inventory (all caps pass) + a drifted inventory. The regression gate (pytestsuite) continues to pass; the new policy tests are additive.
Category: Documentation (docs)
- REQ-306:
adapters/README.mdgains a new row for thekyverno-jsonadapter + a new section "Policy Engine Protocol" documenting thePolicyEngineProtocol, the registry, and the swap boundary (how to add anOpaEngine).adapters/kyverno-json/README.mddocuments the engine, the install path, the policy directory layout, and the four policy categories. - REQ-307:
.ciagent/ARCHITECTURE.mdgains §12.7 "Policy Engine Registry" with the registry diagram.schemas/README.mdnotes theengine: "kyverno"value is shared by the K8s Kyverno adapter and the kyverno-json engine (distinguished byruleIdprefix).modules/STANDARDS.mdgains a "Policy authoring standard" section.docs/METRICS.mdnotes the policy engine is now swappable (Strategic Objective #2 — provable trust via a replaceable substrate, not a vendor lock-in).
Category: Tests (test)
- REQ-308:
tests/test_policy_engine.py— protocol conformance, unknown-engineKeyError,NullEnginefallback when thepolicykey is absent,KyvernoJsonEngine.is_configured()returns false whenwhich kjfails (mocked).tests/test_kyverno_json_engine.py—evaluate()returns valid PCR dicts validated againstschemas/policy_check_result.schema.json; native-output parsing is defensive (malformed →errorPCR, not exception);is_configured()==false→SKIPPEDPCR withKJ_ENGINE_NOT_CONFIGURED. - REQ-309: All new tests use
pytest.skip("kj not installed")whenwhich kjis absent, so the suite passes in environments without the binary (CI matrix: with-kj and without-kj).pyproject.toml+requirements-test.txtunchanged (kyverno-json is a Go binary, not a Python dep).
Out of Scope (v1.25)
- Removing Checkov or Wiz. Both stay as raw-finding adapters.
OpaEngineimplementation. The protocol is the swap boundary; the OPA implementation is a future milestone.- Per-module policies.
modules/<name>/policies/is documented as the future pattern inmodules/STANDARDS.mdbut not populated this milestone. - kyverno-json as a long-running service. v1.25 uses the CLI
(
kj scan); thekj serveweb-app mode is future. - Replacing the K8s Kyverno adapter. The K8s adapter
(
adapters/kyverno/) remains documentation-only (D-053).
v1.25 Traceability
| REQ | Phase | Status |
|---|---|---|
| REQ-291 | P1 | complete |
| REQ-292 | P1 | complete |
| REQ-293 | P1 | complete |
| REQ-294 | P1 | complete |
| REQ-295 | P2 | complete |
| REQ-296 | P2 | complete |
| REQ-297 | P2 | complete |
| REQ-298 | P2 | complete |
| REQ-299 | P2 | complete |
| REQ-300 | P3 | complete |
| REQ-301 | P3 | complete |
| REQ-302 | P3 | complete |
| REQ-303 | P3 | complete |
| REQ-304 | P4 | complete |
| REQ-305 | P4 | complete |
| REQ-306 | P4 | complete |
| REQ-307 | P4 | complete |
| REQ-308 | P1 | complete |
| REQ-309 | P1 | complete |
v1.26 — Live Pilot Estate Activation (active)
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. Tags run on the v1.25.x line:v1.25.0(P0) →v1.25.1..v1.25.4(P1–P4) →v1.25.5(P5 final = milestone release).Multi-project mode: the v1.26 requirements live in
.ciagent/nova-blockchain-exchange/REQUIREMENTS.md(the consumer subproject). The platform-side requirement REQ-322 (DynamoDB L1 primitive) landed in P2 of the platform repo. The 13 requirements (REQ-310..322) cover: 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).
v1.26 Traceability (live — see CHECKPOINT.json for authoritative state)
| REQ | Phase | Status |
|---|---|---|
| REQ-310 | P1 | complete (v1.25.1) |
| REQ-311 | P1 | complete (v1.25.1) |
| REQ-312 | P1 | complete (v1.25.1) |
| REQ-322 | P2 | complete (v1.25.2) |
| REQ-313 | P2 | complete (v1.25.2) |
| REQ-314 | P2 | complete (v1.25.2) |
| REQ-315 | P3 | complete (v1.25.3) |
| REQ-316 | P3 + P4 | complete (v1.25.3 — CAP-025; v1.25.4 — live-verify complete) |
| REQ-317 | P3 | complete (v1.25.3) |
| REQ-318 | P3 | complete (v1.25.3) |
| REQ-319 | P3 | complete (v1.25.3) |
| REQ-320 | P3 | complete (v1.25.3) |
| REQ-321 | P4 | complete (v1.25.4) |
Full v1.26 requirement text:
.ciagent/nova-blockchain-exchange/REQUIREMENTS.md. Active phase plan:
.ciagent/PLAN.md.