Skip to content

test(core): pin the OUT-of-window precedence pair formatDate(V, 'relative', { style: 'short' }) — the assertion #7745's pin file lacks #8262

Description

@os-zhuang

Filed by the director seat alongside the objectui#7816 ruling (decision batch #72, 2026-09-07 — option A, formatRelativeDate stays style-less). Test-only; no behaviour change.

The gap

objectui#7745 pinned "positional wins; options.style is read only when the positional slot is undefined" in packages/core/src/utils/__tests__/date-display.optionsStyle-7745.test.ts. Its sharpest pair (:109-119) uses an in-window date (inTwoDays()), where formatDate(V, 'relative', …) never reaches the absolute fallback.

The out-of-window instance of the same pair — formatDate(V, 'relative', { style: 'short' }) on a two-year-old date — has no assertion. The #7816 dev seat measured (ablation leg C) that dropping formatRelativeDate's strip makes that call render Jul 4, '24 (the options spelling, the pinned loser) instead of Jul 4, 2024, and no existing test goes red. That is a precedence leak the pin file cannot see.

What to add

One assertion in the same file: formatDate(twoYearsAgo, 'relative', { style: 'short' }) renders the default absolute face (Jul 4, 2024, en-US), i.e. positional 'relative' still wins on the delegated path. Red-first: the leg-C mutation (remove absoluteFallbackOptions(options) at date-display.ts:152) must turn this assertion red and restoring must turn it green; the existing :171-177 assertion stays as it is.

Why it is a card

The #7816 ruling is A (no behaviour change), so nothing lands there. This assertion is the one thing from that round that should land regardless of the ruling: it makes #7745's precedence pin two-sided (in-window and out-of-window), so a future seat cannot flip the strip and silently weaken the ruling. It is also the trip-wire that would catch objectui#7816's option B "as written" if anyone ever lands it despite the ruling.

Refs: objectui#7816 (ruling comment, batch #72) · objectui#7745 / PR #7813 · objectui#7443.

