127 lines
5.4 KiB
Markdown
127 lines
5.4 KiB
Markdown
|
|
# Phase 8 Summary — Federated Hub Maturity
|
|||
|
|
|
|||
|
|
Phase 8 completes the IHF v0.1 specification. It introduces the governance
|
|||
|
|
structures needed when multiple teams, hubs, and policies must coexist at
|
|||
|
|
organisational scale.
|
|||
|
|
|
|||
|
|
## What Was Built
|
|||
|
|
|
|||
|
|
### Delegated Ownership (`WidgetOwnership`)
|
|||
|
|
|
|||
|
|
Every widget can now carry an explicit ownership record: `local` (owned by its
|
|||
|
|
hub), `delegated` (steward hub differs from owner hub), or `global` (org-wide).
|
|||
|
|
Ownership records are append-only audit artefacts — `effective_until` signals
|
|||
|
|
expiry, but records are never deleted.
|
|||
|
|
|
|||
|
|
The ownership badge appears on the widget show page (colour-coded: local=gray,
|
|||
|
|
delegated=blue, global=purple).
|
|||
|
|
|
|||
|
|
### Inter-Hub Requirement Routing (`HubRoutingRule`)
|
|||
|
|
|
|||
|
|
A priority-ordered rule engine routes `RequirementCandidate` records across hub
|
|||
|
|
boundaries. When a candidate is created, the engine finds the highest-priority
|
|||
|
|
active rule whose `match_category` and `match_widget_type` match (null = any)
|
|||
|
|
and sets `routed_to_hub_id` on the candidate.
|
|||
|
|
|
|||
|
|
`RouteNowAction` allows manual re-evaluation. `RoutedCandidatesAction { hubId }`
|
|||
|
|
shows all candidates forwarded to a given hub from any source hub.
|
|||
|
|
|
|||
|
|
### Federated Policy Overlays (`FederatedPolicyOverlay`)
|
|||
|
|
|
|||
|
|
Org-wide governance policies applied across selected hubs (or all hubs via
|
|||
|
|
`applies_to_hubs = []`). Overlays follow a `draft → active → retired` lifecycle.
|
|||
|
|
|
|||
|
|
**Immutability pattern:** once activated, an overlay cannot be edited. A new
|
|||
|
|
overlay must be created to supersede the old one. The old overlay remains
|
|||
|
|
readable for audit. This mirrors the Phase 6 `EnvelopeEmissionContract`
|
|||
|
|
immutability pattern.
|
|||
|
|
|
|||
|
|
The Policy Compliance Dashboard shows coverage metrics: decisions referencing
|
|||
|
|
at least one `PolicyReference` as a percentage of total in-scope decisions.
|
|||
|
|
|
|||
|
|
### Stewardship Roles (`StewardshipRole`)
|
|||
|
|
|
|||
|
|
Named governance roles assigned to hubs (e.g. "Hub Lead", "Policy Steward",
|
|||
|
|
"Triage Owner"). Roles have `granted_at` and `revoked_at` timestamps.
|
|||
|
|
Contextual steward queries use the point-in-time pattern:
|
|||
|
|
`granted_at ≤ T AND (revoked_at IS NULL OR revoked_at > T)`.
|
|||
|
|
|
|||
|
|
No edits — create a new record to replace a role.
|
|||
|
|
|
|||
|
|
### Archival and Lineage Inspection (`ArchiveRecord`, `is_archived`)
|
|||
|
|
|
|||
|
|
**Soft-delete pattern:** `is_archived BOOLEAN NOT NULL DEFAULT FALSE` on
|
|||
|
|
`widgets`. Active queries filter with `filterWhere (#isArchived, False)`.
|
|||
|
|
The widget row and all related records are preserved.
|
|||
|
|
|
|||
|
|
`ArchiveWidgetAction` sets the flag and creates an `ArchiveRecord` (subject_type,
|
|||
|
|
subject_id, reason, archived_by, lineage_ref).
|
|||
|
|
|
|||
|
|
`LineageInspectorAction { widgetId }` renders the full IHF traceability chain
|
|||
|
|
in a single read-only timeline:
|
|||
|
|
`Widget → InteractionEvents → Annotations → RequirementCandidates
|
|||
|
|
→ Requirements → DecisionRecords → DeploymentRecords → OutcomeSignals`
|
|||
|
|
plus any `ArchiveRecord` for the widget.
|
|||
|
|
|
|||
|
|
### Federated Governance Dashboard
|
|||
|
|
|
|||
|
|
`FederatedGovernanceDashboardAction` (autoRefresh, five panels):
|
|||
|
|
|
|||
|
|
| Panel | Metric |
|
|||
|
|
|-------|--------|
|
|||
|
|
| 1 — Ownership | % of widgets with ownership records; breakdown by type |
|
|||
|
|
| 2 — Routing | Active rule count; candidates routed cross-hub in 30 days |
|
|||
|
|
| 3 — Policy compliance | Active overlays; % decisions with policy reference |
|
|||
|
|
| 4 — Stewardship | Hubs with ≥1 active steward; hubs with no stewards |
|
|||
|
|
| 5 — Archive activity | Artifact counts archived in last 90 days by subject type |
|
|||
|
|
|
|||
|
|
## Schema Changes
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
widget_ownerships -- delegated ownership records
|
|||
|
|
hub_routing_rules -- inter-hub routing logic
|
|||
|
|
requirement_candidates.routed_to_hub_id -- routing destination (nullable)
|
|||
|
|
federated_policy_overlays -- immutable org-wide policies
|
|||
|
|
stewardship_roles -- point-in-time governance roles
|
|||
|
|
archive_records -- soft-delete audit trail
|
|||
|
|
widgets.is_archived -- soft-delete flag
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Migration: `Application/Migration/1743638400-ihf-phase8-federated-hub-maturity.sql`
|
|||
|
|
|
|||
|
|
## Routing Engine
|
|||
|
|
|
|||
|
|
`Application/Helper/RoutingEngine.hs` — `applyRoutingRules`:
|
|||
|
|
|
|||
|
|
```haskell
|
|||
|
|
ruleMatches category mWidgetType rule =
|
|||
|
|
categoryMatch && widgetTypeMatch
|
|||
|
|
where
|
|||
|
|
categoryMatch = isNothing rule.matchCategory || rule.matchCategory == Just category
|
|||
|
|
widgetTypeMatch = isNothing rule.matchWidgetType ||
|
|||
|
|
(isJust mWidgetType && rule.matchWidgetType == mWidgetType)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Null-inclusive matching: a rule with no `match_category` fires on any category.
|
|||
|
|
Only the highest-priority active matching rule fires per candidate.
|
|||
|
|
|
|||
|
|
## Known Limitations
|
|||
|
|
|
|||
|
|
- `applies_to_hubs` on `FederatedPolicyOverlay` is stored as JSONB; Phase 8
|
|||
|
|
does not enforce referential integrity between hub IDs in this column and the
|
|||
|
|
`hubs` table. A future phase could validate on activation.
|
|||
|
|
- `LineageInspectorAction` is widget-scoped. A fully generic artefact-scoped
|
|||
|
|
lineage inspector (for decisions, deployments, etc.) is a Phase 9+ feature.
|
|||
|
|
- Routing is evaluated on candidate creation and on manual `RouteNowAction`.
|
|||
|
|
There is no background re-evaluation if rules change after candidates exist.
|
|||
|
|
- Ownership records have no uniqueness constraint — multiple active ownerships
|
|||
|
|
per widget are possible. The latest `effective_from` record is authoritative
|
|||
|
|
by convention.
|
|||
|
|
|
|||
|
|
## IHF v0.1 Status
|
|||
|
|
|
|||
|
|
All eight phases of `specs/InteractionHubFrameworkSpecification_v0.1.md` are
|
|||
|
|
now implemented in the reference IHP application. See
|
|||
|
|
`specs/InteractionHubFrameworkSpecification_v0.2.md` for the planned Phases 9–12
|
|||
|
|
roadmap (External API, Marketplace, AI Federation, Platform Memory).
|