generated from coulomb/repo-seed
feat(P2+P3): IHF Phase 2 complete; register Phase 3 workplan
Phase 2 — Structured Feedback and Triage (IHUB-WP-0002): - Schema: annotation_threads, requirement_candidates, triage_states, reviewer_assignments; annotations extended with severity + thread_id - AnnotationThreadsController: create threads, assign annotations - RequirementCandidatesController: CRUD, escalation, triage lifecycle, reviewer assignment, my-queue - Annotation severity (low/medium/high/critical) with Tailwind color cues - TriageDashboardAction on HubsController with autoRefresh - Integration tests (T01–T09), SCOPE.md updated, docs/phase2-summary.md Phase 3 — Governance and Decision Linkage (IHUB-WP-0003): - Workplan registered: 9 tasks, State Hub workstream 5f201ee3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "IHF Phase 2 — Structured Feedback and Triage"
|
||||
domain: custodian
|
||||
repo: inter-hub
|
||||
status: active
|
||||
status: done
|
||||
owner: custodian
|
||||
topic_slug: custodian
|
||||
created: "2026-03-28"
|
||||
@@ -57,7 +57,7 @@ Reference: `docs/ihp-overview.md`, `docs/ihp-data-and-queries.md`,
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "eb267a9e-7e80-4913-b7a3-7f5adb04a0f2"
|
||||
```
|
||||
@@ -80,7 +80,7 @@ Generate IHP types via the IDE code generator.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "fdcbf823-484e-4f0f-a0ca-28f9222520af"
|
||||
```
|
||||
@@ -99,7 +99,7 @@ with correct color coding in list and show views.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "35b989a0-5e2a-4300-990b-f43d67de0727"
|
||||
```
|
||||
@@ -118,7 +118,7 @@ thread; thread list shows per-thread aggregates.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "4eb2a51c-1b3f-4b36-b945-6bfb14c2e680"
|
||||
```
|
||||
@@ -138,7 +138,7 @@ render correctly.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "5c3a154b-38e0-4e40-9e97-57aae1dbc95d"
|
||||
```
|
||||
@@ -157,7 +157,7 @@ action; escalated annotations show a visual marker.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T06
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "cd8c3ef1-e0f7-435f-ae20-e0760df5da83"
|
||||
```
|
||||
@@ -176,7 +176,7 @@ full history visible on candidate show page.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T07
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "3dc9bfdb-06d0-48a5-8973-2e39c6e0f78a"
|
||||
```
|
||||
@@ -195,7 +195,7 @@ for the logged-in reviewer.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T08
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "82498422-1626-4479-9daa-3d7c7e088d8e"
|
||||
```
|
||||
@@ -214,7 +214,7 @@ triage status change without page reload.
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0002-T09
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "935de4d7-867f-49aa-bddf-6ff9435215de"
|
||||
```
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
---
|
||||
id: IHUB-WP-0003
|
||||
type: workplan
|
||||
title: "IHF Phase 3 — Governance and Decision Linkage"
|
||||
domain: inter_hub
|
||||
repo: inter-hub
|
||||
status: active
|
||||
owner: custodian
|
||||
topic_slug: inter_hub
|
||||
created: "2026-03-28"
|
||||
updated: "2026-03-28"
|
||||
state_hub_workstream_id: "5f201ee3-5922-4bdc-981d-e51db0a24f5e"
|
||||
---
|
||||
|
||||
# IHF Phase 3 — Governance and Decision Linkage
|
||||
|
||||
## Goal
|
||||
|
||||
Make the framework governance-capable rather than feedback-capable only. Phase 2
|
||||
established structured, triageable feedback and requirement candidates. Phase 3
|
||||
promotes accepted candidates into formal Requirements, records the decisions that
|
||||
act on them, links decisions to policy constraints and implementation work items,
|
||||
and surfaces the resulting governance audit trail per hub.
|
||||
|
||||
## Background
|
||||
|
||||
Phase 1 (IHUB-WP-0001) delivered the Minimal Interaction Core. Phase 2
|
||||
(IHUB-WP-0002) delivered Structured Feedback and Triage — annotation severity,
|
||||
annotation threads, requirement candidates, triage lifecycle, reviewer assignment,
|
||||
and triage dashboard. All Phase 2 exit criteria are met.
|
||||
|
||||
Phase 3 is the third of eight phases in the IHF specification
|
||||
(`specs/InteractionHubFrameworkSpecification_v0.1.md`, §14 Phase 3). It closes
|
||||
the central traceability chain:
|
||||
|
||||
```
|
||||
Widget → InteractionEvent / Annotation
|
||||
→ RequirementCandidate (Phase 2)
|
||||
→ [accepted] → Requirement
|
||||
→ DecisionRecord ← PolicyReference
|
||||
→ ImplementationChangeReference
|
||||
→ DeploymentRecord → OutcomeSignal (Phase 4+)
|
||||
```
|
||||
|
||||
**Technology stack:** IHP v1.5 (Haskell, Nix), PostgreSQL, AutoRefresh
|
||||
(governance dashboard), IHP forms (CRUD). Outcome immutability enforced at the
|
||||
controller level (no update after creation).
|
||||
|
||||
Reference: `docs/ihp-overview.md`, `docs/ihp-data-and-queries.md`,
|
||||
`docs/ihp-controllers-views-forms.md`, `docs/ihp-realtime.md`.
|
||||
|
||||
## Phase 3 Exit Criteria (from IHF spec §14 Phase 3)
|
||||
|
||||
- The system can explain why a requirement was or was not acted upon
|
||||
- Governance records are linked to observed interaction issues (full traceability)
|
||||
- Decision history is inspectable per hub
|
||||
|
||||
## Data Artifacts Introduced (Phase 3)
|
||||
|
||||
`Requirement`, `DecisionRecord`, `PolicyReference`, `ImplementationChangeReference`
|
||||
|
||||
Also extends: `RequirementCandidate` (adds `requirement_id` back-reference)
|
||||
|
||||
---
|
||||
|
||||
## Tasks
|
||||
|
||||
### T01 — Schema: DecisionRecord, PolicyReference, Requirement, ImplementationChangeReference
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T01
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "829b1121-bde6-4d8e-8c82-2a2e2064f520"
|
||||
```
|
||||
|
||||
Add Phase 3 tables to `Application/Schema.sql` and write migration:
|
||||
|
||||
```sql
|
||||
CREATE TABLE requirements (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
source_candidate_id UUID NOT NULL REFERENCES requirement_candidates(id) ON DELETE RESTRICT,
|
||||
status TEXT NOT NULL DEFAULT 'active',
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX requirements_source_candidate_id_idx ON requirements (source_candidate_id);
|
||||
|
||||
CREATE TABLE decision_records (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
rationale TEXT NOT NULL,
|
||||
outcome TEXT NOT NULL,
|
||||
requirement_id UUID REFERENCES requirements(id) ON DELETE SET NULL,
|
||||
candidate_id UUID REFERENCES requirement_candidates(id) ON DELETE SET NULL,
|
||||
decided_by UUID REFERENCES users(id),
|
||||
decided_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX decision_records_outcome_idx ON decision_records (outcome);
|
||||
CREATE INDEX decision_records_requirement_id_idx ON decision_records (requirement_id);
|
||||
|
||||
CREATE TABLE policy_references (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
decision_id UUID NOT NULL REFERENCES decision_records(id) ON DELETE CASCADE,
|
||||
policy_scope TEXT NOT NULL,
|
||||
constraint_note TEXT,
|
||||
created_by UUID REFERENCES users(id),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX policy_references_decision_id_idx ON policy_references (decision_id);
|
||||
|
||||
CREATE TABLE implementation_change_references (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
decision_id UUID NOT NULL REFERENCES decision_records(id) ON DELETE CASCADE,
|
||||
work_item_ref TEXT NOT NULL,
|
||||
system TEXT NOT NULL DEFAULT 'github',
|
||||
linked_by UUID REFERENCES users(id),
|
||||
linked_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX impl_change_refs_decision_id_idx ON implementation_change_references (decision_id);
|
||||
|
||||
-- Back-reference: track which candidate was promoted to a requirement
|
||||
ALTER TABLE requirement_candidates ADD COLUMN requirement_id UUID REFERENCES requirements(id) ON DELETE SET NULL;
|
||||
```
|
||||
|
||||
- Valid `decision_records.outcome` values: `accepted`, `rejected`, `deferred`, `split`, `merged`, `reframed`
|
||||
- Valid `policy_references.policy_scope` values: `internal`, `external`, `regulatory`, `contractual`, `architectural`
|
||||
- Valid `requirements.status` values: `active`, `superseded`, `withdrawn`
|
||||
- Verify Haskell types are generated correctly
|
||||
|
||||
**Exit criteria:** `migrate` runs cleanly; all Phase 3 types available in GHCi.
|
||||
|
||||
---
|
||||
|
||||
### T02 — Requirement promotion: RequirementCandidate → Requirement
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T02
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "9d1edd55-628c-4354-82c3-2bf273f1b827"
|
||||
```
|
||||
|
||||
1. Add `PromoteToRequirementAction { candidateId }` (POST from candidate show page)
|
||||
2. Validate: candidate must have `status = 'accepted'`; return 422 with message otherwise
|
||||
3. Idempotent: if `candidate.requirement_id` already set, redirect to existing requirement
|
||||
4. On promotion: create `Requirement` record, set `candidate.requirement_id`
|
||||
5. Scaffold `RequirementsController`: index, show (no new/create — requirements come from promotion only)
|
||||
6. Show page: title, description, source candidate link, linked decision (if any), status badge
|
||||
7. Index: table with status, source candidate, linked decision, created_at
|
||||
|
||||
**Exit criteria:** Accepted candidates can be promoted once; second promotion redirects; requirement visible in index and show.
|
||||
|
||||
---
|
||||
|
||||
### T03 — DecisionRecord controller and views
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T03
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "171b38ab-c6e7-4b0e-94c0-ebc35f07488a"
|
||||
```
|
||||
|
||||
1. Scaffold `DecisionRecordsController`
|
||||
2. Actions: index, show, new, create, edit, update (no delete)
|
||||
3. Fields: `title`, `rationale` (textarea), `outcome` (select), `decidedBy` (user select), `notes` (optional textarea)
|
||||
4. Index view: table with outcome badge, linked requirement title, decided_by name, decided_at; filterable by outcome
|
||||
5. Show view: full detail + linked requirement + policy references section + implementation refs section + actor attribution
|
||||
|
||||
**Exit criteria:** Decision records can be created manually, listed, filtered, and viewed with full context.
|
||||
|
||||
---
|
||||
|
||||
### T04 — Candidate → Decision linkage action
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T04
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "eb45a76b-fd75-4a6c-bec6-e47095d5fa36"
|
||||
```
|
||||
|
||||
1. Add "Create Decision" button on `RequirementCandidate` show page (requires `status = 'accepted'`)
|
||||
2. `LinkToDecisionAction { candidateId }` (POST): creates a `DecisionRecord` pre-populated from candidate
|
||||
- `title` = candidate title
|
||||
- `rationale` seeded from candidate description
|
||||
- `candidateId` set on the decision record
|
||||
- If a promoted `Requirement` exists, set `requirementId` on the decision too
|
||||
3. Idempotent: if decision already linked to this candidate, redirect to existing decision
|
||||
4. Show "Linked Decision →" on candidate show page after linkage
|
||||
|
||||
**Exit criteria:** Single-click decision creation from an accepted candidate; idempotent; link visible on candidate show page.
|
||||
|
||||
---
|
||||
|
||||
### T05 — PolicyReference: link decisions to policy scope
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T05
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "4ef86992-d35e-4f62-a601-bd19e3ef63d3"
|
||||
```
|
||||
|
||||
1. `AddPolicyReferenceAction { decisionId }` (POST from decision show page)
|
||||
2. Fields: `policyScope` (select: internal/external/regulatory/contractual/architectural), `constraintNote` (optional)
|
||||
3. Multiple policy refs per decision allowed
|
||||
4. List policy refs on decision show page: scope badge + constraint note + created_at
|
||||
5. Delete: `DeletePolicyReferenceAction` — policy refs may be removed (they are editorial, not audit-critical)
|
||||
|
||||
**Exit criteria:** Policy references can be added and removed from decisions; multiple refs per decision supported.
|
||||
|
||||
---
|
||||
|
||||
### T06 — ImplementationChangeReference: link decisions to work items
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T06
|
||||
status: todo
|
||||
priority: medium
|
||||
state_hub_task_id: "eac1baf2-9df7-48fd-880e-68d07e22a337"
|
||||
```
|
||||
|
||||
1. `AddImplementationRefAction { decisionId }` (POST from decision show page)
|
||||
2. Fields: `workItemRef` (free text — e.g. `#1234`, `PROJ-456`), `system` (select: github/linear/jira/other)
|
||||
3. List refs on decision show page: system badge + ref text + linked_at
|
||||
4. No external API calls — refs are manual pointers only
|
||||
5. Delete: `DeleteImplementationRefAction` — refs are editorial, not audit-critical
|
||||
|
||||
**Exit criteria:** Implementation refs can be added and removed; multiple refs per decision; no external API integration required.
|
||||
|
||||
---
|
||||
|
||||
### T07 — Decision outcomes: full outcome vocabulary
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T07
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "eaa425b3-42a7-4498-8aa6-1610959ce16b"
|
||||
```
|
||||
|
||||
1. Validate outcome on create against allowed set: `accepted`, `rejected`, `deferred`, `split`, `merged`, `reframed`
|
||||
2. Outcome is **immutable** after creation — `UpdateDecisionRecordAction` may not change `outcome`
|
||||
3. Color roles per `specs/TailwindForInteractionHubs_v0.2.md`:
|
||||
- `accepted` → green
|
||||
- `rejected` → red
|
||||
- `deferred` → gray
|
||||
- `split` → purple
|
||||
- `merged` → indigo
|
||||
- `reframed` → orange/amber
|
||||
4. For `split` / `merged` outcomes: `notes` field should capture related candidate IDs or context
|
||||
5. Display outcome badge consistently across index, show, and governance dashboard views
|
||||
|
||||
**Exit criteria:** All six outcomes render with correct color; outcome immutable after create; split/merged notes convention documented inline.
|
||||
|
||||
---
|
||||
|
||||
### T08 — Hub governance audit trail dashboard
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T08
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "6bd3f8f2-13c1-4f95-a1cf-53a210b8e366"
|
||||
```
|
||||
|
||||
1. Add `GovernanceDashboardAction { hubId }` to `HubsController` wrapped with `autoRefresh do`
|
||||
2. Dashboard panels:
|
||||
- **KPI row**: decision counts by outcome (accepted / rejected / deferred / split / merged / reframed)
|
||||
- **Recent decisions** (last 20): title, outcome badge, widget origin (via requirement → candidate → widget), decided_at
|
||||
- **Traceability coverage**: per widget — ✓/✗ for has annotation, has candidate, has decision
|
||||
- **Open requirements awaiting decision**: requirements with no linked `decision_id`
|
||||
3. Link from hub Show page alongside "Triage Dashboard"
|
||||
|
||||
**Exit criteria:** Dashboard live-updates on decision/requirement changes. Traceability coverage gives a quick health signal per widget.
|
||||
|
||||
---
|
||||
|
||||
### T09 — Phase 3 gate: tests, consistency, docs
|
||||
|
||||
```task
|
||||
id: IHUB-WP-0003-T09
|
||||
status: todo
|
||||
priority: high
|
||||
state_hub_task_id: "6f1a08f1-c114-4a19-bf71-cbb2421171e1"
|
||||
```
|
||||
|
||||
1. **Integration tests** (`Test/`):
|
||||
- Requirement promotion: accepted candidate → requirement; unaccepted candidate → 422; duplicate → idempotent
|
||||
- Decision create + link to candidate; link to requirement if promoted
|
||||
- PolicyReference add + delete
|
||||
- ImplementationChangeReference add + delete
|
||||
- Outcome immutability: update attempt on outcome field rejected
|
||||
- Governance dashboard: data fetch compiles and returns correct counts
|
||||
2. **Consistency sync:**
|
||||
```bash
|
||||
cd ~/the-custodian && make fix-consistency REPO=inter-hub
|
||||
```
|
||||
Or via State Hub MCP: `check_repo_consistency(repo_slug="inter-hub", fix=True)`
|
||||
3. **Documentation updates:**
|
||||
- Update `SCOPE.md` current state section: Phase 3 complete
|
||||
- Write `docs/phase3-summary.md`: what was built, known limitations, Phase 4 readiness
|
||||
4. **Smoke test checklist:**
|
||||
- `devenv up` → clean start
|
||||
- Accept a requirement candidate via triage
|
||||
- Promote to requirement
|
||||
- Create decision linked to candidate
|
||||
- Add policy reference (regulatory)
|
||||
- Add implementation ref (github, `#42`)
|
||||
- Confirm governance dashboard shows decision and traceability coverage
|
||||
- Confirm outcome cannot be changed after creation
|
||||
|
||||
**Exit criteria:** All tests pass; consistency sync reports no errors; smoke test completed; SCOPE.md updated.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 Dependencies
|
||||
|
||||
- Phase 2 schema stable (T01 depends on `requirement_candidates`, `users` from Phase 2)
|
||||
- `requirements` before `decision_records` FK reference (T01 ordering)
|
||||
- Schema (T01) before all controller work (T02–T08)
|
||||
- `Requirement` (T02) before `DecisionRecord` linkage (T04)
|
||||
- `DecisionRecord` (T03) before `PolicyReference` (T05), `ImplementationChangeReference` (T06), outcome vocabulary (T07)
|
||||
- All feature tasks (T01–T08) before gate (T09)
|
||||
|
||||
## Notes
|
||||
|
||||
- **Outcome is immutable.** Unlike `TriageState` (which appends rows), `DecisionRecord.outcome`
|
||||
is set at creation and never changed. A wrong decision should be superseded by creating a new
|
||||
decision record with a note referencing the original, not by editing the existing one.
|
||||
- **No delete on DecisionRecord or Requirement.** These are audit artifacts. Use `status =
|
||||
'withdrawn'` on Requirement or `outcome = 'rejected'` on DecisionRecord to express
|
||||
nullification.
|
||||
- **PolicyReference and ImplementationChangeReference are editorial** — they may be added
|
||||
and deleted freely. They do not constitute audit trail themselves; the DecisionRecord is
|
||||
the audit artifact.
|
||||
- **Traceability coverage (T08)** is a spot-check UI, not an enforced constraint. Phase 4+
|
||||
will introduce automated gap detection via outcome signals.
|
||||
- **No state-hub integration in Phase 3.** The `the-custodian` state-hub is a separate system;
|
||||
cross-linking IHF decisions to state-hub decision records is Phase 5+ scope.
|
||||
Reference in New Issue
Block a user