chore(plugin-timeline): retire the five dead timeline.relative.* default rows (objectui#7874) - #7887
Merged
Conversation
…fault rows (objectui#7874)
The five rows had no `en` leaf and no call site anywhere in the tree, so
`fallbackT` could never be asked for one — they rendered for nobody. Day
granularity relative phrases come from `formatRelativeDate` in `@object-ui/core`
through `Intl.RelativeTimeFormat`, which needs no copy row; that is what left
these behind.
Deleted rows, transcribed verbatim so the deletion is reversible from the record
rather than from git archaeology:
'timeline.relative.today': 'Today',
'timeline.relative.tomorrow': 'Tomorrow',
'timeline.relative.yesterday': 'Yesterday',
'timeline.relative.inDays': 'In {{n}} days',
'timeline.relative.daysAgo': '{{n}} days ago',
A retirement pin replaces them: no i18n gate in this repo can see a dead row come
back (each runs call site -> key, pack -> pack, or pack -> call site), so the pin
is the only guard against a silent revival.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Sep 6, 2026
os-sam
marked this pull request as ready for review
September 6, 2026 01:40
This was referenced Sep 6, 2026
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7874
The PM ruling is delete, as residue: the five
timeline.relative.*rows inTIMELINE_DEFAULT_TRANSLATIONShave no reachable path, and no product behaviour attaches to code nothing can reach. Wiring relative dates throught()would be a new feature (copy, plural rules, ten-pack coverage), not the other half of this question.One row deleted from
packages/plugin-timeline/src/useTimelineTranslation.ts, a retirement pin added beside it, and an empty-frontmatter changeset declaring that nothing releases. Measured onorigin/mainat83fe6e741; branch head3ac057309.1. The five rows, transcribed verbatim
The deletion is safe because it is reversible, and it is reversible because the content is written down here (and in the pin test, and in the changeset) - not because "it is in git history somewhere":
2. Escape hatch: "zero callers" re-verified on current main, by PREFIX, with a positive control
Re-measured on this branch's base rather than inherited from the card.
By prefix, not by the five full key names, because a dynamically assembled key (
t(`timeline.relative.${x}`)) is invisible to a literal search for the complete names. Two passes, both returning exactly the five declaration lines and nothing else:node_modules/distexcludedgit grep -n --untracked -I -e 'timeline\.relative'useTimelineTranslation.ts:26-30node_modulesand.gitexcludedrg -n --no-ignore --hidden -g '!node_modules' -g '!.git' 'timeline\.relative'Positive control - the same command shape, on keys that DO have callers. A search that has not been shown to fire is not a measurement:
timeline.bucket.overdueObjectTimeline.tsx:421timeline.scale.weekrenderer.tsx:163(plus its pin test)timeline.gantt.rowLabelrenderer.tsx:1499Dynamic assembly, checked as its own question, not as a by-product of the prefix search:
git grep -nE '\bt\(' -- 'packages//src' 'apps//src'` returns nothing (exit 1).timeline.*key:`timeline.,'timeline.' +,"timeline." +,timeline.${- every hit is prose in a comment or a spec key liketimeline.startDateField, none of them a key handed tot().'daysAgo'isapps/console/src/pages/system/ApprovalsInboxPage.tsx:653, whose localtrresolvest(`approvalsInbox.${key}`)- a different namespace, and its own module-local defaults.TIMELINE_DEFAULT_TRANSLATIONSindexes a named key (timeline.scale.*,timeline.gantt.*); none iterates it or pins its size.Why they are residue, positively rather than by absence. Day-granularity relative phrases are produced by
formatRelativeDate/formatRelativeDaysin@object-ui/core(utils/date-display.ts) throughIntl.RelativeTimeFormat, whose output for theenlocale is literally "Today" / "Tomorrow" / "Yesterday" / "in 3 days" / "3 days ago". A formatter that derives the words from the locale needs no copy row in any pack - that is what left these five behind.Also worth recording:
TIMELINE_DEFAULT_TRANSLATIONSandtranslateTimelineDefaultare not re-exported from the package entry (src/index.tsxre-exports./renderer, which imports them without re-exporting). No consumer of the published tarball can name them, so the deletion cannot move a published API surface either.3. The three instruments: none of them moved
Expected none, measured none. Before and after are the same commands on the same tree, run either side of the edit:
check:i18n-dead-keys(pack keys with no call site)diffof the two full reports is empty - byte-identical, all 1143 linesall-locales-key-parity.test.ts)check:i18n-keys)diffof the two full reports is emptyThat is exactly the card's reading, and it is why these rows survived: class 1 judges call sites (they had none), parity compares packs to each other (ten packs identically lacking a key is full parity), and the reverse sweep judges pack keys (these were in no pack). They were caught by objectui#7567's census printing its abstention count - 5 of 846 factory-table rows - not by any rule judging them.
Two neighbours measured for the same reason, also unmoved:
check:i18n-driftreports0 en value(s) changed (0 key(s) added, 0 removed), andfallback-placeholder-spelling-3512.test.ts- which walks this exact table - stays green.One reading the card did not have, and it goes the other way. There IS a rule in this repo that rejects a defaults row whose key no pack defines:
defaults-maps-mirror-en-pack.test.tsx(objectui#4401), "every row names a key the en pack actually defines". It did not fire because itsMAPSlist is three hand-written entries - detail, list, designer - andTIMELINE_DEFAULT_TRANSLATIONSis not among them. So the blind spot is a fourth gate's coverage, not a fourth gate's absence. Filed separately as #7884; out of scope here, and it changes nothing about this deletion.4. Changeset: the checker's verdict, quoted
Not guessed.
node scripts/check-changeset-presence.mjsfirst refused the change with no changeset:.changeset/7874-timeline-relative-defaults-retired.mdwas added with an empty frontmatter, because nothing reachable changes and nothing published moves (see the export note in section 2). The checker then answered, verbatim:check-changeset-no-major.mjs:✅ No changeset declares a major bump.5. Clause-② stays
noNo key added, no published export moved, no gate predicate or scan population touched. The governed-surface check agrees, on this commit's three paths:
The pin, and the ablation that shows it fires
packages/plugin-timeline/src/__tests__/timeline-relative-defaults-retired-7874.test.tsfollows the retirement-pin series (objectui#4392 / #4730 / #5504 / #6310 / #7125): the retired rows asserted absent by key and by prefix, the exportedtranslateTimelineDefaultasserted to answer a retired key with the raw key rather than its old string, and surviving-sibling assertions so a green cannot be bought by deleting the neighbourhood.timeline.bucket.todayandtimeline.bucket.tomorrowcarry the same two strings the retired rows did, so a sweep by VALUE takes them out as collateral - they are pinned for exactly that reason.The pin exists because no gate can see a dead row come back: each of them runs call site to key, pack to pack, or pack to call site.
Ablation - the rows re-inserted, then restored, with both legs proven on disk rather than by an exit code. No rebuild leg is needed here and none was run: the test imports
../useTimelineTranslationby relative path inside its own package, so vitest compiles the source, with noexports/distindirection to go stale.The mutating script carried
trap restore EXIT INT TERMwith an absolute path resolved fromgit rev-parse --show-toplevel, and both legs were verified by state (blob hash, row count, emptygit diff HEAD), never by the editor's exit code.What ran, on the pushed SHA
3ac057309withgit diff HEADemptypnpm exec vitest run packages/plugin-timeline/ packages/i18n/src/__tests__/all-locales-key-parity.test.ts packages/i18n/src/__tests__/fallback-placeholder-spelling-3512.test.ts packages/app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsxTest Files 26 passed (26)/Tests 353 passed (353)(the timeline package alone: 23 files / 291 tests, from 22 / 287 before)pnpm --filter @object-ui/plugin-timeline run type-checktsc --noEmit && tsc -p tsconfig.test.json).--listFilesconfirms the new test file is IN the program - a typecheck that excluded it would be a true sentence about nothingcheck:changeset-presence/check:changeset-no-major/check:control-bytes/check:i18n-keys/check:i18n-drift/check:i18n-dead-keys/check:unreferenced-sources/ governed-queue-guardeslint --no-inline-configon the two changed source files2 files linted, 0 errors, 0 warningsOn the lint narrowing (two files rather than the repo sweep, which CI runs anyway): the population came from eslint's own resolution of the two paths, the file count is read off
--format json, and this repo's flat config is not type-aware -tseslint.configs.recommended, noparserOptions.projectand noprojectService- so this diff cannot move the verdict on any file it does not touch. That makes the narrowing a measurement rather than a skip.🤖 Generated with Claude Code
https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Generated by Claude Code