--- id: IHUB-WP-0019 type: workplan title: "VSM Hub Bootstrap API Hardening" domain: inter_hub repo: inter-hub status: finished owner: codex topic_slug: inter_hub created: "2026-05-16" updated: "2026-05-19" planning_priority: high planning_order: 19 related_repos: - helix-forge related_workplans: - HF-WP-0001 state_hub_workstream_id: "ebde2b8b-8863-4008-9ebf-9bb0300d7375" --- # VSM Hub Bootstrap API Hardening ## Goal Make Inter-Hub capable of bootstrapping VSM domain hubs, starting with `ops-hub`, through documented API calls or an explicit admin bootstrap command instead of manual UI-only setup or ad hoc database migrations. This workplan is linked from `helix-forge` workplan `HF-WP-0001`, where `ops-hub` is being established as the first VSM Inter-Hub extension. ## Background The current Inter-Hub implementation already supports the essential concepts: - `Hub` - `HubCapabilityManifest` - type registries for widget types, event types, annotation categories, and policy scopes - `ApiConsumer` - `ApiKey` - widgets - v2 interaction events However, the live public v2 API is currently read-heavy. The initial `ops-hub` bootstrap still requires authenticated UI flows or deployment-side migrations for hub creation, manifest creation/activation, API consumer/key creation, and widget seeding. For HelixForge's VSM hub family, the desired repeatable bootstrap shape is: ```text Hub identity + VSM function + manifest vocabulary + API consumer + seed widgets + evidence events ``` The same shape should later work for: - `ops-hub` — Operations / System 1 - `syn-hub` — Synchronization / System 2 - `ctl-hub` — Internal Control / System 3 - `aud-hub` — Audit / System 3* - `int-hub` — Intelligence and Adaptation / System 4 - `pol-hub` — Policy and Identity / System 5 - `env-hub` — Environment boundary ## Constraints - Preserve the GAAF rule that hub-owned type names are declared through `HubCapabilityManifest` before use. - Do not weaken append-only invariants on `interaction_events`. - Do not expose raw static API keys after creation. - Keep UI flows working while adding API/admin bootstrap support. - Prefer explicit request schemas in OpenAPI instead of reusing response schemas as create contracts. ## Tasks ### T01 — Add scriptable hub and widget creation endpoints ```task id: IHUB-WP-0019-T01 status: done priority: high state_hub_task_id: "72c5b7b2-632f-42ab-ac4d-eff123d8f143" ``` Add documented v2 create endpoints for the records needed during a hub bootstrap: - `POST /api/v2/hubs` - `POST /api/v2/widgets` The endpoints should validate the same invariants as the UI controllers: - hub slug/name/domain are required - `hubKind` accepts supported values only - widget type is registered - policy scope is registered when the registry is enforced - widget belongs to an existing hub Done when: a script can create a hub row and seed widgets without direct DB access. Implementation note (2026-05-16): added authenticated v2 `POST /api/v2/hubs` and `POST /api/v2/widgets`, with required-field validation, hub-kind/status validation, widget type and policy-scope registry checks, hub existence checks, initial widget-version snapshots, OpenAPI path entries, SDK helper methods, and focused Hspec helper coverage. The collection controllers now dispatch GET/POST by HTTP method so the create routes are reachable. Local `git diff --check` passed; `scripts/compile-check` could not run because this shell does not have `IHP_LIB`/the IHP dev environment loaded. --- ### T02 — Add manifest and policy-scope API support ```task id: IHUB-WP-0019-T02 status: done priority: high state_hub_task_id: "46a027d0-4831-40af-b8ae-e1f858cdaef7" ``` Add documented API or admin-command support for: - `HubCapabilityManifest` draft creation - manifest vocabulary update - manifest activation - listing policy scopes at `/api/v2/policy-scopes` Done when: manifest activation can be executed without clicking through the UI and all four type registries are visible through v2 list endpoints. Implementation note (2026-05-16): added authenticated `/api/v2/hub-capability-manifests` support for draft create, draft update, and activation, including the same manifest vocabulary conflict checks and idempotent registry upserts used by the UI flow. Added `/api/v2/policy-scopes`, OpenAPI path/schema entries, SDK helper methods, and focused Hspec helper coverage for manifest vocabulary parsing. Local `git diff --check` passed; `scripts/compile-check` could not run because this shell does not have `IHP_LIB`/the IHP dev environment loaded. --- ### T03 — Add first-class VSM hub metadata ```task id: IHUB-WP-0019-T03 status: done priority: medium state_hub_task_id: "a90a0220-3d02-4b97-9fbf-a6bbbfa5019c" ``` Decide where VSM hub-family metadata belongs and implement it consistently. Candidate fields: - `hub_family` - `vsm_function` - `vsm_system` Candidate placement: - new columns on `hubs` - manifest metadata JSON - a separate hub classification table Done when: `ops-hub` can be represented as the VSM Operations / System 1 hub without hiding that classification inside prose. Implementation note (2026-05-19): chose new nullable columns on `hubs` (`hub_family`, `vsm_function`, `vsm_system`) because the VSM role is hub identity/classification metadata, not manifest vocabulary. Added migration `1744588800-vsm-hub-metadata.sql`, schema constraints, v2 hub create/list/show JSON, hub registry JSON, compact registry/UI badges, OpenAPI request/response fields, SDK parameters, and validation tests. API validation now accepts either no VSM fields or `hubFamily=vsm` with non-empty `vsmFunction` and a supported `vsmSystem` (`1`, `2`, `3`, `3*`, `4`, `5`, or `environment`). `git diff --check` passed; `scripts/compile-check` is still blocked in this shell because `IHP_LIB` is not set. --- ### T04 — Add API consumer and API key bootstrap support ```task id: IHUB-WP-0019-T04 status: done priority: high state_hub_task_id: "a50114d7-8719-45d5-9081-948df147d500" ``` Add either documented v2 endpoints or an admin-only bootstrap command for: - creating an `ApiConsumer` - binding it to an active manifest - creating a static API key - returning the full key exactly once Done when: an operator can create an ops-hub API credential from a repeatable command while preserving the one-time secret display invariant. Implementation note (2026-05-19): added authenticated v2 `/api/v2/api-consumers` support for consumer create/list/show, including active manifest binding validation, positive rate-limit/quota validation, and `POST /api/v2/api-consumers/:id/api-keys` for one-time static key generation. Key hashes are stored; the raw `fullKey` is returned only in the key creation response. Added OpenAPI/SDK entries and focused Hspec helper coverage. Local `git diff --check` passed; `scripts/compile-check` could not run because this shell does not have `IHP_LIB`/the IHP dev environment loaded. --- ### T05 — Fix interaction-event create contract gaps ```task id: IHUB-WP-0019-T05 status: done priority: high state_hub_task_id: "1febfdb6-757b-420a-b4bd-709ce3cd1252" ``` Fix the current v2 interaction event create behavior: - decode active manifest `declaredEventTypes` instead of treating it as empty - persist submitted `metadata` if metadata is part of the create contract - dispatch webhooks using the submitted event type instead of hard-coded `"clicked"` - add tests around manifest-declared domain events Done when: `ops-endpoint-verified` can be submitted with metadata and routed as an ops-owned event. Implementation note (2026-05-16): v2 interaction-event creation now validates against active manifest-declared event types, persists submitted metadata from JSON request bodies, dispatches webhooks with the submitted event type, and has focused Hspec coverage for manifest-declared ops domain events. Local `git diff --check` passed; `scripts/compile-check` could not run because this shell does not have `IHP_LIB`/the IHP dev environment loaded. --- ### T06 — Update OpenAPI request schemas and hub quickstart docs ```task id: IHUB-WP-0019-T06 status: done priority: medium state_hub_task_id: "84c92e05-3e0f-490a-a48f-e2d9ddace764" ``` Update OpenAPI and docs to match the real API: - add distinct create request schemas for hubs, widgets, annotations, interaction events, manifests, consumers, and keys where applicable - remove or clearly mark aspirational quickstart calls until the endpoints exist - document the VSM hub bootstrap recipe using `ops-hub` as the example Done when: a new hub implementer can follow docs without discovering missing API endpoints at runtime. Implementation note (2026-05-19): updated the generated OpenAPI contract to use distinct request schemas for hub, manifest, API consumer/key, widget, interaction-event, and annotation writes. The spec now represents manifest activation and widget-pattern adoption as no-body actions, documents the one-time `ApiKeyCreatedResponse.fullKey`, adds missing hub registry and widget pattern response schemas, and fixes path parameter naming for `hubId`. Updated `docs/new-hub-quickstart.md` to show the supported `ops-hub` bootstrap path through `/api/v2`, including VSM metadata, manifest activation, consumer/key creation, widget seeding, and `metadata` event submission. Updated the functional contract endpoint list. `git diff --check` passed; `scripts/compile-check` remains blocked in this shell because `IHP_LIB` is not set. --- ### T07 — Add an ops-hub bootstrap smoke test ```task id: IHUB-WP-0019-T07 status: done priority: medium state_hub_task_id: "409b5f85-ec97-42e4-ad21-09e91b49639c" ``` Add a smoke test or scripted check that exercises the full bootstrap path: 1. create `ops-hub` 2. create and activate the manifest 3. create API consumer/key 4. seed a widget 5. submit an `ops-endpoint-verified` event with metadata 6. verify the event is listed by v2 Done when: the next VSM hub can be bootstrapped by adapting the same script and changing only vocabulary/configuration values. Implementation note (2026-05-19): added executable `scripts/ops-hub-bootstrap-smoke.py`. The script uses only Python standard library modules and drives the documented v2 path end to end: creates or reuses `ops-hub`, creates/activates the ops manifest, creates a fresh runtime API consumer and one-time key, creates or reuses an ops widget, submits `ops-endpoint-verified` with metadata, and verifies the event through the v2 list endpoint. It requires `IHUB_OPERATOR_KEY` and accepts `IHUB_BASE` plus hub identity overrides for adapting the same recipe to another VSM hub. Updated the quickstart to point to the script. `python3 -m py_compile` and `git diff --check` passed; the live smoke run itself requires a running Inter-Hub service and an operator API key. ## Acceptance Criteria This workplan is complete when: 1. `ops-hub` can be created without direct DB access. 2. Its manifest can be created and activated without manual UI-only steps. 3. Its API consumer/key can be created by a repeatable operator path. 4. Its widgets can be seeded by API or a documented admin command. 5. Its first operational event can persist metadata and dispatch webhooks using the actual submitted event type. 6. OpenAPI and docs accurately describe the supported bootstrap path. 7. The same path is reusable for `syn-hub`, `ctl-hub`, `aud-hub`, `int-hub`, `pol-hub`, and `env-hub`.