- hub_core/runtime/data/legacy_topic_aliases.json: checked-in, versioned (2026-10-13.1) seed of the 16 State Hub topics from the STATE-WP-0098-T01 capture -> primary_domain facet, residual owner STATE-WP-0079, expiry 2027-03-31T23:59:59Z. Never fetched live; topic UUIDs kept verbatim. - legacy_topic_aliases.py: loader validated against the 1.0.0 legacyTopicAlias schema; per-response active/expired status; underscore slugs emitted hyphenated (1.0.0 pattern forbids '_'). - RM_SLICE_TOPICSPINE setting (off|shadow|on, default off). off keeps the navigation output unchanged (aliases []); shadow/on serve the aliases and mark responses with X-RM-Slice-Topicspine. Documented as the A5 rollback switch in docs/runtime.md. - tests/test_legacy_topic_aliases.py: seed, flag and local A5 comparison cases (C01, C02/C08, C03, C10) against fixtures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 356991@bnt-lap001 Assistant-Session: 5d99ea69-ed55-4a1e-8d97-f4f312db247f
108 lines
5.4 KiB
Markdown
108 lines
5.4 KiB
Markdown
# Repository navigation contract 1.0.0
|
|
|
|
Status: frozen for HUB-WP-0006 T02 on 2026-08-22.
|
|
|
|
The packaged contract is `helixforge.repository-navigation` version `1.0.0`.
|
|
It consumes only `helixforge.repository-classification-projection` version
|
|
`1.0.0`, representing `RMGR-CONTRACT-CLASSIFICATION-0001` version `1.0`.
|
|
Unsupported versions are rejected; hub-core does not coerce them.
|
|
|
|
## Authority and identity
|
|
|
|
Repository `.repo-classification.yaml` files remain authoritative. Repo Manager
|
|
validates and publishes them. Hub-core owns only rebuildable navigation rows,
|
|
facets, query cursors, diagnostics, and temporary compatibility aliases.
|
|
|
|
Every change carries the registrar's stable `repository_id` UUID. Slugs may
|
|
change and are display/routing labels, not identity. The Repo Manager adapter
|
|
adds that UUID when converting its local observation into this envelope.
|
|
`locations`, `repo_root`, work-record bodies, credentials, and other host-local
|
|
or authority-bearing data are forbidden by the closed schemas.
|
|
|
|
## Pages, snapshots, and changes
|
|
|
|
All pages in a transfer have the same `snapshot_id`, `mode`, `generated_at`,
|
|
`source_revision`, and `total_repository_count`. Entries are ordered by
|
|
`repository_id`; duplicate IDs in one transfer are invalid.
|
|
|
|
- The first page has a null `page_cursor`.
|
|
- `next_cursor` is null exactly when `final_page` is true.
|
|
- Cursors are opaque, signed or equivalently integrity-protected, bound to the
|
|
snapshot and normalized filter set, and never parsed by clients.
|
|
- A full snapshot consists of upserts. Absence means deletion only after every
|
|
page validates and the final page is accepted.
|
|
- An incremental snapshot contains explicit idempotent upsert/delete changes.
|
|
A change is newer only by its source observation/revision semantics; duplicate
|
|
delivery has no effect.
|
|
- `total_repository_count` is required for a full snapshot and may be null for
|
|
incremental delivery.
|
|
|
|
Activation is atomic. Hub-core builds into a new generation, derives all six
|
|
facet kinds, computes SHA-256 over canonical JSON repository rows ordered by
|
|
UUID, and swaps the active generation only after the complete transfer passes
|
|
schema and semantic validation. A failed full rebuild never deletes or partly
|
|
replaces the last accepted generation.
|
|
|
|
## Failure and diagnostics
|
|
|
|
An error diagnostic, malformed page, inconsistent snapshot metadata,
|
|
unsupported version, duplicate identity, invalid controlled value, or upstream
|
|
failure rejects that transfer. The last accepted projection remains readable
|
|
as `stale`, includes a diagnostic and `source_checked_at`, and readiness reports
|
|
the Repo Manager dependency as degraded. If no accepted generation exists, the
|
|
query port returns `503`. Successful acceptance restores `current`.
|
|
|
|
Provenance on every repository includes the Repo Manager URI, classification
|
|
contract version, source fingerprint, observed time, and repository revision.
|
|
The response also carries the source snapshot/revision and rebuild content
|
|
hash. Diagnostics must not include secrets or unbounded source content.
|
|
|
|
## Query semantics
|
|
|
|
Repositories are returned in ascending UUID order. Repeated values within one
|
|
filter family are ORed; different filter families are ANDed. The six families
|
|
are primary domain, secondary domain, category, capability tag, business stake,
|
|
and business mechanic. An unknown value produces `400`; an empty match is a
|
|
successful empty page.
|
|
|
|
Response cursors are bound to both the active content hash and normalized
|
|
filters. Reusing a cursor after a rebuild or with different filters returns
|
|
`409 cursor_snapshot_mismatch`, so a client restarts from the first page.
|
|
|
|
## Legacy topic aliases
|
|
|
|
`legacy_topic_aliases` is temporary, read-only compatibility metadata. Each
|
|
entry maps one State Hub topic UUID/slug to one derived facet and must name an
|
|
`expires_at` time and `residual_owner`. It cannot create, update, or delete
|
|
classification. Expired aliases return `410` until removed; there are no write
|
|
operations in the navigation OpenAPI surface. STATE-WP-0079 owns alias expiry
|
|
and the consumer route switch.
|
|
|
|
### Runtime alias source (HUB-WP-0006-T06)
|
|
|
|
The runtime serves aliases from one checked-in, versioned seed:
|
|
`hub_core/runtime/data/legacy_topic_aliases.json` (`alias_set_version`
|
|
`2026-10-13.1`). It holds the 16 active State Hub topics captured on
|
|
2026-10-13 by `GET /topics/?status=active` (State Hub packet
|
|
STATE-WP-0098-T01). Each alias maps `legacy_topic_id` to
|
|
`facet_kind = primary_domain` and `facet_value = topic.domain_slug`, with
|
|
`residual_owner = STATE-WP-0079` and `expires_at = 2027-03-31T23:59:59Z`.
|
|
hub-core never fetches topics from State Hub at runtime. Topic UUIDs are
|
|
identity and must not change while repositories carry `topic_id`. To renew
|
|
or retire aliases, edit the seed and bump `alias_set_version`.
|
|
|
|
The 1.0.0 `legacy_topic_slug` pattern forbids underscores. Three legacy
|
|
slugs (`inter_hub`, `vergabe_teilnahme`, `citation_evidence_mvp`) are
|
|
emitted with hyphens; the seed keeps the State Hub spelling. Comparisons
|
|
must normalise `_` to `-`. Emitting the exact spelling needs a contract
|
|
patch that widens the pattern.
|
|
|
|
`status` is computed per response: `expired` from `expires_at` onward.
|
|
Aliases are emitted unfiltered on every navigation response, so a facet
|
|
query still carries all of them. There is no per-alias route yet, so the
|
|
`410` behaviour above applies only once such a route exists.
|
|
|
|
Aliases are served only when `RM_SLICE_TOPICSPINE` is `shadow` or `on`
|
|
(see `docs/runtime.md`). With the default `off`, `legacy_topic_aliases`
|
|
stays `[]`.
|
|
|