2026-06-06 19:33:53 +02:00
# Hub-Core Extraction Boundary
Last reviewed: 2026-06-06
## Purpose
This note starts `CUST-WP-0025-T05` by translating the original hub-core idea
into a current implementation boundary. The State Hub implementation no longer
lives under `the-custodian/state-hub` ; the authoritative source checkout is
`/home/worsch/state-hub` , and the planned package target is
`/home/worsch/hub-core` .
The extraction must preserve a clean FOS split:
- `hub-core` owns reusable hub primitives.
- `state-hub` becomes the first dev-hub implementation and keeps development
coordination concepts such as topics, workstreams, tasks, decisions,
dependencies, SBOM, token accounting, and kaizen agents.
- Future hubs such as ops-hub and fin-hub depend on `hub-core` without pulling
in dev-hub coordination tables.
## First Package Slice
Create `/home/worsch/hub-core` as a uv-managed Python package with this initial
layout:
```text
hub_core/
__init__ .py
database.py
models/
__init__ .py
base.py
domain.py
managed_repo.py
agent_message.py
2026-06-06 22:30:29 +02:00
capability_catalog.py
capability_request.py
progress_event.py
2026-06-06 19:33:53 +02:00
tpsc.py
schemas/
__init__ .py
domain.py
managed_repo.py
agent_message.py
2026-06-06 22:30:29 +02:00
capability.py
progress_event.py
2026-06-06 19:33:53 +02:00
tpsc.py
routers/
__init__ .py
domains.py
repos.py
messages.py
tpsc.py
policy.py
```
This slice avoids the models that currently carry dev-hub foreign keys. It is
large enough to prove packaging, import style, SQLAlchemy metadata ownership,
router dependency injection, and State Hub compatibility before the more
entangled surfaces move.
2026-06-06 20:17:31 +02:00
Current implementation status:
- 2026-06-06: `/home/worsch/hub-core` was created and committed with base,
domain, managed repo, agent message, capability catalog, and TPSC models plus
matching schemas.
- 2026-06-06: router factory functions were added for domains, repos, messages,
TPSC, and policy lookup. These factories accept host-supplied dependencies
instead of importing State Hub globals.
2026-06-06 22:14:02 +02:00
- 2026-06-06: shared utilities and migration scaffold were added: slug
normalization, pagination, repo path resolution, trailing-slash path
normalization, Alembic templates, and an initial core-schema migration.
2026-06-06 22:30:29 +02:00
- 2026-06-06: progress event and capability request adapter seams were added.
Hub-core uses generic JSON context fields where State Hub currently has
dev-specific workstream/task/topic/decision foreign keys.
2026-06-06 20:17:31 +02:00
2026-06-06 19:33:53 +02:00
## Extract Now
These State Hub files are suitable for the first extraction after import-path
rewriting and small router seams:
| Source in `/home/worsch/state-hub` | Target role |
| --- | --- |
| `api/models/base.py` | Declarative base, timestamps, UUID helper. |
| `api/models/domain.py` | Core domain identity; remove relationships to dev-hub-only models from core. |
| `api/models/managed_repo.py` | Core repo registry; make `topic_id` , SBOM, and sync timestamps extension fields or keep them in dev-hub until a second pass. |
| `api/models/agent_message.py` | Generic agent inbox and thread model. |
| `api/models/tpsc.py` | Third-party service catalog/snapshot primitives. |
| `api/schemas/domain.py` | Core domain schemas; split dev-hub counts from generic read models. |
| `api/schemas/managed_repo.py` | Core repo schemas; keep dispatch/scope-health schemas in dev-hub. |
| `api/schemas/agent_message.py` | Generic message schemas. |
| `api/schemas/tpsc.py` | Generic TPSC schemas. |
| `api/routers/messages.py` | Mostly self-contained generic router. |
| `api/routers/tpsc.py` | Generic catalog and GDPR report router. |
| `api/routers/policy.py` | Generic policy document router if policy roots become configurable. |
2026-06-06 20:17:31 +02:00
The first committed router seam is factory-based rather than global:
```python
from hub_core.routers import create_domains_router
app.include_router(create_domains_router(get_session))
```
That shape lets each hub keep its own database session configuration and mount
only the generic routers it wants.
2026-06-06 22:14:02 +02:00
## Shared Utilities
The initial utility set is intentionally small and dependency-light:
| Module | Purpose |
| --- | --- |
| `hub_core.utils.slugs` | Convert user-facing names into stable lowercase slugs. |
| `hub_core.utils.pagination` | Shared limit/offset bounds and SQLAlchemy pagination. |
| `hub_core.utils.paths` | Resolve repo paths from `host_paths` before falling back to `local_path` . |
| `hub_core.utils.routing` | Normalize a path or URL path component while preserving query strings and fragments. |
## Migration Scaffold
`/home/worsch/hub-core` now carries Alembic template files under
`hub_core/migrations/` plus `versions/0001_core_schema.py` . The first migration
covers only the currently extracted core tables:
- `domains`
- `managed_repos`
- `agent_messages`
- `capability_catalog`
2026-06-06 22:30:29 +02:00
- `capability_requests`
- `progress_events`
2026-06-06 22:14:02 +02:00
- `tpsc_catalog`
- `tpsc_snapshots`
- `tpsc_entries`
2026-06-06 19:33:53 +02:00
## Needs An Adapter Seam
These are still part of the target architecture, but the current State Hub
implementation is coupled to dev-hub concepts:
| Surface | Coupling to resolve |
| --- | --- |
| `Domain` and `domains.py` detail views | Counts topics, workstreams, extension points, and technical debt. Hub-core should expose a domain summary hook that dev-hub can implement. |
| `ManagedRepo` | Contains `topic_id` , SBOM fields, and state-sync timestamps. Keep minimal repo identity in core, then add dev-hub extensions. |
2026-06-06 22:30:29 +02:00
| `CapabilityRequest` | Adapter seam implemented with generic `request_context` and `fulfillment_context` ; State Hub still needs a later refactor to map workstream/task references into those fields or a dev-hub extension table. |
| `ProgressEvent` | Adapter seam implemented with generic `subject_refs` ; State Hub still needs a later refactor to map topic/workstream/task/decision foreign keys into that field or a dev-hub extension table. |
2026-06-06 19:33:53 +02:00
| MCP tools in `mcp_server/server.py` | Generic tools are mixed into a single dev-hub server module. T06 should create a base registration class that receives API client/config dependencies and lets dev-hub add its own tools. |
2026-06-06 22:30:29 +02:00
The first two adapter seams are now implemented in hub-core:
- `ProgressEvent.subject_refs` : generic JSON references for hub-local subjects.
- `CapabilityRequest.request_context` and `fulfillment_context` : generic JSON
context for hub-local workstreams, tasks, incidents, services, budgets, or
other future hub entities.
2026-06-06 19:33:53 +02:00
## Keep In Dev-Hub
The following State Hub areas should not move into hub-core during T05:
- Topics, workstreams, tasks, decisions, dependencies, and flow state.
- Extension points, technical debt, interface changes, SBOM, token events, and
contribution accounting.
- Dashboard-specific loaders and Observable views.
- Workplan-file parsing and consistency reconciliation.
- Kaizen agents, scope health, dispatch views, and recently-on-scope reports.
## Verification Plan
The first hub-core commit should pass these checks before State Hub is refactored
to import it:
1. `python3 -m compileall hub_core`
2. A minimal import test that imports every model, schema, and router module.
3. SQLAlchemy metadata inspection proving the initial core tables are registered.
4. A FastAPI smoke app that mounts the extracted routers with an injected
`get_session` dependency.
5. `cd /home/worsch/state-hub && make test` remains green before and after the
editable `hub-core` dependency is introduced.
## Next Step
Create the `/home/worsch/hub-core` package with only the first package slice,
commit that seed independently, then return to `/home/worsch/state-hub` for the
first import-based refactor. Do not rename State Hub to dev-hub until T05-T08
prove the shared package boundary.