repo-manager/docs/work-record-uuid-derivation_v1.md
tegwick 885575802c fix(identity): enforce qualified ad-hoc identifiers
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02b22-9638-76d2-bbff-b7ea1770b118
2026-08-23 14:45:26 +02:00

4.5 KiB

id type title version status created updated workplan_task
RMGR-CONTRACT-UUID-0001 contract Deterministic work-record UUID derivation 1 active 2026-08-21 2026-08-21 RMGR-WP-0005-T03

Work-record UUID derivation v1

For a live workplan or task, implementations derive the existing state_hub_workstream_id or state_hub_task_id field with UUIDv5:

namespace UUID: a4058507-5c4a-5a00-ab06-fffa4fb46009
name bytes:      UTF-8(<fleet-namespace> + "\n" + <canonical-identifier>)

The fixed UUID is itself UUIDv5(URL, https://helixforge.org/repo-manager/work-record/v1), but consumers use the fixed value above rather than recomputing it. Fleet namespace names are lowercase DNS-label style. Canonical identifiers are PREFIX-WP-NNNN, PREFIX-WP-NNNN-TNN, or the repository-qualified daily forms PREFIX-WP-ADHOC-YYYY-MM-DD[-TNN]. Historic unqualified ADHOC-* records are grandfathered and keep their minted identifiers; new records never use that collision-prone form.

The repository is not a namespace. The fleet owner declared the current shared namespace as helixforge on 2026-08-21; the versioned declaration is config/fleet-namespace.yaml. This raises the namespace posture from implied N1 to declared N2. A future fork uses its own namespace name and therefore derives different UUIDs for the same unqualified identifier, as required by ADR-011.

Only proposed, ready, active, blocked, or backlog workplans and their unfinished tasks enter the live derivation set. Finished and archived history retains its minted identifiers. Before creating, re-deriving, or unarchiving a record, run the live-collision preflight. Any duplicate is a hard refusal; it is never silently disambiguated with a repository slug.

rmgr identifier derive --record-id RMGR-WP-0005
rmgr identifier preflight --root /path/to/fleet
rmgr identifier migration-plan --root /path/to/fleet --output uuid-migration.json
rmgr identifier migration-verify --plan uuid-migration.json
rmgr identifier migration-verify --plan uuid-migration.json --repo repo-manager
rmgr identifier migration-batch-plan \
  --plan uuid-migration.json \
  --repo whynot-design \
  --projection-api-base http://127.0.0.1:8000 \
  --projection-api-base http://127.0.0.1:18000 \
  --output batch.json
rmgr identifier migration-batch-verify \
  --plan uuid-migration.json \
  --batch batch.json

migration-plan is non-mutating. Its versioned JSON output preserves every current-to-derived UUID mapping and marks each repository as one atomic apply unit. A collision or malformed live identifier makes that whole repository ineligible while leaving unaffected repositories visible in the plan. Existing output files are not replaced unless --force is explicit.

Plans carry a canonical UTC creation time, SHA-256 integrity seal, and per-repo Git HEAD/source fingerprints. migration-verify rejects a modified plan, a namespace mismatch, an ineligible repository, or authoritative-source drift. HEAD movement is reported but is not a hard failure when the source fingerprint is unchanged; otherwise committing the plan itself would invalidate its own repository. --repo verifies one atomic apply unit, so unrelated fleet churn does not invalidate a stable repository. A new plan is required for each unit whose authoritative source drifts.

migration-batch-plan converts selected atomic units into a bounded approval package. Each selected repository must still match the planned Git HEAD, have a clean worktree, exactly match its configured upstream, and use a non-retired origin. The batch records these facts and its own SHA-256 seal, but always emits apply_authorized: false. An explicit decision must cite that batch hash before any database or file mutation. Repeat --projection-api-base for every hub in the cutover: each replacement must resolve its current UUID with HTTP 200 and its derived target with HTTP 404 on every named projection, or the manifest is not ready for approval. Saved projection endpoints are rechecked by migration-batch-verify; omitting the option retains the offline source/Git-only planning mode. A projection-aware batch containing UUID assignments fails closed until an assignment-specific projection identity check is implemented.

Activation and applying a bulk migration remain separate governed steps. Publishing or planning this function does not retroactively rewrite existing identifiers. --namespace remains an explicit override for a foreign/forked fleet; omitting it uses the checked-in helixforge declaration.