fix(identity): enforce qualified ad-hoc identifiers

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02b22-9638-76d2-bbff-b7ea1770b118
This commit is contained in:
tegwick 2026-08-23 14:45:26 +02:00
parent 2f74cbd3dd
commit 885575802c
4 changed files with 25 additions and 6 deletions

View file

@ -7,16 +7,22 @@ kinds:
- kind: workplan - kind: workplan
id_patterns: id_patterns:
- "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-[0-9]{4}$" - "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-[0-9]{4}$"
- "^ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}$" - "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}$"
legacy_patterns: legacy_patterns:
- pattern: "^ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}$"
source: daily ad-hoc containers created before repository-qualified ad-hoc ids
grandfathered: true
- pattern: "^MASON-0001$" - pattern: "^MASON-0001$"
source: ops-mason bootstrap workplan created before WP infix convention source: ops-mason bootstrap workplan created before WP infix convention
grandfathered: true grandfathered: true
- kind: task - kind: task
id_patterns: id_patterns:
- "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-[0-9]{4}-T[0-9]{2,3}$" - "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-[0-9]{4}-T[0-9]{2,3}$"
- "^ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}-T[0-9]{2}$" - "^[A-Z][A-Z0-9]*(?:-[A-Z][A-Z0-9]*)*-WP-ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}-T[0-9]{2}$"
legacy_patterns: legacy_patterns:
- pattern: "^ADHOC-[0-9]{4}-[0-9]{2}-[0-9]{2}-T[0-9]{2}$"
source: daily ad-hoc tasks created before repository-qualified ad-hoc ids
grandfathered: true
- pattern: "^[A-Z]+-WP-[0-9]{4}-T[0-9]$" - pattern: "^[A-Z]+-WP-[0-9]{4}-T[0-9]$"
source: early single-digit task suffixes (pre task-block convention) source: early single-digit task suffixes (pre task-block convention)
grandfathered: true grandfathered: true

View file

@ -22,8 +22,11 @@ name bytes: UTF-8(<fleet-namespace> + "\n" + <canonical-identifier>)
The fixed UUID is itself UUIDv5(URL, The fixed UUID is itself UUIDv5(URL,
`https://helixforge.org/repo-manager/work-record/v1`), but consumers use the `https://helixforge.org/repo-manager/work-record/v1`), but consumers use the
fixed value above rather than recomputing it. Fleet namespace names are fixed value above rather than recomputing it. Fleet namespace names are
lowercase DNS-label style. Canonical identifiers are lowercase DNS-label style. Canonical identifiers are `PREFIX-WP-NNNN`,
`PREFIX-WP-NNNN` or `PREFIX-WP-NNNN-TNN`. `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 The repository is not a namespace. The fleet owner declared the current shared
namespace as **`helixforge`** on 2026-08-21; the versioned declaration is namespace as **`helixforge`** on 2026-08-21; the versioned declaration is

View file

@ -49,8 +49,10 @@ def test_grandfathered_mason_identity_is_loaded_from_canon_registry() -> None:
def test_current_canon_accepts_repository_and_ad_hoc_workplan_forms() -> None: def test_current_canon_accepts_repository_and_ad_hoc_workplan_forms() -> None:
assert classify_record_id("workplan", "RAPP-OPENBAO-WP-0002") == "canonical" assert classify_record_id("workplan", "RAPP-OPENBAO-WP-0002") == "canonical"
assert classify_record_id("task", "RAPP-OPENBAO-WP-0002-T01") == "canonical" assert classify_record_id("task", "RAPP-OPENBAO-WP-0002-T01") == "canonical"
assert classify_record_id("workplan", "ADHOC-2026-08-23") == "canonical" assert classify_record_id("workplan", "ACTIVITY-WP-ADHOC-2026-08-23") == "canonical"
assert classify_record_id("task", "ADHOC-2026-08-23-T01") == "canonical" assert classify_record_id("task", "ACTIVITY-WP-ADHOC-2026-08-23-T01") == "canonical"
assert classify_record_id("workplan", "ADHOC-2026-08-23") == "grandfathered"
assert classify_record_id("task", "ADHOC-2026-08-23-T01") == "grandfathered"
assert classify_record_id("workplan", "RAPP--OPENBAO-WP-0002") is None assert classify_record_id("workplan", "RAPP--OPENBAO-WP-0002") is None

View file

@ -394,6 +394,14 @@ explicit override for foreign namespaces. The derivation contract, fixed UUID,
collision/unarchive guard, and independent reproduction test are all active; collision/unarchive guard, and independent reproduction test are all active;
bulk replacement remains the separately governed T04 operation. bulk replacement remains the separately governed T04 operation.
**Ad-hoc identity correction (2026-08-23):** Activity Core and Net Kingdom both
created the canon-prescribed `ADHOC-2026-08-23` identifier. The repository is
not a namespace, so UUIDv5 correctly collided. Repo Manager's canon copy now
recognizes `{PREFIX}-WP-ADHOC-YYYY-MM-DD[-TNN]` as canonical and retains the
unqualified form only as grandfathered history. The governed Activity Core
retry registered `ACTIVITY-WP-ADHOC-2026-08-23` and its task under correlation
`f272ab73-35fb-44e7-aabd-23b124e3c135`, with no missing identifiers afterward.
## Migrate the fleet ## Migrate the fleet
```task ```task