core-hub/docs/specs/runtime-absorption-plan.md
tegwick 4a9df801c3
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / pytest-smoke (push) Failing after 3s
docs: define hub-core absorption plan
2026-08-21 10:57:13 +02:00

9.5 KiB
Raw Blame History

Core Hub to hub-core absorption plan

Status: recorded for CORE-WP-0010-T02; joint artifact for HUB-WP-0004-T06
Reviewed: 2026-08-21
Strategy: route-group migration with Core Hub retained as rollback; no client dual-write and no big-bang cutover

This plan turns the inventory in runtime-absorption-inventory.md into ordered, testable migration slices. Hub-core owns the surviving runtime selected by its ADR-0001. Core Hub remains the public /api/v2 authority until each route group passes its own data, contract, consumer, and rollback gates.

Decisions

  1. One target runtime. Hub-core ships the importable wheel and primary OCI image. Core Hub is a temporary source and rollback runtime, not a permanent host for hub-core.
  2. Internal candidate first. A hub-core candidate deployment receives no public traffic until it has a published source revision, immutable image digest, durable PostgreSQL backend, migrations, compatible authentication, and green readiness.
  3. Route groups, not percentages. Traffic moves by coherent API group. Random percentage canaries would send related bootstrap calls to different authorities and are not permitted.
  4. One writer per route group. Read-only requests may be mirrored for comparison. Production clients never dual-write. Write cutover uses a short drain, final delta replay, route switch, and one active writer.
  5. Isolated metadata during dual-run. Core Hub keeps the core_hub schema; hub-core uses its own migration lineage and schema. Cross-importing either service's SQLAlchemy metadata is prohibited.
  6. Stable identity and safe key migration. Durable IDs are preserved. API-key prefixes, hashes, scopes, and status may move; raw bearer tokens or one-time full keys must never enter migration bundles or evidence.
  7. Archive last. Core Hub stays deployable until the final stabilization gate, reverse-delta requirement, and residual ownership record are closed.

Entry gates

Absorption implementation does not begin until all of these are evidenced:

  • the completed HUB-WP-0004-T01T05 work is committed and pushed;
  • a hub-core wheel and OCI image identify the same revision and version;
  • rapp-core-hub can deploy a second, cluster-internal candidate without changing hub.coulomb.social;
  • hub-core has a production PostgreSQL PortStore/compatibility store and fails readiness when durable storage is unavailable;
  • the existing operator token and copied API-key hashes authenticate through the candidate without exposing credential values;
  • Core Hub export, hub-core import, row-count, canonical-digest, and delta replay commands are repeatable and record non-secret migration metadata;
  • the hub-core conformance profile and Core Hub compatibility tests pass against the candidate.

The current in-memory hub-core backend is a conformance implementation, not an absorption target. Its deliberate production-readiness failure is a useful gate and must not be bypassed.

Ordered slices

Slice Surface Move condition Consumer gate
0 — candidate foundation image, API/MCP processes, migrations, durable store, auth adapter, health/readiness All entry gates above; no public route hub-core conformance plus Core Hub contract suite
1 — stateless compatibility widget/event/annotation/policy catalogs; empty annotation, requirement, decision, deployment, and outcome collections; compatibility OpenAPI/docs Response status, headers, and canonical JSON match; unprefixed OpenAPI aliases retained unauthenticated catalog and OpenAPI probes
2 — protected bootstrap hubs, capability manifests and activation, API consumers/key issuance, widgets, hub registry IDs/FKs preserved; source and target counts/digests match; copied key hashes authenticate; isolated create/read fixture passes complete ops-hub bootstrap/gate probe
3 — interaction evidence interaction-event append/list and mapping to port.events.interaction Historical IDs/timestamps retained; adapter mapping is reversible; append/readback fixture passes activity-core resolver and evidence-sink probe
4 — operator surface /console, readiness summary, compatibility redirects and remaining aliases Console reads target projections; no source-only API calls remain operator CLI, protected console, visual smoke
5 — public authority all /api/v2, health/readiness, API/MCP entrypoints Earlier slices stable; rollback and residual-owner evidence current ops-hub and activity-core gates together

