feat(WP-0009): IHF GAAF Compliance Foundation — type registries, extension manifests, architectural contracts
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:
2026-03-31 21:17:39 +00:00
parent 1a7732d7da
commit b5d73aa18b
47 changed files with 4855 additions and 104 deletions

View File

@@ -24,6 +24,7 @@ instance View IndexView where
<th class="text-left px-4 py-3 font-medium text-gray-700">Name</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">Slug</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">Domain</th>
<th class="text-left px-4 py-3 font-medium text-gray-700">Kind</th>
<th class="px-4 py-3"></th>
</tr>
</thead>
@@ -34,6 +35,11 @@ instance View IndexView where
</div>
|]
kindBadge :: Text -> Html
kindBadge "framework" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-purple-100 text-purple-800">framework</span>|]
kindBadge "shared" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-teal-100 text-teal-800">shared</span>|]
kindBadge _ = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-blue-100 text-blue-800">domain</span>|]
renderHub :: Hub -> Html
renderHub hub = [hsx|
<tr class="border-b border-gray-100 hover:bg-gray-50">
@@ -45,6 +51,7 @@ renderHub hub = [hsx|
</td>
<td class="px-4 py-3 text-gray-500 font-mono text-xs">{hub.slug}</td>
<td class="px-4 py-3 text-gray-500">{hub.domain}</td>
<td class="px-4 py-3">{kindBadge hub.hubKind}</td>
<td class="px-4 py-3 text-right">
<a href={EditHubAction { hubId = hub.id }}
class="text-gray-500 hover:text-gray-700 text-xs mr-3">Edit</a>

View File

@@ -10,6 +10,7 @@ data ShowView = ShowView
, widgets :: ![Widget]
, recentEvents :: ![InteractionEvent]
, recentAnnotations :: ![Annotation]
, mManifest :: !(Maybe HubCapabilityManifest)
}
instance View ShowView where
@@ -22,7 +23,10 @@ instance View ShowView where
</div>
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-semibold">{hub.name}</h1>
<div class="flex items-center gap-2">
<h1 class="text-2xl font-semibold">{hub.name}</h1>
{kindBadge hub.hubKind}
</div>
<p class="text-sm text-gray-500 mt-1">
<span class="font-mono bg-gray-100 px-1 rounded">{hub.slug}</span>
<span class="ml-2">{hub.domain}</span>
@@ -131,6 +135,11 @@ instance View ShowView where
{forEach recentAnnotations renderAnnotationCard}
</div>
</section>
<section class="mt-8">
<h2 class="text-lg font-medium mb-3">Capability Manifest</h2>
{renderManifestSection mManifest hub.id}
</section>
|]
renderWidgetRow :: Widget -> Html
@@ -171,3 +180,48 @@ renderAnnotationCard a = [hsx|
<p class="text-sm text-gray-700">{a.body}</p>
</div>
|]
renderManifestSection :: Maybe HubCapabilityManifest -> Id Hub -> Html
renderManifestSection Nothing hubId = [hsx|
<div class="bg-white rounded-lg border border-gray-200 p-5 flex items-center justify-between">
<div>
<p class="text-sm text-gray-600">No capability manifest registered for this hub.</p>
<p class="text-xs text-gray-400 mt-1">
Domain hubs should declare their vocabulary before creating hub-owned type registry entries.
</p>
</div>
<a href={NewHubCapabilityManifestAction}
class="text-sm border border-indigo-300 text-indigo-700 px-3 py-1.5 rounded hover:bg-indigo-50">
Register Capabilities
</a>
</div>
|]
renderManifestSection (Just m) _ = [hsx|
<div class="bg-white rounded-lg border border-gray-200 p-5">
<div class="flex items-center justify-between mb-3">
<div class="flex items-center gap-2">
{manifestStatusBadge m.status}
<span class="text-sm text-gray-600">v{m.manifestVersion}</span>
{forEach (maybeText m.capabilityDescription) (\d -> [hsx|<span class="text-sm text-gray-500"> {d}</span>|])}
</div>
<a href={ShowHubCapabilityManifestAction { hubCapabilityManifestId = m.id }}
class="text-sm text-indigo-600 hover:text-indigo-800">View manifest </a>
</div>
{forEach (maybeText m.contact) (\c -> [hsx|<p class="text-xs text-gray-400">Contact: {c}</p>|])}
</div>
|]
manifestStatusBadge :: Text -> Html
manifestStatusBadge "active" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-green-100 text-green-800">active</span>|]
manifestStatusBadge "draft" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-amber-100 text-amber-800">draft</span>|]
manifestStatusBadge "retired" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-gray-100 text-gray-500">retired</span>|]
manifestStatusBadge s = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-gray-100 text-gray-600">{s}</span>|]
kindBadge :: Text -> Html
kindBadge "framework" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-purple-100 text-purple-800">framework</span>|]
kindBadge "shared" = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-teal-100 text-teal-800">shared</span>|]
kindBadge _ = [hsx|<span class="px-2 py-0.5 rounded text-xs bg-blue-100 text-blue-800">domain</span>|]
maybeText :: Maybe Text -> [Text]
maybeText Nothing = []
maybeText (Just t) = [t]