fix: show one year instead of 12 months in relative timestamps#3174
Conversation
Listings updated 360-364 days ago rendered as "12mo ago" because 30-day months do not tile a 365-day year, leaving a five-day gap that still divided into twelve whole months. Derive years from whole months so they roll over at 12, matching formatRelativeUpdatedAt in routes/user/$handle.tsx, which already caps months at 11.
|
@Yigtwxx is attempting to deploy a commit to the OpenClaw Foundation Team on Vercel. A member of the Team first needs to authorize it. |
|
Codex review: needs maintainer review before merge. Reviewed July 19, 2026, 5:09 AM ET / 09:09 UTC. Summary Reproducibility: yes. source-reproducible with high confidence: a fixed Review metrics: 2 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Merge the focused helper and regression tests if routine CI remains clean, preserving the shared 12-month rollover convention between the relative-time renderers. Do we have a high-confidence way to reproduce the issue? Yes, source-reproducible with high confidence: a fixed Is this the best way to solve the issue? Yes. Deriving the year branch from the helper's existing whole-month calculation is the narrowest maintainable solution and matches the sibling formatter convention cited in the PR. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against aaa73625ed41. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: fix: show one year instead of 12 months in relative timestamps This is item 1/1 in the current shard. Shard 10/20. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
Patrick-Erichsen
left a comment
There was a problem hiding this comment.
This fixes the shared relative-time helper so ClawHub never renders 12mo ago; at 12 whole 30-day months it now rolls over to 1y ago, matching the publisher-profile formatter.
LOC: +70/-7 (2 files)
No blocking findings.
Best-fix verdict: best. The change updates the owner helper used by skill rows, skill/plugin details, browse results, dashboard views, and GitHub sync settings. Deriving years from the same 30-day month convention is the narrowest fix that also agrees with formatRelativeUpdatedAt.
Boundary review: 359d -> 11mo, 360d -> 1y, 364d -> 1y, 365d -> 1y, and later 12-month rollovers remain internally consistent. Future timestamps still return just now. The output remains the existing locale-independent compact English format; this PR does not add or remove localization behavior.
Alternatives considered: clamping only the literal 12mo case would preserve two competing year units and let the helpers disagree; consolidating both formatters would be a broader refactor than this bug requires.
Code read: src/lib/timeAgo.ts, its new boundary tests, all production callers, src/routes/user/$handle.tsx, and the adjacent profile/list-item tests.
Validation on 39f424e9b06ab5509aae32a9705cb5417eca62e3:
- focused consumers: 3 files, 29 tests passed
bun run ci:static: passedbunx tsc --noEmit -p tsconfig.json: passedbun run ci:unit: 4,803 passed, 1 skipped, with one unrelatedpackage-detail-routeresponsive-layout timeout; that test passes immediately in isolation on both the exact PR head and a clean synthetic merge with currentmain- synthetic merge with current
main57d1e1530b5517d01c916a032efd1653abe691c9: conflict-free; the same 29 focused tests passed
Provenance: the mixed 30-day-month/365-day-year helper was introduced by Vincent Koc in commit 150470820838 through #1567 (PR author BunsDev, merged April 7, 2026). Current fix author: Yigtwxx.
Remaining uncertainty: GitHub's Vercel status is red only because the fork author is not authorized for the OpenClaw Foundation team preview. No preview is needed to validate this deterministic text-only helper change.
What Problem This Solves
Fixes an issue where listings last updated between 360 and 364 days ago displayed
"Updated 12mo ago" instead of "Updated 1y ago".
timeAgomeasures months as 30 days but years as 365 days. Those two units do nottile: 360-364 days still divides into twelve whole 30-day months while remaining
below the 365-day year threshold, so the month branch renders a twelve-month value
that should already have rolled over into years.
The affected surfaces are the skill list rows, skill header, browse results, plugin
detail page, dashboard catalog and needs-attention views, and the GitHub sync
timestamp in settings.
Why This Change Was Made
The repository already contains the intended semantics.
formatRelativeUpdatedAtin
src/routes/user/$handle.tsxderives years from whole months and caps the monthbranch at 11:
timeAgois now aligned with that rule, so the two relative-time renderers agree atthe one-year boundary. Deriving years from months also removes the unit mismatch at
its source rather than special-casing the twelve-month output.
Non-goals, kept out to hold the change to one concern:
timeAgoandformatRelativeUpdatedAtinto a single helper. Theyare now consistent; merging them is a separate refactor.
clamping the difference would be a no-op here.
User Impact
Relative timestamps no longer show a twelve-month value. A listing that has not been
updated for just under a year now reads "1y ago", matching what the publisher profile
route has always shown for the same listing.
Evidence
Added
src/lib/timeAgo.test.ts, which had no test coverage before this change eventhough
src/lib/**is inside thevitest.config.tscoverageincludelist.The new boundary case fails on the parent commit and passes with the fix:
The other five cases pass on both sides, so the existing minute, hour, day, week and
month branches are unchanged.
Rendered
SkillListItemoutput, reading.skill-list-item-meta-item.is-updatedfromthe mounted component with the clock fixed at 2026-06-23T12:00:00Z:
Regression check on the consumers and on the sibling renderer:
Gates run locally on Windows:
bun run format:check -- src/lib/timeAgo.ts src/lib/timeAgo.test.ts— cleanbun run lint— cleanbunx tsc --noEmit -p tsconfig.json— cleanbun run deadcode:ci— cleanbun run ci:unit— 4722 passed. The 22 failures are pre-existing on this platformand unrelated to this change: they are
spawn bun ENOENTin the worker andsecurity-dataset suites plus the design-contract and management route suites. I
confirmed they fail identically on the unmodified parent commit, so I have left
them alone. CI on Linux is the authoritative signal here.
The Vercel preview check will need OpenClaw Foundation team authorization, as with
other fork pull requests.