Slice 2 is intentionally atomic at the traffic boundary. The ops-hub bootstrap creates records whose identifiers cross hubs, manifests, consumers, keys, and widgets; splitting those calls across two authorities would manufacture referential drift. Its code and data migration may still land in smaller reviewable commits before the route group switches.

Compatibility adapters

Hub-core's named ports are not themselves the legacy /api/v2 contract. The target needs an explicit compatibility composition layer:

  • hub and manifest resources map to port.registry while preserving legacy IDs, body fields, activation behavior, pagination envelope, and hub-registry projection;
  • interaction events map to port.events.interaction with a stable correlation ID, original event ID, widget reference, view context, event type, metadata, and occurrence/recording timestamps;
  • widgets and API consumers/keys remain compatibility resources until a named replacement port is accepted; they must not be forced into registry records;
  • health/readiness retain the response shape expected by deployed Core Hub smoke tooling until consumers adopt the hub-core-native shape;
  • /api/v2/openapi.json, YAML/docs discovery, and required unprefixed aliases remain versioned compatibility artifacts through final cutover.

Data movement and comparison

For each durable slice:

  1. Export source records in dependency order with a schema version, source revision, high-water mark, and bundle SHA-256.
  2. Validate without writing; reject unknown fields, missing parents, raw secret shapes, duplicate identities, or a lower target schema version.
  3. Upsert into the target by stable ID. Re-running the same bundle must be idempotent and recorded as such.
  4. Compare table/resource counts, sorted identity sets, and canonical row digests. Timestamp formatting and JSON key order are normalized before hashing; semantic field differences are not ignored.
  5. Mirror only safe GET requests and compare status plus canonical response. Exercise writes with isolated migration fixtures, never by duplicating a production client request.
  6. At route cutover, drain writes for that group, capture the final high-water delta, import/compare it, switch the route group, and enable target writes.

Migration evidence may contain IDs, counts, hashes, versions, timestamps, and pass/fail results. It must not contain raw API keys, bearer tokens, database credentials, Authorization headers, or copied Kubernetes Secrets.

Traffic controls and rollback

rapp-core-hub owns one logical switch per slice with the states source, shadow-read, and target. The concrete gateway or Helm key names are a deployment implementation detail, but every rendered release must reveal the selected state as non-secret evidence.

Rollback remains possible while a slice is target-owned:

  1. stop new target writes for the affected route group;
  2. export and verify the target-only delta by stable ID;
  3. replay that delta to Core Hub when the old source must become writable;
  4. compare counts/digests and run the consumer gate;
  5. switch the whole route group back to source.

If reverse replay is not implemented for a write slice, rollback is limited to the period before target writes are enabled. That limitation blocks public cutover and must be visible in the evidence report.

Required evidence per slice

  • hub-core source revision, package version, and OCI digest;
  • Core Hub source revision and deployed Helm revision;
  • source/target schema versions and migration bundle hash;
  • before/after counts, identity-set comparison, and canonical digest result;
  • compatibility/OpenAPI diff result;
  • auth positive and negative checks without credential disclosure;
  • named consumer smoke reports and correlation IDs;
  • selected route state, switch time, observer, and rollback result or reason it was not invoked.

Any schema mismatch, unexplained count/digest drift, secret-shaped evidence, auth broadening, consumer failure, or non-green readiness stops the slice and keeps public authority on Core Hub.

Ownership

Owner Responsibility
hub-core compatibility modules, durable store/migrations, import/delta/reverse-delta, conformance
core-hub source export, legacy fixtures/OpenAPI, canonical response comparison, rollback service
rapp-core-hub candidate deployment, immutable image pin, route switches, rollout/rollback evidence
railiance-platform / rapp-postgres PostgreSQL, credential delivery, backup/restore readiness
ops-hub bootstrap and registry consumer gate
activity-core interaction resolver, append, and readback gate
operator approval for Slice 5 public-authority cutover and later repository archive

Next executable work

After hub-core publishes its completed T01T05 revision, start Slice 0. The first implementation commit should add the durable PostgreSQL boundary and legacy auth/health compatibility in hub-core, plus a candidate deployment mode in rapp-core-hub. It must not change public DNS or ingress.