# Policy Engine · Overlay Projection Prep (POLICY-ENGINE-30-001) - **Date:** 2025-11-20 - **Depends on:** Path/Scope schema (29-002) and observability contract (29-004) - **Working directory:** `src/Policy/StellaOps.Policy.Engine` ## Projection contract - Input: `PathScope` documents (see 29-002) + `PolicyRule` definitions. - Output: `OverlayProjection` objects stored/snapshotted for replay: - `tenant` (string) - `ruleId` (string) - `subject` (purl/cpe, optional packagePath) - `scope` (copied from input) - `decision` (`allow|deny|warn|defer`) - `reasons[]` (machine-readable codes; e.g., `path-match`, `severity-threshold`, `capability-needed`) - `artifacts` (hash list) — `evidenceHash`, `treeDigest?`, `dsseEnvelopeHash?` used in evaluation - `effectiveAt` (ISO-8601 UTC) — time projection became active - `expiresAt?` (ISO-8601 UTC) — optional - `version` (int) — monotonic per ruleId ## Ordering & determinism - Projection list sorted by (`ruleId`, `subject.purl|cpe`, `scope.pathMatch`, `scope.pattern`, `effectiveAt`). - Hash for `artifacts.evidenceHash` reused from input to keep replay stable. ## Storage hints - Persist overlays as NDJSON under `overlay/{tenant}/{ruleId}/{version}.ndjson` for air-gapped export. - Snapshots include header line with schema version `overlay-projection-v1` followed by sorted projections. ## Acceptance for prep completion - Projection shape, ordering, and filenames are frozen for implementation tasks 30-001..30-003. - Downstream simulation/change-event work (30-002/30-003) must emit/consume this structure without mutation.