Skip to content

settings(localization): retire date_format, time_format, number_format and first_day_of_week from the Localization manifest — no renderer honours them; formats follow the locale (ruled on objectui#11675, B) #21958

Description

@objectstack-fleet

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

Filed by the triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U, executing the maintainer's ruling on objectstack-ai/objectui#11675. Provenance: the maintainer, in the triage seat's live chat (session_01AavokzJ5DndAwitDXvKy4U), answering decision batch 2 (director format), verbatim: 「同意」, for item 1, which recommended B. ⛔ Not a claim, ⛔ not a dispatch.

Triage: lands in packages/services/service-settings/src/manifests/localization.manifest.ts (the four rows, about :84–:120) and its translations/*.ts ⇒ domain:services; rationale: the settings page offers four controls that nothing reads.

Ruled

Dates, times, numbers and the first day of the week follow the locale (language and region), as Salesforce derives formats from the user's Locale. The four separate format settings are retired. ⛔ They are not implemented.

Read before filing (main)

  • objectstack: no server reader of the four keys. The only matches are SQL's own date_format() in driver-sql, an export transform enum value, and comments.
  • objectui: no renderer reads them (objectui#11672's sweep, re-verified for objectui#11675).
  • cloud and hotcrm: no reader.

Done when

  • The four rows and their translation entries leave the manifest. timezone, locale, default_country, currency and fiscal_year_start stay.
  • Stored values: the dev measures how a stored value of a retired key is treated on read and write after removal, and states it. Any stored row is kept, never silently dropped. If the settings contract requires a retirement or migration entry for a removed key, it is added in the existing shape.
  • The settings docs, if they list the four, are updated.
  • Pin: GET /api/settings/localization and the Setup → Localization form no longer offer the four keys.
  • The calendar and timeline week start following the locale is objectui#11675's own remainder, not this card's.

bug · priority:p2 · pm:queue.


Generated by Claude Code

Activity

objectstack-fleet commented on Oct 6, 2026

@objectstack-fleet
ContributorAuthor

Claim: PM loop round 1 · 2026-10-06T07:29Z
Session: session_01WMQprn46CND82KmY8sZWBu
Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-21958-retire-locale-format-settings
Worktree: objectstack-issue-21958
Domain: domain:services
Seat: domain:services#2 (seat post #21118)
Ruling-ref: objectstack-ai/objectui#11675 comment 6010771237, read in this act: the maintainer's 「同意」 on decision batch 2, item 1, B.
File surface (at origin/main 80f9f7e6ba):

Clause-②: no (narrowing): four offered settings keys leave the published manifest, and no accepted shape widens. How a stored value of a retired key reads and writes afterwards is measured and stated, and the row is kept, never silently dropped, as the card's "Done when" requires.


Generated by Claude Code

objectstack-fleet commented on Oct 6, 2026

@objectstack-fleet
ContributorAuthor

os-dev-report
{
"issue": 21958,
"status": "done",
"branch": "claude/issue-21958-retire-locale-format-settings",
"pr": "#21970",
"session": "session_01WMQprn46CND82KmY8sZWBu (shared, mode:subagent; parent's harness-stamped id)",
"premise_still_valid": true,
"summary": "date_format, time_format, number_format and first_day_of_week leave localizationSettingsManifest together with the now-empty 'formats' group. Their entries and the formats group leave the en, es-ES, ja-JP and zh-CN bundles. The namespace description now reads 'Default timezone, language, country, currency, and fiscal year.' timezone, locale, default_country, currency and fiscal_year_start are unchanged. The manifest version goes from 1 to 2: the spec's SettingsManifestSchema.version describe/TSDoc is the settings contract's only retirement entry ('Increment when keys are renamed/removed.'); no spec edit, and nothing reads version in objectstack or objectui. Stored values, measured through the real REST handlers on origin/main 80f9f7e (simulated retirement over a store holding a date_format row) and on the branch, with identical answers. The row is KEPT and never deleted. GET /api/settings/localization neither serves nor resolves the key. A PUT naming it is refused 400 UNKNOWN_KEY (details.namespace/key), whole-batch. A save of the live keys succeeds over the stale row. The reset action clears only the live keys. In-process get rejects SETTINGS_UNKNOWN_KEY. A rollback re-registration reads the row back unchanged. OS_LOCALIZATION_DATE_FORMAT and the other three are no longer read, silently. No service code changed: this is the existing undeclared-key path, now pinned at the REST surface. Docs: no content/docs page lists the four (searched outside references/ and releases/), so there are no doc edits. The skills/** hits are SQL's date_format() in objectstack-query/rules/aggregation.md:82 and objectstack-ui/rules/dashboards.md:327, not the settings key.",
"files_changed": [
".changeset/21958-retire-locale-format-settings.md",
"packages/services/service-settings/src/manifests/localization.manifest.ts",
"packages/services/service-settings/src/manifests/localization.manifest.test.ts",
"packages/services/service-settings/src/translations/en.ts",
"packages/services/service-settings/src/translations/es-ES.ts",
"packages/services/service-settings/src/translations/ja-JP.ts",
"packages/services/service-settings/src/translations/zh-CN.ts",
"packages/services/service-settings/src/translations/settings-translation-coverage.test.ts",
"packages/services/service-settings/src/settings-service.test.ts",
"packages/services/service-settings/src/settings-routes.test.ts"
],
"tests": "head 397edab, the final commit; gates run after it. Build: dependency closure pnpm --workspace-concurrency=2 --filter '@objectstack/service-settings^...' build, VERDICT command-exit 0; then pnpm --filter @objectstack/service-settings build, exit 0. pnpm --filter @objectstack/service-settings typecheck: exit 0 (tsc --noEmit; --listFiles shows 36 test files compiled, including all 4 edited). pnpm --filter @objectstack/service-settings test: 'Test Files 36 passed (36) / Tests 626 passed (626)', VERDICT command-exit 0. The built dist serves version 2 and keys timezone,locale,default_country,currency,fiscal_year_start through both require('./dist/index.cjs') and import('./dist/index.js'). Gates: dispatch-gates --commands --repo objectstack-ai/objectstack re-derived 63 on the final tree, the dispatch's 49 plus 14: adr-0087-registration x2, empty-changeset x2, release-rehearsal-clone/release-pending-publish self-tests, engine-double-contract, objectql-double-limit, objectui-changeset, pm-changeset-deadline-census, query-options-erasure, type-check-coverage, type-check-debt, where-matcher. Results: 62 exit 0; pnpm check:dual-build-cjs-loads exit 3, PREREQUISITE NOT MET (53 packages outside the closure have no dist/), NOT MEASURED, reason: CI's full build owns it, with the direct CJS load above as the narrowed substitute. --ran reconciliation (exit codes recorded): '63 derived, 62 run, 1 NOT-MEASURED, 0 UNRUN'. check-adr-0087-registration: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition ... not-required (no-migration-prescription)'. check-changeset-no-major: 'This diff introduces no major bump'. ESLint narrowed: eslint --no-inline-config --format json over the 9 touched .ts files gave 9 files linted, 0 errors, 0 warnings. Population is **/.{ts,...} per eslint.config.mjs, and the config enables no type-aware linting, so untouched files' verdicts cannot move. Ablation via scripts/ablation-replace.mjs, nothing built (the subject is the package's own src, imported relatively; vitest aliases resolve to source). (A) date_format row re-inserted into the manifest: on-disk count 1, blob e8f3039af917 to 38665aa77765. 8 red: 3 new route pins, the 'five keys' and 'offers none of the four' manifest pins, and zh-CN/ja-JP/es-ES coverage. Restored blob == HEAD e8f3039af917 and git diff HEAD empty. A first attempt was a refused no-op, because the replacement contained its anchor; nothing was measured on it. (B) date_format: {label} re-added to en.ts: on-disk count 1. The reverse pin went red: 'en has undeclared settings copy: localization.key:date_format'. Restored blob == HEAD 0b0918e9ece5, git diff HEAD empty. Direction observed: red, as expected. The refusal pin asserts status 400 + error.code UNKNOWN_KEY + error.details.",
"mcp_calls": "0",
"api_writes": "3 REST writes, each through the fleet-write relay as objectstack-fleet[bot] (each is one POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, draft #21970, read back byte-identical (10063 bytes); (2) label-write --assign os-warren, POST /repos//issues/21970/assignees, read back MATCHES; (3) this os-dev-report comment, POST /repos//issues/21958/comments. Plus git push x3 (the empty branch probe and 2 commits), which is not REST. Reads used plain gh api: scripts/pm/with-fleet.sh --read refused with exit 3 because auto resolves to dispatch in this cloud container.",
"deviations": [
"Test surface beyond the three named files. The stored-value pins live in src/settings-routes.test.ts, inside service-settings, because that file already holds the REST harness and the seedGlobalSecret store-level seeding precedent. settings-translation-coverage.test.ts gained the reverse direction (no copy for an undeclared group/key, en included), which measured zero such entries across all ten manifests and closes the class.",
"version 1 to 2 is a judgment. The spec contract text is the only 'retirement entry' the settings contract names, there is no packages/spec edit, and the bump is pinned in localization.manifest.test.ts.",
"Same-docblock accuracy fix: localization.manifest.ts named resolveExecutionContext, which no longer exists. It now names resolveLocalizationContext (@objectstack/core) and says it reads timezone, locale and currency.",
"Mechanism hypothesis 3 partly falsified: settings-routes.ts:25 cites envelope siblings retired from the route module, not a settings key. settings-service.ts ~:920 is retired mail.provider OPTION values. Measured over an unshallowed history (15,821 commits): no settings key ever left a manifest before, and no manifest version was ever above 1.",
"History deepening: git fetch --deepen=20000 origin main in the shared clone, to measure the precedent. This changes the common object store and the shallow file, not any branch or worktree.",
"pnpm check:dual-build-cjs-loads NOT MEASURED (exit 3, PREREQUISITE NOT MET); declared narrowing, CI runs it."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted in PR Acceptance notes, not filed: an OS_LOCALIZATION_
variable naming a retired key (or any undeclared key, e.g. a typo) is silently unread. No namespace audits undeclared OS_ variables. Pre-existing, general, and never read before either.",
"carrier: none · noted, not filed: SettingsManifest.version has no reader in objectstack or objectui (grep manifest.version over the settings code), so the 'increment when keys are renamed/removed' contract is declared but unenforced. No pull.",
"carrier: whoever next edits objectui apps/console/src/pages/settings/tests/SettingsField.valueDomain.test.tsx (objectui#11675 remainder possibly) · noted, not filed: it uses date_format/first_day_of_week as hand-built fixture keys, does not import this manifest, and stays green."
]
}


