From ec533020149f48f14ed1a4251ac23d4d2745128b Mon Sep 17 00:00:00 2001 From: Jon Chery Date: Wed, 12 Aug 2026 18:11:00 +0000 Subject: [PATCH] =?UTF-8?q?docs(P00):=20create=20phase=20plans=20=E2=80=94?= =?UTF-8?q?=20v1.25=20(4=20phases,=204=20waves)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLAN.md: 4 execution phases (P1 engine-core, P2 contract+stack-IR policies, P3 plan-JSON+meta+pipeline wiring, P4 regression-gate+docs) + P5 final review/ship. Wave ordering with parallelization (3-2-2-3 concurrent personas). Each phase is a vertical slice (end-to-end: policies + Python wiring + tests + docs). Tags v1.24.0..v1.24.5. 19 requirements (REQ-291..309) mapped to phases and personas. ---ci--- project: acdl phase: 0 milestone: v1.25 status: plan ---/ci--- --- .ciagent/CHECKPOINT.json | 19 +- .ciagent/PLAN.md | 449 ++++++++++++++++++++++++++++----------- 2 files changed, 327 insertions(+), 141 deletions(-) diff --git a/.ciagent/CHECKPOINT.json b/.ciagent/CHECKPOINT.json index 48b01e6..c4b3fa1 100644 --- a/.ciagent/CHECKPOINT.json +++ b/.ciagent/CHECKPOINT.json @@ -1,22 +1,17 @@ { "phase": 0, - "stage": "ideate", + "stage": "plan", "milestone": "v1.25", "phase_role": "pre_execution", "attempts": 0, - "updated_at": "2026-08-12T16:40:00Z", + "updated_at": "2026-08-12T16:45:00Z", "project": "acdl", "milestone_complete": false, "tag_line": "v1.24.x", "next_tag": "v1.24.0", - "ideation": { - "tiers_run": ["mechanical", "backend-enriched"], - "cross_project": "deferred (single-project, config disabled)", - "ideas_accepted": 5, - "ideas_deferred": 3, - "ideas_rejected": 0, - "accepted_into_reqs": ["REQ-295", "REQ-297", "REQ-300", "REQ-303", "REQ-304", "REQ-305"], - "deferred": ["I6-env-transition-as-policy", "I7-drift-as-policy", "I8-cross-project-sharing"] - }, - "notes": "IDEATE complete — 5 accepted (already in REQ-291..309), 3 deferred with documented blockers. No new reqs added; the pass validated the requirement set." + "phases": 6, + "execution_phases": 4, + "requirements_total": 19, + "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"], + "notes": "v1.25 PLAN complete — 4 execution phases (P1 engine-core, P2 contract+stack-IR policies, P3 plan-JSON+meta+pipeline, P4 regression+docs) + P5 final review/ship. Wave ordering with parallelization (3-2-2-3 concurrent personas). Each phase is a vertical slice. Tags v1.24.0..v1.24.5." } \ No newline at end of file diff --git a/.ciagent/PLAN.md b/.ciagent/PLAN.md index 04f9752..3d4d4ce 100644 --- a/.ciagent/PLAN.md +++ b/.ciagent/PLAN.md @@ -1,180 +1,371 @@ -# PLAN — v1.24 (Consumer Guide Accuracy & Env-Promotion Lifecycle Enforcement) +# PLAN — v1.25 (kyverno-json Unified Policy Engine) -> Feature milestone (one `feat` phase: env-transition destroy enforcement; -> the rest are `fix`/`docs`/`test`). Tags on the **v1.23.x** line: -> v1.23.0 (P0) → v1.23.1 (P1) → v1.23.2 (P2) → v1.23.3 (P3) → v1.23.4 (P4 -> final = milestone release). 15 requirements (REQ-276..290), 4 phases + -> P0 pre-execution. +> Feature milestone. Tags on the **v1.24.x** line: v1.24.0 (P0) → +> v1.24.1 (P1) → v1.24.2 (P2) → v1.24.3 (P3) → v1.24.4 (P4) → v1.24.5 +> (P5 final = milestone release). 19 requirements (REQ-291..309), +> 4 execution phases + P0 pre-execution + P5 final review/ship. + +## Wave model + +Each phase is a **vertical slice** (end-to-end: policy files + Python +wiring + tests + docs). Phases are ordered by dependency: the engine +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 — consumer-guide-fixes (Wave 1, lead-developer) +### Phase P1 — engine-core (Wave 1, backend-engineer + policy-engineer + data-engineer) -**Type:** `docs` + `fix` + `test` (consumer guide accuracy + guide test updates) +**Type:** `feat` (engine protocol + registry + kyverno-json engine adapter + install + tests) -**Requirements:** REQ-276, REQ-277, REQ-278, REQ-279, REQ-280, REQ-281, REQ-290 +**Requirements:** REQ-291, REQ-292, REQ-293, REQ-294, REQ-308, REQ-309 **Must-haves:** -- `docs/consumer-guide.md` Step 3 contract fields table corrected (REQ-276) -- `docs/consumer-guide.md` Step 4 caller consistent with Step 2 (REQ-277) -- `docs/consumer-guide.md` Step 5 stage 8 "(dev only)" → "(autonomous in dev; higher environments apply after HITL attestation)" (REQ-278) -- `docs/consumer-guide.md` Step 8 rewritten with destroy-then-rebuild semantics + cross-ref to Shape B (REQ-279) -- `docs/consumer-guide.md` Per-env section gains Shape B lead sentence (REQ-280) -- `docs/consumer-guide.md` Reference table `@v1.19` wording corrected (REQ-281) -- `tests/test_consumer_guide_per_env_section.py` updated: rename `test_consumer_guide_states_no_field_editing` → `test_consumer_guide_documents_both_promotion_shapes`; add `test_consumer_guide_documents_destroy_on_env_change` (REQ-290) +- `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 --payload --output json`, translates + native output → `list[dict]` PCR records (`engine: "kyverno"`, + `ruleId` prefixed `KJ_`, 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:** A reader of `docs/consumer-guide.md` can promote via -either shape (A: edit environment + platform destroys prior; B: per-env -caller workflow) without contradiction. The guide's field table, caller -examples, and stage descriptions match the actual schema and platform -behavior. All consumer-guide tests pass. +**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:** -- `docs/consumer-guide.md` -- `tests/test_consumer_guide_per_env_section.py` +- `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_consumer_guide_per_env_section.py -v` -(all 7 tests pass). Manual read of `docs/consumer-guide.md` end-to-end -for internal consistency. +**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 P2 — env-transition-detect-and-destroy (Wave 2, backend-engineer) +### Phase P2 — contract + stack-IR policies (Wave 2, policy-engineer + backend-engineer) -**Type:** `feat` (new platform feature: env-transition detect-and-destroy) +**Type:** `feat` (policies + resolver wiring + tests) -**Requirements:** REQ-282, REQ-283, REQ-284, REQ-285, REQ-286, REQ-287 +**Requirements:** REQ-295, REQ-296, REQ-297, REQ-298, REQ-299 **Must-haves:** -- `core/env_transition.py` new module: `detect_prior_env()` + `record_applied_env()` with boto3 DynamoDB queries (REQ-282, REQ-283) -- `scripts/run_platform.sh` Step 0b: environment-transition check — detect prior env, re-resolve with `environment_override=prior_env` + `deletion_protection=false`, `terraform init -reconfigure` + `terraform destroy -auto-approve` against prior state key, emit `nova.env.destroyed` evidence event, fail closed on destroy failure (REQ-284) -- `scripts/run_platform.sh` records applied env after successful apply (REQ-285) -- `.github/workflows/deploy.yml` passes `NOVA_CONSUMER_REPO=${{ github.repository }}` to `run_platform.sh` (REQ-286) -- `adapters/terraform/adapter.py` state-key block gains doc comment (REQ-287) +- `adapters/kyverno-json/policies/contract/` — 4 policies over consumer + contract JSON: `require-id-pattern.json`, + `require-env-in-enum.json`, `require-infrastructure-min-1.json`, + `forbid-unknown-fields.json` — each a `ValidatingPolicy` with one + `validate.assert` rule using JMESPath against the payload root; + severity via `nova.cloudinit.dev/severity` annotation (REQ-295) +- `core/contract_resolver.py` invokes + `PolicyEngineRegistry.get_engine().evaluate(contract_dict, + 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:** When a consumer changes `environment:` on a stable -`contract.id`, the pipeline detects the prior env from DynamoDB, destroys -the prior env's Terraform state (with `deletion_protection=false`), emits -an evidence event, and only then applies the new env. If the destroy -fails, the pipeline exits non-zero (no orphan path). If no prior env -exists (first deploy or Shape B), the pipeline proceeds normally. +**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:** -- `core/env_transition.py` (NEW) -- `scripts/run_platform.sh` -- `.github/workflows/deploy.yml` -- `adapters/terraform/adapter.py` (doc comment only) +- `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:** `python3 -m py_compile core/env_transition.py`. -`pytest tests/test_pipeline.py tests/test_deploy_workflow_env_input.py -v` -(existing tests still pass). The new tests in P3 validate the behavior. - -**Key implementation notes (from RESEARCH §5 pitfalls):** -1. The destroy step must re-resolve with `environment_override=prior_env` - so the emitted TF matches the prior env's resources. -2. `terraform init -reconfigure` is required when switching state backends. -3. `deletion_protection: false` must be injected (same as decommission - Step 2 in `scripts/run_decommission.sh:34-37`) or `prevent_destroy` - blocks the destroy. -4. DynamoDB unreachable in local/CI → log warning + return `None` - (conservative, no prior env assumed). -5. The state key `spike/{id}/{env}/terraform.tfstate` stays as-is — the - env segment is what lets the destroy target the prior env. +**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 P3 — env-transition-tests (Wave 3, backend-engineer + lead-developer) +### Phase P3 — plan-JSON policies + meta-orchestration + pipeline wiring (Wave 3, policy-engineer + backend-engineer) -**Type:** `test` (new test coverage for env-transition + pipeline integration) +**Type:** `feat` (plan-JSON policies + meta-policies + run_platform.sh wiring + tests) -**Requirements:** REQ-288, REQ-289 +**Requirements:** REQ-300, REQ-301, REQ-302, REQ-303 **Must-haves:** -- `tests/test_env_transition.py` (NEW): `detect_prior_env` returns `None` when no record; returns prior env when record differs; returns `None` when record matches; `record_applied_env` writes record. Uses moto for DynamoDB (REQ-288) -- `tests/test_run_platform_env_transition.py` (NEW): asserts `run_platform.sh` has Step 0b; calls `env_transition.py detect`; calls `terraform destroy` on prior env; fails closed on destroy failure; records applied env after success (REQ-289) +- `adapters/kyverno-json/policies/plan-json/` — 3 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); JMESPath over + `planned_values.root_module.resources[]` (REQ-300) +- `run_platform.sh` Step 5 gains a parallel kyverno-json pass: after + Checkov/Wiz produce raw PCRs, the script runs + `kj scan --policy adapters/kyverno-json/policies/plan-json/ + --payload -o json` and pipes through + `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:** The env-transition detect-and-destroy behavior is -fully covered by automated tests. The DynamoDB query logic is unit-tested -with moto. The pipeline orchestration is tested via shell-text assertions -(pattern from `tests/test_pipeline.py:79-95`). +**Vertical slice:** `run_platform.sh` Step 5 produces a merged PCR list +(Checkov/Wiz + kj plan-JSON policies + kj meta-policies over the +merged list) that feeds the confidence signal. A plan with a plaintext +secret produces two `fail` PCRs (one Checkov, one kj) for the same +resource — visible defense-in-depth. A critical finding anywhere +produces a `KJ_META_BLOCK_CRITICAL` meta-PCR that the confidence +signal's hard-override blocks. The pipeline runs with or without `kj` +(graceful skip). **Files touched:** -- `tests/test_env_transition.py` (NEW) -- `tests/test_run_platform_env_transition.py` (NEW) +- `adapters/kyverno-json/policies/plan-json/forbid-plaintext-secrets.json` (NEW) +- `adapters/kyverno-json/policies/plan-json/forbid-iam-wildcard.json` (NEW) +- `adapters/kyverno-json/policies/plan-json/require-kms-reference.json` (NEW) +- `adapters/kyverno-json/policies/meta/block-on-any-critical.json` (NEW) +- `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_env_transition.py tests/test_run_platform_env_transition.py -v` (all new tests pass). Full suite: `pytest tests/ -k "env_transition or consumer_guide or pipeline or adapter or deploy_workflow" -v`. +**Verification:** `pytest tests/test_plan_json_policies.py +tests/test_meta_policies.py tests/test_run_platform_plan_json_policies.py +tests/test_pipeline.py -v` (new tests pass or skip-without-kj; existing +pipeline tests pass). `python3 -m py_compile` on any modified Python. +Shellcheck on `run_platform.sh` if available. --- -### Phase P4 — final-review-ship (Wave 4, lead-developer) +### Phase P4 — regression-gate policies + docs (Wave 4, policy-engineer + data-engineer + lead-developer) -**Type:** `docs` (review + audit + milestone ship) +**Type:** `feat` (regression policies) + `docs` (adapter READMEs + ARCHITECTURE + STANDARDS + METRICS) -**Requirements:** (none new — milestone completion) +**Requirements:** REQ-304, REQ-305, REQ-306, REQ-307 **Must-haves:** -- Multi-persona code review across P1-P3 changes (ci-code-reviewer) -- Project health audit (ci-doc-verifier + ci-audit) -- Milestone ship: tag v1.23.4 (final phase patch = milestone release), merge to main, Gitea release -- Update REQUIREMENTS.md traceability (all REQ-276..290 → complete) -- Update ROADMAP.md (v1.24 → complete) +- `adapters/kyverno-json/policies/regression/` — 3 policies over + capability-inventory JSON frontmatter: `cap-013-adapter-dedup.json`, + `cap-023-metrics-collector.json`, `cap-024-deck-structure.json`; + emit `pass`/`fail` PCRs per capability; the existing + `core/regression_verify.py` is kept (drives the CI gate); the + policies are the declarative mirror (REQ-304) +- `tests/test_regression_policies.py` + + `tests/fixtures/capability_inventory/clean.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 +declarative policies auditable as artifacts. A new module owner can +read `modules/STANDARDS.md` "Policy authoring standard" and write a +per-module kyverno-json policy. A new engineer can read +`adapters/README.md` "Policy Engine Protocol" and implement an +`OpaEngine`. The 287/287 baseline is unchanged. + +**Files touched:** +- `adapters/kyverno-json/policies/regression/cap-013-adapter-dedup.json` (NEW) +- `adapters/kyverno-json/policies/regression/cap-023-metrics-collector.json` (NEW) +- `adapters/kyverno-json/policies/regression/cap-024-deck-structure.json` (NEW) +- `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 +tests/test_kyverno_json_engine.py -v` (new tests pass or skip-without- +kj). Full regression gate `pytest tests/` still at 287/287 baseline + +new tests (skip without kj). Manual read of `adapters/README.md` + +`adapters/kyverno-json/README.md` + `modules/STANDARDS.md` policy +section for clarity. --- -## Wave ordering +### Phase P5 — final review + audit + milestone ship (Final Phase) -``` -Wave 1 (P1): consumer-guide-fixes [lead-developer] - ↓ -Wave 2 (P2): env-transition-detect-and-destroy [backend-engineer] - ↓ -Wave 3 (P3): env-transition-tests [backend-engineer + lead-developer] - ↓ -Wave 4 (P4): final-review-ship [lead-developer] -``` +**Type:** `docs` (review + audit + milestone completion) -**Dependencies:** -- P2 depends on P1: the Step 8 rewrite in P1 documents the destroy - semantics that P2 implements. Doing P1 first ensures the docs and code - land in the right order (docs describe the intended behavior, then code - implements it). -- P3 depends on P2: the tests validate the env-transition module and - pipeline Step 0b that P2 creates. -- P4 depends on P1+P2+P3: the final review covers all changes. +**Requirements:** All REQ-291..309 (mark complete) -**Parallelization:** P1 and P2 could run in parallel (different -territories: docs vs code), but the wave ordering is sequential for -safety — if P1's Step 8 rewrite reveals a design issue, P2's -implementation should follow the corrected design. With -`parallelization.enabled=true` and `min_plans_for_parallel=2`, the -orchestrator *could* run them concurrently; however, the dependency -(P2 follows P1's design) makes sequential the safer choice. P3 must -follow P2 (tests validate the code). P4 must follow all. +**Must-haves:** +- `ciagent-review` multi-persona code review across P1..P4 + (lead-developer, backend-engineer, data-engineer, policy-engineer). + Auto-fix P0; flag P1+ for post-hoc review. If P1+ issues found, fix + them in this final phase (not loop back to EXECUTE). +- `ciagent-audit` — reconstruction test (git log ↔ `.ciagent/` files), + `.ciagent/` file discipline, branch hygiene, commit discipline. + Critical issues fixed in this phase. +- `ciagent-ship` (milestone) — merge `phase/05-final-review-ship` → + `milestone/v1.25-kyverno-json` → `main`; tag `v1.24.5` (= the v1.25 + release per the prev-minor tagging rule); create Gitea release with + full milestone summary (all phases, all requirements); delete all + 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). -## Requirement → Phase mapping +**Vertical slice:** The v1.25 milestone is complete: kyverno-json is +the primary policy tool, behind a swappable adapter, with policies +over all 4 Nova artifacts. Tags v1.24.0..v1.24.5 on the v1.24.x line. +The milestone branch merges to main. -| REQ | Phase | Type | Description | -|-----|-------|------|-------------| -| REQ-276 | P1 | docs | Contract fields table corrected | -| REQ-277 | P1 | docs | Step 4 caller consistent with Step 2 | -| REQ-278 | P1 | docs | Step 5 stage 8 "dev only" corrected | -| REQ-279 | P1 | docs | Step 8 rewritten with destroy semantics | -| REQ-280 | P1 | docs | Per-env section Shape B lead sentence | -| REQ-281 | P1 | docs | Reference table @v1.19 wording corrected | -| REQ-282 | P2 | feat | env_transition.py detect_prior_env() | -| REQ-283 | P2 | feat | env_transition.py record_applied_env() | -| REQ-284 | P2 | feat | run_platform.sh Step 0b detect-and-destroy | -| REQ-285 | P2 | feat | run_platform.sh records applied env | -| REQ-286 | P2 | feat | deploy.yml passes NOVA_CONSUMER_REPO | -| REQ-287 | P2 | docs | adapter.py state-key doc comment | -| REQ-288 | P3 | test | test_env_transition.py | -| REQ-289 | P3 | test | test_run_platform_env_transition.py | -| REQ-290 | P1 | test | consumer guide test updates | +**Verification:** `pytest tests/ -v` full suite passes (287 baseline + +new tests). `git log --oneline` shows the v1.25 phase commits. +`git tag` shows v1.24.0..v1.24.5. `git branch` shows no leftover +milestone/phase branches (all deleted post-ship). -## Tag plan +--- -- P0 (this phase): `v1.23.0` — pre-execution patch -- P1: `v1.23.1` — consumer guide fixes -- P2: `v1.23.2` — env-transition detect-and-destroy -- P3: `v1.23.3` — env-transition tests -- P4: `v1.23.4` — final review + ship = **milestone release** \ No newline at end of file +## Wave ordering (parallelization) + +With `parallelization.enabled: true`, `max_concurrent_agents: 5`, +`min_plans_for_parallel: 2`: + +- **P1 Wave 1:** backend-engineer (protocol + registry + install) ‖ + data-engineer (config.json policy object) ‖ policy-engineer (engine + adapter + smoke policy). 3 concurrent personas. Merge in order: + data-engineer → backend-engineer → policy-engineer. +- **P2 Wave 2:** policy-engineer (contract + stack-IR policies) ‖ + backend-engineer (resolver wiring — depends on P1 registry). 2 + 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 +personas.territory_enforcement: "warn"`). Cross-territory edits +(e.g., backend-engineer touching a policy file) emit a warning, not a +block. + +## Requirement → phase → persona matrix + +| REQ | Phase | Primary persona | Type | +|-----|-------|-----------------|------| +| REQ-291 | P1 | backend-engineer | feat | +| REQ-292 | P1 | data-engineer | feat (config) | +| REQ-293 | P1 | policy-engineer | feat | +| REQ-294 | P1 | backend-engineer | feat (install) | +| REQ-295 | P2 | policy-engineer | feat | +| REQ-296 | P2 | backend-engineer | feat (wiring) | +| REQ-297 | P2 | policy-engineer | feat | +| REQ-298 | P2 | backend-engineer | feat (wiring) | +| REQ-299 | P2 | policy-engineer | test | +| 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) | +| REQ-304 | P4 | policy-engineer | feat | +| REQ-305 | P4 | policy-engineer + data-engineer | test | +| REQ-306 | P4 | policy-engineer + lead-developer | docs | +| REQ-307 | P4 | lead-developer | docs | +| REQ-308 | P1 | backend-engineer | test | +| REQ-309 | P1 | policy-engineer | test | \ No newline at end of file