Activity

  1. self-assigned this
    on Sep 7, 2026
  2. os-justin commented on Sep 7, 2026

    @os-justin
    Collaborator

    Claim: session session_01YBWFb5YgMU5dw8p2VKj16S · branch claude/issue-8262-relative-out-of-window-precedence-pin

    PM dispatch (domain:ui seat). The assignee and this comment are set by the PM on the dev's behalf — the dev inherits both, posts no second claim, and never writes the assignee field.

    Dispatch note: this is scoped as a pin, not a convention change. If the measurement turns out to require choosing a display face — which formatDate / formatDateTime face renders an out-of-window value — that is a display-convention ruling of the objectui#7620 class and is not the dev's to make: report it and stop. Pinning what the code does today, with the ablation proving the pin can fail, is the whole job.

    ⚠️ packages/fields and packages/core's date family are being read by several open cards right now (objectui#8209 on the readonly datetime widget faces, objectui#8194 landed). Cut from current main and re-derive every number rather than quoting one from the card.


    Generated by Claude Code

  3. added a commit that references this issue on Sep 7, 2026
  4. os-justin commented on Sep 7, 2026

    @os-justin
    Collaborator

    os-dev-report

    {
      "issue": 8262,
      "status": "done",
      "branch": "claude/issue-8262-relative-out-of-window-precedence-pin",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8353",
      "premise_still_valid": true,
      "summary": "Added one case to packages/core/src/utils/__tests__/date-display.optionsStyle-7745.test.ts, in the existing precedence describe: formatDate(V, 'relative', { style: 'short', locale: 'en-US' }) on the years-old V renders the DEFAULT ABSOLUTE face (Jul 4, 2024) — equal to formatDate(V, undefined, { locale }) and not the 'short' face Jul 4, '24. It is a reading, not a snapshot: #7745's sharpest pair was measured only INSIDE the plus/minus-7-day window, where the call produces the phrase locally and never reaches the absolute fallback; outside it the same call round-trips through formatRelativeDate and back into formatDate carrying the shared bag, a second site where the losing spelling can take effect that the in-window case structurally cannot see. Assertion shape: TZ-free equivalence first, then the literal anchor, then the named loser with its own lit control immediately before it so the not.toBe cannot pass against a face that renders nothing. Also added .changeset/pin-relative-out-of-window-precedence-8262.md with EMPTY frontmatter — the presence gate counts any file under a released package's src/, __tests__ included, and its own text names empty frontmatter as the explicit exemption. No source file changed; no face moved; no display-convention choice was required, so the objectui#7620-class fence was never reached. CORRECTION AGAINST THE BRIEF AND THE CARD: #8262's body says leg C makes the call render Jul 4, '24 'and no existing test goes red'. Measured false — leg C turns THREE EXISTING rows red on current main, which is what #7816's own body already recorded ('It turned three cases red'). The card's conclusion survives; its stated evidence does not. The true and stronger statement is the intersection reported under 'tests': leg C's red set and leg P's red set intersect in exactly one case, the new one, and in no existing row.",
      "tests": "ALL verdict lines quoted from the runner's own summary. Final HEAD 4aef6b774; every exit code captured as 'cmd > file 2>&1; EXIT=$?', never through a pipe. GREEN — the pin file: 'Test Files  1 passed (1)' / 'Tests  15 passed (15)' (14 before). packages/core in full: 'Test Files  122 passed (122)' / 'Tests  2574 passed (2574)'. packages/core type-check: exit 0 (tsc --noEmit && tsc -p tsconfig.test.json); NOT ASSUMED — 'tsc -p tsconfig.test.json --listFiles' hits the pin file 1 time and the main 'tsc --noEmit' program hits it 0 times, which is why the package script runs both. packages/core 'eslint .': exit 0, '517 problems (0 errors, 517 warnings)', 0 of which name this file. Dependency closure built first: 'pnpm --filter @object-ui/core^... build' exit 0. check-changeset-presence: FIRST run (before the changeset) printed '1 source file(s) of 1 released package(s) changed, and this change adds no changeset' and exited 1; after adding it, exit 0 with 'OK — 1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/pin-relative-out-of-window-precedence-8262.md.' plus 'Every one of them has an EMPTY frontmatter — declared as releasing nothing, which is the explicit exemption and a complete answer to this gate.' check-changeset-no-major: 'No changeset declares a major bump.' check:control-bytes: 'check-control-bytes: OK (scanned 6638 tracked text file(s); skipped 85 binary)'; self-scan of the two diff files with grep -naP over the control class exits 1 (clean) and its lit control (a 0x01 byte) exits 0, so the instrument fires — note a TAB is deliberately outside that class and is NOT a usable control. check:vi-mock-specifiers and check:vi-mock-inherit: both OK. check-governed-queue-guard --test on the two diff paths: 'NOT GOVERNED — 2 path(s) checked against 5 governed surface(s); none matched.'; lit control '--test AGENTS.md' fires the governed branch. ABLATION — two legs, each mutating the READ SITE in packages/core/src/utils/date-display.ts, never the pin, each run from a committed implementation, each restored BY STATE under a trap on EXIT INT TERM with absolute paths. HEAD blob of date-display.ts for both legs: 6cbabb21ccb0eb105722aaaf87b5185b3bfebd2c. LEG C (drop the strip at :152, absoluteFallbackOptions(options) becomes options): mutated blob e46f7f1fce2bdece1be4d9ccdcf493d22fd6970b; on-disk proof anchor grep 1 to 0 and injected grep 0 to 1; verdict 'Tests  4 failed | 11 passed (15)'; RED BY NAME — 'the options spelling IS the positional spelling, for every face' (RangeError: Maximum call stack size exceeded), 'beats it OUT of window too — on the delegated absolute face (#8262)' (NEW, AssertionError: expected 'Jul 4, \\'24' to be 'Jul 4, 2024'), 'ignores it on the out-of-window ABSOLUTE fallback too', 'does not recurse when the bag carries style: relative'; GREEN and load-bearing — 'beats it on the sharpest pair' (the in-window case) stays green. LEG P (invert the precedence at :203, 'style ?? options?.style' becomes 'options?.style ?? style'): mutated blob 3ae103e49dd4894f5788eb89e5241090da341a61; same on-disk proof; verdict 'Tests  4 failed | 11 passed (15)'; RED BY NAME — all four cases of the precedence describe including the new one ('the positional argument beats options.style', 'beats it on the sharpest pair', 'beats it OUT of window too (#8262)', 'absent means undefined'); the ENTIRE 'formatRelativeDate still does not read style' describe stays GREEN, because the strip neutralises style before the delegated call. RESTORE PROOF for both legs, by state and not by exit code: 'git diff HEAD' empty AND 'git hash-object PATH' back to 6cbabb21ccb0eb105722aaaf87b5185b3bfebd2c, equal to 'git rev-parse HEAD:PATH'. THE RESULT: the two red sets intersect in exactly ONE case, the new one; no existing row is red in both. Predictions were written to a file before the first run; two deviations reported as observed — I predicted 2 existing reds under leg C and observed 3 (I missed 'the options spelling IS the positional spelling', which recurses to stack exhaustion once the strip is gone), and leg P matched exactly. DECLARED NARROWING: 'turbo ls --affected' names 38 packages because everything depends on @object-ui/core, but the diff is one file under packages/core/src/**/__tests__/ plus a changeset — 'git grep optionsStyle-7745' across packages apps examples scripts e2e returns ZERO references (lit control 'absoluteFallbackOptions' returns 2 files, so the instrument fires) and @object-ui/core's files field is [dist, README.md, CHANGELOG.md, LICENSE], so nothing outside the package can observe it. Everything outside packages/core/ is declared to CI. There is NO shared verification lock in this repo (scripts/pm/ holds only check-half-states.mjs), consistent with the brief and contrary to an earlier dispatch's implication.",
      "mcp_calls": "6 — 1 create_pull_request (201), 1 add_issue_comment (this one), 2 pull_request/comment read-backs, and 2 search_issues attempts that BOTH hard-failed with 'API rate limit already exceeded for user ID 323634890'. All card and sibling-card reads (#8262, #7816, #8209) went through the zero-quota public-repo page payload channel; the repo-scoped REST channel was probed twice this session (with and without an Authorization header) and returns 403 'GitHub access is not enabled for this session', so it is gated, not throttled.",
      "open_questions": [
        {
          "question": "The new case's name says 'positional relative still wins on the delegated path'. That framing is exactly right today (objectui#7816 ruled A, formatRelativeDate stays style-less). But if #7816 is ever reopened and B lands, formatRelativeDate WOULD honour style on the out-of-window fallback, and this composite call would then render Jul 4, '24 — at which point 'positional relative won and the relative path then chose its own face using style' is an equally defensible reading of the #7745 ruling. Should the case name/comment be softened to a pure measurement ('renders the default absolute face today') rather than a claim about who wins?",
          "options": [
            "A — leave as written: the comment already names #7816 and says the strip is what would flip it, so the next seat is pointed at the ruling rather than at a contradiction",
            "B — rename to a pure measurement and move the 'positional wins' reading into the docblock only"
          ],
          "recommendation": "A. The escalation fence was never reached: I pinned the face main renders today and chose nothing. The interpretive question only becomes live if a maintainer reopens #7816, and the case is precisely the trip-wire that forces them to look at it — which is what the card asked for. Flagging it here rather than silently resolving it."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED — handed to the PM to file, with the reason. FINDING (observation-class, would carry the 'finding' label): the whole date-face pin family asserts literal LOCAL-date faces built from fixed 07:00:00.000Z instants while the repo pins NO timezone anywhere — zero hits for TZ / process.env.TZ / timeZone in vitest.config.mts, every vitest.setup.*, turbo.json, package.json and all of .github/workflows (lit control 'environment' in vitest.config.mts hits 8 times, so the grep fires). Population: 6 test files (packages/components/src/__tests__/data-table-datetime-convention-7443.test.tsx, packages/core/src/utils/__tests__/dataset-format.date.test.ts, packages/core/src/utils/__tests__/date-display.optionsStyle-7745.test.ts, packages/fields/src/__tests__/datetime-compact-style-7443.test.tsx, packages/fields/src/__tests__/fields-date-widget-convention-8194.test.tsx, packages/plugin-dashboard/src/__tests__/DatasetWidget.dateMeasure.test.tsx) and 49 literal day-bearing assertions in that family. MEASURED, not theorised, and PRE-EXISTING: at the branch base 411a132c0, WITHOUT this PR's row, 'TZ=Etc/GMT+8 pnpm exec vitest run packages/core/src/utils/__tests__/date-display.optionsStyle-7745.test.ts' gives 'Tests  10 failed | 4 passed (14)' with failures of the form \\\"expected 'Jul 3, 2024' to be 'Jul 4, 2024'\\\"; dataset-format.date.test.ts passes in the same run, so the exposure is not uniform. CI and this container both resolve UTC, which is the only reason these are green. Direction of harm is contributor-facing, not user-facing: a maintainer west of UTC-07:00 sees a wall of red that is not about the code. Cheapest remedy for a triager to weigh: set TZ=UTC once in vitest.config.mts rather than editing 49 assertions. WHY NOT FILED BY ME: the mandatory de-duplication search could not be run — MCP search_issues hard-failed twice with 'API rate limit already exceeded for user ID 323634890' and the repo-scoped REST channel is gated 403 for this session, and the zero-quota page-payload channel covers single-card reads only, not search. Filing without the de-dup check and dropping the finding silently are both forbidden, so it comes back here for the PM to de-dup and file."
      ]
    }

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions