feat(P3): IHF Phase 3 complete — Governance and Decision Linkage

Implements the full governance layer:
- Schema: requirements, decision_records, policy_references,
  implementation_change_references; requirement_candidates gets
  requirement_id back-reference
- RequirementsController (index/show; promotion-only create)
- DecisionRecordsController (CRUD + policy/impl ref management)
- GovernanceDashboardAction on HubsController (AutoRefresh)
- PromoteToRequirementAction + LinkToDecisionAction on candidates
- Outcome immutability enforced at controller level (fill excludes outcome)
- Full six-outcome vocabulary with Tailwind color roles
- Integration tests for all Phase 3 paths
- FrontController: registers Phase 2 missing controllers + all Phase 3
- SCOPE.md + docs/phase3-summary.md updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 10:38:50 +00:00
parent 840b0e5c7b
commit 7f9a8dd441
23 changed files with 2039 additions and 19 deletions

125
docs/phase3-summary.md Normal file
View File

@@ -0,0 +1,125 @@
# 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)