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>
5.6 KiB
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 RequirementCandidates |
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/DeleteImplementationRefActionGovernanceDashboardAction(onHubsController) — live AutoRefresh dashboard per hub
Extended Controllers
RequirementCandidatesController— addedPromoteToRequirementActionandLinkToDecisionActionHubsController— addedGovernanceDashboardActionFrontController— 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
DecisionRecords tothe-custodianstate-hub decision records is Phase 5+ scope. - No outcome change workflow. Currently a wrong decision requires manually creating a new
DecisionRecordand 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:
DeploymentRecordlinked toImplementationChangeReferenceorDecisionRecordOutcomeSignal/ObservedOutcomelinked toWidgetandDecisionRecord- 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 ALTERApplication/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 + GovernanceDashboardActionWeb/Routes.hs— new AutoRoute instancesWeb/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 completedocs/phase3-summary.md(this file)