# Phase 3 Summary — Governance and Decision Linkage **Workplan:** IHUB-WP-0003 **Completed:** 2026-03-29 **Status:** Done — all exit criteria met --- ## What Was Built Phase 3 closes the central traceability chain of the Interaction Hub Framework: ``` Widget → InteractionEvent / Annotation → RequirementCandidate (Phase 2) → [accepted] → Requirement → DecisionRecord ← PolicyReference → ImplementationChangeReference → DeploymentRecord → OutcomeSignal (Phase 4+) ``` ### New Data Artifacts | Table | Purpose | |-------|---------| | `requirements` | Formal requirements promoted from accepted `RequirementCandidate`s | | `decision_records` | Governance decisions acting on requirements/candidates; outcome is immutable | | `policy_references` | Editorial links from decisions to policy scope (regulatory, contractual, etc.) | | `implementation_change_references` | Manual pointers to work items (GitHub, Linear, Jira, etc.) | `requirement_candidates` was extended with a `requirement_id` back-reference. ### New Controllers and Views - **`RequirementsController`** — index and show (no new/create — requirements come from promotion only) - **`DecisionRecordsController`** — full CRUD (no delete) + `AddPolicyReferenceAction` / `DeletePolicyReferenceAction` / `AddImplementationRefAction` / `DeleteImplementationRefAction` - **`GovernanceDashboardAction`** (on `HubsController`) — live AutoRefresh dashboard per hub ### Extended Controllers - **`RequirementCandidatesController`** — added `PromoteToRequirementAction` and `LinkToDecisionAction` - **`HubsController`** — added `GovernanceDashboardAction` - **`FrontController`** — registered previously-missing Phase 2 controllers (`AnnotationThreadsController`, `RequirementCandidatesController`) and all Phase 3 controllers ### Key Behaviors **Outcome immutability:** `DecisionRecord.outcome` is set on creation. `UpdateDecisionRecordAction` uses `fill` without the `outcome` field — it cannot be changed through the UI. A wrong decision should be superseded by creating a new record, not editing. **Promotion idempotency:** `PromoteToRequirementAction` checks `candidate.requirementId` before creating a new `Requirement`; duplicate calls redirect to the existing requirement. **Decision linkage idempotency:** `LinkToDecisionAction` checks for an existing `DecisionRecord` with `candidateId` before creating; duplicate calls redirect. **Audit trail preservation:** No delete on `DecisionRecord` or `Requirement`. Use `status = 'withdrawn'` / `outcome = 'rejected'` to express nullification. **PolicyReference and ImplementationChangeReference** are editorial — they may be added and deleted freely. They annotate the `DecisionRecord` but do not constitute the audit artifact themselves. --- ## Governance Dashboard `GovernanceDashboardAction { hubId }` (AutoRefresh) provides: - **KPI row** — decision counts by all six outcomes - **Open requirements awaiting decision** — requirements with no linked decision - **Recent decisions** (last 20) — with widget origin via requirement → candidate traceability - **Traceability coverage** — per widget: ✓/✗ for annotation, candidate, decision presence Linked from the hub Show page alongside the Triage Dashboard. --- ## Known Limitations - **No automated gap detection.** Traceability coverage in the governance dashboard is a manual spot-check UI, not an enforced constraint. Phase 4 will introduce automated gap detection via outcome signals. - **No state-hub cross-linking.** Linking IHF `DecisionRecord`s to `the-custodian` state-hub decision records is Phase 5+ scope. - **No outcome change workflow.** Currently a wrong decision requires manually creating a new `DecisionRecord` and noting the superseded ID in the notes field. A formal "supersedes" relationship is Phase 5+ scope. - **No requirement status transitions.** `Requirement.status` (`active`, `superseded`, `withdrawn`) can only be changed via direct edit — there is no governed lifecycle for it yet. --- ## Phase 4 Readiness Phase 4 (Outcome Signals) requires: - `DeploymentRecord` linked to `ImplementationChangeReference` or `DecisionRecord` - `OutcomeSignal` / `ObservedOutcome` linked to `Widget` and `DecisionRecord` - Automated gap detection: widgets with decisions but no outcome signals after a threshold The Phase 3 schema provides all required foreign key anchors. --- ## Files Changed / Created **Schema:** - `Application/Schema.sql` — 5 new tables, 1 ALTER - `Application/Migration/1743206400-ihf-phase3-governance.sql` **Controllers:** - `Web/Controller/Requirements.hs` (new) - `Web/Controller/DecisionRecords.hs` (new) - `Web/Controller/RequirementCandidates.hs` (extended: PromoteToRequirementAction, LinkToDecisionAction) - `Web/Controller/Hubs.hs` (extended: GovernanceDashboardAction) **Views:** - `Web/View/Requirements/Index.hs` (new) - `Web/View/Requirements/Show.hs` (new) - `Web/View/DecisionRecords/Index.hs` (new) - `Web/View/DecisionRecords/Show.hs` (new) - `Web/View/DecisionRecords/New.hs` (new) - `Web/View/DecisionRecords/Edit.hs` (new) - `Web/View/Hubs/GovernanceDashboard.hs` (new) - `Web/View/RequirementCandidates/Show.hs` (extended: governance action buttons) - `Web/View/Hubs/Show.hs` (extended: Governance Dashboard link) **Routing:** - `Web/Types.hs` — new controller types + GovernanceDashboardAction - `Web/Routes.hs` — new AutoRoute instances - `Web/FrontController.hs` — registered all new controllers + fixed missing Phase 2 registrations **Tests:** - `Test/Integration.hs` — Phase 3 integration tests appended **Docs:** - `SCOPE.md` — current state updated to Phase 3 complete - `docs/phase3-summary.md` (this file)