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>
2026-03-28 23:37:34 +00:00
|
|
|
-- IHF Phase 1 + Phase 2 Schema
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
-- Hub, Widget, WidgetVersion, InteractionEvent, Annotation
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
-- Phase 2: AnnotationThread, RequirementCandidate, TriageState, ReviewerAssignment
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
-- See workplans/IHUB-WP-0001-ihf-phase1-minimal-interaction-core.md
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
-- See workplans/IHUB-WP-0002-ihf-phase2-structured-feedback-and-triage.md
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
|
|
|
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
|
|
|
|
|
|
|
|
-- Users (T10 — authentication)
|
|
|
|
|
CREATE TABLE users (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
email TEXT NOT NULL UNIQUE,
|
|
|
|
|
password_hash TEXT NOT NULL,
|
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
|
locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
|
|
|
|
failed_login_attempts INT NOT NULL DEFAULT 0,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Hubs — bounded domains of responsibility
|
|
|
|
|
CREATE TABLE hubs (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
slug TEXT NOT NULL UNIQUE,
|
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
|
domain TEXT NOT NULL,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Widgets — smallest semantically governable interaction units
|
|
|
|
|
CREATE TABLE widgets (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE RESTRICT,
|
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
|
widget_type TEXT NOT NULL,
|
|
|
|
|
capability_ref TEXT,
|
|
|
|
|
view_context TEXT,
|
|
|
|
|
policy_scope TEXT NOT NULL DEFAULT 'internal',
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
|
|
|
version INT NOT NULL DEFAULT 1,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Widget version history
|
|
|
|
|
CREATE TABLE widget_versions (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
|
|
|
|
|
version INT NOT NULL,
|
|
|
|
|
schema_snapshot JSONB NOT NULL,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
UNIQUE (widget_id, version)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
-- Interaction events — append-only capture
|
|
|
|
|
CREATE TABLE interaction_events (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
|
|
|
|
|
event_type TEXT NOT NULL,
|
|
|
|
|
actor_id UUID,
|
|
|
|
|
actor_type TEXT NOT NULL DEFAULT 'user',
|
|
|
|
|
view_context_ref TEXT,
|
|
|
|
|
metadata JSONB DEFAULT '{}' NOT NULL,
|
|
|
|
|
occurred_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX interaction_events_widget_id_idx ON interaction_events (widget_id);
|
|
|
|
|
CREATE INDEX interaction_events_occurred_at_idx ON interaction_events (occurred_at DESC);
|
|
|
|
|
|
|
|
|
|
-- Enforce append-only on interaction_events
|
|
|
|
|
CREATE OR REPLACE FUNCTION prevent_interaction_event_mutation()
|
|
|
|
|
RETURNS TRIGGER AS $$
|
|
|
|
|
BEGIN
|
|
|
|
|
RAISE EXCEPTION 'interaction_events is append-only: UPDATE and DELETE are not permitted';
|
|
|
|
|
END;
|
|
|
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
|
CREATE TRIGGER interaction_events_no_update
|
|
|
|
|
BEFORE UPDATE ON interaction_events
|
|
|
|
|
FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();
|
|
|
|
|
|
|
|
|
|
CREATE TRIGGER interaction_events_no_delete
|
|
|
|
|
BEFORE DELETE ON interaction_events
|
|
|
|
|
FOR EACH ROW EXECUTE FUNCTION prevent_interaction_event_mutation();
|
|
|
|
|
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
-- Annotation threads — groups related annotations for triage (Phase 2)
|
|
|
|
|
CREATE TABLE annotation_threads (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
|
|
|
|
|
title TEXT NOT NULL,
|
|
|
|
|
description TEXT,
|
|
|
|
|
created_by UUID REFERENCES users(id),
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
-- Annotations — structured commentary, also append-only by convention
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
-- Phase 2 additions: severity, thread_id
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
CREATE TABLE annotations (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
|
|
|
|
|
parent_id UUID REFERENCES annotations(id) ON DELETE CASCADE,
|
|
|
|
|
body TEXT NOT NULL,
|
|
|
|
|
category TEXT NOT NULL DEFAULT 'friction',
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
severity TEXT NOT NULL DEFAULT 'medium',
|
|
|
|
|
thread_id UUID REFERENCES annotation_threads(id) ON DELETE SET NULL,
|
feat(T02-T11): IHF Phase 1 schema, controllers, views, and helpers
- Schema: hubs, widgets, widget_versions, interaction_events (append-only
trigger), annotations, users — single migration file
- Web layer: Types, Routes, FrontController with auth + AutoRefresh layout
- Controllers: Hubs (CRUD), Widgets (CRUD + versioning), InteractionEvents
(JSON capture, canonical event_type validation), Annotations (threaded,
append-only)
- Sessions controller for IHP auth
- Views: Hubs (index/show/new/edit), Widgets (index/show/new/edit),
Annotations (index/new), Sessions (login)
- widgetEnvelope helper with full data-* governance attributes
- Integration tests: Hub CRUD, Widget versioning, event capture, append-only
guard, annotation threading, validation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:42:43 +00:00
|
|
|
actor_id UUID,
|
|
|
|
|
actor_type TEXT NOT NULL DEFAULT 'user',
|
|
|
|
|
widget_state_ref TEXT,
|
|
|
|
|
retracted_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX annotations_widget_id_idx ON annotations (widget_id);
|
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>
2026-03-28 23:37:34 +00:00
|
|
|
|
|
|
|
|
-- Requirement candidates — escalated from annotations/threads (Phase 2)
|
|
|
|
|
CREATE TABLE requirement_candidates (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
title TEXT NOT NULL,
|
|
|
|
|
description TEXT NOT NULL,
|
|
|
|
|
source_widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE RESTRICT,
|
|
|
|
|
source_thread_id UUID REFERENCES annotation_threads(id) ON DELETE SET NULL,
|
|
|
|
|
source_annotation_id UUID REFERENCES annotations(id) ON DELETE SET NULL,
|
|
|
|
|
category TEXT NOT NULL DEFAULT 'friction',
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'open',
|
|
|
|
|
created_by UUID REFERENCES users(id),
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX requirement_candidates_widget_id_idx ON requirement_candidates (source_widget_id);
|
|
|
|
|
CREATE INDEX requirement_candidates_status_idx ON requirement_candidates (status);
|
|
|
|
|
|
|
|
|
|
-- Triage state history — append-only audit trail of status transitions (Phase 2)
|
|
|
|
|
CREATE TABLE triage_states (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
candidate_id UUID NOT NULL REFERENCES requirement_candidates(id) ON DELETE CASCADE,
|
|
|
|
|
status TEXT NOT NULL,
|
|
|
|
|
notes TEXT,
|
|
|
|
|
changed_by UUID REFERENCES users(id),
|
|
|
|
|
changed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX triage_states_candidate_id_idx ON triage_states (candidate_id);
|
|
|
|
|
|
|
|
|
|
-- Reviewer assignments — one reviewer per candidate (Phase 2)
|
|
|
|
|
CREATE TABLE reviewer_assignments (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
candidate_id UUID NOT NULL REFERENCES requirement_candidates(id) ON DELETE CASCADE,
|
|
|
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
|
|
|
assigned_by UUID REFERENCES users(id),
|
|
|
|
|
assigned_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
UNIQUE (candidate_id)
|
|
|
|
|
);
|
2026-03-29 10:38:50 +00:00
|
|
|
|
|
|
|
|
-- Requirements — promoted from accepted RequirementCandidates (Phase 3)
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
-- Decision records — governance decisions acting on requirements/candidates (Phase 3)
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
-- Policy references — editorial links from decisions to policy scope (Phase 3)
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
-- Implementation change references — editorial links to work items (Phase 3)
|
|
|
|
|
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: which candidate was promoted to a requirement (Phase 3)
|
|
|
|
|
ALTER TABLE requirement_candidates ADD COLUMN requirement_id UUID REFERENCES requirements(id) ON DELETE SET NULL;
|
2026-03-29 12:27:30 +00:00
|
|
|
|
|
|
|
|
-- Deployment records — connect decisions to deployed versions (Phase 4)
|
|
|
|
|
CREATE TABLE deployment_records (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
impl_ref_id UUID REFERENCES implementation_change_references(id) ON DELETE SET NULL,
|
|
|
|
|
decision_id UUID NOT NULL REFERENCES decision_records(id) ON DELETE RESTRICT,
|
|
|
|
|
version_ref TEXT NOT NULL,
|
|
|
|
|
deployed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
deployed_by UUID REFERENCES users(id),
|
|
|
|
|
notes TEXT,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX deployment_records_decision_id_idx ON deployment_records (decision_id);
|
|
|
|
|
CREATE INDEX deployment_records_deployed_at_idx ON deployment_records (deployed_at DESC);
|
|
|
|
|
|
|
|
|
|
-- Outcome signals — append-only observation of widget behaviour post-deployment (Phase 4)
|
|
|
|
|
CREATE TABLE outcome_signals (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
widget_id UUID NOT NULL REFERENCES widgets(id) ON DELETE CASCADE,
|
|
|
|
|
deployment_id UUID NOT NULL REFERENCES deployment_records(id) ON DELETE CASCADE,
|
|
|
|
|
signal_type TEXT NOT NULL,
|
|
|
|
|
value NUMERIC,
|
|
|
|
|
observed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX outcome_signals_widget_id_idx ON outcome_signals (widget_id);
|
|
|
|
|
CREATE INDEX outcome_signals_deployment_id_idx ON outcome_signals (deployment_id);
|
|
|
|
|
CREATE INDEX outcome_signals_observed_at_idx ON outcome_signals (observed_at DESC);
|
|
|
|
|
|
|
|
|
|
CREATE OR REPLACE FUNCTION prevent_outcome_signal_mutation()
|
|
|
|
|
RETURNS TRIGGER AS $$
|
|
|
|
|
BEGIN
|
|
|
|
|
RAISE EXCEPTION 'outcome_signals is append-only: UPDATE and DELETE are not permitted';
|
|
|
|
|
END;
|
|
|
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
|
|
|
|
|
|
CREATE TRIGGER outcome_signals_no_update
|
|
|
|
|
BEFORE UPDATE ON outcome_signals
|
|
|
|
|
FOR EACH ROW EXECUTE FUNCTION prevent_outcome_signal_mutation();
|
|
|
|
|
|
|
|
|
|
CREATE TRIGGER outcome_signals_no_delete
|
|
|
|
|
BEFORE DELETE ON outcome_signals
|
|
|
|
|
FOR EACH ROW EXECUTE FUNCTION prevent_outcome_signal_mutation();
|
|
|
|
|
|
|
|
|
|
-- Change evaluations — one score per deployment (Phase 4)
|
|
|
|
|
CREATE TABLE change_evaluations (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
deployment_id UUID NOT NULL REFERENCES deployment_records(id) ON DELETE CASCADE,
|
|
|
|
|
decision_id UUID REFERENCES decision_records(id) ON DELETE SET NULL,
|
|
|
|
|
score SMALLINT NOT NULL CHECK (score BETWEEN 1 AND 5),
|
|
|
|
|
rationale TEXT NOT NULL,
|
|
|
|
|
evaluated_by UUID REFERENCES users(id),
|
|
|
|
|
evaluated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
UNIQUE (deployment_id)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX change_evaluations_deployment_id_idx ON change_evaluations (deployment_id);
|
feat(P5): IHF Phase 5 complete — agent-assisted distillation
Adds bounded AI support to the IHF governance loop. All AI outputs are
attributed (model_ref), reviewable (AgentReviewRecord), and reversible.
No autonomous decisions; no silent requirement promotion.
- T01: Schema — agent_proposals, agent_review_records,
confidence_annotations (migration 1743379200)
- T02: AgentProposalsController (index/show/accept/reject, idempotent
review guard), global nav "Agent" link
- T03: SummarizeClusterAction — Claude API cluster summary on widget show
- T04: DraftRequirementAction — AI requirement draft; acceptance creates
RequirementCandidate (human-gated)
- T05: DetectDuplicatesAction — duplicate_flag proposal on candidate show
- T06: DetectPolicySensitivityAction — policy_flag with
ConfidenceAnnotations per concern scope
- T07: ProposeImplementationAction — impl_proposal from decision show
- T08: AgentAuditDashboardAction — autoRefresh; KPI row, unreviewed queue,
recent proposals, attribution log matrix
- T09: integration tests, SCOPE.md updated, phase5-summary.md, flake.nix
adds http-conduit/aeson/string-conversions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 15:54:33 +00:00
|
|
|
|
|
|
|
|
-- Agent proposals — AI-generated outputs awaiting human review (Phase 5)
|
|
|
|
|
CREATE TABLE agent_proposals (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
proposal_type TEXT NOT NULL,
|
|
|
|
|
-- proposal_type values: summary | requirement_draft | duplicate_flag |
|
|
|
|
|
-- policy_flag | impl_proposal
|
|
|
|
|
source_widget_id UUID REFERENCES widgets(id) ON DELETE SET NULL,
|
|
|
|
|
source_candidate_id UUID REFERENCES requirement_candidates(id) ON DELETE SET NULL,
|
|
|
|
|
source_thread_id UUID REFERENCES annotation_threads(id) ON DELETE SET NULL,
|
|
|
|
|
source_decision_id UUID REFERENCES decision_records(id) ON DELETE SET NULL,
|
|
|
|
|
content TEXT NOT NULL,
|
|
|
|
|
model_ref TEXT NOT NULL,
|
|
|
|
|
confidence NUMERIC CHECK (confidence BETWEEN 0 AND 1),
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
|
|
|
-- status values: pending | accepted | rejected | superseded
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX agent_proposals_proposal_type_idx ON agent_proposals (proposal_type);
|
|
|
|
|
CREATE INDEX agent_proposals_status_idx ON agent_proposals (status);
|
|
|
|
|
CREATE INDEX agent_proposals_source_widget_id_idx ON agent_proposals (source_widget_id);
|
|
|
|
|
CREATE INDEX agent_proposals_created_at_idx ON agent_proposals (created_at DESC);
|
|
|
|
|
|
|
|
|
|
-- One review record per proposal (human decision on AI output) (Phase 5)
|
|
|
|
|
CREATE TABLE agent_review_records (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
proposal_id UUID NOT NULL REFERENCES agent_proposals(id) ON DELETE CASCADE,
|
|
|
|
|
reviewer_id UUID REFERENCES users(id),
|
|
|
|
|
decision TEXT NOT NULL, -- accepted | rejected | modified
|
|
|
|
|
notes TEXT,
|
|
|
|
|
reviewed_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
UNIQUE (proposal_id)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX agent_review_records_proposal_id_idx ON agent_review_records (proposal_id);
|
|
|
|
|
|
|
|
|
|
-- Confidence annotations — per-dimension breakdown of AI confidence (Phase 5)
|
|
|
|
|
CREATE TABLE confidence_annotations (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
proposal_id UUID NOT NULL REFERENCES agent_proposals(id) ON DELETE CASCADE,
|
|
|
|
|
dimension TEXT NOT NULL,
|
|
|
|
|
-- dimension values: accuracy | relevance | completeness | policy_alignment
|
|
|
|
|
score NUMERIC NOT NULL CHECK (score BETWEEN 0 AND 1),
|
|
|
|
|
explanation TEXT,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX confidence_annotations_proposal_id_idx ON confidence_annotations (proposal_id);
|
2026-03-29 21:03:00 +00:00
|
|
|
|
|
|
|
|
-- ============================================================
|
|
|
|
|
-- Phase 6 — Cross-Framework UI Adaptation Layer
|
|
|
|
|
-- ============================================================
|
|
|
|
|
|
|
|
|
|
-- Formalises the rules for widget envelope emission: which data-* attributes
|
|
|
|
|
-- are required, their format, and the contract version.
|
|
|
|
|
CREATE TABLE envelope_emission_contracts (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
contract_version TEXT NOT NULL UNIQUE, -- e.g. "1.0", "1.1"
|
|
|
|
|
required_attributes JSONB NOT NULL,
|
|
|
|
|
-- e.g. ["data-widget-id", "data-view-context", "data-hub-id"]
|
|
|
|
|
optional_attributes JSONB NOT NULL DEFAULT '[]',
|
|
|
|
|
validation_rules JSONB NOT NULL DEFAULT '{}',
|
|
|
|
|
-- machine-readable rules: format checks, presence guards
|
|
|
|
|
description TEXT,
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
|
|
|
-- status values: draft | active | superseded
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX envelope_emission_contracts_status_idx ON envelope_emission_contracts (status);
|
|
|
|
|
|
|
|
|
|
-- Standardised REST interface contract for external event and annotation
|
|
|
|
|
-- submission — used by non-IHP adapters.
|
|
|
|
|
CREATE TABLE interaction_reporting_contracts (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
contract_version TEXT NOT NULL UNIQUE, -- e.g. "1.0"
|
|
|
|
|
endpoint_path TEXT NOT NULL, -- e.g. "/api/v1/interaction-events"
|
|
|
|
|
accepted_event_types JSONB NOT NULL, -- e.g. ["clicked","viewed","submitted"]
|
|
|
|
|
required_fields JSONB NOT NULL,
|
|
|
|
|
-- minimum payload: widget_id, hub_id, event_type, occurred_at
|
|
|
|
|
auth_scheme TEXT NOT NULL DEFAULT 'bearer',
|
|
|
|
|
description TEXT,
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'active',
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX interaction_reporting_contracts_status_idx ON interaction_reporting_contracts (status);
|
|
|
|
|
|
|
|
|
|
-- Describes how a specific UI technology maps to IHF widget protocol obligations.
|
|
|
|
|
CREATE TABLE widget_adapter_specs (
|
|
|
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
|
|
|
|
name TEXT NOT NULL UNIQUE, -- e.g. "react-18", "vue-3", "web-component"
|
|
|
|
|
framework TEXT NOT NULL, -- e.g. "react", "vue", "vanilla"
|
|
|
|
|
version TEXT NOT NULL, -- adapter spec version, e.g. "1.0"
|
|
|
|
|
envelope_contract_id UUID REFERENCES envelope_emission_contracts(id),
|
|
|
|
|
reporting_contract_id UUID REFERENCES interaction_reporting_contracts(id),
|
|
|
|
|
status TEXT NOT NULL DEFAULT 'draft',
|
|
|
|
|
-- status values: draft | active | deprecated
|
|
|
|
|
notes TEXT,
|
|
|
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
|
|
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX widget_adapter_specs_framework_idx ON widget_adapter_specs (framework);
|
|
|
|
|
CREATE INDEX widget_adapter_specs_status_idx ON widget_adapter_specs (status);
|
|
|
|
|
|
|
|
|
|
-- Link widgets to their adapter spec (null = native IHP widget).
|
|
|
|
|
ALTER TABLE widgets
|
|
|
|
|
ADD COLUMN adapter_spec_id UUID REFERENCES widget_adapter_specs(id);
|
|
|
|
|
|
|
|
|
|
CREATE INDEX widgets_adapter_spec_id_idx ON widgets (adapter_spec_id);
|
|
|
|
|
|
|
|
|
|
-- Per-hub API key for bearer-token auth on the interaction reporting endpoint.
|
|
|
|
|
ALTER TABLE hubs
|
|
|
|
|
ADD COLUMN api_key TEXT;
|