Skip to content
docsv0.1.0

GovernanceCompiler

Compiles decisions + profile (already validated) into a deterministic GovernancePlan. Loading doctrine (Amendment 2 of ADR#14): supersession is DERIVED, the past is never mutated. ADR files are `accepted` byte-identical forever; a decision ending up `superseded` is a CALCULATED effect in the plan (`effectiveStatus`), never a change in the input decision (`declaredStatus`, which reflects the file as-is, immutable). The same Amendment 2 requires the plan to reflect ONLY accepted governance. That is enforced in code with two criteria (see `entersPlan()` / `isActive()`), a single source of truth used uniformly in `compileDecisions()`, `compileRules()`, `compileGates()`, `compileArtifacts()`, and `indexSupersededBy()`: - **Enters the plan** (`entersPlan`): `status === Accepted`. A `superseded` decision has `status === Accepted` in its file (the file never changes) — that's why it DOES enter, with its `effectiveStatus` derived to `superseded` to show the lineage honestly. `rejected`/`proposed`/`deprecated` NEVER enter: neither as a `decisions` entry, nor do their gates/artifacts declared via policies govern anything. - **Active** (`isActive`): enters the plan AND is not superseded. Only active decisions generate `rules`, and their `kind:gate`/`kind:artifact` policies flow into `gates`/`artifacts` — a superseded decision still appears in `plan.decisions` for traceability, but no longer governs (the successor replaced it). `$decisions` is the full corpus known to the compiler (includes historical lineage: already-superseded decisions, or even rejected/proposed ones that never governed, needed to derive `supersededBy` and so the plan can honestly show its history). `$profile->decisionIds` is, instead, the set of CURRENT decisions the profile declares — `validate()` (the T2 wall) rejects any profile that directly references an already-superseded decision, even when the one that supersedes it is also listed. That's why the plan's `decisions`/`gates`/`artifacts` sections are derived from ALL of `$decisions` (the full lineage, filtered by the criteria above), not just from `$profile->decisionIds` — so the plan can honestly show "ADR-0004 was superseded by ADR-0014" without the profile having to break the wall.

GovernanceCompiler::__construct()

public function __construct(Milpa\Governance\GovernanceValidator $validator):

Parameters

Parameters of __construct()
NameTypeDescription
$validatorMilpa\Governance\GovernanceValidator

GovernanceCompiler::compile()

public function compile(array $decisions, Milpa\Governance\GovernanceProfile $profile): Milpa\Governance\GovernancePlan

Validates and compiles a deterministic governance plan.

Parameters

Parameters of compile()
NameTypeDescription
$decisionslist<GovernanceDecision>Full corpus of known decisions (includes historical superseded lineage and rejected/proposed decisions that never governed)
$profileMilpa\Governance\GovernanceProfile

Throws

GovernanceException if `$decisions`/`$profile` do not form a coherent and honest contract (propagated unwrapped from `validate()`), or if a `kind:gate`/`kind:artifact` policy declares an unrecognized tier