generated from coulomb/repo-seed
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>
126 lines
5.6 KiB
Markdown
126 lines
5.6 KiB
Markdown
# 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)
|