--- project: acdl milestone: v1.25 generated_at: 2026-08-12 generator: lead-developer 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" 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" lint: "ruff check core/policy_engine.py adapters/kyverno-json/ 2>/dev/null || python3 -m py_compile core/policy_engine.py" note: | v1.25 is the kyverno-json Unified Policy Engine milestone — a feat milestone. Four active personas: lead-developer (coordination + docs + ARCHITECTURE.md §12.7), backend-engineer (core/policy_engine.py protocol + registry + contract_resolver.py wiring + run_platform.sh Step 5 + pipeline tests), policy-engineer (adapters/kyverno-json/ engine + policies across all 4 target dirs + meta-policies + policy tests + adapter README + STANDARDS.md policy-authoring section), data-engineer (config.json policy object + schemas/README.md note + capability-inventory JSON fixture for regression policies). frontend-engineer stays deactivated (no UI). The policy-engineer is a new custom persona created for this milestone's policy domain (see 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) > v1.25 roster. Four active personas + one deactivated. This is a feat > milestone: the work is a swappable policy-engine protocol + a new > adapter + policies across 4 Nova artifacts + pipeline wiring + docs. > The policy-engineer is a new custom persona — kyverno-json + JMESPath > is a specialized domain that doesn't fit backend-engineer's > fastify/hono frameworks or data-engineer's drizzle/postgresql. ## Active personas ### lead-developer - **Domain:** coordination + docs - **Frameworks:** [] - **Constraints:** ["pragmatic", "battle-tested defaults", "docs match code", "swap boundary is the moat"] - **Territory:** - `.ciagent/ARCHITECTURE.md` (§12.7 Policy Engine Registry — NEW) - `.ciagent/PROJECT.md` (v1.25 section) - `.ciagent/REQUIREMENTS.md` (v1.25 section) - `.ciagent/ROADMAP.md` (v1.25 section) - `.ciagent/PLAN.md`, `.ciagent/RESEARCH.md`, `.ciagent/CLARIFY.md`, `.ciagent/GRILL.md`, `.ciagent/PERSONAS.md` - `docs/METRICS.md` (swappable engine narrative — REQ-307) - **Reason:** Owns the milestone coordination + the architecture narrative. The swap boundary (PolicyEngine protocol) is the moat per Strategic Objective #2 — the lead-developer owns the boundary description in ARCHITECTURE.md §12.7 and the docs/METRICS.md note. No Python policy code (backend-engineer + policy-engineer territory). No UI (frontend-engineer deactivated). ### backend-engineer - **Domain:** backend (Python + bash + pipeline wiring) - **Frameworks:** ["boto3", "terraform"] - **Constraints:** ["api-first", "strict-typing", "engine-agnostic confidence signal", "fail-soft when kj absent"] - **Territory:** - `core/policy_engine.py` (NEW — PolicyEngine Protocol + PolicyEngineRegistry + NullEngine) - `core/contract_resolver.py` (MODIFIED — invoke registry pre/post resolve) - `scripts/run_platform.sh` (MODIFIED — Step 5 kyverno-json parallel pass) - `scripts/install-kyverno-json.sh` (NEW) - `tests/test_policy_engine.py` (NEW — protocol conformance, registry, NullEngine) - `tests/test_run_platform_plan_json_policies.py` (NEW — script-substring assertion) - `.github/workflows/ci.yml` + `.gitea/workflows/ci.yml` (MODIFIED — Go + kj install) - **Reason:** Owns the Python protocol layer + the pipeline wiring. The `PolicyEngine` Protocol + `PolicyEngineRegistry` are Python structural- typing constructs (PEP 544) — backend-engineer's strict-typing constraint. The `contract_resolver.py` wiring + `run_platform.sh` Step 5 are backend territory. Does NOT write kyverno-json policy files (policy-engineer territory) — only the Python that *invokes* the engine. Does NOT modify the confidence signal (it already consumes `list[PolicyCheckResult]` engine-agnostically — PROJECT.md hard- constraint). ### policy-engineer - **Domain:** policy (declarative compliance rules) - **Frameworks:** ["kyverno-json", "jmespath", "kyverno ValidatingPolicy"] - **Constraints:** ["declarative-policies", "no-imperative-rules", "schema-validated", "severity-via-annotation", "assertion-trees-not-foreach"] - **Territory:** - `adapters/kyverno-json/` (NEW — engine impl + __init__.py + README) - `adapters/kyverno-json/kyverno_json_engine.py` (NEW — KyvernoJsonEngine) - `adapters/kyverno-json/policies/` (NEW — all 4 target dirs: contract/, stack-ir/, plan-json/, meta/, regression/) - `adapters/kyverno-json/policies/_smoke.json` (NEW) - `adapters/README.md` (MODIFIED — new adapter row + PolicyEngine Protocol section) - `tests/test_kyverno_json_engine.py` (NEW — PCR schema validity, defensive parsing) - `tests/test_stack_ir_policies.py` (NEW) - `tests/test_plan_json_policies.py` (NEW) - `tests/test_meta_policies.py` (NEW) - `tests/test_regression_policies.py` (NEW) - `tests/fixtures/stack_ir/`, `tests/fixtures/plan_json/`, `tests/fixtures/capability_inventory.json` (NEW) - `modules/STANDARDS.md` (MODIFIED — Policy authoring standard section — REQ-307) - **Reason:** The policy-engineer owns the declarative policy artifacts. kyverno-json's `ValidatingPolicy` + assertion trees + JMESPath is a 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 - **Domain:** data (config schema + structured fixtures) - **Frameworks:** ["jsonschema", "yaml"] - **Constraints:** ["schema-first", "type-safe config", "backward-compatible additions"] - **Territory:** - `.ciagent/config.json` (MODIFIED — new `policy` object: engine + policy_root) - `schemas/policy_check_result.schema.json` (READ-ONLY — no change per D-116) - `schemas/README.md` (MODIFIED — note engine: "kyverno" shared by K8s adapter + kj) - `tests/fixtures/capability_inventory.json` (NEW — clean + drifted inventory fixtures for regression policies) - **Reason:** The `config.json.policy` object is a schema-first addition (new top-level key with `engine` + `policy_root` fields). The capability-inventory JSON fixtures for the regression-gate policies (REQ-304) are structured data — the data-engineer owns the fixture shape. The `policy_check_result.schema.json` is read-only (D-116 — no enum change); the data-engineer documents the `engine: "kyverno"` sharing in `schemas/README.md`. No migrations (no database). No Python (backend-engineer + policy-engineer territory). ## Deactivated personas ### frontend-engineer - **active:** false - **Reason:** ACDL has no frontend (no package.json — confirmed in config.json personas.personas[frontend-engineer].reason). v1.25 adds no UI work — the policy engine is backend + policy artifacts only. Deactivated per the v1.15+ convention.