generated from coulomb/repo-seed
feat(WP-0009): IHF GAAF Compliance Foundation — type registries, extension manifests, architectural contracts
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
Implements IHUB-WP-0009: closes four GAAF-2026 gaps before domain hub work begins. - TypeRegistry helper + controllers/views (hub_kind, hub_capability_manifest) - HubCapabilityManifest entity with validation and registry linkage - ARCHITECTURE-LAYERS.md + CI-enforced boundary contracts - Alembic migration 1743724800, fitness tests (Test/Architecture/) - GAAF spec, Operational Architecture spec, domain hub extension guide - Updates to CLAUDE.md, SCOPE.md, Schema.sql, Routes, FrontController, Types state_hub_sync: pending (tunnel was STALE at completion time; run fix-consistency) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
155
contracts/extensions/hub-capability-manifest-v1.md
Normal file
155
contracts/extensions/hub-capability-manifest-v1.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# Hub Capability Manifest Contract
|
||||
|
||||
**Name:** hub-capability-manifest
|
||||
**Version:** 1.0
|
||||
**Date:** 2026-03-31
|
||||
**Status:** Active
|
||||
**Layer:** Extensions
|
||||
**Maturity:** Beta
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Hub Capability Manifest is the formal extension registration mechanism of
|
||||
the IHF. It is the contract by which a domain hub (dev-hub, ops-hub, fin-hub,
|
||||
sec-hub) declares the vocabulary it introduces to the framework: widget types,
|
||||
event types, annotation categories, and policy scopes.
|
||||
|
||||
Without an active manifest, a domain hub is an unregistered participant. Its
|
||||
widgets and events are accepted by the framework, but its type vocabulary is
|
||||
not namespaced, not validated, and not discoverable in Phase 10's marketplace.
|
||||
|
||||
---
|
||||
|
||||
## Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE hub_capability_manifests (
|
||||
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||
hub_id UUID NOT NULL UNIQUE REFERENCES hubs(id),
|
||||
manifest_version TEXT NOT NULL DEFAULT '1.0',
|
||||
declared_widget_types JSONB NOT NULL DEFAULT '[]',
|
||||
declared_event_types JSONB NOT NULL DEFAULT '[]',
|
||||
declared_annotation_categories JSONB NOT NULL DEFAULT '[]',
|
||||
declared_policy_scopes JSONB NOT NULL DEFAULT '[]',
|
||||
capability_description TEXT,
|
||||
contact TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'draft',
|
||||
activated_at TIMESTAMP WITH TIME ZONE,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Registration Workflow
|
||||
|
||||
```
|
||||
1. Create manifest in draft
|
||||
↓
|
||||
2. Declare types (edit declared_* arrays)
|
||||
↓
|
||||
3. Activate (ActivateManifestAction)
|
||||
↓ ← auto-registers declared types into their registries
|
||||
4. Active manifest governs the hub's vocabulary
|
||||
```
|
||||
|
||||
### Step 1 — Create in draft
|
||||
|
||||
```
|
||||
POST /HubCapabilityManifests/new?hubId=<hub-id>
|
||||
```
|
||||
|
||||
One manifest per hub (UNIQUE constraint on `hub_id`). Creating a manifest
|
||||
for a hub that already has one (in any status) requires retiring the existing
|
||||
active manifest first.
|
||||
|
||||
### Step 2 — Declare types
|
||||
|
||||
While in `draft` status, edit the `declared_*` JSONB arrays. Each array
|
||||
contains the string names of types the hub will own:
|
||||
|
||||
```json
|
||||
{
|
||||
"declared_widget_types": ["dev-pipeline-run", "dev-build-status"],
|
||||
"declared_event_types": ["dev-pipeline-started", "dev-pipeline-failed"],
|
||||
"declared_annotation_categories": ["dev-blocker", "dev-flaky-test"],
|
||||
"declared_policy_scopes": ["dev-internal"]
|
||||
}
|
||||
```
|
||||
|
||||
**Naming convention**: domain-owned types should be prefixed with the domain
|
||||
shortcode to prevent collisions (e.g. `dev-`, `fin-`, `sec-`, `ops-`).
|
||||
Framework-level types (no prefix) are owned by inter-hub and shared by all hubs.
|
||||
|
||||
### Step 3 — Activate
|
||||
|
||||
```
|
||||
POST /HubCapabilityManifests/ActivateManifest?hubCapabilityManifestId=<id>
|
||||
```
|
||||
|
||||
On activation:
|
||||
- For each name in `declared_widget_types`: insert into `widget_type_registry`
|
||||
with `owner_hub_id = hub.id` if not already present.
|
||||
- Same for `declared_event_types`, `declared_annotation_categories`,
|
||||
`declared_policy_scopes`.
|
||||
- If any declared name already exists in a registry with a **different**
|
||||
`owner_hub_id`, activation is rejected with a conflict error.
|
||||
- If any declared name exists with `owner_hub_id = NULL` (framework-level),
|
||||
activation is rejected: framework types cannot be claimed by a domain hub.
|
||||
- `status` is set to `active`, `activated_at` is set to `now()`.
|
||||
|
||||
---
|
||||
|
||||
## Invariants
|
||||
|
||||
1. **Type names are permanent.** Once a type name is registered (either via
|
||||
seed or manifest activation), it cannot be deleted from the registry —
|
||||
only deprecated. Other hubs may already depend on it.
|
||||
|
||||
2. **Activated manifests are read-only on declared arrays.** To add new types,
|
||||
retire the manifest and create a new draft, or use `DraftAmendmentAction`
|
||||
which creates an amended draft pending re-activation.
|
||||
|
||||
3. **One active manifest per hub.** The UNIQUE constraint on `hub_id` plus the
|
||||
activation workflow enforce this.
|
||||
|
||||
4. **Framework types cannot be claimed.** Type names with `owner_hub_id = NULL`
|
||||
are owned by the framework. A domain hub manifest that attempts to declare
|
||||
an existing framework type name is rejected.
|
||||
|
||||
---
|
||||
|
||||
## Status Lifecycle
|
||||
|
||||
```
|
||||
draft → active → retired
|
||||
↓
|
||||
(superseded by a new draft → active cycle)
|
||||
```
|
||||
|
||||
A retired manifest's types remain in the registry. If the hub is decommissioned,
|
||||
the types should be deprecated (not deleted) in the registry.
|
||||
|
||||
---
|
||||
|
||||
## Failure Modes
|
||||
|
||||
| Scenario | Behaviour |
|
||||
|---|---|
|
||||
| Duplicate type name (same hub) | Idempotent — skipped, not an error |
|
||||
| Duplicate type name (different hub) | Activation rejected with conflict error |
|
||||
| Framework type name claimed | Activation rejected |
|
||||
| Edit of active manifest declared arrays | Rejected — manifest is read-only |
|
||||
| Hub with no manifest creates hub-owned type | Warning in fitness function; types accepted but unmanifested |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Reference
|
||||
|
||||
- Schema: `Application/Schema.sql` (added in IHUB-WP-0009-T05)
|
||||
- Controller: `Web/Controller/HubCapabilityManifests.hs`
|
||||
- Guide: `docs/domain-hub-extension-guide.md`
|
||||
- Phase 10 dependency: Hub Registry = active manifests + health snapshots
|
||||
Reference in New Issue
Block a user