feat(WP-0015/B1-B6): StaticPages controller and public intro/tutorial UI

B1 — Web/Controller/StaticPages.hs: LandingAction, CapabilitiesAction,
     TutorialAction, ExtensionGuideAction (no auth guard)
B2 — Web/View/StaticPages/Landing.hs: hero, traceability chain, capability
     grid, GAAF status bar, CTAs to capabilities and management UI
B3 — Web/View/StaticPages/Capabilities.hs: 12-phase capability map, GAAF
     scorecard, API v1/v2 surface table, learning loop, type registry system
B4 — Web/View/StaticPages/Tutorial.hs: 6-step developer tutorial (widgets,
     events, governance, deployment, learning, federation)
     Web/View/StaticPages/ExtensionGuide.hs: 6-step hub extension guide
     (HubCapabilityManifest, type registry, widgets, patterns, agents)
     with GAAF rules summary
B5 — Web/Routes.hs: StaticPagesController manual routes; "/" → Landing,
     "/capabilities", "/tutorial", "/extension-guide"
     Web/Types.hs: StaticPagesController data type
B6 — Web/FrontController.hs: import StaticPagesController; register route
     (last, catches root); nav adds About/Tutorial/Extend links and
     separator; logo now links to LandingAction

B7 (deployment verification) remains pending until devenv up is available.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-08 02:02:44 +00:00
parent 74bab5f6f2
commit 5510ae22da
8 changed files with 591 additions and 1 deletions

View File

@@ -0,0 +1,18 @@
module Web.Controller.StaticPages where
-- WP-0015 — Public-facing intro and tutorial pages (no auth required)
import Web.Types
import Generated.Types
import IHP.Prelude
import IHP.ControllerPrelude
import Web.View.StaticPages.Landing
import Web.View.StaticPages.Capabilities
import Web.View.StaticPages.Tutorial
import Web.View.StaticPages.ExtensionGuide
instance Controller StaticPagesController where
action LandingAction = render LandingView
action CapabilitiesAction = render CapabilitiesView
action TutorialAction = render TutorialView
action ExtensionGuideAction = render ExtensionGuideView

View File

