Files
acdl/.ciagent/REQUIREMENTS.md
T
Jon Chery 3a32c3b898 fix(P05): REQ-316 traceability — P4 live-verify complete (not pending)
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 (commit 6ced8ed), 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
---
2026-08-19 03:53:15 +00:00

16 KiB
Raw Permalink Blame History

Nova — Requirements

Compressed. The full v1.0v1.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 per config.json).

Earlier requirement sets (v1.0v1.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-json becomes the primary compliance / policy tool, implemented behind a swappable PolicyEngine adapter 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). Tag v1.24.5 = the milestone release.

One problem, one architectural correction:

  1. 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 a PolicyEngine protocol so it is replaceable. The confidence signal is untouched — it already consumes list[PolicyCheckResult] engine-agnostically.

Decisions (locked in CLARIFY, full autonomy — load-bearing for v1.26)

  • D-115 (C-1): kyverno-json is a runtime dependency installed via go install github.com/kyverno/kyverno-json/cmd/kj@latest (pinned in a scripts/install-kyverno-json.sh helper; the CI image installs it). Not a Python package — kyverno-json is a Go binary. The KyvernoJsonEngine.is_configured() checks which kj and skips gracefully when absent (emits SKIPPED PCR, mirroring the Wiz adapter).
  • D-116 (C-2): kyverno-json PCR records carry engine: "kyverno" (no new enum value). The existing engine enum in schemas/policy_check_result.schema.json already includes "kyverno"; adding "kyverno-json" would force a schema change + checkov_adapter test regression for no semantic gain. The ruleId prefix KJ_ distinguishes kyverno-json rules from the K8s Kyverno adapter's KYVERNO_ 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 in adapters/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 in adapters/terraform/policy/custom_rules/nova_tagging.py) is kept. A kyverno-json mirror policy require-tagging-standard.json is added in adapters/kyverno-json/policies/stack-ir/. 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). 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.py defines a PolicyEngine Python Protocol (PEP 544) with three members: name -> str, is_configured() -> bool, and evaluate(payload: dict | str, policy_dir: Path, contract_id: str) -> list[dict] (where each dict conforms to schemas/policy_check_result.schema.json). A PolicyEngineRegistry singleton selects the active engine from config.json's new policy.engine key (default "kyverno-json"); raises KeyError on an unknown engine name. The registry exposes get_engine() and register(name, factory). Pure stdlib, no engine imports at the protocol layer.
  • REQ-292: .ciagent/config.json gains a new top-level policy object: {"engine": "kyverno-json", "policy_root": "adapters/kyverno-json/policies"}. The registry reads policy.engine to select the active engine and policy.policy_root as the default policy directory. Backward-compatible: if the policy key is absent, the registry returns a NullEngine that emits only SKIPPED records (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.py implements KyvernoJsonEngine satisfying the PolicyEngine protocol. is_configured() returns True when which kj succeeds. evaluate() writes the payload to a temp JSON file, invokes kj scan --policy <policy_dir> --payload <payload.json> -o json, parses the native result list, and translates each entry to a PCR dict (engine: "kyverno", ruleId prefixed KJ_<policy_name>, severity mapped, result mapped pass/fail/skip → pass/fail/skipped). When is_configured() is false, evaluate() returns a single SKIPPED PCR with ruleId: "KJ_ENGINE_NOT_CONFIGURED". Native output parsing is defensive: any kyverno-json output that doesn't match the expected shape produces an error PCR, never an exception.
  • REQ-294: adapters/kyverno-json/__init__.py exports KyvernoJsonEngine. adapters/kyverno-json/policies/_smoke.json is a single trivial policy (require-contract-id) used to validate the engine round-trip end-to-end in tests. scripts/install-kyverno-json.sh runs go install github.com/kyverno/kyverno-json/cmd/kj@latest and prints kj version; documented in adapters/kyverno-json/README.md. The CI image installs Go + kj when policy.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 mirroring schemas/contract.schema.json constraints: require-id-pattern.json, require-env-in-enum.json, require-infrastructure-min-1.json, forbid-unknown-fields.json. Each policy is a single Kyverno Policy resource with one validate.assert rule using JMESPath against the payload root.
  • REQ-296: core/contract_resolver.py invokes the PolicyEngineRegistry.get_engine().evaluate() with the contract dict and policies/contract/ before resolving (early-fail on contract violations) and emits a nova.policy.evaluated metrics event. Failures feed the confidence signal's policy input as fail PCRs; the resolver does not exit — the confidence signal decides the gate (consistent with the existing --soft-fail Checkov 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 carries nova:owner + nova:environment tags — ports nova_tagging.py into a declarative Kyverno policy). forbid-public-ingress.json (no resource has public_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.py invokes the engine with the resolved Stack IR and policies/stack-ir/ after resolving. The resulting PCRs are appended to the contract-policy PCRs and fed to the confidence signal. The resolver's existing tests/test_contract_resolver.py continues to pass (the policy call is additive — it does not change resolver return values or exceptions).
  • REQ-299: tests/test_stack_ir_policies.py + fixture tests/fixtures/stack_ir/ — a passing IR + a failing IR. Tests run the KyvernoJsonEngine against real kj when which kj succeeds, and pytest.skip("kj not installed") when absent.

Category: Plan-JSON Policies + Pipeline Wiring (feat)

  • REQ-300: adapters/kyverno-json/policies/plan-json/ holds policies over terraform show -json output. forbid-plaintext-secrets.json (ports CKV_AWS_41/45/46). forbid-iam-wildcard.json (ports CKV_AWS_1/40). require-kms-reference.json (ports CKV_AWS_7/33). The Checkov RULE_MAP in checkov_adapter.py is unchanged — these are declarative mirrors, not replacements.
  • REQ-301: run_platform.sh Step 5 ("runtime policy scan") gains a parallel kyverno-json pass: after Checkov/Wiz produce raw PCRs, the script runs kj scan and pipes through adapters/kyverno-json/kyverno_json_engine.py to produce a second PCR list. Both lists are concatenated and fed to the confidence signal's policy input. When which kj is false, the script logs and proceeds with the Checkov/Wiz list only (no hard failure).
  • REQ-302: tests/test_plan_json_policies.py + fixture tests/fixtures/plan_json/ — a passing + failing plan JSON. tests/test_run_platform_plan_json_policies.py asserts run_platform.sh has 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 merged list[PolicyCheckResult] itself. block-on-any-critical.json — asserts no PCR in the list 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"; the confidence_signal.py PENALTY["critical"]: None hard-override stays as defense-in-depth. tagging-rules-agree.json — for every resource in the Stack IR, asserts the Checkov NOVA_TAG_NAMING result and the kyverno-json KJ_REQUIRE_TAGGING_STANDARD result agree; divergence emits an error PCR. tests/test_meta_policies.py covers 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 in core/regression_verify.py: cap-013-adapter-dedup.json, cap-023-metrics-collector.json, cap-024-deck-structure.json. The existing core/regression_verify.py is 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 + fixture tests/fixtures/capability_inventory.json — a clean inventory (all caps pass) + a drifted inventory. The regression gate (pytest suite) continues to pass; the new policy tests are additive.

Category: Documentation (docs)

  • REQ-306: adapters/README.md gains a new row for the kyverno-json adapter + a new section "Policy Engine Protocol" documenting the PolicyEngine Protocol, the registry, and the swap boundary (how to add an OpaEngine). adapters/kyverno-json/README.md documents the engine, the install path, the policy directory layout, and the four policy categories.
  • REQ-307: .ciagent/ARCHITECTURE.md gains §12.7 "Policy Engine Registry" with the registry diagram. schemas/README.md notes the engine: "kyverno" value is shared by the K8s Kyverno adapter and the kyverno-json engine (distinguished by ruleId prefix). modules/STANDARDS.md gains a "Policy authoring standard" section. docs/METRICS.md notes 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-engine KeyError, NullEngine fallback when the policy key is absent, KyvernoJsonEngine.is_configured() returns false when which kj fails (mocked). tests/test_kyverno_json_engine.pyevaluate() returns valid PCR dicts validated against schemas/policy_check_result.schema.json; native-output parsing is defensive (malformed → error PCR, not exception); is_configured()==falseSKIPPED PCR with KJ_ENGINE_NOT_CONFIGURED.
  • REQ-309: All new tests use pytest.skip("kj not installed") when which kj is absent, so the suite passes in environments without the binary (CI matrix: with-kj and without-kj). pyproject.toml + requirements-test.txt unchanged (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.
  • OpaEngine implementation. 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 in modules/STANDARDS.md but not populated this milestone.
  • kyverno-json as a long-running service. v1.25 uses the CLI (kj scan); the kj serve web-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 (P1P4) → 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.