Skip to content

decision: the tenant Localization settings (date format, time format, number format, first day of week) are applied by no renderer — honour them, or stop offering them #11675

Description

@objectstack-fleet

Path: ② the capabilities an end user meets in the app — localization | 缺项 | P2

Split by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U from objectui#11672 (the 2026-10-06 console dogfood sweep, showcase, framework ce577ec4), item 2. Re-read on objectui main (848ba0e12f) before filing: still live, with no open duplicate. ⛔ Not a claim, ⛔ not a dispatch.

Triage: the choice lands in objectstack (the settings manifest the Settings form is drawn from) or in objectui (the formatters) ⇒ domain:ui, with the objectstack half declared on the card; rationale: a setting that no renderer reads is a surface that lies, and the two ways to fix it differ in cost by an order of magnitude. So this is the maintainer's call, not triage's.

What happens

GET /api/settings/localization reports date_format: "YYYY-MM-DD", time_format: "24h", number_format: "1,234.56" and first_day_of_week: "monday" (all source: default), and Setup → Settings → Localization shows them. Nothing honours them:

  • Users list "10/6/2026 1:44 am";
  • the Field Zoo record "6/17/2026 2:30 pm" next to "14:30:00", so 12h and 24h in one record;
  • the audit log "10/6/2026, 2:05:57 AM";
  • the approval drawer "2026-07-23";
  • the Task Calendar's weeks start on Sunday (CalendarView.tsx about :438–:451) while the timeline's start on Monday (ObjectTimeline.tsx about :745).

Outside packages/types/src/data.ts, no objectui source reads those four keys. core/src/utils/date-display.ts (about :517) hard-codes hour12: true.

Options

