feat(P8): IHF Phase 8 complete — Federated Hub Maturity

Implements the final phase of the IHF v0.1 specification:

- WidgetOwnership: delegated ownership registry (local/delegated/global),
  append-only audit artefacts, ownership badge on widget show page
- HubRoutingRule + RoutingEngine: priority-ordered inter-hub routing engine;
  null-inclusive category/widget-type matching; RouteNowAction for manual
  re-evaluation; RoutedCandidates view per hub
- FederatedPolicyOverlay: draft → active → retired lifecycle; activated
  overlays are immutable (same pattern as Phase 6 contracts); policy
  compliance dashboard with decision coverage metrics
- StewardshipRole: named governance roles per hub; point-in-time revocation
  pattern; hub and ops-board integration
- ArchiveRecord + is_archived: soft-delete on widgets; lineage inspector
  traces full traceability chain (Widget → Events → Annotations → Candidates
  → Requirements → Decisions → Deployments → Signals + ArchiveRecord)
- FederatedGovernanceDashboard: 5-panel autoRefresh org-wide governance view
  (ownership coverage, routing activity, policy compliance, stewardship
  coverage, archive activity)

Schema: widget_ownerships, hub_routing_rules, federated_policy_overlays,
stewardship_roles, archive_records; ALTER widgets ADD is_archived;
ALTER requirement_candidates ADD routed_to_hub_id

Migration: 1743638400-ihf-phase8-federated-hub-maturity.sql
Tests: Phase 8 integration tests appended to Test/Integration.hs
Docs: docs/phase8-summary.md; SCOPE.md updated to Phase 8 complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-29 22:53:01 +00:00
parent 63fb0e8277
commit 9265ca2d9c
37 changed files with 2400 additions and 12 deletions

View File

@@ -447,3 +447,101 @@ CREATE TABLE cross_hub_propagations (
CREATE INDEX cross_hub_propagations_status_idx ON cross_hub_propagations (status);
CREATE INDEX cross_hub_propagations_pattern_idx ON cross_hub_propagations (pattern_type);
-- Phase 8: Federated Hub Maturity
-- Explicit ownership record for a widget.
CREATE TABLE widget_ownerships (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
widget_id UUID NOT NULL REFERENCES widgets(id),
owner_hub_id UUID NOT NULL REFERENCES hubs(id),
steward_hub_id UUID REFERENCES hubs(id),
ownership_type TEXT NOT NULL DEFAULT 'local',
-- 'local' | 'delegated' | 'global'
effective_from TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
effective_until TIMESTAMP WITH TIME ZONE,
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);
CREATE INDEX widget_ownerships_widget_id_idx ON widget_ownerships (widget_id);
CREATE INDEX widget_ownerships_owner_hub_idx ON widget_ownerships (owner_hub_id);
CREATE INDEX widget_ownerships_steward_hub_idx ON widget_ownerships (steward_hub_id);
-- Routing rule: automatically routes a RequirementCandidate to another hub.
CREATE TABLE hub_routing_rules (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
source_hub_id UUID NOT NULL REFERENCES hubs(id),
target_hub_id UUID NOT NULL REFERENCES hubs(id),
match_category TEXT,
match_widget_type TEXT,
priority INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'inactive',
-- 'active' | 'inactive'
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);
CREATE INDEX hub_routing_rules_source_idx ON hub_routing_rules (source_hub_id);
CREATE INDEX hub_routing_rules_status_idx ON hub_routing_rules (status);
-- Routing destination on requirement candidates.
ALTER TABLE requirement_candidates
ADD COLUMN routed_to_hub_id UUID REFERENCES hubs(id);
CREATE INDEX requirement_candidates_routed_hub_idx
ON requirement_candidates (routed_to_hub_id)
WHERE routed_to_hub_id IS NOT NULL;
-- Org-wide policy overlay applied across selected hubs.
CREATE TABLE federated_policy_overlays (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
title TEXT NOT NULL,
policy_text TEXT NOT NULL,
applies_to_hubs JSONB NOT NULL DEFAULT '[]',
enforced_from TIMESTAMP WITH TIME ZONE,
status TEXT NOT NULL DEFAULT 'draft',
-- 'draft' | 'active' | 'retired'
notes TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
);
CREATE INDEX federated_policy_overlays_status_idx ON federated_policy_overlays (status);
-- Named governance role assigned to a hub.
CREATE TABLE stewardship_roles (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
hub_id UUID NOT NULL REFERENCES hubs(id),
role_name TEXT NOT NULL,
assigned_to TEXT NOT NULL,
granted_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
revoked_at TIMESTAMP WITH TIME ZONE,
notes TEXT
);
CREATE INDEX stewardship_roles_hub_id_idx ON stewardship_roles (hub_id);
CREATE INDEX stewardship_roles_active_idx ON stewardship_roles (revoked_at)
WHERE revoked_at IS NULL;
-- Long-term archival entry for any IHF artifact.
CREATE TABLE archive_records (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
subject_type TEXT NOT NULL,
subject_id UUID NOT NULL,
archived_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
reason TEXT NOT NULL,
archived_by TEXT NOT NULL,
lineage_ref TEXT
);
CREATE INDEX archive_records_subject_type_idx ON archive_records (subject_type);
CREATE INDEX archive_records_subject_id_idx ON archive_records (subject_id);
-- Soft-archive flag on widgets.
ALTER TABLE widgets
ADD COLUMN is_archived BOOLEAN NOT NULL DEFAULT FALSE;
CREATE INDEX widgets_is_archived_idx ON widgets (is_archived)
WHERE is_archived = TRUE;