feat: finish register receiving and authority routing

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
This commit is contained in:
tegwick 2026-08-21 23:15:48 +02:00
parent 6d134425df
commit d103955217
28 changed files with 970 additions and 48 deletions

View file

@ -0,0 +1,65 @@
---
id: RMGR-ADR-002
type: architecture-decision-record
title: "Canonical UTC timestamps; local time only at I/O boundaries"
status: accepted
decided: "2026-08-21"
deciders: ["Bernd Worsch"]
related:
- RMGR-WP-0008
- RMGR-WP-0005
- docs/observation-command-contracts_v0.1.md
---
# ADR-002: Canonical UTC timestamps; local time only at I/O boundaries
## Status
**Accepted** (2026-08-21).
## Context
Repo Manager emits timestamps into repository records, indexes, mutation
meters, events, evidence, and compatibility contracts. Host-local clocks and
implicit calendar conversion make identical events serialize differently,
create daylight-saving ambiguity, and make deterministic reconciliation harder.
Users and external systems still need local calendars, wall-clock times, and
locale-specific formatting. Those are presentation and ingestion concerns, not
stored identity.
## Decision
1. Every value representing an **instant** is created, stored, compared, and
exchanged in UTC.
2. New textual timestamps use RFC 3339/ISO 8601 with the canonical `Z` suffix.
Readers may accept legacy explicit offsets and normalize them to UTC before
comparison or re-emission. Naive datetimes are rejected at boundaries.
3. Database timestamp columns use timezone-aware types and UTC values. Epoch
values, where a foreign contract requires them, denote UTC instants.
4. Conversion to or from a local timezone, locale, calendar, or wall-clock
representation occurs only in UI and I/O adapters. The converted value never
replaces the canonical instant.
5. Inputs that omit a timezone are invalid unless the specific I/O contract
also supplies an explicit timezone. DST gaps and folds must be resolved at
that boundary before producing UTC.
6. A genuine **date-only domain value**—for example a contractual due date—is
not a timestamp and keeps its declared calendar semantics. A date derived
from the current instant for repository metadata uses the UTC calendar date.
7. Tests, fixtures, logs, filenames, events, and idempotency material follow the
same rule; test convenience is not an exception.
## Enforcement
- Repo Manager timestamp creation goes through `repo_manager.time`.
- Ruff `DTZ` and `UP` rules remain explicitly selected so naive datetime use
and non-canonical UTC APIs fail lint even if Ruff defaults change.
- Contract tests require UTC-aware values and canonical `Z` serialization.
## Consequences
Stored and exchanged instants are byte-stable across hosts. Ordering and
reconciliation no longer depend on operator locale or daylight-saving rules.
Presentation clients must retain the canonical value and treat local rendering
as a reversible view. Legacy offset-bearing timestamps remain readable but are
normalized when rewritten.

View file

@ -0,0 +1,52 @@
---
id: RMGR-ADR-003
type: architecture-decision-record
title: "Projection UI ownership stays outside Repo Manager"
status: accepted
decided: "2026-08-21"
deciders: ["Repo Manager and hub-core architecture"]
related:
- RMGR-WP-0008
- HUB-WP-0004
- SHR-ARCH-HUB-0001
---
# ADR-003: Projection UI ownership stays outside Repo Manager
## Status
**Accepted** (2026-08-21).
## Context
The State Hub retirement inventory initially assigned slice A4's work and
repository pages to Repo Manager because Repo Manager owns the underlying
file-backed records. That assignment conflated authority with presentation.
Repo Manager is a functional component with governed CLI and adapter surfaces;
it is not a cross-repository hub or dashboard runtime.
The accepted `HUB-WP-0004` architecture keeps repository work authoritative in
Git through Repo Manager and assigns projection/query and hub UI capabilities
to hub-core and its operator clients. Building another dashboard here would
duplicate those projections and blur the one-authority boundary.
## Decision
1. Repo Manager owns repository observation, governed file-backed mutation,
reconciliation, indexes, and stable machine-facing contracts. It does not
own a dashboard or general operator UI.
2. hub-core owns cross-repository projection/query contracts and the surviving
hub UI runtime. Ops or domain clients may render narrower views through
those contracts.
3. User interfaces consume Repo Manager and hub-core ports. They do not write
repository authority or projection storage directly.
4. State Hub retirement slice A4 is therefore a hub-core/projection-client
replacement, not a UI migration into Repo Manager. Repo Manager's A1A3 and
A5 contracts remain inputs to those projections.
## Consequences
RMGR-WP-0008 does not need a dashboard deliverable. A4 route redirects and UI
replacement remain in the retirement program's hub-core cutover work. Any
future repository-local UI must be proposed separately and remain a client of
the same governed contracts.