@@ -70,6 +70,8 @@ import Web.Controller.LineageEnrichment ()
import Web.Controller.LearningDashboard ()
import Web.Controller.Api.V2.Learning ()
import Web.Controller.Sessions ()
-- WP-0015 — Public intro / tutorial pages
import Web.Controller.StaticPages ()
instance FrontController WebApplication where
controllers =
@@ -135,6 +137,8 @@ instance FrontController WebApplication where
, parseRoute @LineageEnrichmentController
, parseRoute @LearningDashboardController
, parseRoute @ApiV2LearningController
-- WP-0015 — Public intro / tutorial pages (must be last; catches "/" root)
, parseRoute @StaticPagesController
]
instance InitControllerContext WebApplication where
@@ -165,7 +169,11 @@ defaultLayout inner = [hsx|
</head>
<body class="bg-gray-50 text-gray-900">
<nav class="bg-white border-b border-gray-200 px-6 py-3 flex items-center gap-6">
<a href={HubsAction} class="font-semibold text-indigo-600">inter-hub</a>
<a href={LandingAction} class="font-semibold text-indigo-600">inter-hub</a>
<a href={CapabilitiesAction} class="text-sm text-gray-600 hover:text-gray-900">About</a>
<a href={TutorialAction} class="text-sm text-gray-600 hover:text-gray-900">Tutorial</a>
<a href={ExtensionGuideAction} class="text-sm text-gray-600 hover:text-gray-900">Extend</a>
<span class="text-gray-200">|</span>
<a href={HubsAction} class="text-sm text-gray-600 hover:text-gray-900">Hubs</a>
<a href={WidgetsAction} class="text-sm text-gray-600 hover:text-gray-900">Widgets</a>
<a href={RequirementCandidatesAction} class="text-sm text-gray-600 hover:text-gray-900">Candidates</a>

View File

@@ -300,3 +300,18 @@ instance HasPath ApiV2LearningController where
-- Sessions
instance AutoRoute SessionsController
-- WP-0015 — Public intro / tutorial pages (manual routing so / is the root)
instance CanRoute StaticPagesController where
parseRoute' = choice
[ do endOfInput; pure LandingAction
, do _ <- string "/capabilities"; endOfInput; pure CapabilitiesAction
, do _ <- string "/tutorial"; endOfInput; pure TutorialAction
, do _ <- string "/extension-guide"; endOfInput; pure ExtensionGuideAction
]
instance HasPath StaticPagesController where
pathTo LandingAction = "/"
pathTo CapabilitiesAction = "/capabilities"
pathTo TutorialAction = "/tutorial"
pathTo ExtensionGuideAction = "/extension-guide"

View File

@@ -489,3 +489,12 @@ data SessionsController
| CreateSessionAction
| DeleteSessionAction
deriving (Eq, Show, Data)
-- WP-0015 — Public intro / tutorial pages
data StaticPagesController
= LandingAction
| CapabilitiesAction
| TutorialAction
| ExtensionGuideAction
deriving (Eq, Show, Data)

View File

@@ -0,0 +1,135 @@
module Web.View.StaticPages.Capabilities where
import Web.View.Prelude
data CapabilitiesView = CapabilitiesView
instance View CapabilitiesView where
html CapabilitiesView = [hsx|
<div class="max-w-4xl mx-auto py-10 px-6">
<div class="mb-8">
<a href={LandingAction} class="text-sm text-indigo-600 hover:underline"> Home</a>
<h1 class="text-3xl font-bold text-gray-900 mt-3 mb-2">Platform Capabilities</h1>
<p class="text-gray-500">IHF v0.2 GAAF 3.68 Strong 12 phases complete</p>
</div>
{-- Phase map --}
<section id="phases" class="mb-12">
<h2 class="text-xl font-semibold text-gray-800 mb-4 border-b pb-2">12-Phase Capability Map</h2>
<div class="space-y-3">
{phaseRow "1" "Core Domain Model" "Hubs, Widgets, WidgetVersions, InteractionEvents (append-only), Annotations, ViewContexts, CapabilityReferences. Widget envelope helper injects stable widget-id attributes."}
{phaseRow "2" "Requirement Candidates" "Triage lifecycle, duplicate detection, policy sensitivity routing, reviewer assignment, promotion to Requirement."}
{phaseRow "3" "Decision Records" "Requirement → DecisionRecord chain with policy references, implementation change references, and governance status."}
{phaseRow "4" "Deployment & Outcomes" "DeploymentRecord, OutcomeSignal (append-only), ChangeEvaluation. Outcome feedback closes the loop to DecisionRecords."}
{phaseRow "5" "Agent-Assisted Distillation" "AI agents (Anthropic API) draft Requirements from widget clusters, route via configurable model selection. AgentProposals with confidence annotations."}
{phaseRow "6" "Cross-Framework UI Adaptation" "EnvelopeEmissionContracts, InteractionReportingContracts, WidgetAdapterSpecs. Adapts widgets across framework boundaries."}
{phaseRow "7" "Advanced Observability" "FrictionScores, BottleneckRecords, HubHealthSnapshots, CrossHubPropagation detection. Heatmaps and operational review board."}
{phaseRow "8" "Federated Hub Maturity" "WidgetOwnerships, HubRoutingRules, FederatedPolicyOverlays, StewardshipRoles, ArchiveRecords with LineageInspector."}
{phaseRow "9" "External API Surface" "REST v1 + v2, JWT auth, OpenAPI 3.1, TypeScript + Python SDKs, WebhookSubscriptions, per-consumer ApiKeys, ApiDashboard."}
{phaseRow "10" "Hub Registry & Widget Marketplace" "WidgetPatterns with versioned adoption, GovernanceTemplates, HubRegistry, Marketplace dashboard. Phase 10 API v2 endpoints."}
{phaseRow "11" "Advanced AI Federation" "AgentRegistrations, ModelRoutingPolicies, AgentDelegations (tree), CollectiveProposals, AiGovernancePolicies, AgentPerformanceRecords."}
{phaseRow "12" "Platform Memory & Continuous Learning" "OutcomeCorrelations, PatternPerformanceRecords, AdaptiveThresholdConfigs, InstitutionalKnowledgeBase (GIN FTS), LearningInsights, retroactive lineage enrichment."}
</div>
</section>
{-- GAAF scorecard --}
<section id="gaaf" class="mb-12">
<h2 class="text-xl font-semibold text-gray-800 mb-4 border-b pb-2">GAAF-2026 Scorecard</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
{scoreCard "Core Architecture" "3.9" "Append-only invariants, type registry, FK discipline"}
{scoreCard "Functional Completeness" "3.8" "All 12 phases implemented with full controller+view coverage"}
{scoreCard "Observability" "3.5" "Friction heatmaps, health snapshots, lineage inspector"}
{scoreCard "Overall" "3.68" "Strong — GAAF 2026 threshold for production readiness"}
</div>
</section>
{-- API surface --}
<section id="api" class="mb-12">
<h2 class="text-xl font-semibold text-gray-800 mb-4 border-b pb-2">API Surface</h2>
<div class="bg-white rounded-lg border border-gray-200 overflow-hidden">
<table class="w-full text-sm">
<thead class="bg-gray-50 border-b border-gray-200">
<tr>
<th class="px-4 py-3 text-left font-medium text-gray-700">Version</th>
<th class="px-4 py-3 text-left font-medium text-gray-700">Endpoints</th>
<th class="px-4 py-3 text-left font-medium text-gray-700">Auth</th>
</tr>
</thead>
<tbody>
<tr class="border-b border-gray-100">
<td class="px-4 py-3 font-mono text-xs text-gray-600">v1</td>
<td class="px-4 py-3 text-gray-700">POST /api/v1/interaction-events</td>
<td class="px-4 py-3 text-gray-500">None (legacy write path)</td>
</tr>
<tr class="border-b border-gray-100">
<td class="px-4 py-3 font-mono text-xs text-gray-600">v2</td>
<td class="px-4 py-3 text-gray-700">Widgets, Events, Annotations, Candidates, Decisions, Deployments, Signals, Registries, Patterns, Learning</td>
<td class="px-4 py-3 text-gray-500">JWT Bearer</td>
</tr>
<tr>
<td class="px-4 py-3 font-mono text-xs text-gray-600">v2 spec</td>
<td class="px-4 py-3 text-gray-700">GET /api/v2/openapi.json · /api/v2/openapi.yaml · /api/v2/docs</td>
<td class="px-4 py-3 text-gray-500">None (public)</td>
</tr>
</tbody>
</table>
</div>
</section>
{-- Learning loop --}
<section id="learning" class="mb-12">
<h2 class="text-xl font-semibold text-gray-800 mb-4 border-b pb-2">The Learning Loop</h2>
<p class="text-sm text-gray-600 mb-4">
Phase 12 closes the full learning loop. The system continuously improves routing
and triage thresholds based on observed outcomes:
</p>
<div class="bg-indigo-50 border border-indigo-200 rounded-lg p-5 font-mono text-xs text-indigo-800 leading-relaxed">
Widget Annotation RequirementCandidate Requirement<br/>
DecisionRecord DeploymentRecord OutcomeSignal<br/>
OutcomeCorrelation / PatternPerformanceRecord<br/>
InstitutionalKnowledgeEntry AdaptiveThresholdConfig<br/>
improved routing + triage (loop closed)
</div>
</section>
{-- Type registry --}
<section id="type-registry" class="mb-12">
<h2 class="text-xl font-semibold text-gray-800 mb-4 border-b pb-2">Type Registry System</h2>
<p class="text-sm text-gray-600 mb-3">
GAAF Rule 1: all type discriminator columns reference a registry table.
New hub-owned types must be registered before use (GAAF Rule 2).
</p>
<div class="grid grid-cols-2 gap-3 text-sm">
<div class="bg-white border rounded p-3"><strong class="text-gray-700">widget_type_registry</strong> <span class="text-gray-400"> hub-owned widget types</span></div>
<div class="bg-white border rounded p-3"><strong class="text-gray-700">event_type_registry</strong> <span class="text-gray-400"> interaction event types</span></div>
<div class="bg-white border rounded p-3"><strong class="text-gray-700">annotation_category_registry</strong> <span class="text-gray-400"> annotation categories</span></div>
<div class="bg-white border rounded p-3"><strong class="text-gray-700">policy_scope_registry</strong> <span class="text-gray-400"> policy sensitivity scopes</span></div>
</div>
</section>
<div class="flex gap-4 text-sm">
<a href={TutorialAction} class="text-indigo-600 hover:underline">Developer Tutorial </a>
<a href={ExtensionGuideAction} class="text-indigo-600 hover:underline">Extension Guide </a>
<a href={HubsAction} class="text-indigo-600 hover:underline">Management UI </a>
</div>
</div>
|]
where
phaseRow num title_ desc = [hsx|
<div class="bg-white rounded-lg border border-gray-200 p-4 flex gap-4">
<div class="w-8 h-8 rounded-full bg-indigo-100 text-indigo-700 flex items-center justify-center text-sm font-bold flex-shrink-0">
{num :: Text}
</div>
<div>
<div class="font-medium text-gray-800">{title_ :: Text}</div>
<div class="text-sm text-gray-500 mt-0.5">{desc :: Text}</div>
</div>
</div>
|]
scoreCard label_ score_ detail_ = [hsx|
<div class="bg-white border border-gray-200 rounded-lg p-4 text-center">
<div class="text-2xl font-bold text-indigo-700">{score_ :: Text}</div>
<div class="text-sm font-medium text-gray-700 mt-1">{label_ :: Text}</div>
<div class="text-xs text-gray-400 mt-1">{detail_ :: Text}</div>
</div>
|]

View File

@@ -0,0 +1,150 @@
module Web.View.StaticPages.ExtensionGuide where
import Web.View.Prelude
data ExtensionGuideView = ExtensionGuideView
instance View ExtensionGuideView where
html ExtensionGuideView = [hsx|
<div class="max-w-4xl mx-auto py-10 px-6">
<div class="mb-8">
<a href={LandingAction} class="text-sm text-indigo-600 hover:underline"> Home</a>
<h1 class="text-3xl font-bold text-gray-900 mt-3 mb-2">Domain Hub Extension Guide</h1>
<p class="text-gray-500">
How to build and register a domain hub extension: HubCapabilityManifest,
type registry entries, hub-owned widget types, and hub-scoped controllers.
</p>
</div>
{-- Overview --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">Overview</h2>
<p class="text-gray-600 mb-3">
inter-hub provides the governance substrate. Domain hubs (dev-hub, ops-hub, fin-hub, sec-hub)
extend it by registering their own capability manifests and type discriminators.
This keeps core tables stable while allowing domain-specific specialisation.
</p>
<div class="bg-amber-50 border border-amber-200 rounded-lg p-4 text-sm text-amber-800">
<strong>GAAF Rule 2:</strong> New hub-owned types must be declared in the hub's
<code class="bg-amber-100 px-1 rounded">HubCapabilityManifest</code> before use.
Register via the Extensions admin UI before creating any hub-owned widget types.
</div>
</section>
{-- Step 1: Create a Hub --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "1"} Create a Hub</h2>
<p class="text-gray-600 mb-3">
Navigate to <a href={HubsAction} class="text-indigo-600 hover:underline">Management UI Hubs</a>
and create a new hub. Each hub has a <code class="bg-gray-100 px-1 rounded text-sm">slug</code>
that will prefix its owned types (e.g. <code>dev.code-review</code>).
</p>
</section>
{-- Step 2: Register a HubCapabilityManifest --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "2"} Register a HubCapabilityManifest</h2>
<p class="text-gray-600 mb-3">
A <strong>HubCapabilityManifest</strong> is the DB-side contract for a domain hub.
Go to <a href={HubCapabilityManifestsAction} class="text-indigo-600 hover:underline">Extensions</a>
and create a manifest for your hub. Set status to <code class="bg-gray-100 px-1 rounded text-sm">active</code>.
</p>
<p class="text-sm text-gray-500">
The manifest includes: <code>hubId</code>, <code>manifestVersion</code>,
<code>capabilitySchema</code> (JSON), and an optional <code>apiEndpointBase</code>.
It is the anchor point for per-consumer API keys in Phase 9.
</p>
</section>
{-- Step 3: Register type discriminators --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "3"} Register Type Discriminators</h2>
<p class="text-gray-600 mb-3">
Before creating widgets of a new type, register the type in the appropriate registry.
Go to <a href={WidgetTypeRegistryAction} class="text-indigo-600 hover:underline">Registries</a>:
</p>
<ul class="text-sm text-gray-600 space-y-1 list-disc list-inside mb-3">
<li><strong>Widget Type Registry</strong> new widget types your hub will own</li>
<li><strong>Event Type Registry</strong> custom interaction event types</li>
<li><strong>Annotation Category Registry</strong> custom annotation categories</li>
<li><strong>Policy Scope Registry</strong> custom policy sensitivity scopes</li>
</ul>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 text-sm text-gray-600">
Set <code>owner_hub_id</code> to your hub. Once registered, your hub-scoped code
can create widgets of that type and the type will appear in the marketplace.
</div>
</section>
{-- Step 4: Create widgets --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "4"} Create Widgets</h2>
<p class="text-gray-600 mb-3">
With the type registered, create widgets via the
<a href={WidgetsAction} class="text-indigo-600 hover:underline">Widgets</a> page
or the API:
</p>
<div class="bg-gray-900 rounded-lg p-4 text-sm font-mono text-green-400">
POST /api/v2/widgets<br/>
<span class="text-gray-400">{"{"} "name": "PR Review Widget",<br/>
&nbsp;&nbsp;"widgetType": "dev.code-review",<br/>
&nbsp;&nbsp;"hubId": "...",<br/>
&nbsp;&nbsp;"viewContext": "pull-request-sidebar" {"}"}</span>
</div>
</section>
{-- Step 5: Publish a widget pattern --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "5"} Publish a Widget Pattern (optional)</h2>
<p class="text-gray-600 mb-3">
If your widget design is reusable, publish it to the
<a href={MarketplaceDashboardAction} class="text-indigo-600 hover:underline">Widget Marketplace</a>.
Other hubs can adopt it and pin to specific versions. Patterns support
semantic versioning and adoption tracking.
</p>
</section>
{-- Step 6: AI agent integration --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "6"} Connect an AI Agent (Phase 11)</h2>
<p class="text-gray-600 mb-3">
Register an <a href={AgentRegistrationsAction} class="text-indigo-600 hover:underline">AgentRegistration</a>
for your hub, then create a
<a href={ModelRoutingPoliciesAction} class="text-indigo-600 hover:underline">ModelRoutingPolicy</a>
to route task types to specific models or agents.
Agents can draft Requirements, propose governance decisions, and participate in
CollectiveProposals.
</p>
</section>
{-- GAAF rules reminder --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">GAAF Architecture Rules (Summary)</h2>
<div class="space-y-2 text-sm">
{ruleBox "1" "Type discriminator columns must reference a registry table or carry a CHECK constraint. No bare TEXT for new type discriminators."}
{ruleBox "2" "New hub-owned types must be declared in the hub's HubCapabilityManifest before use."}
{ruleBox "3" "Core tables (widgets, interaction_events, annotations, hubs) must not have new columns without updating /contracts/core/."}
{ruleBox "4" "Append-only invariant on interaction_events and outcome_signals is permanent. Never bypass those triggers."}
</div>
</section>
<div class="flex gap-4 text-sm mt-6">
<a href={TutorialAction} class="text-indigo-600 hover:underline"> Developer Tutorial</a>
<a href={CapabilitiesAction} class="text-indigo-600 hover:underline">Full Capabilities </a>
<a href={HubsAction} class="text-indigo-600 hover:underline">Management UI </a>
</div>
</div>
|]
where
stepBadge n = [hsx|
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-indigo-600 text-white text-sm font-bold mr-2">
{n :: Text}
</span>
|]
ruleBox n desc = [hsx|
<div class="flex gap-3 bg-white border border-gray-200 rounded-lg p-3">
<div class="w-6 h-6 rounded-full bg-amber-100 text-amber-800 flex items-center justify-center text-xs font-bold flex-shrink-0">
{n :: Text}
</div>
<p class="text-gray-600">{desc :: Text}</p>
</div>
|]

View File

@@ -0,0 +1,129 @@
module Web.View.StaticPages.Landing where
import Web.View.Prelude
data LandingView = LandingView
instance View LandingView where
html LandingView = [hsx|
<div class="max-w-4xl mx-auto py-12 px-6">
{-- Hero --}
<div class="text-center mb-16">
<h1 class="text-4xl font-bold text-gray-900 mb-4">inter-hub</h1>
<p class="text-xl text-gray-600 mb-2">
Reference implementation of the <strong>Interaction Hub Framework (IHF)</strong>
</p>
<p class="text-gray-500 max-w-2xl mx-auto">
A governed, observable interaction substrate for hub-based AI-enabled software
systems. Every UI element is a governed artifact with a full traceability chain
from rendered widget to observed outcome.
</p>
<div class="mt-8 flex justify-center gap-4">
<a href={CapabilitiesAction}
class="bg-indigo-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-indigo-700 transition-colors">
Explore Capabilities
</a>
<a href={HubsAction}
class="border border-gray-300 text-gray-700 px-6 py-3 rounded-lg font-medium hover:bg-gray-50 transition-colors">
Go to Management UI
</a>
</div>
</div>
{-- Traceability chain --}
<div class="mb-16">
<h2 class="text-2xl font-semibold text-gray-800 mb-6 text-center">Full Traceability Chain</h2>
<div class="bg-white rounded-xl border border-gray-200 p-6">
<div class="flex flex-wrap items-center justify-center gap-2 text-sm font-medium">
{chainLink "Widget" "indigo"}
{arrow}
{chainLink "InteractionEvent" "blue"}
{chainLink "Annotation" "blue"}
{arrow}
{chainLink "RequirementCandidate" "violet"}
{arrow}
{chainLink "Requirement" "purple"}
{arrow}
{chainLink "DecisionRecord" "fuchsia"}
{arrow}
{chainLink "DeploymentRecord" "rose"}
{arrow}
{chainLink "OutcomeSignal" "orange"}
{arrow}
{chainLink "Learning" "emerald"}
</div>
<p class="text-center text-gray-400 text-xs mt-4">
Append-only event log · PostgreSQL-enforced invariants · Full lineage inspector
</p>
</div>
</div>
{-- Key capabilities grid --}
<div class="mb-16">
<h2 class="text-2xl font-semibold text-gray-800 mb-6 text-center">Key Capabilities</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
{capCard "Governed Widgets"
"Every UI element carries a stable widget-id, version history, and owner hub. Type discriminators reference a registry — no bare TEXT."
"indigo"}
{capCard "AI Agent Federation"
"Multi-agent routing, delegation trees, collective proposals, model selection policies, and AI governance overlays. Phase 11 complete."
"violet"}
{capCard "Continuous Learning"
"Outcome correlation engine, pattern performance ranking, adaptive friction thresholds, and institutional knowledge base with full-text search. Phase 12 complete."
"emerald"}
{capCard "External API Surface"
"REST API v2 with JWT auth, OpenAPI 3.1 spec, TypeScript + Python SDKs, webhook subscriptions, and per-consumer API keys."
"blue"}
{capCard "Hub Federation"
"Cross-hub propagation detection, routing rules, stewardship roles, federated policy overlays, and GAAF compliance governance."
"orange"}
{capCard "Widget Marketplace"
"Published widget patterns with versioned adoption, governance template library, and hub registry for domain extension discovery."
"rose"}
</div>
</div>
{-- Status bar --}
<div class="bg-emerald-50 border border-emerald-200 rounded-xl p-6 text-center">
<div class="flex justify-center gap-8 text-sm">
<div>
<div class="font-bold text-emerald-700 text-lg">12 / 12</div>
<div class="text-emerald-600">IHF Phases Complete</div>
</div>
<div>
<div class="font-bold text-emerald-700 text-lg">3.68</div>
<div class="text-emerald-600">GAAF Score (Strong)</div>
</div>
<div>
<div class="font-bold text-emerald-700 text-lg">58</div>
<div class="text-emerald-600">Controllers</div>
</div>
<div>
<div class="font-bold text-emerald-700 text-lg">IHF v0.2</div>
<div class="text-emerald-600">Specification</div>
</div>
</div>
</div>
{-- Nav to docs --}
<div class="mt-10 flex justify-center gap-6 text-sm text-gray-500">
<a href={TutorialAction} class="hover:text-indigo-600">Tutorial </a>
<a href={ExtensionGuideAction} class="hover:text-indigo-600">Extension Guide </a>
<a href={CapabilitiesAction} class="hover:text-indigo-600">Full Capabilities </a>
</div>
</div>
|]
where
chainLink label color = [hsx|
<span class={"inline-block px-2 py-1 rounded text-xs bg-" <> color <> "-100 text-" <> color <> "-800 font-mono"}>
{label :: Text}
</span>
|]
arrow = [hsx|<span class="text-gray-400"></span>|]
capCard title_ body_ color = [hsx|
<div class={"bg-white rounded-lg border border-gray-200 p-5 border-l-4 border-l-" <> color <> "-500"}>
<h3 class="font-semibold text-gray-800 mb-2">{title_ :: Text}</h3>
<p class="text-sm text-gray-600">{body_ :: Text}</p>
</div>
|]

View File

@@ -0,0 +1,126 @@
module Web.View.StaticPages.Tutorial where
import Web.View.Prelude
data TutorialView = TutorialView
instance View TutorialView where
html TutorialView = [hsx|
<div class="max-w-4xl mx-auto py-10 px-6">
<div class="mb-8">
<a href={LandingAction} class="text-sm text-indigo-600 hover:underline"> Home</a>
<h1 class="text-3xl font-bold text-gray-900 mt-3 mb-2">Developer Tutorial</h1>
<p class="text-gray-500">How IHF works from a developer perspective widget lifecycle, governance flow, outcome loop.</p>
</div>
{-- Step 1: Hubs and Widgets --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "1"} Hubs and Widgets</h2>
<p class="text-gray-600 mb-3">
A <strong>Hub</strong> is a bounded domain of responsibility (e.g. Dev Hub, Ops Hub, Fin Hub).
Hubs own Widgets the smallest semantically governable interaction unit.
Each widget has a <code class="bg-gray-100 px-1 rounded text-sm">widget_id</code> (stable UUID),
a <code class="bg-gray-100 px-1 rounded text-sm">widget_type</code> (from the registry),
and a version history.
</p>
<div class="bg-gray-900 rounded-lg p-4 text-sm font-mono text-green-400">
<div class="text-gray-400 mb-1">-- Every rendered widget wraps its HSX in widgetEnvelope</div>
widgetEnvelope widgetId viewContext [hsx|...|]
</div>
<p class="text-sm text-gray-500 mt-2">
The envelope injects <code>data-widget-id</code> and <code>data-view-context</code> attributes,
enabling client-side event capture without coupling to implementation.
</p>
</section>
{-- Step 2: Interaction Events --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "2"} Interaction Events</h2>
<p class="text-gray-600 mb-3">
When a user or agent interacts with a widget, an <strong>InteractionEvent</strong> is recorded
clicked, viewed, submitted, dismissed, etc. Events are <strong>append-only</strong>:
a PostgreSQL trigger prevents UPDATE and DELETE on the <code class="bg-gray-100 px-1 rounded text-sm">interaction_events</code> table.
</p>
<div class="bg-gray-900 rounded-lg p-4 text-sm font-mono text-green-400">
POST /api/v1/interaction-events<br/>
POST /api/v2/interaction-events
</div>
<p class="text-sm text-gray-500 mt-2">
Events flow into <strong>Annotations</strong> (human/agent commentary with category)
and eventually surface as RequirementCandidates.
</p>
</section>
{-- Step 3: Governance flow --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "3"} Governance Flow</h2>
<p class="text-gray-600 mb-3">
RequirementCandidates go through a triage lifecycle: <em>open triaged reviewed promoted or dismissed</em>.
Phase 5 agents can draft Requirements from widget clusters using the Anthropic API.
Promoted candidates become <strong>Requirements</strong>, which are linked to <strong>DecisionRecords</strong>.
</p>
<div class="grid grid-cols-3 gap-3 text-xs text-center">
{flowBox "RequirementCandidate" "open · triaged · reviewed"}
{arrow_}
{flowBox "Requirement" "linked to Decision"}
{arrow_}
{flowBox "DecisionRecord" "policy refs · impl refs"}
</div>
</section>
{-- Step 4: Deployment and outcomes --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "4"} Deployment and Outcomes</h2>
<p class="text-gray-600 mb-3">
A DecisionRecord links to a <strong>DeploymentRecord</strong>. After deployment,
<strong>OutcomeSignals</strong> are recorded (also append-only) and evaluated via
<strong>ChangeEvaluations</strong>. Outcome feedback flows back to the DecisionRecord,
closing the governance loop.
</p>
</section>
{-- Step 5: Learning --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "5"} Continuous Learning (Phase 12)</h2>
<p class="text-gray-600 mb-3">
Phase 12 layers a learning engine on top of the governance loop:
</p>
<ul class="text-sm text-gray-600 space-y-1 list-disc list-inside">
<li><strong>OutcomeCorrelations</strong> compute correlation scores between widget patterns and outcomes</li>
<li><strong>PatternPerformanceRecords</strong> rank widget patterns by observed outcome quality</li>
<li><strong>AdaptiveThresholdConfigs</strong> auto-calibrate friction and triage thresholds per hub</li>
<li><strong>InstitutionalKnowledgeBase</strong> GIN full-text search over all governance decisions</li>
<li><strong>LearningInsights</strong> actionable recommendations surfaced in the Learning Dashboard</li>
</ul>
</section>
{-- Step 6: Hub federation --}
<section class="mb-10">
<h2 class="text-xl font-semibold text-gray-800 mb-3">{stepBadge "6"} Hub Federation</h2>
<p class="text-gray-600 mb-3">
Multiple hubs interact via routing rules, stewardship roles, and federated policy overlays.
Cross-hub propagation patterns are detected automatically. The GAAF compliance layer
enforces type registry discipline and contract stability across hub boundaries.
</p>
</section>
<div class="flex gap-4 text-sm mt-6">
<a href={ExtensionGuideAction} class="text-indigo-600 hover:underline">Build a domain hub extension </a>
<a href={CapabilitiesAction} class="text-indigo-600 hover:underline">Full Capabilities </a>
<a href={HubsAction} class="text-indigo-600 hover:underline">Management UI </a>
</div>
</div>
|]
where
stepBadge n = [hsx|
<span class="inline-flex items-center justify-center w-7 h-7 rounded-full bg-indigo-600 text-white text-sm font-bold mr-2">
{n :: Text}
</span>
|]
flowBox label_ sub_ = [hsx|
<div class="bg-indigo-50 border border-indigo-200 rounded p-3">
<div class="font-medium text-indigo-800 text-xs">{label_ :: Text}</div>
<div class="text-indigo-500 text-xs mt-0.5">{sub_ :: Text}</div>
</div>
|]
arrow_ = [hsx|<div class="flex items-center justify-center text-gray-400 text-xl"></div>|]