chore: remove ralph loop state file
Some checks failed
Test / test (push) Has been cancelled

.claude/ralph-loop.local.md is a local session artifact — should not be tracked.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 10:42:25 +00:00
parent 7f9a8dd441
commit 8ca61c3577

View File

@@ -1,398 +0,0 @@
---
active: true
iteration: 1
session_id:
max_iterations: 20
completion_promise: "HEUREKA"
workplan_id: IHUB-WP-0003
workplan_file: workplans/IHUB-WP-0003-ihf-phase3-governance-and-decision-linkage.md
started_at: "2026-03-29T09:26:30Z"
---
## Workplan Status Check — Do This First, Every Iteration
Read the workplan file at: `workplans/IHUB-WP-0003-ihf-phase3-governance-and-decision-linkage.md`
Count the task blocks (fenced code blocks with language tag `task`):
- How many tasks exist in total?
- How many have `status: done`?
If **every task** has `status: done` AND the frontmatter `status` is `done`:
The workplan is complete. Output exactly: <promise>HEUREKA</promise>
Do nothing else. Stop here.
Otherwise: continue with the implementation below.
---
## Workplan: IHUB-WP-0003 — IHF Phase 3 — Governance and Decision Linkage
**File:** `workplans/IHUB-WP-0003-ihf-phase3-governance-and-decision-linkage.md`
# 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 (T02T08)
- `Requirement` (T02) before `DecisionRecord` linkage (T04)
- `DecisionRecord` (T03) before `PolicyReference` (T05), `ImplementationChangeReference` (T06), outcome vocabulary (T07)
- All feature tasks (T01T08) 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.
---
## How to Work
- Stay strictly within the scope of the workplan above
- Work through tasks in priority order (high → medium → low)
- Use TDD where applicable: write a failing test, make it pass, then refactor
- Use whatever test runner, linter, and build tools this repository already uses
- Consult existing documentation (README, docs/, wiki/, specs/) for context
- Document significant architecture decisions as ADRs if the project uses them
## Updating Task Status
As you complete each task, edit the workplan file to update its status:
```
status: todo → status: in_progress (when you start it)
status: in_progress → status: done (when it is verified complete)
```
When **every task** is `done`, also update the workplan frontmatter:
```
status: active → status: done
```
## Success Criteria
Before marking the workplan done and outputting `<promise>HEUREKA</promise>`,
verify all of the following are true:
1. Every task block in `workplans/IHUB-WP-0003-ihf-phase3-governance-and-decision-linkage.md` has `status: done`
2. The workplan frontmatter `status` is `done`
3. The full test suite passes with no failures
4. The codebase passes the project's standard code-quality checks
(linting, type checking, formatting — whatever applies to this project)
5. Documentation reflects the implemented behaviour
Output `<promise>HEUREKA</promise>` only when all five are genuinely true.