Authenticated user session aggregate. Post-create immutable at v0.5.0
(claims update deferred post-publish). Per A4 §5.1.
Expiry encoding: expiresAt: Date (not expiresAtMs: number) is intentional
for A4 aggregates. Per A3 §5.1: low-level storage primitives (A3:
ChallengeStore, RefreshTokenFamilyStore, ReplaySeenSet) use epoch-ms
number to eliminate Date mutation surface. A4 higher-level aggregates use
Date for ergonomics at the application layer. Callers bridging A3 and A4
convert explicitly at the boundary (new Date(epochMs) to lift, or
someDate.getTime() to lower) so the two encodings never alias the same
field. This is a deliberate two-tier design, not an inconsistency.
Authenticated user session aggregate. Post-create immutable at v0.5.0 (claims update deferred post-publish). Per A4 §5.1.
Expiry encoding:
expiresAt: Date(notexpiresAtMs: number) is intentional for A4 aggregates. Per A3 §5.1: low-level storage primitives (A3: ChallengeStore, RefreshTokenFamilyStore, ReplaySeenSet) use epoch-msnumberto eliminate Date mutation surface. A4 higher-level aggregates useDatefor ergonomics at the application layer. Callers bridging A3 and A4 convert explicitly at the boundary (new Date(epochMs)to lift, orsomeDate.getTime()to lower) so the two encodings never alias the same field. This is a deliberate two-tier design, not an inconsistency.