View file

@ -35,8 +35,18 @@ confirmed live hub-first workplans in this snapshot.
The 217 closed rows remain cheap historical provenance. They need not be
reconstructed as files, but the cache-rebuild procedure must export or retain
them before replacing the local database. Repairing the seven live bindings is
the remaining prerequisite for T07.
them before replacing the local database.
## Repair result
All seven bindings were submitted together to the preferred
`PUT /workplans/index/bindings` route and the hub acknowledged
`{"updated":7,"received":7}`. A fresh query now finds exactly 217 unbound rows:
201 `finished`, 16 `archived`, and **zero live**. No repository file or
lifecycle status was changed. The broad `fix-consistency --all` path was not
used for the repair because it aborts while refreshing the brief for stale
registered path `/home/worsch/inter-hub`; the targeted binding route avoided
coupling this data repair to that unrelated registry defect.
## Reproduction

View file

@ -0,0 +1,40 @@
# RMGR-WP-0008 SBOM receiving and cutover evidence — 2026-08-21
Repo Manager now derives an SBOM snapshot from repository-owned lockfiles and
the reviewed `sbom-tools.yaml` escape hatch. The snapshot includes source path
and SHA-256 provenance, Git revision, canonical UTC generation time, ecosystem,
direct/development flags, licence grouping, and direct production copyleft
findings.
## Live projection reconciliation
The workstation State Hub held 22 historical snapshots for 18 repositories.
For migration planning, only the newest snapshot per repository was compared
with a fresh Repo Manager scan of its registered local path:
- 18 repositories scanned; 0 parse failures;
- 9 entry counts matched exactly;
- newest State Hub projections totalled 2,659 entries;
- current authoritative lockfiles produce 1,565 entries.
The differing counts are expected evidence of source drift, not rows to copy:
the stored snapshots date from March through July 2026, while the rescan reads
the current checked-out lockfiles. Copying the 2,659 cached rows into repository
records would reverse the authority boundary. Cutover therefore rebuilds each
repository snapshot from its current lockfiles and retains the old State Hub
snapshot ids/timestamps as historical provenance until the retirement retention
gate permits deletion.
## Compatibility contract
State Hub's retirement adapter calls `rmgr sbom scan --path <repo> --slug
<slug>` and receives `repo-manager.sbom-snapshot.v1` JSON. Route-level tests
pin that invocation and response shape. The adapter is read/derive-only: it
does not commit, push, or mutate a register file.
## Verification
- `uv run ruff check src tests`
- focused SBOM and compatibility-adapter tests
- live `repo-manager` scan: 39 entries, no parse errors, canonical `Z`
timestamp, Git revision present, and no direct production copyleft finding

View file

@ -53,3 +53,12 @@ the database a source of repository truth.
This narrows the offline-buffer part of `STATE-WP-0068`; it does not authorize
changes in repositories owned by hub-core, activity-core, ops-hub, or fin-hub.
## Enforced routing
`rmgr authority route` is the executable gate for this contract. File-derived
records require both repository and domain context and resolve to
`repository:<domain>/<repo>` under Repo Manager. Central and derived record
types resolve to their one declared hub owner. Unknown types and writes whose
claimed owner disagrees with the contract are rejected instead of falling back
to whichever hub received the request.

View file

@ -54,3 +54,22 @@ rmgr register defer --kind technical-debt --entry-id TD-001
Mutations use the same expected-HEAD, idempotency, Git commit, optional
push-seal, normalized-event, reindex, and dual-run-meter mechanism as workplan
and task mutations.
## Derived SBOM inventory
SBOM is the exception to ordinary register mutation: recognised lockfiles and a
reviewed root `sbom-tools.yaml` remain authoritative. Repo Manager derives a
replaceable snapshot and licence/copyleft report without copying State Hub rows
back into a new source-of-truth file.
```bash
rmgr sbom scan --path . --output sbom-snapshot.json
rmgr sbom licence-report --path .
```
Detection covers `uv.lock`, `requirements.txt`, `package-lock.json`,
`yarn.lock`, `Cargo.lock`, `go.sum`, `.terraform.lock.hcl`, Ansible requirements
under `ansible/`, and root `sbom-tools.yaml`. Each source carries a SHA-256 and
the snapshot carries the Git revision and canonical UTC generation timestamp.
An output file is optional evidence, never authority, and is not overwritten
without `--force`.