Generated by Claude Code

objectstack-fleet commented on Oct 6, 2026

@objectstack-fleet
ContributorAuthor

Review: PR #21970 at 397edabf04 · seat domain:services#2 (#21118) · session_01WMQprn46CND82KmY8sZWBu · 2026-10-06T08:20Z

ACCEPT (verdict on the dev report 6012265052). Checked against the PR, not the report:

  • Shape: draft, base main. Line 1 is Fixes #21958 and line 2 Clause-②: no (narrowing). No other closing keyword appears, and the body carries no HTML comment. Not governed (check-governed-merges.mjs --pr 21970), 316 changed lines.

  • What moved, read in the diff: the four rows and the emptied formats group leave localizationSettingsManifest. Their copy leaves en, es-ES, ja-JP and zh-CN. timezone, locale, default_country, currency and fiscal_year_start are untouched. version goes from 1 to 2, under the spec's own SettingsManifest.version contract ("increment when keys are renamed/removed"), with no packages/spec edit. The namespace description now names what remains. No service code moved.

  • Stored values, the card's judgment, pinned at the REST surface (settings-routes.test.ts, with rows seeded store-level the way seedGlobalSecret is):

    • GET neither offers nor resolves the four;
    • a PUT naming one is refused 400 UNKNOWN_KEY with details.key, the existing answer for any undeclared key;
    • the stored rows read back unchanged after read, write and reset;
    • a save of the live keys succeeds over them.

    This matches the ruling and the card's "kept, never silently dropped".

  • The new reverse coverage pin (settings-translation-coverage.test.ts: no bundle carries copy for an undeclared group or key) is a test pin inside the existing coverage suite, not a gate. It measured zero across all ten manifests. Accepted.

  • Ablations: a re-inserted row turned 8 cases red, and re-added en copy turned the reverse pin red. Both were restored by blob.

  • Changeset sentences checked against the diff: the title; the BREAKING paragraph (four specifiers and the Formats group, four bundles, Setup and GET, the ruling, the five live keys, version 2); each stored-value bullet (row kept, GET absent, PUT 400 UNKNOWN_KEY whole-batch, save and reset, in-process SETTINGS_UNKNOWN_KEY, OS_LOCALIZATION_* no longer read); "What to do after upgrading". minor with the BREAKING banner, ADR-0087 not-required.

  • Docs: no content/docs/** page lists the four. The seat's own read at 80f9f7e6ba agrees: the only hit is references/api/export.mdx's unrelated transform: 'date_format'. The two skills/** hits are SQL's date_format(), not these keys.

  • Writes: mcp_calls 0, and 3 relay writes.

  • CI at review: 15 success, 3 skipped and 13 in progress on 397edabf04. The seat lands it once every check is green.

out_of_scope_findings: all three → Acceptance notes:

  • an OS_LOCALIZATION_* variable naming an undeclared key is silently unread;
  • SettingsManifest.version has no reader;
  • objectui's SettingsField.valueDomain fixture keys.

objectui#11675's remainder (the calendar and timeline week start) stays with objectui.


Generated by Claude Code

objectstack-fleet commented on Oct 6, 2026

@objectstack-fleet
ContributorAuthor

Landed · domain:services seat 2 (#21118) · session_01WMQprn46CND82KmY8sZWBu · 2026-10-06T09:25Z


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:servicespriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions