Repository navigation
fix(status): reopen a status whose preset deadlines coincide as Today - #3449
Conversation
statusDuration infers the duration preset from a saved expiry by taking
the preset whose deadline is closest to it, iterating 1 hour, 8 hours,
Today and This week with a strict `<`. At exactly 16:00 local time the
8 hours and Today deadlines are the same midnight, and the earlier-listed
8 hours won the tie, so a Today status saved in that second reopened as
"Duration: 8 hours". Flake check (webkit, 2/9) job 129271665827
(2026-11-09) failed user-status.spec.mjs:116 this way. The triage read
the re-run's artifact; the failed attempt's own artifact (13688728980)
has the trace, and it puts the first Save status click at 16:00:00.559
UTC, so created_at was 16:00:00 and the expiry midnight. The same tie
occurs for 1 hour at 23:00, and on a Sunday This week ends at the same
midnight as Today.
Let Today win a tie. The stored expiry is the same either way; the label
the editor shows now matches the deadline it describes, and a re-save
without changing the duration keeps that expiry. Today already won the
Sunday tie with This week by list order and still does, so a This week
status saved on a Sunday reopens as it did before. An hour preset can
only tie with the midnight that is also Today's, so preferring Today
covers every tie; the 121 s tolerance and the custom fallback are
unchanged.
Unit coverage: status-duration.test.ts gains the 16:00 and 23:00 ties,
the Sunday three-way tie, and the Sunday Today/This week tie. On the
unfixed code the first assertion fails with '28800'; with the fix the
file's 3 tests and all 29 tests under src/features/user-status pass.
Verified with `bin/pnpm test:browser:ci --project webkit --no-deps
--workers=1 --repeat-each=8 --reporter=list
tests/browser/user-status.spec.mjs`: 8/8 passed (12.5-12.8 s each,
1.8 m). The spec only meets the tie in the 16:00:00 UTC second, so a
scratch copy truncated after the reopen check, with
`page.clock.setFixedTime("2026-11-12T16:00:00Z")` before the first save,
served as evidence: HEAD's status-duration.ts fails it with the CI error
(Expected "Duration: Today", Received "Duration: 8 hours"), the fix
passes it. The scratch is not kept: the unit case is the gate, and a
fixed clock would change the rest of the spec's timing. Biome and
tsc --noEmit are clean.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Signed-off-by: mtoohey <[email protected]>
Signed-off-by: Matt Toohey <[email protected]>
The Today tie-break fired whenever a preset's distance equalled bestDistance, which starts at the 121 s tolerance, so a saved expiry exactly 121 s from midnight reopened as Today where it was custom before the tie-break was added, although that change's message said the tolerance was unchanged. Restrict the tie to presets (best !== "custom"), so a tie can only occur at a distance already under the tolerance. The new unit expectation (midnight + 121 saved at 18:00 is "custom") fails on the unfixed code with 'today' and passes with the fix. Verified as part of the combined review follow-up, before it was split by path: - bin/pnpm exec vitest run src/features/user-status: 29 passed. - biome check --error-on-warnings on the touched files and tsc --noEmit are clean. Co-Authored-By: Claude Fable 5.1 <[email protected]> Signed-off-by: mtoohey <[email protected]> Signed-off-by: Matt Toohey <[email protected]>
kazemek21
left a comment
There was a problem hiding this comment.
I reviewed the PR and went through the Nexus review-tracker notes. I didn't see any P2-or-higher issues in this change.
Posted by Codex (gpt-6.1-sol) on behalf of kylez
wesbillman
left a comment
There was a problem hiding this comment.
🤖 Star Lord’s automated source review via Wes’s account.
No actionable findings at 93752d7445098db018eca95c7357604eb3f9715f against base/merge-base 7f03764beb8eb0ddcb4ff9ec0b8bda3e07699716.
The tie-break gives Today preference only after a preset has qualified, preserving the strict <121s tolerance and Custom fallback. Unequal distances still choose the closest preset. The added cases cover the eight-hour, one-hour and Sunday ties plus the tolerance edge; the editor preserves an unchanged future expiry when re-saving. Undefined expiry still selects Don’t clear.
Reviewed helper/test changes and the editor/persistence callers, including refresh, failure/retry and expiry renewal. This is source-only review: no local tests, builds or app execution. The hosted check snapshot reports CI required successful, but the author’s fixed-clock reproduction and human/desktop acceptance were not independently verified. No approval or merge recommendation is implied.
…y-unreads * origin/main: (24 commits) [1/2] feat(agents): add a recommended agent setup (core) (#3344) test(browser): survive the live-stream restart a page-clock jump causes (#3442) chore(renovate): hold rusqlite below 0.41 for mesh-llm (#3438) test(browser): serve the diffs and CLI reload fixtures outside the navigation budget (#3445) test(browser): play the draft clip at rate 0 instead of looping it before the Play click (#3446) fix(status): reopen a status whose preset deadlines coincide as Today (#3449) fix(messages): tolerate a cancelled reaction-name chunk load (#3450) fix(pairing): tolerate /proc/net/tcp rows printed twice or missed (#3451) test(browser): wait on the signal each test asserts in local-agent-activity and message-navigation (#3444) Expose native channel headings to Solo sources (#3523) test(browser-host): run the 100,000-channel broker scale check alone in the measurements lane (#3447) fix(solo): keep every contributed destination action (#3516) fix(identity): report an issuer that keeps rate-limiting an agent as a limit (#2365) fix(identity): let a stuck at-launch sign-in copy its link (#2453) fix(profiles): open avatar previews on hover in compact density (#3510) feat(solo): smooth chat recency reordering (#3502) Reject self-mentions that cannot wake another session (#3513) feat(status): offer don't clear for every status (#3515) Let plugin panels name their tab with panels.useTabTitle (#3251) fix(agents): report a conversation wake that fails before its turn starts (#2192) ... # Conflicts: # tests/browser/message-management.spec.mjs
* origin/main: (27 commits) [2/2] feat(agents): offer Automatic (Recommended) in Create agent and Identity (#3345) fix(solo): preserve and resume unsent chat drafts (#3525) fix(builderlab): give refused app sign-ins and Identity links a route to Organization sign-in (#3078) fix(agents): say why Import an agent can't import here, and link Manage plugins (#3073) [1/2] feat(agents): add a recommended agent setup (core) (#3344) test(browser): survive the live-stream restart a page-clock jump causes (#3442) chore(renovate): hold rusqlite below 0.41 for mesh-llm (#3438) test(browser): serve the diffs and CLI reload fixtures outside the navigation budget (#3445) test(browser): play the draft clip at rate 0 instead of looping it before the Play click (#3446) fix(status): reopen a status whose preset deadlines coincide as Today (#3449) fix(messages): tolerate a cancelled reaction-name chunk load (#3450) fix(pairing): tolerate /proc/net/tcp rows printed twice or missed (#3451) test(browser): wait on the signal each test asserts in local-agent-activity and message-navigation (#3444) Expose native channel headings to Solo sources (#3523) test(browser-host): run the 100,000-channel broker scale check alone in the measurements lane (#3447) fix(solo): keep every contributed destination action (#3516) fix(identity): report an issuer that keeps rate-limiting an agent as a limit (#2365) fix(identity): let a stuck at-launch sign-in copy its link (#2453) fix(profiles): open avatar previews on hover in compact density (#3510) feat(solo): smooth chat recency reordering (#3502) ... # Conflicts: # src-tauri/src/federated_identity/agent/tests.rs # src-tauri/src/federated_identity/mod.rs # src-tauri/src/federated_identity/protocol.rs
* origin/main: (133 commits) Expose ordinary chats without workspace headings (block#3530) [2/2] feat(agents): offer Automatic (Recommended) in Create agent and Identity (block#3345) fix(solo): preserve and resume unsent chat drafts (block#3525) fix(builderlab): give refused app sign-ins and Identity links a route to Organization sign-in (block#3078) fix(agents): say why Import an agent can't import here, and link Manage plugins (block#3073) [1/2] feat(agents): add a recommended agent setup (core) (block#3344) test(browser): survive the live-stream restart a page-clock jump causes (block#3442) chore(renovate): hold rusqlite below 0.41 for mesh-llm (block#3438) test(browser): serve the diffs and CLI reload fixtures outside the navigation budget (block#3445) test(browser): play the draft clip at rate 0 instead of looping it before the Play click (block#3446) fix(status): reopen a status whose preset deadlines coincide as Today (block#3449) fix(messages): tolerate a cancelled reaction-name chunk load (block#3450) fix(pairing): tolerate /proc/net/tcp rows printed twice or missed (block#3451) test(browser): wait on the signal each test asserts in local-agent-activity and message-navigation (block#3444) Expose native channel headings to Solo sources (block#3523) test(browser-host): run the 100,000-channel broker scale check alone in the measurements lane (block#3447) fix(solo): keep every contributed destination action (block#3516) fix(identity): report an issuer that keeps rate-limiting an agent as a limit (block#2365) fix(identity): let a stuck at-launch sign-in copy its link (block#2453) fix(profiles): open avatar previews on hover in compact density (block#3510) ... Signed-off-by: Joah Gerstenberg <[email protected]> # Conflicts: # src/bundled/codex/prompt.test.ts # src/bundled/goose/runtime.ts
Why
user-status.spec.mjs, "statuses edit, synchronize, clear, reject stale traffic and retain failed drafts", failed once in CI withExpected "Duration: Today", Received "Duration: 8 hours": 9 Nov, Flake check, WebKit 2/9, passed on re-run.The failure is a real product bug that the journey only meets in one second of the day. A status saved as "Today" at exactly 16:00 local time reopens in the editor as "8 hours".
Root cause
statusDurationinfers the duration preset from a saved expiry. It takes the preset whose deadline is closest to the expiry, iterating 1 hour, 8 hours, Today and This week with a strict<. At exactly 16:00 the 8 hours and Today deadlines are the same midnight, and the earlier-listed 8 hours won the tie.The failed attempt's trace (artifact 13688728980) puts the first "Save status" click at 16:00:00.559 UTC, so the status was created at 16:00:00 and its expiry was midnight. The same tie occurs for 1 hour at 23:00, and on a Sunday This week ends at the same midnight as Today.
Fix
Let Today win a tie between presets.
Tests
status-duration.test.tsgains the 16:00 and 23:00 ties, the Sunday three-way tie, the Sunday Today and This week tie, and the tolerance-edge case.'28800'.'today'.Evidence
bin/pnpm exec vitest run src/features/user-statususer-status.spec.mjs,--workers=1 --repeat-each=8tsc --noEmitThe scratch copy is not kept. The unit cases are the gate, and a fixed clock would change the rest of the journey's timing.
Not run
buzz-review-completedis not set.Overlap with open PRs
status-duration.tsand extends the same test file. A trial merge against this change is clean. A 30 minutes status saved at 23:30 would tie with Today the same way, and this change's rule already resolves that tie as Today.status-duration.tsor how the preset is inferred. A trial merge against this change is clean.🤖 Generated with Claude Code