{"version":3,"sources":["../src/utils/date.ts","../src/core/temporal.ts"],"names":["ValidationError","INVERTED_VALIDITY_WINDOW_CODE","IMMUTABLE_VALIDITY_LOWER_BOUND_CODE"],"mappings":"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","file":"chunk-L4L4AV6F.cjs","sourcesContent":["/**\n * Date encoding utilities for consistent storage.\n *\n * Contract: All dates are stored as ISO 8601 strings in UTC.\n * - Always includes milliseconds\n * - Always UTC (Z suffix)\n * - Sorts correctly as strings\n */\n\nimport {\n  IMMUTABLE_VALIDITY_LOWER_BOUND_CODE,\n  INVERTED_VALIDITY_WINDOW_CODE,\n  ValidationError,\n} from \"../errors\";\n\n/**\n * ISO 8601 datetime pattern.\n * Matches formats like:\n * - 2024-01-15T10:30:00.000Z\n * - 2024-01-15T10:30:00Z\n * - 2024-01-15T10:30:00.123Z\n */\nconst ISO_DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$/;\n\n/**\n * Checks if a string is a valid ISO 8601 datetime.\n *\n * @param value - String to validate\n * @returns True if valid ISO 8601 datetime\n */\nexport function isValidIsoDate(value: string): boolean {\n  if (!ISO_DATE_PATTERN.test(value)) {\n    return false;\n  }\n  // Also check that Date parsing produces a valid date\n  const date = new Date(value);\n  return !Number.isNaN(date.getTime());\n}\n\n/**\n * Validates that a string is a valid ISO 8601 datetime.\n * Throws ValidationError if invalid.\n *\n * @param value - String to validate\n * @param fieldName - Name of field for error message\n * @returns The validated string\n * @throws ValidationError if not a valid ISO datetime\n */\nexport function validateIsoDate(value: string, fieldName: string): string {\n  if (!isValidIsoDate(value)) {\n    throw new ValidationError(\n      `Invalid ISO 8601 datetime for \"${fieldName}\": \"${value}\". ` +\n        `Expected format: YYYY-MM-DDTHH:mm:ss.sssZ`,\n      {\n        issues: [\n          {\n            path: fieldName,\n            message: `Invalid ISO 8601 datetime format. Expected: YYYY-MM-DDTHH:mm:ss.sssZ, got: \"${value}\"`,\n          },\n        ],\n      },\n      {\n        suggestion: `Use a valid ISO 8601 UTC datetime like \"2024-01-15T10:30:00.000Z\"`,\n      },\n    );\n  }\n  return value;\n}\n\n/**\n * Strict canonical ISO 8601 pattern: fixed-width UTC with exactly\n * millisecond precision (`YYYY-MM-DDTHH:mm:ss.sssZ`). Unlike\n * {@link ISO_DATE_PATTERN}, which tolerates a missing or variable-width\n * fractional part, this is the only shape whose lexicographic text order\n * matches chronological order — avoiding cases like `\"...:00.1Z\"` (= `.100`)\n * sorting *after* `\"...:00.101Z\"`.\n */\nconst CANONICAL_ISO_DATE_PATTERN =\n  /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/;\n\nconst ZONELESS_DATETIME_PATTERN =\n  /^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?$/;\nconst OFFSET_DATETIME_PATTERN =\n  /^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?)(Z|[+-]\\d{2}(?::?\\d{2})?)$/i;\nconst DATE_ONLY_PATTERN = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction normalizedOffset(offset: string): string {\n  if (offset.toUpperCase() === \"Z\") return \"Z\";\n  if (/^[+-]\\d{2}$/.test(offset)) return `${offset}:00`;\n  if (/^[+-]\\d{4}$/.test(offset)) {\n    return `${offset.slice(0, 3)}:${offset.slice(3)}`;\n  }\n  return offset;\n}\n\nfunction databaseTimestampMilliseconds(value: string): number {\n  if (ZONELESS_DATETIME_PATTERN.test(value)) {\n    return Date.parse(`${value.replace(\" \", \"T\")}Z`);\n  }\n  const offsetMatch = OFFSET_DATETIME_PATTERN.exec(value);\n  if (offsetMatch !== null) {\n    const date = offsetMatch[1];\n    const time = offsetMatch[2];\n    const offset = offsetMatch[3];\n    if (date === undefined || time === undefined || offset === undefined) {\n      return Number.NaN;\n    }\n    return Date.parse(`${date}T${time}${normalizedOffset(offset)}`);\n  }\n  if (DATE_ONLY_PATTERN.test(value)) {\n    return Date.parse(`${value}T00:00:00.000Z`);\n  }\n  return Number.NaN;\n}\n\n/**\n * Canonicalizes a database-driver timestamp without interpreting a zoneless\n * string in the host timezone. PostgreSQL drivers can return values such as\n * `2026-06-25 12:00:00`; TypeGraph treats that shape as UTC so the same stored\n * clock value cannot move across hosts or daylight-saving boundaries.\n *\n * Returns `undefined` for an unsupported or unrepresentable value so callers\n * can raise an error specific to their storage boundary.\n */\nexport function canonicalizeDatabaseTimestamp(\n  value: unknown,\n): string | undefined {\n  if (value instanceof Date) {\n    if (Number.isNaN(value.getTime())) return undefined;\n    return value.toISOString();\n  }\n  if (typeof value !== \"string\") return undefined;\n  const milliseconds = databaseTimestampMilliseconds(value);\n  if (Number.isNaN(milliseconds)) return undefined;\n  return new Date(milliseconds).toISOString();\n}\n\n/**\n * Checks if a string is a canonical UTC ISO 8601 datetime with fixed\n * millisecond width (`YYYY-MM-DDTHH:mm:ss.sssZ`).\n */\nexport function isCanonicalIsoDate(value: string): boolean {\n  if (!CANONICAL_ISO_DATE_PATTERN.test(value)) return false;\n  const date = new Date(value);\n  return !Number.isNaN(date.getTime()) && date.toISOString() === value;\n}\n\n/**\n * Validates that a string is a canonical UTC ISO 8601 datetime with fixed\n * millisecond width. Stricter than {@link validateIsoDate} (which also\n * accepts missing or 1–2 digit milliseconds): required wherever the value\n * is compared **as text** against stored timestamps and must sort\n * chronologically — e.g. a temporal `asOf` coordinate, where a\n * variable-width value would mis-order and silently include or exclude the\n * wrong rows. Produce one with `new Date(value).toISOString()`.\n *\n * @param value - String to validate\n * @param fieldName - Name of field for error message\n * @returns The validated string\n * @throws ValidationError if not a canonical UTC ISO datetime\n */\nexport function validateCanonicalIsoDate(\n  value: string,\n  fieldName: string,\n): string {\n  if (!isCanonicalIsoDate(value)) {\n    throw new ValidationError(\n      `Invalid canonical ISO 8601 datetime for \"${fieldName}\": \"${value}\". ` +\n        `Expected fixed-width UTC: YYYY-MM-DDTHH:mm:ss.sssZ`,\n      {\n        issues: [\n          {\n            path: fieldName,\n            message: `Expected canonical UTC ISO 8601 (YYYY-MM-DDTHH:mm:ss.sssZ), got: \"${value}\"`,\n          },\n        ],\n      },\n      {\n        suggestion: `Use a fixed-width UTC datetime like \"2024-01-15T10:30:00.000Z\" (e.g. new Date(value).toISOString()).`,\n      },\n    );\n  }\n  return value;\n}\n\n/**\n * Validates an optional canonical ISO date string. Returns `undefined` for an\n * absent value; otherwise enforces canonical fixed-width UTC ISO 8601 via\n * {@link validateCanonicalIsoDate}. Used for stored validity-window inputs\n * (`validFrom` / `validTo`) so every timestamp the temporal filters compare as\n * text is canonical and sorts chronologically — the same contract the `asOf`\n * read coordinate already enforces.\n */\nexport function validateOptionalCanonicalIsoDate(\n  value: string | undefined,\n  fieldName: string,\n): string | undefined {\n  if (value === undefined) return undefined;\n  return validateCanonicalIsoDate(value, fieldName);\n}\n\n/** Validates the write protocol: omission uses the default; null states no lower bound. */\nexport function validateStatedValidityLowerBound(\n  value: string | null | undefined,\n  fieldName: string,\n): string | null | undefined {\n  if (value === null) return value;\n  return validateOptionalCanonicalIsoDate(value, fieldName);\n}\n\n/**\n * Whether a CANONICAL stated bound names the same instant a row already stores.\n *\n * The one comparison of a caller's bound against a stored one, so the coalesce\n * dirty check (\"would this write move the window?\") and the write guard (\"can\n * this stated bound be applied?\") can never disagree about what \"the same bound\"\n * means. Two copies of it did disagree — one comparing driver text, one\n * comparing instants — which is how a re-stated window wrote on one backend and\n * coalesced on the other.\n *\n * Only the STORED side is canonicalized. It arrives as the driver rendered it,\n * and the dialects do not render a timestamp the same way (SQLite returns the\n * written text; a Postgres driver may hand back a zoned string equivalent to the\n * canonical form without being identical to it). The stated side needs no\n * canonicalization because every write path validates it as canonical first —\n * which is a PRECONDITION here, not an assumption: a non-canonical stated bound\n * would compare unequal to an equivalent stored instant and must be rejected by\n * {@link validateCanonicalIsoDate} rather than silently treated as a mismatch.\n */\nexport function statedBoundMatchesStored(\n  stated: string | null,\n  stored: string | undefined,\n): boolean {\n  return (stated ?? undefined) === canonicalizeDatabaseTimestamp(stored);\n}\n\n/**\n * Whether a stated validity window has NEGATIVE width — a row that stopped\n * being true before it started. The one comparison every window refusal is\n * built on, so paths that must report the fault through their own error type\n * (trusted import) decide it identically to the ones that throw a\n * `ValidationError`.\n *\n * PRECONDITION: both endpoints are canonical fixed-width UTC ISO 8601, which is\n * what makes a lexicographic compare a chronological one. Every caller\n * establishes that before comparing, with no exception: the paths that throw a\n * `ValidationError` reach this through {@link validateOptionalCanonicalIsoDate},\n * and trusted import — which skips schema validation for throughput —\n * format-checks the stated window fields of every streamed row against\n * {@link isCanonicalIsoDate} before reaching here. A bound read back from a row\n * needs no check of its own: it is canonical because the write that stored it\n * was held to this same contract — SQLite hands that text back verbatim, and the\n * PostgreSQL row mapper normalizes the driver's shape back to it. So no caller\n * can compare a value that would mis-sort, here or later against an `asOf`\n * coordinate.\n *\n * ZERO width (`validFrom === validTo`) is not inverted: it is what a\n * same-instant retraction produces at millisecond precision, and the store's own\n * output must round-trip.\n */\nexport function isInvertedValidityWindow(\n  validFrom: string | null | undefined,\n  validTo: string | undefined,\n): boolean {\n  if (validFrom === undefined || validFrom === null || validTo === undefined)\n    return false;\n  return validFrom > validTo;\n}\n\n/**\n * Whether a validity window is readable at NO instant — inverted OR zero width.\n * The CHOICE predicate, sibling to {@link isInvertedValidityWindow}'s REFUSAL\n * predicate, and the two answer different questions on purpose:\n *\n *  - a window a caller STATED in full is refused only when it is inverted, because\n *    zero width is what a same-instant retraction produces and the store's own\n *    output must round-trip;\n *  - a bound a write CHOOSES for a caller who stated none must never satisfy this\n *    one, because a row nobody can read at any coordinate is not a window the\n *    caller asked for.\n *\n * `inverted ⇒ empty`, and `empty ∧ ¬inverted ⟺ zero width`. That law is a\n * property in `tests/property/temporal-window.test.ts`, so the pair cannot drift\n * into disagreeing about anything but the boundary they deliberately differ on.\n *\n * PRECONDITION: as {@link isInvertedValidityWindow} — both endpoints canonical\n * fixed-width UTC ISO 8601, so the lexicographic compare is a chronological one.\n */\nexport function isEmptyValidityWindow(\n  validFrom: string | undefined,\n  validTo: string | undefined,\n): boolean {\n  if (validFrom === undefined || validTo === undefined) return false;\n  return validFrom >= validTo;\n}\n\n/**\n * Whether a canonical instant belongs to the half-open validity interval\n * `[validFrom, validTo)`. An omitted bound is unbounded on that side.\n *\n * This is the single JavaScript owner of validity-window membership. SQL read\n * paths express the same decision through the shared temporal compiler.\n */\nexport function validityWindowContainsInstant(\n  validFrom: string | undefined,\n  validTo: string | undefined,\n  instant: string,\n): boolean {\n  return (\n    (validFrom === undefined || validFrom <= instant) &&\n    (validTo === undefined || instant < validTo)\n  );\n}\n\n/**\n * THE lower bound a write that STAMPS its own start stores, decided against the\n * instant it is about to stamp. One owner for every such write, so no two of them\n * can spell the decision differently. Three inputs, three outcomes:\n *\n *  - a stated `null`   → no lower bound (a CONFIRMED open-left window, which is\n *                        how interchange round-trips a row that has none);\n *  - a stated string   → that bound, the caller's own assertion, verbatim;\n *  - nothing stated    → the write instant, UNLESS stamping it would leave the\n *                        window readable at no instant. A row carrying only a\n *                        `validTo` at or before the write instant is \"born already\n *                        ended\": its start is UNKNOWN, not at-or-after its end, so\n *                        it stores no lower bound and reads back at every `asOf`\n *                        before that end (issue #407).\n *\n * The comparison against `validTo` is NON-STRICT: `validTo === writeInstant`\n * stores no bound too. A stamped `[T, T)` is a successful write no coordinate can\n * observe, and the millisecond of skew between a caller's own `Date.now()` and the\n * backend's sample is enough to land there — so the rule is total, and there is no\n * input for which a stamped bound yields an empty window.\n *\n * The write instant is a PARAMETER, not a clock read: the caller passes the very\n * value it binds into `created_at`/`updated_at` (or, for a resurrection, the\n * instant its guard judged), so the decision and the stamp cannot come from two\n * different samples (issue #413's failure mode). This function has no way to\n * sample a clock, which is what makes that structural rather than tested.\n *\n * PRECONDITION: as {@link isEmptyValidityWindow}. This is called BELOW the\n * validation boundary, on a public `GraphBackend` surface, so canonicality is\n * established by whoever reached the backend: store paths through\n * {@link validateStatedValidityLowerBound}, interchange import through its own\n * window validator, trusted import through its per-chunk format check. A direct\n * `GraphBackend` caller establishes it itself — a pre-existing property of that\n * surface, written down here rather than left implicit.\n */\nexport function resolveStampedValidityLowerBound(\n  statedValidFrom: string | null | undefined,\n  validTo: string | undefined,\n  writeInstant: string,\n): string | undefined {\n  if (statedValidFrom === null) return undefined;\n  if (statedValidFrom !== undefined) return statedValidFrom;\n  return isEmptyValidityWindow(writeInstant, validTo) ? undefined : (\n      writeInstant\n    );\n}\n\n/**\n * The lower bound a write that PASSES THROUGH a stated one stores: `null` — the\n * write-protocol spelling of a confirmed open-left window — becomes \"no bound\", and\n * a string is stored verbatim.\n *\n * Separate from {@link resolveStampedValidityLowerBound} because it answers a\n * different question. Its one caller (`buildUpdateEdge`'s resurrection leg) writes\n * the window only when the caller NAMED a lower bound; an edge resurrection that\n * names none RETAINS the stored window rather than choosing a new one, so there is\n * no instant to judge and none is offered.\n */\nexport function resolveStatedValidityLowerBound(\n  validFrom: string | null,\n): string | undefined {\n  return validFrom ?? undefined;\n}\n\n/**\n * Refuses a `validTo` whose EFFECTIVE lower bound would invert the window. On an\n * in-place update the row's stored lower bound is the effective one and must stay\n * <= the new `validTo`; on a resurrection that RESETS `valid_from` it is the\n * write instant, so a lone past `validTo` would be born inverted.\n *\n * A ZERO-width window (`validTo === effectiveValidFrom`) is legal and stays\n * legal: it is what a same-instant retraction produces at millisecond\n * precision, and the identity-import window check sanctions it for the same\n * reason. Only NEGATIVE width refuses.\n *\n * Reached through {@link assertWritableValidityWindow} rather than called\n * directly, so no writer can check the effective bound without also checking a\n * stated pair.\n */\nfunction assertEffectiveValidityLowerBound(\n  subject: string,\n  effectiveValidFrom: string | undefined,\n  validTo: string | undefined,\n): void {\n  if (!isInvertedValidityWindow(effectiveValidFrom, validTo)) return;\n  throw new ValidationError(\n    `Inverted validity window for ${subject}: the effective validFrom \"${effectiveValidFrom}\" is after validTo \"${validTo}\".`,\n    {\n      issues: [\n        {\n          path: \"validTo\",\n          code: INVERTED_VALIDITY_WINDOW_CODE,\n          message: `Expected the effective validFrom <= validTo, got \"${effectiveValidFrom}\" > \"${validTo}\". The effective validFrom is the row's stored lower bound, or the write instant where the write stamps one.`,\n        },\n      ],\n    },\n    {\n      suggestion:\n        \"Provide both validFrom and validTo for a historical window, or drop validTo to keep the row current.\",\n    },\n  );\n}\n\n/**\n * Rejects an inverted validity window. `validFrom > validTo` describes a row\n * that stopped being true before it started, so no current-mode or `asOf` read\n * can ever observe it — the write succeeds and the row is then reachable only\n * through `includeEnded`, which reads as data loss rather than as the error it\n * is. Call this wherever both endpoints are supplied together; both are\n * canonical ISO 8601 by then, so a lexicographic compare is a chronological\n * compare.\n *\n * @param subject - Human-readable identification of the row, for the message\n *   (e.g. `Person \"01H...\"`).\n * @throws ValidationError if both endpoints are present and out of order\n */\nexport function assertOrderedValidityWindow(\n  subject: string,\n  validFrom: string | null | undefined,\n  validTo: string | undefined,\n): void {\n  if (!isInvertedValidityWindow(validFrom, validTo)) return;\n  throw new ValidationError(\n    `Inverted validity window for ${subject}: validFrom \"${validFrom}\" is after validTo \"${validTo}\".`,\n    {\n      issues: [\n        {\n          path: \"validFrom\",\n          code: INVERTED_VALIDITY_WINDOW_CODE,\n          message: `Expected validFrom <= validTo, got \"${validFrom}\" > \"${validTo}\"`,\n        },\n      ],\n    },\n    {\n      suggestion:\n        \"Pass a validFrom at or before validTo, or omit validTo to leave the window open.\",\n    },\n  );\n}\n\n/**\n * What an UPDATE will do with the row's validity lower bound — the two facts the\n * write guard needs, stated by the writer that knows them.\n *\n * Every update path must decide `appliesStatedValidFrom` explicitly, because the\n * answer is not a property of the guard's other arguments: the same\n * `(validFrom, storedBound, validTo)` triple is a legal window restatement on a\n * resurrection and an unappliable bound on an in-place update.\n */\nexport type UpdateValidityLowerBound = Readonly<{\n  /**\n   * The bound the row will hold when the caller states no `validFrom`: the\n   * stored `valid_from` for an in-place update, the write instant for a\n   * resurrection that stamps a new one, `undefined` where there is no bound to\n   * invert against.\n   */\n  effectiveValidFrom: string | undefined;\n  /**\n   * Whether the write STORES a stated `validFrom`. False for an in-place update\n   * of a live row — `buildUpdateNode` / `buildUpdateEdge` rewrite `valid_from`\n   * only on a resurrection — which is what makes a differing stated bound a\n   * refusal rather than a silent drop.\n   */\n  appliesStatedValidFrom: boolean;\n  /**\n   * Whether `effectiveValidFrom` IS the row's stored `valid_from` — the value an\n   * `expectedValidFrom` predicate would name — rather than a bound this write is\n   * about to stamp itself.\n   *\n   * A node resurrection resets `valid_from` to the write instant and passes THAT\n   * as the effective bound, so its verdict never looked at what the row holds and\n   * a fence on the stored value would predicate the write on something nothing\n   * read. An edge retains its bound through a resurrection, so its effective\n   * bound is the stored one on both legs.\n   */\n  effectiveBoundIsStored: boolean;\n}>;\n\n/**\n * The `expectedValidFrom` predicate a write owes its verdict, shaped for\n * spreading straight into the backend's update params.\n *\n * `{}` means \"assert nothing\"; `{ expectedValidFrom: null }` means \"assert the\n * row still has NO lower bound\". The two are different claims and the object\n * form keeps them distinguishable at every call site — see\n * `UpdateNodeParams.expectedValidFrom`.\n */\nexport type ValidityLowerBoundFence = Readonly<{\n  expectedValidFrom?: string | null;\n}>;\n\n/**\n * Whether a {@link ValidityLowerBoundFence} STATES anything. Returns a\n * boolean, despite the `asserts` in its name reading like a TypeScript\n * assertion function: it answers \"does this fence assert the row's stored\n * lower bound?\".\n *\n * THE SINGLE OWNER of that question, placed beside the type it decides about.\n * Two spellings of it existed — `args.expectedValidFrom !== undefined` at the\n * write step that carries the fence into the UPDATE, and a key-membership test\n * wherever a fence had to be recognised as empty. They agree today under\n * `exactOptionalPropertyTypes`, which is exactly the state in which a second\n * implementation of an existing decision is still a defect: the copies WILL\n * drift, and this one decides whether a write is fenced at all.\n *\n * `{ expectedValidFrom: null }` is a STATED fence — \"assert the row still has\n * NO lower bound\" — not an empty one, which is why the test is against\n * `undefined` and not against nullishness.\n */\nexport function assertsStoredLowerBound<T extends ValidityLowerBoundFence>(\n  fence: T,\n): fence is T & StatedValidityLowerBoundFence {\n  return fence.expectedValidFrom !== undefined;\n}\n\n/**\n * A {@link ValidityLowerBoundFence} that states a bound — what\n * {@link assertsStoredLowerBound} narrows to, so a caller that has asked the\n * question does not have to re-ask it to satisfy `exactOptionalPropertyTypes`.\n * Re-asking is how the second spelling gets reintroduced.\n */\nexport type StatedValidityLowerBoundFence = Readonly<{\n  expectedValidFrom: string | null;\n}>;\n\n/**\n * The `expectedValidTo` predicate a write owes a verdict that read the row's\n * stored window END, shaped for spreading straight into the update params.\n *\n * The counterpart of {@link ValidityLowerBoundFence}, and stated separately for\n * the same reason: `{}` means \"assert nothing\" and `{ expectedValidTo: null }`\n * means \"assert the row is still open-ended\". A reopen of an `oneActive` edge\n * judged the end the row carried, so its UPDATE asserts it.\n */\nexport type ValidityUpperBoundFence = Readonly<{\n  expectedValidTo?: string | null;\n}>;\n\n/**\n * Whether a {@link ValidityUpperBoundFence} STATES anything — the single owner\n * of that question, for the same reason {@link assertsStoredLowerBound} is the\n * single owner of its own.\n */\nexport function assertsStoredUpperBound<T extends ValidityUpperBoundFence>(\n  fence: T,\n): fence is T & Readonly<{ expectedValidTo: string | null }> {\n  return fence.expectedValidTo !== undefined;\n}\n\n/**\n * What {@link assertWritableValidityWindow} reports back about the verdict it\n * just reached — not about the window, but about what the verdict DEPENDED ON.\n *\n * THE SINGLE OWNER of the question \"must this write assert the row's stored\n * lower bound?\", and it answers by handing over the predicate ITSELF rather than\n * a flag a caller then turns into one. A write asserts every component its\n * verdict read (see `UpdateNodeParams.expectedValidFrom`), and which components\n * those are is decided by which branches the guard actually took — so a caller\n * that could still spell the fence on its own would eventually spell a different\n * one. Interchange import did exactly that: it asserted the probed\n * `valid_from` unconditionally, over-fencing props-only updates the store paths\n * (correctly) left unfenced. There is now nothing to re-derive.\n *\n * Too FEW assertions is a silent race; too many is a refusal of writes that are\n * legitimate. Both failures come from a second spelling.\n */\nexport type ValidityWindowVerdict = Readonly<{\n  /**\n   * The fence this verdict obliges the write to carry. Non-empty when the\n   * verdict consulted the row's STORED `valid_from` — either by comparing a\n   * stated bound against it, or by inverting a lone `validTo` against it — and\n   * empty when the caller named no window at all, when the write applies the\n   * bound it stated, or when the effective bound was one this write will stamp\n   * rather than one the row holds. In those cases the verdict is independent of\n   * what the row carries, and predicating the write on it would refuse a\n   * concurrent recreate that changed nothing this decision looked at.\n   */\n  storedLowerBoundFence: ValidityLowerBoundFence;\n}>;\n\n/**\n * Whether an upsert explicitly treats its stated lower bound as\n * create/resurrection-only input.\n *\n * This predicate owns the policy decision for both write execution and\n * unchanged-upsert coalescing, so those paths cannot drift on whether a live\n * row's stored lower bound is preserved.\n */\nexport function preservesImmutableLowerBound(\n  policy: \"preserve\" | \"refuse\" | undefined,\n): policy is \"preserve\" {\n  return policy === \"preserve\";\n}\n\n/**\n * Refuses a stated `validFrom` the write would not apply.\n *\n * A live row's lower bound is HISTORY: it records when the row started being\n * true, and an in-place update never moves it. Accepting a bound that names a\n * different instant and then dropping it is the API lying — the caller's stated\n * window silently is not the stored one, while the write still spends a version\n * bump and a history row moving nothing. Restating the bound the row already\n * holds stays legal, so a caller that echoes a row's own window back (a merge\n * commit, a re-delivered upsert) is unaffected.\n *\n * Reached through {@link assertWritableValidityWindow} rather than called\n * directly, so no writer can accept a lower bound without declaring whether it\n * applies one.\n */\nfunction assertStatedLowerBoundIsApplicable(\n  subject: string,\n  statedValidFrom: string | null,\n  storedValidFrom: string | undefined,\n): void {\n  if (statedBoundMatchesStored(statedValidFrom, storedValidFrom)) return;\n  const storedDescription =\n    storedValidFrom === undefined ?\n      \"the row has no lower bound\"\n    : `the row's stored lower bound is \"${storedValidFrom}\"`;\n  throw new ValidationError(\n    `Unappliable validFrom for ${subject}: stated \"${statedValidFrom}\", but ${storedDescription} and the row is live.`,\n    {\n      issues: [\n        {\n          path: \"validFrom\",\n          code: IMMUTABLE_VALIDITY_LOWER_BOUND_CODE,\n          message: `A live row's lower bound is history and an in-place update never rewrites it, so \"${statedValidFrom}\" could not be applied.`,\n        },\n      ],\n    },\n    {\n      suggestion:\n        storedValidFrom === undefined ?\n          \"Restate validFrom: null or omit validFrom; only a resurrection can give this row a lower bound.\"\n        : `Restate the stored bound (\"${storedValidFrom}\") or omit validFrom.`,\n    },\n  );\n}\n\n/**\n * THE window-ordering guard a valid-time UPDATE goes through, identically for\n * nodes and edges. Refuses a window of negative width — a row that stopped\n * being true before it started — whether the caller states both endpoints or\n * only the new end. Also refuses a stated lower bound the write cannot apply,\n * so no update accepts a `validFrom` it will ignore.\n *\n * Three checks, because the failures deserve different messages: the caller who\n * supplied both endpoints out of order gets told about the pair, the caller who\n * stated a lower bound this write cannot store gets told which bound the row\n * holds, and the caller whose lone `validTo` inverts against the bound the row\n * will actually carry gets told which bound that is.\n *\n * The stated pair is judged FIRST — an inverted pair is wrong whatever the row\n * holds — and the applicability of the lower bound before the effective-bound\n * check, so a caller is told their bound will not be stored rather than being\n * told about a bound they did not name.\n *\n * INSERTS use {@link assertOrderedValidityWindow} alone, and that is now the\n * COMPLETE stated-pair rule rather than a partial one. An insert carrying a lone\n * historical `validTo` means \"born already ended\", and there is no bound to hold\n * the caller to because the write stamps none:\n * {@link resolveStampedValidityLowerBound} stores no lower bound whenever the\n * instant it would stamp cannot precede the stated end (I1b). So no insert path\n * can store a window readable at no coordinate, on any `GraphBackend` caller —\n * the decision lives in the SQL builders, below the store, below interchange and\n * below trusted import (I5). Only an UPDATE has a lower bound the caller can be\n * held to.\n *\n * @param subject - Human-readable identification of the row, for the message\n *   (e.g. `Person \"01H...\"`).\n * @param validFrom - The caller's explicit lower bound, if any.\n * @param lowerBound - What the write will do with the row's lower bound; see\n *   {@link UpdateValidityLowerBound}.\n * @returns {@link ValidityWindowVerdict} — the `expectedValidFrom` fence this\n *   verdict obliges the write to carry, empty when it read no stored bound.\n * @throws ValidationError with issue code {@link INVERTED_VALIDITY_WINDOW_CODE}\n *   or {@link IMMUTABLE_VALIDITY_LOWER_BOUND_CODE}\n */\nexport function assertWritableValidityWindow(\n  subject: string,\n  validFrom: string | null | undefined,\n  lowerBound: UpdateValidityLowerBound,\n  validTo: string | undefined,\n): ValidityWindowVerdict {\n  assertOrderedValidityWindow(subject, validFrom, validTo);\n\n  // The stated bound is COMPARED against the stored one only here — a write\n  // that applies what the caller stated has nothing to compare it to.\n  const comparedStatedBound =\n    validFrom !== undefined && !lowerBound.appliesStatedValidFrom;\n  if (comparedStatedBound) {\n    assertStatedLowerBoundIsApplicable(\n      subject,\n      validFrom,\n      lowerBound.effectiveValidFrom,\n    );\n  }\n\n  assertEffectiveValidityLowerBound(\n    subject,\n    validFrom === undefined ?\n      lowerBound.effectiveValidFrom\n    : (validFrom ?? undefined),\n    validTo,\n  );\n  // ...and the inversion check falls back to the row's bound only when the\n  // caller named an end without a start. Note this is true whether or not the\n  // row HAS a bound: \"no lower bound to invert against\" is itself a reading of\n  // the row, and a recreate that gives the row one changes the answer.\n  const comparedStoredBoundAgainstEnd =\n    validFrom === undefined && validTo !== undefined;\n\n  const readEffectiveLowerBound =\n    comparedStatedBound || comparedStoredBoundAgainstEnd;\n  return {\n    storedLowerBoundFence:\n      readEffectiveLowerBound && lowerBound.effectiveBoundIsStored ?\n        // eslint-disable-next-line unicorn/no-null -- `expectedValidFrom` distinguishes \"assert IS NULL\" (null) from \"assert nothing\" (an absent key); see UpdateNodeParams.\n        { expectedValidFrom: lowerBound.effectiveValidFrom ?? null }\n      : {},\n  };\n}\n\n/**\n * Encodes a Date to an ISO 8601 string for storage.\n */\nexport function encodeDate(date: Date): string {\n  return date.toISOString();\n}\n\n/**\n * Decodes an ISO 8601 string to a Date.\n * Validates the string format first.\n *\n * @throws ValidationError if not a valid ISO datetime\n */\nexport function decodeDate(isoString: string): Date {\n  validateIsoDate(isoString, \"date\");\n  return new Date(isoString);\n}\n\n/**\n * Returns the current timestamp as an ISO string.\n */\nexport function nowIso(): string {\n  return new Date().toISOString();\n}\n","/**\n * Shared temporal coordinate + validation.\n */\nimport { ValidationError } from \"../errors\";\nimport { validateCanonicalIsoDate } from \"../utils/date\";\nimport { type TemporalMode } from \"./types\";\n\nconst RECORDED_INSTANT_VERSION = \"r1\";\nconst ENGINE_INSTANT_VERSION = \"e1\";\nconst RECORDED_REVISION_WIDTH = 16;\n/** Open interval ceiling for numeric recorded-revision columns. */\nexport const RECORDED_MAX_REVISION = Number.MAX_SAFE_INTEGER;\nconst RECORDED_INSTANT_PATTERN =\n  /^r1:(\\d{16}):(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z)$/;\n/**\n * Engine-native form: `e1:<opaque engine revision>:<canonical ISO instant>`.\n * The revision is whatever URL-safe token the engine itself hands back from\n * `EngineRecordedTimeMembers.revisionNow` — never parsed as a number, so the\n * charset is deliberately the unreserved RFC 3986 set rather than digits.\n */\nconst ENGINE_INSTANT_PATTERN =\n  /^e1:([A-Za-z0-9._~-]+):(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z)$/;\n\ndeclare const RECORDED_INSTANT_BRAND: unique symbol;\n\n/**\n * A versioned recorded-time anchor, in one of two forms sharing one grammar:\n * `<version>:<revision>:<recordedAt>`.\n *\n * - `r1:0000000000000001:YYYY-MM-DDTHH:mm:ss.sssZ` — TypeGraph's own form. The\n *   fixed-width logical revision is strictly monotonic per graph and makes\n *   every commit addressable even when many commits share one wall-clock\n *   millisecond.\n * - `e1:<engine revision>:YYYY-MM-DDTHH:mm:ss.sssZ` — engine-native form,\n *   minted by a backend that supplies `GraphBackend.recordedTime`. The\n *   revision is an opaque token the engine itself assigns, never a TypeGraph\n *   counter; ordering between two engine-native anchors compares the\n *   timestamp only (see {@link compareRecordedInstants}).\n *\n * Either form's timestamp is a non-decreasing physical wall-time high-water\n * mark used by diagonal valid-time reads: same-millisecond commits repeat it,\n * and backward clock corrections hold it at the previous value until wall\n * time catches up. The string round-trips through plain string checkpoint\n * columns without a custom serializer.\n */\nexport type RecordedInstant = string & {\n  readonly [RECORDED_INSTANT_BRAND]: \"RecordedInstant\";\n};\n\n/**\n * The parsed halves of a TypeGraph-owned (`r1:`) recorded instant. Not\n * exported on its own — callers narrow {@link RecordedInstantParts} by\n * `kind` rather than naming either variant directly.\n */\ntype TypeGraphRecordedInstantParts = Readonly<{\n  kind: \"typegraph\";\n  revision: number;\n  recordedAt: string;\n}>;\n\n/**\n * The parsed halves of an engine-native (`e1:`) recorded instant. Not\n * exported on its own — see {@link TypeGraphRecordedInstantParts}.\n */\ntype EngineRecordedInstantParts = Readonly<{\n  kind: \"engine\";\n  revision: string;\n  recordedAt: string;\n}>;\n\n/**\n * The parsed halves of a {@link RecordedInstant}, discriminated by which\n * ownership form minted it. {@link parseRecordedInstant} is the one owner of\n * this grammar for both forms — a caller that needs the TypeGraph-only\n * numeric revision (or the engine-only opaque one) narrows on `kind` rather\n * than re-deriving the parse.\n */\nexport type RecordedInstantParts =\n  TypeGraphRecordedInstantParts | EngineRecordedInstantParts;\n\nfunction invalidRecordedInstant(value: string, path: string): ValidationError {\n  return new ValidationError(\n    `${path} must be a canonical versioned recorded instant.`,\n    {\n      issues: [\n        {\n          path,\n          message: `Expected ${RECORDED_INSTANT_VERSION}:<${RECORDED_REVISION_WIDTH}-digit revision>:YYYY-MM-DDTHH:mm:ss.sssZ or ${ENGINE_INSTANT_VERSION}:<engine revision>:YYYY-MM-DDTHH:mm:ss.sssZ, got \"${value}\"`,\n        },\n      ],\n    },\n    {\n      suggestion:\n        \"Persist the exact string returned by store.recordedNow(); migrate preview-schema checkpoints with migrateLegacyRecordedTime() and migrateRecordedAnchor().\",\n    },\n  );\n}\n\nexport function parseRecordedInstant(\n  value: string,\n  path = \"RecordedInstant\",\n): RecordedInstantParts {\n  const typeGraphMatch = RECORDED_INSTANT_PATTERN.exec(value);\n  if (typeGraphMatch !== null) {\n    const revisionText = typeGraphMatch[1];\n    const recordedAt = typeGraphMatch[2];\n    if (revisionText === undefined || recordedAt === undefined) {\n      throw invalidRecordedInstant(value, path);\n    }\n    const revision = Number(revisionText);\n    if (\n      !Number.isSafeInteger(revision) ||\n      revision < 1 ||\n      revision >= RECORDED_MAX_REVISION\n    ) {\n      throw invalidRecordedInstant(value, path);\n    }\n    validateCanonicalIsoDate(recordedAt, path);\n    return { kind: \"typegraph\", revision, recordedAt };\n  }\n  const engineMatch = ENGINE_INSTANT_PATTERN.exec(value);\n  if (engineMatch !== null) {\n    const revision = engineMatch[1];\n    const recordedAt = engineMatch[2];\n    if (revision === undefined || recordedAt === undefined) {\n      throw invalidRecordedInstant(value, path);\n    }\n    validateCanonicalIsoDate(recordedAt, path);\n    return { kind: \"engine\", revision, recordedAt };\n  }\n  throw invalidRecordedInstant(value, path);\n}\n\nexport function assertValidRecordedInstant(value: string, path: string): void {\n  parseRecordedInstant(value, path);\n}\n\n/**\n * Splits an optional recorded anchor into its parsed halves — the revision\n * (a numeric TypeGraph counter or an opaque engine token, discriminated by\n * `kind`) that a recorded read narrows to, and the wall time that valid-time\n * windows are measured against. Compilers that consult both halves parse once\n * through this instead of per predicate.\n */\nexport function optionalRecordedInstantParts(\n  value: string | undefined,\n  path = \"RecordedInstant\",\n): RecordedInstantParts | undefined {\n  return value === undefined ? undefined : parseRecordedInstant(value, path);\n}\n\n/** Mints TypeGraph's own (`r1:`) form of a recorded instant. */\nexport function createRecordedInstant(\n  revision: number,\n  recordedAt: string,\n): RecordedInstant {\n  if (\n    !Number.isSafeInteger(revision) ||\n    revision < 1 ||\n    revision >= RECORDED_MAX_REVISION\n  ) {\n    throw new ValidationError(\n      \"createRecordedInstant revision must be a valid recorded revision.\",\n      {\n        issues: [\n          {\n            path: \"createRecordedInstant.revision\",\n            message: `Expected a safe integer from 1 through ${String(RECORDED_MAX_REVISION - 1)}, got ${String(revision)}`,\n          },\n        ],\n      },\n    );\n  }\n  const revisionText = revision\n    .toString()\n    .padStart(RECORDED_REVISION_WIDTH, \"0\");\n  return asRecordedInstant(\n    `${RECORDED_INSTANT_VERSION}:${revisionText}:${recordedAt}`,\n  );\n}\n\n/**\n * Mints an engine-native (`e1:`) recorded instant from the revision an\n * `EngineRecordedTimeMembers.revisionNow` call returned. `revision` is opaque\n * and never parsed as a number, but it must still be non-empty and safe to\n * embed in the colon-delimited grammar, so it is restricted to the RFC 3986\n * unreserved charset (letters, digits, `. _ ~ -`).\n */\nexport function createEngineRecordedInstant(\n  revision: string,\n  recordedAt: string,\n): RecordedInstant {\n  if (!/^[A-Za-z0-9._~-]+$/.test(revision)) {\n    throw new ValidationError(\n      \"createEngineRecordedInstant revision must be a non-empty URL-safe token.\",\n      {\n        issues: [\n          {\n            path: \"createEngineRecordedInstant.revision\",\n            message: `Expected one or more of [A-Za-z0-9._~-], got ${JSON.stringify(revision)}`,\n          },\n        ],\n      },\n    );\n  }\n  return asRecordedInstant(\n    `${ENGINE_INSTANT_VERSION}:${revision}:${recordedAt}`,\n  );\n}\n\n/**\n * Returns the canonical UTC wall-time component of a recorded anchor. Works\n * for both ownership forms — every {@link RecordedInstantParts} variant\n * carries `recordedAt`.\n *\n * The value is non-decreasing per graph, but it is not the commit-order key;\n * use the complete {@link RecordedInstant} when ordering or replaying commits.\n */\nexport function recordedInstantWallTime(instant: RecordedInstant): string {\n  return parseRecordedInstant(instant).recordedAt;\n}\n\n/**\n * Returns the strict per-graph logical revision carried by a TypeGraph-owned\n * (`r1:`) anchor. TypeGraph's numeric revision is meaningless for an\n * engine-native (`e1:`) anchor, so this refuses one rather than returning a\n * number parsed from an opaque token.\n *\n * @throws {ValidationError} when `instant` is an engine-native anchor.\n */\nexport function recordedInstantRevision(instant: RecordedInstant): number {\n  const parts = parseRecordedInstant(instant);\n  if (parts.kind !== \"typegraph\") {\n    throw new ValidationError(\n      \"recordedInstantRevision requires a TypeGraph-owned (r1) recorded instant.\",\n      {\n        issues: [\n          {\n            path: \"recordedInstantRevision.instant\",\n            message: `Expected an r1 anchor, got an engine-native (e1) anchor with opaque revision \"${parts.revision}\"`,\n          },\n        ],\n      },\n      {\n        suggestion:\n          \"Use recordedInstantWallTime(instant) for a value that works on both anchor forms.\",\n      },\n    );\n  }\n  return parts.revision;\n}\n\n/**\n * Compares two recorded anchors of the SAME ownership form.\n *\n * For TypeGraph-owned (`r1:`) anchors, comparison is by logical revision:\n * revisions are local to a graph, so only compare anchors produced by the\n * same graph, and the physical wall-time component deliberately does not\n * participate. For engine-native (`e1:`) anchors there is no shared numeric\n * counter to compare — the engine's revision token is opaque — so comparison\n * falls back to the canonical ISO timestamp, which is lexicographically\n * ordered.\n *\n * Caveat for engine-native anchors: the timestamp has millisecond\n * resolution, so two distinct engine revisions minted within the same\n * millisecond compare equal here even though they are not the same commit.\n * TypeGraph-owned anchors have no such gap — their logical revision is a\n * strict per-commit counter — so this caveat is specific to the\n * timestamp-only fallback, not a general property of recorded-instant\n * comparison.\n *\n * @throws {ValidationError} when the two anchors were minted by different\n *   ownership forms — there is no shared axis to compare them on.\n */\nexport function compareRecordedInstants(\n  left: RecordedInstant,\n  right: RecordedInstant,\n): -1 | 0 | 1 {\n  const leftParts = parseRecordedInstant(left);\n  const rightParts = parseRecordedInstant(right);\n  if (leftParts.kind !== rightParts.kind) {\n    throw new ValidationError(\n      \"compareRecordedInstants requires both anchors to share the same recorded-time ownership form.\",\n      {\n        issues: [\n          {\n            path: \"compareRecordedInstants\",\n            message: `Got a \"${leftParts.kind}\" anchor and a \"${rightParts.kind}\" anchor.`,\n          },\n        ],\n      },\n    );\n  }\n  if (leftParts.kind === \"typegraph\" && rightParts.kind === \"typegraph\") {\n    if (leftParts.revision < rightParts.revision) return -1;\n    if (leftParts.revision > rightParts.revision) return 1;\n    return 0;\n  }\n  if (leftParts.recordedAt < rightParts.recordedAt) return -1;\n  if (leftParts.recordedAt > rightParts.recordedAt) return 1;\n  return 0;\n}\n\n/**\n * Brands a canonical versioned anchor string as a {@link RecordedInstant}.\n *\n * The escape hatch for an instant that round-trips through untyped storage:\n * captured from {@link Store.recordedNow}, persisted as a plain string, read\n * back, and replayed into `asOfRecorded`. Validates the canonical form eagerly —\n * the same check `asOfRecorded` applies — so a malformed value fails here, at the\n * brand site, rather than deeper in a read. Does *not* assert the instant is a\n * real captured commit; it only guarantees the value is well-formed enough to\n * compare correctly against the recorded relations.\n *\n * @throws {ValidationError} when `value` is not a canonical versioned anchor.\n */\nexport function asRecordedInstant(value: string): RecordedInstant {\n  assertValidRecordedInstant(value, \"asRecordedInstant\");\n  return value as RecordedInstant;\n}\n\n/**\n * The single opaque temporal coordinate every pinned read is resolved\n * against. It carries the valid-time axis plus an optional recorded/system-time\n * axis, so every surface can inject one coordinate object instead of threading\n * each temporal dimension separately.\n */\nexport type ReadCoordinate = Readonly<{\n  /**\n   * The valid-time axis: a resolved temporal mode and (only for `\"asOf\"`) the\n   * instant it is pinned to.\n   */\n  valid: Readonly<{\n    mode: TemporalMode;\n    /** Defined only when `mode` is `\"asOf\"`. */\n    asOf?: string;\n  }>;\n  /** The recorded/system-time axis. Defined only for recorded-pinned views. */\n  recorded?: Readonly<{ asOf: RecordedInstant }>;\n}>;\n\n/**\n * Resolves and validates a `(mode, asOf)` pair into a {@link ReadCoordinate}.\n * Rejects an `asOf` paired with any non-`\"asOf\"` mode rather than silently\n * dropping it — pinning an instant is only meaningful in `\"asOf\"` mode, so a\n * `view({ mode: \"current\", asOf })` is a caller mistake, not a coordinate to\n * quietly discard. Then validates via {@link assertValidAsOf}.\n *\n * @param mode - The temporal mode to pin.\n * @param asOf - The supplied timestamp. Required for `\"asOf\"`; rejected for\n *   every other mode.\n * @param suggestion - Caller-specific remediation hint for the\n *   missing/invalid-timestamp case.\n */\nexport function resolveReadCoordinate(\n  mode: TemporalMode,\n  asOf: string | undefined,\n  suggestion?: string,\n): ReadCoordinate {\n  if (mode !== \"asOf\" && asOf !== undefined) {\n    throw new ValidationError(\n      `Temporal mode \"${mode}\" does not take an asOf timestamp.`,\n      {\n        issues: [\n          {\n            path: \"asOf\",\n            message: `asOf is only valid with mode \"asOf\", not \"${mode}\"`,\n          },\n        ],\n      },\n      {\n        suggestion:\n          'Pin an instant with store.asOf(timestamp) or store.view({ mode: \"asOf\", asOf }); drop asOf for other modes.',\n      },\n    );\n  }\n  assertValidAsOf(\n    mode,\n    asOf,\n    suggestion === undefined ? undefined : { suggestion },\n  );\n  return { valid: asOf === undefined ? { mode } : { mode, asOf } };\n}\n\n/**\n * Adds a recorded/system-time pin to an existing valid-time coordinate.\n * Direct `store.asOfRecorded(T)` passes the diagonal valid-time coordinate\n * (`mode: \"asOf\", asOf: T`); `store.asOf(vt).asOfRecorded(rt)` passes the\n * already-resolved valid coordinate and adds the recorded sibling.\n */\nexport function withRecordedCoordinate(\n  coordinate: ReadCoordinate,\n  recordedAsOf: RecordedInstant,\n): ReadCoordinate {\n  assertValidRecordedInstant(recordedAsOf, \"asOfRecorded\");\n  return {\n    ...coordinate,\n    recorded: { asOf: recordedAsOf },\n  };\n}\n\n/**\n * Validates the `asOf` coordinate of a temporal read: `\"asOf\"` mode\n * requires a timestamp, and any supplied timestamp must be a canonical\n * fixed-width UTC ISO-8601 string (`YYYY-MM-DDTHH:mm:ss.sssZ`). The latter\n * is load-bearing — temporal filters compare `asOf` against `valid_from` /\n * `valid_to` as text on SQLite, so a non-canonical value (date-only, an\n * offset, natural language, or variable-width / missing milliseconds like\n * `.1Z`) would sort and compare wrong rather than error. Reached only through\n * {@link resolveReadCoordinate}, which every temporal read entry point routes\n * through (direct reads, queries, subgraphs, algorithms, and StoreView), so\n * they all fail identically.\n *\n * @param mode - The resolved temporal mode.\n * @param asOf - The supplied timestamp (may be `undefined`).\n * @param options.suggestion - A caller-specific remediation hint for the\n *   missing-timestamp case.\n *\n * @throws {ValidationError} when `mode` is `\"asOf\"` and `asOf` is missing, or\n *   when any supplied `asOf` is not a canonical UTC ISO-8601 timestamp. The\n *   canonical check runs for *every* mode that consumes `asOf`, so a\n *   non-canonical value can never reach a text comparison.\n */\nfunction assertValidAsOf(\n  mode: TemporalMode,\n  asOf: string | undefined,\n  options?: Readonly<{ suggestion?: string }>,\n): void {\n  if (mode === \"asOf\" && asOf === undefined) {\n    throw new ValidationError(\n      'Temporal mode \"asOf\" requires a timestamp',\n      {\n        issues: [\n          { path: \"asOf\", message: \"Timestamp is required for asOf mode\" },\n        ],\n      },\n      {\n        suggestion:\n          options?.suggestion ??\n          'Provide an ISO-8601 timestamp for asOf mode, e.g. \"2026-01-01T00:00:00.000Z\".',\n      },\n    );\n  }\n  if (asOf !== undefined) {\n    validateCanonicalIsoDate(asOf, \"asOf\");\n  }\n}\n\n/**\n * A human-readable description of a coordinate for error messages, e.g.\n * `mode \"current\"` or `mode \"asOf\" asOf 2026-01-01T00:00:00.000Z`. Shared by\n * every refusal path (the `StoreView` read-only / current-only / search facades\n * and the sealed-query builder) so they describe a coordinate identically — and\n * a future axis (recorded time) is reflected everywhere from one place.\n */\nexport function describeCoordinate(coordinate: ReadCoordinate): string {\n  const { mode, asOf } = coordinate.valid;\n  const valid =\n    asOf === undefined ? `mode \"${mode}\"` : `mode \"${mode}\" asOf ${asOf}`;\n  return coordinate.recorded === undefined ?\n      valid\n    : `${valid}, recorded asOf ${coordinate.recorded.asOf}`;\n}\n\n/**\n * The structured error-context fields describing a coordinate, shared by the\n * same refusal paths as {@link describeCoordinate}.\n */\nexport function coordinateContext(\n  coordinate: ReadCoordinate,\n): Record<string, unknown> {\n  const { mode, asOf } = coordinate.valid;\n  return {\n    temporalMode: mode,\n    ...(asOf !== undefined && { asOf }),\n    ...(coordinate.recorded === undefined ?\n      {}\n    : { recordedAsOf: coordinate.recorded.asOf }),\n  };\n}\n"]}