What it means Cost (measured)
A. Honour them Dates, times, numbers and week starts follow the tenant's effective settings. objectstack's /api/v1/auth/me/localization must serve the four values (today it confirms only currency, locale and timezone; the console's fetch at apps/console/src/LocalizationFetchProvider.tsx about :108 already drops the timezone it gets). LocalizationValue grows. About 5 central formatters change, about 194 direct toLocale* / Intl.* calls in about 72 files across 21 packages are migrated, and 2 week-start sites are fixed. number_format needs a meaning ruled, because a fixed pattern conflicts with locale-driven Intl grouping.
B. Stop offering them The four settings leave the Settings manifest (objectstack) until something honours them. Rendering stays locale-driven. Small: an objectstack manifest change, plus a migration note for stored values.
A then B — This is not an option: offering a setting while the renderers ignore it is the defect.

Triage's recommendation: B now, and A as its own measured feature card if a customer pulls for it. It is the smallest change that stops the surface lying, and A's 194-site migration has no measured pull today. The fallback is A, scoped to the 5 central formatters plus the week start, with number_format ruled out.

Reply with one letter.


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:i18nThe customer's own language, across UI, metadata and notifications
    on Oct 6, 2026
  2. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling recorded — B: formats follow the locale, the four separate format settings retire, and this card keeps only the week start

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T06:32Z.

    Provenance (who / verbatim / where): the maintainer, in the triage seat's live chat (session_01AavokzJ5DndAwitDXvKy4U), answering decision batch 2 (director format, item 1, recommending B), verbatim: 「同意」.

    Ruled:

    • Dates, times, numbers and the first day of the week follow the user's locale (language and region), the Salesforce Locale model.
    • date_format, time_format, number_format and first_day_of_week leave the Localization settings. ⛔ They are not implemented. The fallback (A, honour them) is not taken.
    • timezone, locale and currency stay live settings.

    Read before executing: nothing reads the four keys in objectstack (server), objectui, cloud or hotcrm. The only matches are SQL's own date_format(), an export transform name and comments.

    Execution:

    State: needs-user-decision → pm:queue, re-graded bug · priority:p3 (the remaining scope is two sites).


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FngvPpdrnhHMdHHq6vwwju
    Account: os-justin
    Branch: claude/issue-11675-week-start-from-locale
    Worktree: objectui-issue-11675
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/plugin-calendar/src/CalendarView.tsx (the week grid's start, about :438–:451), packages/plugin-timeline/src/ObjectTimeline.tsx (startOfWeek, about :745), one shared locale week-start helper in a package both plugins already import (if the dev measures that one is needed), the tests beside them, and .changeset/11675-*.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
    Clause-②: yes
    Thread-read: 6010771237
    Ruling-ref: 6010771237 (ruling B, the maintainer's 「同意」 recorded by the triage seat), retrieved this round.
    Serial constraints cleared: none blocking. No open PR (objectui#11703, #11706, #11707, #11708, #11069) touches CalendarView.tsx or ObjectTimeline.tsx. objectui#11676's remainder (retiring timeline.bucket.overdue) is unclaimed and touches useTimelineTranslation.ts and the locale packs, not startOfWeek. It is held behind this card for the same file. objectstack-ai/objectstack#21958 (the server half of ruling B) touches no objectui file. Read 2026-10-06T09:01Z.

    Why Clause-②: yes: two plugins take one locale rule, so the likely shape is one shared helper exported from a package both import, which widens that package's surface. If the dev keeps the rule module-private, it reports the built-declaration reading and the seat amends this line to no before any review.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 11675,
      "status": "done",
      "branch": "claude/issue-11675-week-start-from-locale",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11710",
      "session": "session_01FngvPpdrnhHMdHHq6vwwju — subagent = parent's (container CLAUDE_CODE_REMOTE_SESSION_ID cse_01FngvPpdrnhHMdHHq6vwwju; the relay stamped the same session)",
      "premise_still_valid": true,
      "summary": "Ruling B's remaining scope is implemented in draft PR objectui#11710 (head e4f3430, base daa7caf), and its premise held on origin/main. @object-ui/i18n now exports firstDayOfWeek(locale) plus a WeekdayIndex type (0 = Sunday, the getDay and react-day-picker weekStartsOn numbering). It reads the engine's Intl.Locale week info (getWeekInfo(), else the weekInfo accessor; Node 22 has the accessor only, Chromium 141 has both, Firefox was not measured) and falls back to a CLDR 47 region table, with Monday, CLDR's 001 default, for regions the table does not list. A parity test checks the table against the runtime region by region. CalendarView reads it once from effectiveLocale and starts every week from it: the month grid and its heads, the week view's columns, the header's week range, a wrapped span's title day, and the date popover via weekStartsOn (date-fns's own week start differs for es-MX and reads enUS until the locale loads). ObjectTimeline's This week and Next week buckets start on firstDayOfWeek(useDisplayLocale()), and the bucket-bounds block now steps local midnights, which also corrects the DST misbucketing of Tomorrow and of next week's first day. Pins cover en-US (Sunday), en-GB and zh-CN (Monday) and ar-EG (Saturday). Clause-② holds: the built dist/utils/first-day-of-week.d.ts declares export declare function firstDayOfWeek(locale: string): WeekdayIndex, and dist/index.d.ts re-exports it. The PR assignee is NOT set: the auto-mode classifier refused the label-write (see deviations).",
      "tests": "All runs are at head e4f3430 unless marked, the heavy ones through os-verify-lock (slot issue-11675). (1) pnpm exec vitest run packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/ exited 0: 'Test Files 184 passed (184) / Tests 2281 passed | 145 skipped (2426)'. (2) pnpm exec vitest run scripts/__tests__/date-only-zone-pins-10183.test.ts exited 0: 'Tests 27 passed (27)'. The driver counts a skipped child case as a failure, so the new DST cases ran. (3) type-check for the three packages exited 0, and --listFiles shows every touched test file in its package's test program. (4) The new pins: firstDayOfWeek-11675 has 12 cases, CalendarView.weekStartFromLocale-11675 has 10, ObjectTimeline.weekBucketsFromLocale-11675 has 4, plus a DST block in ObjectTimeline.dateOnlyZone-10866 (rig, fixture validity, buckets). (5) Before the fixture re-judge (at 4f1fc12, the implementation alone): 'Tests 4 failed | 961 passed' across the plugins, every failure in CalendarView.gridcellLocale-10144 and CalendarView.displayLocale-10442, whose weekday-head helpers assumed a Sunday-first grid under de / de-CH / fr-FR. They now take the first day as an explicit literal, and their assertions are otherwise unchanged. (6) Eight ablations, each through objectstack scripts/ablation-replace.mjs from a committed tree, each printing 'ok mutation landed: anchor 1 to 0, blob X to Y' and 'ok restored: blob == HEAD and git diff HEAD is empty'. No rebuild was needed: vitest.config.mts aliases @object-ui/i18n to packages/i18n/src, and the plugin tests import the components relatively. A1a (timeline week start hard-coded Monday): 2 failed / 2 passed, en-US and ar-EG red, en-GB and zh-CN green, as predicted. A1b (endOfWeek back to 24-hour steps) and A1c (tomorrow = today + 86400000): the zone driver went red on its timeline-pin row, and the failing child case was the new DST case. A2 (calendar weekStart = 0): 11 failed / 8 passed, every non-Sunday case red, en-US and es-MX green. A2b (popover weekStartsOn removed): 1 failed, Expected domingo, Received lunes. A2c (title day back to getDay() === 0): 1 failed, the title-day case. A3 (CLDR table removed): 5 failed / 7 passed, the table-path and parity cases. A3b (engine path skipped): 2 failed / 10 passed, the -u-fw- and getWeekInfo cases. Every observed direction was the predicted one.",
      "gates": [
        { "cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-calendar^...' --filter '@object-ui/plugin-timeline^...' build", "exit": 0, "head": "4f1fc12 (i18n src unchanged since)" },
        { "cmd": "pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm exec vitest run --maxWorkers=2 packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm exec vitest run scripts/__tests__/date-only-zone-pins-10183.test.ts", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm --filter @object-ui/i18n --filter @object-ui/plugin-calendar --filter @object-ui/plugin-timeline run type-check", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm --filter @object-ui/i18n --filter @object-ui/plugin-calendar --filter @object-ui/plugin-timeline run lint", "exit": 0, "head": "e4f3430", "note": "0 errors; per-rule warning counts identical at daa7caf and e4f3430 for CalendarView.tsx, ObjectTimeline.tsx and the i18n entry files; new files 0 warnings" },
        { "cmd": "pnpm check:new-line-citations", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:control-bytes", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:changeset-claims", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:pending-changeset-literals", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:readme-exports", "exit": 0, "head": "e4f3430", "note": "after the scoped build; before it, exit 1 on its population-collapse floor (prerequisite: 23 packages unbuilt), and --list already judged firstDayOfWeek in the i18n README as real" },
        { "cmd": "pnpm check:doc-snippets", "exit": 0, "head": "e4f3430", "note": "779 of 779 blocks judged, 0 failed; before the scoped build, exit 2 PRECONDITION NOT MET" },
        { "cmd": "pnpm check:self-import", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:phantom-deps", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:unused-deps", "exit": 0, "head": "e4f3430" },
        { "cmd": "node scripts/check-changeset-no-major.mjs", "exit": 0, "head": "e4f3430" },
        { "cmd": "node scripts/check-changeset-presence.mjs", "exit": 0, "head": "e4f3430" },
        { "cmd": "node scripts/check-changeset-overwrite.mjs", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:doc-fences", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:vi-mock-specifiers", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:vi-mock-inherit", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:vi-mock-override-shape", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:test-path-roots", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:unreferenced-sources", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:esm-specifiers", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:shell-escape-residue", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:dist-completeness", "exit": 0, "head": "e4f3430" },
        { "cmd": "pnpm check:published-dist", "exit": 0, "head": "e4f3430" },
        { "cmd": "node scripts/check-governed-queue-guard.mjs --test (17 changed paths)", "exit": 0, "head": "e4f3430", "note": "NOT GOVERNED" },
        { "cmd": "pnpm check:node-esm-load", "exit": 1, "head": "e4f3430", "note": "NOT MEASURED: its provenance leg refused 8 entries turbo replayed from another worktree's shared cache (auth, core, data-objectstack, mobile, permissions, providers, react-runtime, types); none is in this diff and none of the three touched packages was refused or failed; a clean reading needs --force-build (CI's whole-tree run)" },
        { "cmd": "CI", "exit": null, "head": "e4f3430", "note": "in_progress: not read; CI convergence is the PM's. Repo-wide pnpm lint and the full pnpm test are CI's" }
      ],
      "line_budget": "not applicable: the diff touches no skills/** and no governed surface (17 files, +863 / -41)",
      "files_changed": [
        ".changeset/11675-week-start-from-locale.md",
        "content/docs/plugins/plugin-calendar.mdx",
        "content/docs/plugins/plugin-timeline.mdx",
        "packages/i18n/README.md",
        "packages/i18n/src/__tests__/firstDayOfWeek-11675.test.ts",
        "packages/i18n/src/index.ts",
        "packages/i18n/src/utils/first-day-of-week.ts",
        "packages/i18n/src/utils/index.ts",
        "packages/plugin-calendar/README.md",
        "packages/plugin-calendar/src/CalendarView.displayLocale-10442.test.tsx",
        "packages/plugin-calendar/src/CalendarView.gridcellLocale-10144.test.tsx",
        "packages/plugin-calendar/src/CalendarView.tsx",
        "packages/plugin-calendar/src/__tests__/CalendarView.weekStartFromLocale-11675.test.tsx",
        "packages/plugin-timeline/README.md",
        "packages/plugin-timeline/src/ObjectTimeline.tsx",
        "packages/plugin-timeline/src/__tests__/ObjectTimeline.dateOnlyZone-10866.test.tsx",
        "packages/plugin-timeline/src/__tests__/ObjectTimeline.weekBucketsFromLocale-11675.test.tsx"
      ],
      "deviations": [
        "PR assignee NOT written: node scripts/pm/label-write.mjs --repo objectstack-ai/objectui --issue 11710 --assign os-justin was refused by the Claude Code auto-mode classifier ('[External System Writes]') before any request was sent. Not re-routed (no curl, no MCP, no hand write); the seat performs it.",
        "File surface: beyond the claim's list, the diff adds docs that AGENTS.md #2 requires (packages/i18n/README.md, packages/plugin-calendar/README.md, packages/plugin-timeline/README.md, content/docs/plugins/plugin-calendar.mdx, content/docs/plugins/plugin-timeline.mdx) and the helper's two export lines (packages/i18n/src/index.ts, src/utils/index.ts). All are additive; the seat may amend the claim's surface.",
        "Touched published defect corrected in place: the timeline's bucket-bounds block was rewritten as a unit, so tomorrow and the two week ends now step local midnights instead of 24-hour multiples, which misbucketed across a DST change. Pinned by the driven DST case; ablations A1b and A1c each show it red alone. Declared in the PR's Acceptance notes.",
        "Two existing pins re-judged, not weakened: the weekday-head helpers in CalendarView.gridcellLocale-10144 and CalendarView.displayLocale-10442 modelled a Sunday-first grid; they now take the first day as a stated literal.",
        "Attribution: commits end with AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named trailer, and the PR body ends with os-dev.md's session-URL footer, not the harness reminder's form. Both follow the rule that the repo or role file wins.",
        "check:node-esm-load recorded as NOT MEASURED (provenance refusal of foreign cache entries), and repo-wide lint and the full test are declared to CI; the claim's and order's named gate clues were all run."
      ],
      "mcp_calls": "0 — no MCP GitHub tool was called",
      "api_writes": "2 — (1) pr_create through the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft), giving objectui#11710, body read back identical (12453 of 12453 bytes); (2) this os-dev-report comment via post-stamped: POST /repos/objectstack-ai/objectui/issues/11675/comments. Refused before any request: the PR-assignee label-write (classifier). Not REST: 4 git pushes to the branch.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者: 无 · noted, not filed — date pickers outside the calendar, built on the @object-ui/components Calendar primitive with no weekStartsOn, take date-fns's week start for the tag. That is not CLDR's for tags date-fns has no locale of its own for (es-MX reads es, a Monday start, where CLDR starts on Sunday), and it is a Sunday start until the date-fns locale loads. The mechanism was measured on the primitive (ablation A2b: lunes where domingo is expected), not through a field's public door, so there is no reach reading. Dedupe words: weekStartsOn, date-fns week start, es-MX, date picker first day of week",
        "carrier: 承接者: 无 · noted, not filed — the gantt variant's week axis counts plan weeks (Week 1, Week 2) from the axis's first day, a choice its renderer docblock documents. It hard-codes no weekday, so ruling B does not reach it. Dedupe words: gantt week axis, Week N, calendar week snap",
        "carrier: 承接者: 无 · noted, not filed — firstDayOfWeek's table path reads the region only, so a -u-fw- or -u-rg- keyword is honoured only where the engine has week info. No producer writes those keywords today. Dedupe words: -u-fw-, -u-rg-, week info fallback"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR objectui#11710 at e4f3430 (Fixes #11675). The at-tier contract review is owed before enqueue

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T10:01Z. Dev report: os-dev-report on this card.

    • Shape: draft, base main, first line Fixes #11675, and the body has no other closing keyword. Clause-②: yes is at the start of a line. 17 files: the helper and its two export lines in @object-ui/i18n, CalendarView.tsx, ObjectTimeline.tsx, three new pin files, two re-judged calendar pins, the timeline's DST zone suite, three package READMEs, two content/docs/plugins/*.mdx pages and one changeset. No governed path, no content/docs/releases/ edit. +863/−41.
    • Beyond the claim's listed surface: the READMEs, the docs pages and the export lines. The seat accepts them: the export lines are the claimed helper's, and the docs follow AGENTS.md Add automated testing infrastructure and CI/CD workflows #2 for the changed behaviour.
    • Seat's own reading of the diff:
      • firstDayOfWeek(locale) reads Intl.Locale's getWeekInfo(), else its weekInfo accessor. Without either, it falls back to a CLDR first-day table by region (or the likely-subtags region), with Monday as CLDR's 001 default. A parity test checks the table against the runtime.
      • It is exported with WeekdayIndex from @object-ui/i18n's entry. That is the one widening, which makes this Clause-②: yes.
      • CalendarView starts every week surface from it. ObjectTimeline's "This week" / "Next week" bounds start from it.
      • The bucket-bounds block now steps local midnights. That is a touched published defect (DST misbucketing), fixed in place and pinned by the driven DST case.
    • Ruling B (6010771237): no setting is added, and the first day comes from the locale the dates are already formatted with. The four retired settings are not read.
    • Changeset prose (i18n, plugin-calendar, plugin-timeline, all minor), checked sentence by sentence against the diff:
      • the en-US / en-GB / zh-CN / ar-EG sentence matches the pins;
      • the helper bullet (engine week info, then the CLDR table, Monday default, RangeError on a malformed tag) matches first-day-of-week.ts;
      • the calendar bullet (grid, heads, week view, header range, wrapped-span title day, popover weekStartsOn) and the timeline bullet (week bounds and DST stepping) match the two components;
      • the host-behaviour sentence and the gantt-unchanged sentence state the boundary.
    • Tests:
      • 26 new pin cases plus the DST block; two calendar pins re-judged to take the first day as a literal, with no assertion weakened.
      • Eight ablations, each red in the predicted direction and restored by blob.
      • i18n + plugin-calendar + plugin-timeline: 184 files passed. The zone driver: 27 passed.
      • check:readme-exports and check:doc-snippets (779 of 779) are green after the scoped build.
    • Out-of-scope findings (3), Acceptance notes, none filed:
      • date pickers on the Calendar primitive outside the calendar take date-fns's week start (mechanism measured on the primitive, no reach reading at a field door);
      • the gantt axis counts plan weeks (documented, not a weekday);
      • the table path reads the region only, so -u-fw- / -u-rg- are honoured only with engine week info (no producer).
    • Deviation: the dev's PR-assignee write was refused by its session's permission classifier. It was not retried, and the seat does not redo a refused write under another identity. It has been raised to the maintainer.
    • Owed before enqueue: the at-tier contract review. needs:contract-review is hung on the PR in this stroke.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 11675,
      "round": "patch 1",
      "status": "done",
      "branch": "claude/issue-11675-week-start-from-locale",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11710",
      "head": "a393686",
      "session": "session_01FngvPpdrnhHMdHHq6vwwju — subagent = parent's (container CLAUDE_CODE_REMOTE_SESSION_ID cse_01FngvPpdrnhHMdHHq6vwwju)",
      "premise_still_valid": true,
      "summary": "CI went red at e4f3430 on this PR's own parity pin. Cause: the table transcribed CLDR 47, while CI's floating 22.x Node ships CLDR 48, where Iceland starts the week on Sunday, and the pin compared the table with whatever CLDR the runtime ships. Fixed at the root in a393686, after merging main (da35453) in the merge commit 98877dd (no rebase, no force-push). The table now declares the release it transcribes (WEEK_DATA_CLDR = '48') and carries IS on Sunday; all three rows equal the CLDR 48 measurement region for region. The parity pin reads the runtime's release from process.versions.cldr and requires the set of table/engine disagreements to EQUAL a measured ledger row for that release (RELEASE_DELTAS: 46 and 47 each record IS on Monday). That set must be empty on the table's own release and on any release the ledger does not list. A rig case and a ledger-honesty case sit beside it. Three official Node builds, checksum-verified, were measured: 22.13.0 (CLDR 46, the engines floor), 22.22.0 (CLDR 47, this container) and 22.23.3 (CLDR 48, CI's 22.x). IS is the only region that differs. The pin is green on all three, and ablations show it red on real drift on every runtime. Every other pin is unchanged in assertion. The PR body needs the seat-applied pr_body_patch below.",
      "tests": "At head a393686, heavy runs through os-verify-lock (slot issue-11675). (1) pnpm exec vitest run --maxWorkers=2 packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/ exited 0 on Node 22.22.0 (CLDR 47): 'Test Files 184 passed (184) / Tests 2283 passed | 145 skipped (2428)'. The same command through node_modules/vitest/vitest.mjs under Node 22.23.3 (CLDR 48, CI's release) exited 0 with the same counts. (2) firstDayOfWeek-11675.test.ts alone: 'Tests 14 passed (14)' on CLDR 46, 47 and 48. (3) The zone driver scripts/__tests__/date-only-zone-pins-10183.test.ts exited 0: 'Tests 27 passed (27)'. (4) type-check for the three packages exited 0. (5) Ablations through objectstack scripts/ablation-replace.mjs, each printing 'ok mutation landed' and 'ok restored: blob == HEAD and git diff HEAD is empty', each run on all three runtimes. A4 (IS removed from the table, i.e. the CLDR 47 content): red on all three; CLDR 48 reproduces CI's shape ('expected { IS: +0 } to deeply equal {}'), 46 and 47 give 'expected {} to deeply equal { IS: 1 }', and the ledger-honesty case is red everywhere. A6 (the ledger's 47 row removed): red on CLDR 47 only ('expected { IS: 1 } to deeply equal {}'), green on 46 and 48. A3 (CLDR table removed): 6 failed / 8 passed on each runtime (round one's 5 plus ledger honesty). A3b (engine path skipped): 2 failed / 12 passed on each runtime (the -u-fw- and getWeekInfo cases). Every observed direction was the predicted one.",
      "gates": [
        {
          "cmd": "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-calendar^...' --filter '@object-ui/plugin-timeline^...' build",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm exec vitest run --maxWorkers=2 packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/ (Node 22.22.0, CLDR 47)",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "node_modules/vitest/vitest.mjs run --maxWorkers=2 packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/ (Node 22.23.3, CLDR 48)",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "vitest run packages/i18n/src/__tests__/firstDayOfWeek-11675.test.ts on Node 22.13.0 (CLDR 46) / 22.22.0 (47) / 22.23.3 (48)",
          "exit": 0,
          "head": "a393686",
          "note": "14 of 14 on each"
        },
        {
          "cmd": "pnpm exec vitest run scripts/__tests__/date-only-zone-pins-10183.test.ts",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm --filter @object-ui/i18n --filter @object-ui/plugin-calendar --filter @object-ui/plugin-timeline run type-check",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm --filter @object-ui/i18n --filter @object-ui/plugin-calendar --filter @object-ui/plugin-timeline run lint",
          "exit": 0,
          "head": "a393686",
          "note": "0 errors; package warning totals unchanged from round one (33 / 146 / 248); both edited files 0 warnings"
        },
        {
          "cmd": "pnpm check:new-line-citations",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:control-bytes",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:changeset-claims",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:pending-changeset-literals",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "node scripts/check-changeset-no-major.mjs",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "node scripts/check-changeset-presence.mjs",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "node scripts/check-changeset-overwrite.mjs",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:unreferenced-sources",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:test-path-roots",
          "exit": 0,
          "head": "a393686"
        },
        {
          "cmd": "pnpm check:readme-exports / pnpm check:doc-snippets",
          "exit": null,
          "head": "a393686",
          "note": "not re-run: no README, doc or changeset text changed this round (the order's condition); round one's readings at e4f3430 were exit 0"
        },
        {
          "cmd": "CI",
          "exit": null,
          "head": "a393686",
          "note": "in_progress: not read; CI convergence is the PM's"
        }
      ],
      "line_budget": "not applicable: the diff touches no skills/** and no governed surface (17 files against da35453, +925 / -41; this round's own change is 2 files, +82 / -20)",
      "files_changed": [
        "packages/i18n/src/utils/first-day-of-week.ts",
        "packages/i18n/src/__tests__/firstDayOfWeek-11675.test.ts"
      ],
      "files_changed_note": "This round's commits are 98877dd (a merge of main at da35453) and a393686 (the two files above). The PR's whole file set against da35453 is the same 17 paths as round one.",
      "deviations": [
        "Measurement inputs: to make the pin deterministic on every supported runtime, I downloaded official Node 22.13.0 and 22.23.3 linux-x64 builds from nodejs.org into fresh directories under my scratchpad issue-11675/runtimes, verified them against nodejs.org's SHASUMS256.txt, and ran the repo's own vitest with them from the repo root. These are reads, not GitHub writes. The verified binaries are kept there for reproduction; the tarballs were deleted.",
        "Ledger rows are measured, not inferred: RELEASE_DELTAS lists only releases measured on a runtime that ships them (46, 47). A runtime shipping an unlisted release must agree with the table entirely, and its failure message names both remedies.",
        "Carried from round one, still the seat's: the PR assignee (os-justin) is unset, because the classifier refused the label-write; and the contract review 6014049550 covers e4f3430 only, so a new at-tier record is needed for a393686.",
        "The PR body says 'a snapshot of CLDR 47' and describes the old parity case, so it is now stale. pr_body_patch gives the exact edits for the seat to apply; I did not PATCH it."
      ],
      "mcp_calls": "0 — no MCP GitHub tool was called",
      "api_writes": "1 — this os-dev-report comment via post-stamped (fleet relay): POST /repos/objectstack-ai/objectui/issues/11675/comments. Not REST: 1 git push (98877dd + a393686). Reads only otherwise: GET of PR comment 6014128933, of pull 11710 (to check the patch anchors), and the nodejs.org downloads.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者: 无 · noted, not filed — CI's node-version '22.x' floats, so any test that reads the runtime's ICU/CLDR data can turn red on main when the runner picks up a newer Node 22 minor, with no repository change. This PR's pin now records per-release differences, so it goes red only when a first day actually moves. Other Intl-reading pins were not surveyed. Dedupe words: node-version 22.x floating, process.versions.cldr, ICU update CI red"
      ],
      "pr_body_patch": [
        {
          "op": "replace",
          "find": "- The table is a snapshot of CLDR 47, generated from Node's ICU. Engines carry their own CLDR release, and releases differ: Chromium 141 starts `AE` on Saturday, CLDR 47 on Monday. That is why the engine's answer wins wherever there is one. A parity case re-derives the table against the running engine, region by region.",
          "replace": "- The table transcribes one CLDR release, declared in the source as `WEEK_DATA_CLDR` (`48`, the release CI's floating `22.x` Node ships), and was generated from Node's ICU. Engines carry their own week data, and it differs: CLDR 48 moved Iceland to a Sunday start, and Chromium 141 starts `AE` on Saturday where Node's CLDR 46, 47 and 48 all start it on Monday. That is why the engine's answer wins wherever there is one. A parity case re-derives the table against the running engine, region by region (see Patch round 1)."
        },
        {
          "op": "replace",
          "find": "- New `packages/i18n/src/__tests__/firstDayOfWeek-11675.test.ts` (12 cases):",
          "replace": "- New `packages/i18n/src/__tests__/firstDayOfWeek-11675.test.ts` (14 cases):"
        },
        {
          "op": "replace",
          "find": "  - a **parity** case: for every region the runtime names, the table answers what the engine answers;",
          "replace": "  - a **parity** case: for every region the runtime names, the regions where the table and the engine disagree must equal exactly the ones a measured ledger (`RELEASE_DELTAS`) records for the runtime's CLDR release, which is none on the table's own release. A rig case and a ledger-honesty case sit beside it;"
        },
        {
          "op": "insert_before",
          "anchor": "## Acceptance notes",
          "text": "## Patch round 1: CI red on the parity pin at `e4f3430`\n\n**Cause.** CI's `node-version: '22.x'` floats to the newest Node 22, which ships CLDR 48.0. In CLDR 48 Iceland's week starts on Sunday. The table transcribed CLDR 47, where `IS` reads the Monday default, and the pin compared it with whatever CLDR the runtime ships. So the pin was green in a CLDR 47 container and red on CI (`IS: engine 0, table 1`), and updating the table alone would only have moved the red to the CLDR 47 runtime.\n\n**Measured runtimes.** Three official Node builds were run, checksum-verified against nodejs.org's `SHASUMS256.txt`: 22.13.0 (CLDR 46.0, the `engines` floor), 22.22.0 (CLDR 47.0) and 22.23.3 (CLDR 48.0, what CI's `22.x` resolves to). Across the three, `IS` is the only region whose first day differs (Monday, Monday, Sunday).\n\n**Shape chosen: a declared release and an exact-equality ledger.**\n- `utils/first-day-of-week.ts` declares the release its table transcribes, `WEEK_DATA_CLDR = '48'`, and the table now carries `IS` on Sunday. All three rows equal the CLDR 48 measurement, region for region.\n- The pin reads the runtime's release from the major part of `process.versions.cldr`. The set of regions where the table and the engine disagree must EQUAL `RELEASE_DELTAS[release]`, a ledger in the test whose rows were measured on those runtimes (`46: { IS: Monday }`, `47: { IS: Monday }`). On the table's own release, and on a release the ledger does not list, that set is empty.\n- Why equality, not \"every disagreement is listed in the delta\": a subset check would stay green on a CLDR 46 or 47 runtime if Iceland were reverted in the table, because the disagreement simply disappears there. Equality goes red for that edit on every runtime, and also when a recorded row stops holding.\n- Why an empty set for an unlisted release: such a runtime is green when it agrees with the table, and red, naming each region and the remedy, when its CLDR moves a first day. That red is the real drift signal. A new release that moves nothing does not go red.\n- Not chosen: skipping the comparison when the release differs. That would turn the pin into a no-op on two of the three supported runtimes.\n- What remains: when CI's Node moves to a CLDR release that moves a first day, this pin goes red until the table or the ledger is updated. That is the drift the round asked to keep catching, and the failure message names both remedies.\n\n**Ablations on the new head**, each through `scripts/ablation-replace.mjs`, each with the mutation proven landed and the restore proven (`blob == HEAD`, `git diff HEAD` empty), and each run on all three runtimes:\n\n| Leg | Mutation | CLDR 46 | CLDR 47 | CLDR 48 |\n| --- | --- | --- | --- | --- |\n| A4 | Iceland removed from the table (back to CLDR 47 content) | red: parity and ledger honesty | red: parity and ledger honesty | red: parity (CI's shape, `{ IS: 0 }` found) and ledger honesty |\n| A6 | the ledger's `47` row removed | green | red: `{ IS: 1 }` found, `{}` expected | green |\n| A3 | the CLDR table removed | 6 red | 6 red | 6 red |\n| A3b | the engine path skipped | 2 red | 2 red | 2 red |\n\n**Re-run at `a393686`** (after merging `main` at `da35453` in `98877dd`, a merge commit; no rebase, no force-push):\n- `pnpm exec vitest run --maxWorkers=2 packages/i18n/ packages/plugin-calendar/ packages/plugin-timeline/` exited 0 on CLDR 47: 184 files, 2283 passed, 145 skipped. The same suites under Node 22.23.3 (CLDR 48, CI's release) exited 0 with the same counts.\n- `firstDayOfWeek-11675.test.ts` alone: 14 of 14 passed on CLDR 46, 47 and 48.\n- The zone driver `scripts/__tests__/date-only-zone-pins-10183.test.ts` exited 0, 27 passed.\n- `type-check` and `lint` for the three packages exited 0. The package warning totals are unchanged, and both edited files have 0 warnings.\n- `check:new-line-citations`, `check:control-bytes`, `check:changeset-claims`, `check:pending-changeset-literals`, `check-changeset-no-major`, `check-changeset-presence`, `check-changeset-overwrite`, `check:unreferenced-sources` and `check:test-path-roots` each exited 0.\n- No README, doc or changeset text changed this round, so `check:readme-exports` and `check:doc-snippets` were not re-run.\n\n"
        }
      ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT (patch round 1): PR objectui#11710 at a393686 (Fixes #11675). A new at-tier contract review is owed before enqueue

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T11:16Z. Dev report: the round-1 os-dev-report on this card. This supersedes the seat's ACCEPT 6013900089 (at e4f3430) for the new head. Contract review 6014049550 covers e4f3430 only.

    • Shape: still draft, base main, first line Fixes #11675, Clause-②: yes at the start of a line. 17 files against da35453, +925/−41. NOT GOVERNED. This round's commits: 98877dd merges main at da35453 (a merge commit; no rebase, no force-push), and a393686 touches two files (utils/first-day-of-week.ts, __tests__/firstDayOfWeek-11675.test.ts).
    • The round's fix, read by the seat:
      • The table declares the release it transcribes, WEEK_DATA_CLDR = '48', and adds IS to the Sunday row.
      • The parity pin compares the set of table/engine disagreements, by exact equality, with RELEASE_DELTAS[major(process.versions.cldr)]: 46 and 47 record IS on Monday, measured on Node 22.13.0 and 22.22.0, and the table's own release expects none. A rig case and a ledger-honesty case sit beside it.
      • The pin is not skipped or loosened. Equality stays red on every runtime when the table is edited away from its release, when an unrecorded region moves, and when a recorded row stops holding. The dev's A4 / A6 / A3 / A3b ablations, each on CLDR 46, 47 and 48 and each restored by blob, show it.
    • Surface: the entry is unchanged from round one (firstDayOfWeek, WeekdayIndex). WEEK_DATA_CLDR is a module export that the test imports. It is not re-exported from src/index.ts, and the entry's type graph does not reach it. Published behaviour moves by one region: the table path, used where the engine has no week info, starts is-IS on Sunday, which is CLDR 48. The changeset prose names no CLDR release, so it still holds sentence by sentence. The PR body's CLDR 47 sentence and parity description are corrected in this stroke from the dev's pr_body_patch, with a "Patch round 1" section added.
    • CI on a393686: 43 check-runs, 40 success and 3 skipped, 0 failed. Test (shard 4/8), red at e4f3430, is green.
    • Out-of-scope finding, Acceptance note, not filed: CI's floating node-version: '22.x' can turn any Intl-data pin red with no repository change. This pin now records per-release differences; other Intl-reading pins were not surveyed.
    • Still the maintainer's: the PR assignee is unset, because the dev's label-write was refused by its session's classifier. It is not redone under another identity.
    • Owed before enqueue: an at-tier contract review on a393686. needs:contract-review is hung on the PR in this stroke.

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11710 → main 9ca3cac, verified by content. Fixes closed this card

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T11:48Z.

    • The merge. Squash 9ca3cac went through the merge queue, with one parent, abd374b, and is an ancestor of origin/main. 17 files, +925/−41. Its diff against the parent is byte-identical to the PR's net diff at a393686 (md5 2c501b13… on both, same 17 paths). Contract review 6015247684 PASS, on the landed head a393686.

    • Content check against the first parent:

      reading abd374b 9ca3cac
      firstDayOfWeek in packages/i18n/src/index.ts 0 1
      WEEK_DATA_CLDR = '48' in utils/first-day-of-week.ts absent 1
      firstDayOfWeek in plugin-calendar's CalendarView.tsx 0 2
      firstDayOfWeek in plugin-timeline's ObjectTimeline.tsx 0 3
    • Closures. Fixes #11675 closed this card as completed at the merge. No other issue closed in the landing window. pm:dispatched comes off in this stroke.

    • Unblocked: objectui#11676's remainder (retiring timeline.bucket.overdue) was serialised behind this PR's ObjectTimeline.tsx. It can now be dispatched.

    • Recorded, not filed:

      • CI's floating node-version: '22.x' can turn an Intl-data pin red with no repository change. This pin now records per-release differences.
      • The date pickers on the Calendar primitive outside the calendar keep date-fns's week start, with no reach reading at a field door.

    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

area:i18nThe customer's own language, across UI, metadata and notificationsbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions