Mint entity identifiers as UUIDv7 via central ViegardId helper #14

Merged
hannah-vernon merged 1 commit from feat/uuidv7-ids into dev 2026-08-25 18:00:52 -05:00

What does this PR do?

Adopts D-0030: every entity identifier is now a version 7 UUID from Guid.CreateVersion7(), minted exclusively through the new Viegard.Domain.ViegardId.New() helper (all 17 former Guid.NewGuid() sites converted), so the generation policy is one line to change forever after.

Why: random v4 ids scatter inserts across the primary-key b-tree, causing page splits, full-page-write WAL amplification, and a large hot working set on exactly the tables that grow (events, classifications, audit). v7''s leading 48-bit millisecond timestamp keeps inserts on the rightmost leaves and gives the admin GUI an index-friendly keyset-pagination cursor. 62+ bits of randomness remain, so ids stay unguessable; rows already carry explicit timestamp columns, so the embedded timestamp leaks nothing new inside the trust boundary.

Constraints kept explicit in the helper doc and D-0030: id order is approximate only (per-generator clocks, no intra-millisecond guarantee); event ordering semantics always come from explicit timestamp fields. Existing v4 rows coexist harmlessly in the same uuid columns; no schema change or migration.

How was this tested?

  • dotnet build - 0 errors, 0 warnings
  • dotnet test - 267 passed, 7 skipped (live-PostgreSQL integration tests; local WSL Docker unavailable)
  • New ViegardIdTests: version/variant fields, uniqueness across 10,000 mints, embedded timestamp is current, and later-minted ids sort later under PostgreSQL uuid byte order

Checklist

  • I have read the Contributing Guide
  • Changes are focused - one logical change per PR
  • Documentation updated (README.md / DECISIONS.md / TODO.md / AGENT-README.md, if applicable)
  • New dependencies are MIT/Apache-2.0/BSD, security-vetted, and recorded in THIRD-PARTY-NOTICES.md (none added)
  • No secrets, credentials, or real infrastructure identifiers in the diff
  • No commented-out code or debug leftovers
## What does this PR do? Adopts **D-0030**: every entity identifier is now a version 7 UUID from `Guid.CreateVersion7()`, minted exclusively through the new `Viegard.Domain.ViegardId.New()` helper (all 17 former `Guid.NewGuid()` sites converted), so the generation policy is one line to change forever after. Why: random v4 ids scatter inserts across the primary-key b-tree, causing page splits, full-page-write WAL amplification, and a large hot working set on exactly the tables that grow (events, classifications, audit). v7''s leading 48-bit millisecond timestamp keeps inserts on the rightmost leaves and gives the admin GUI an index-friendly keyset-pagination cursor. 62+ bits of randomness remain, so ids stay unguessable; rows already carry explicit timestamp columns, so the embedded timestamp leaks nothing new inside the trust boundary. Constraints kept explicit in the helper doc and D-0030: id order is approximate only (per-generator clocks, no intra-millisecond guarantee); event ordering semantics always come from explicit timestamp fields. Existing v4 rows coexist harmlessly in the same `uuid` columns; no schema change or migration. ## How was this tested? - [x] `dotnet build` - 0 errors, 0 warnings - [x] `dotnet test` - 267 passed, 7 skipped (live-PostgreSQL integration tests; local WSL Docker unavailable) - [x] New `ViegardIdTests`: version/variant fields, uniqueness across 10,000 mints, embedded timestamp is current, and later-minted ids sort later under PostgreSQL uuid byte order ## Checklist - [x] I have read the [Contributing Guide](../CONTRIBUTING.md) - [x] Changes are focused - one logical change per PR - [x] Documentation updated (README.md / DECISIONS.md / TODO.md / AGENT-README.md, if applicable) - [x] New dependencies are MIT/Apache-2.0/BSD, security-vetted, and recorded in THIRD-PARTY-NOTICES.md (none added) - [x] No secrets, credentials, or real infrastructure identifiers in the diff - [x] No commented-out code or debug leftovers
Adopts D-0030: all entity ids are version 7 UUIDs from
Guid.CreateVersion7(), minted exclusively through the new
Viegard.Domain.ViegardId.New() helper so the generation policy is a
single line to change.

Random v4 ids scatter inserts across the primary-key b-tree: page
splits, full-page-write WAL amplification, and a large hot working
set on the tables that grow.  v7's leading 48-bit millisecond
timestamp keeps inserts on the rightmost leaves and gives the admin
GUI an index-friendly keyset-pagination cursor.  62+ bits of
randomness remain (ids stay unguessable); rows already carry explicit
timestamps, so the embedded timestamp leaks nothing new.

Ordering from ids is approximate only; event ordering semantics stay
on the explicit timestamp fields.  Existing v4 rows coexist in the
same uuid columns; no migration needed.

- ViegardId.New() in Viegard.Domain; all 17 minting sites converted
- Tests: version/variant, uniqueness, embedded timestamp, and
  PostgreSQL byte-order sortability
- D-0030 recorded; AGENT-README conventions updated

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
hannah-vernon/viegard-sentinel!14
No description provided.