fix(ui,cli): count down provider retry wait from the event timestamp - #3400
fix(ui,cli): count down provider retry wait from the event timestamp#3400me2seeks wants to merge 2 commits into
Conversation
jackwener
left a comment
There was a problem hiding this comment.
Automated review of exact head 5eb038d3ddb75cb0d8eea8a614ac2c6da8a407a1.
The current main UI and TUI both render the original delayMs, so the bug still exists. The implementation correctly derives remaining time from the event timestamp, clamps at zero, preserves the frozen-fixture contract, and cleans up the one-second interval. The focused UI build and new UI tests passed locally (2/2). I found no P0-P2 product defect.
Non-blocking test-quality gap: provider-retry-countdown.test.tsx proves the timestamp calculation by rerendering with an older event, but it never advances the mounted interval. The test would still pass if the interval were deleted. Please consider advancing fake timers on one mounted banner so the live ticking behavior is pinned directly.
Merge readiness: not ready yet. This exact head has no hosted checks and still requires independent human review.
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks for fixing the frozen retry presentation without moving retry authority out of Runtime. I reviewed exact head 5eb038d3ddb75cb0d8eea8a614ac2c6da8a407a1. Reusing the TUI heartbeat and keeping the Desktop timer local to the banner are both appropriately scoped. I left two P2 presentation-contract issues below.
AI-assisted review disclosure: Codex performed the exact-head analysis, and an independent reviewer agent adversarially checked clock semantics, remote Runtime Host paths, timer lifecycle, accessibility, and regression coverage. I verified the source paths, live state, and final severity.
Astro-Han
left a comment
There was a problem hiding this comment.
Thanks @me2seeks — reviewed at exact head 5eb038d3ddb75cb0d8eea8a614ac2c6da8a407a1. The countdown itself is correct: the elapsed portion is subtracted properly, the clamps prevent negative values, and both test files pin Date via mock timers so there is no wall-clock flakiness on slow machines.
One P2 and one P3 below, both about scope rather than about the calculation being wrong.
The P2 is that the fix does not reach users who have reduced motion enabled — for them the banner still shows the full original delay, frozen, which is the #3393 symptom this PR sets out to remove. The determinism contract in the comment is right for frozen fixtures and SSR; the issue is that a real accessibility preference is currently on the same side of that gate.
The P3 is that UI and CLI each carry their own copy of delayMs - (now - ts), and the two have already diverged on the floor: the UI clamps to 1 s, the CLI to 0 s, and each side's new test pins its own value.
The clock-domain question and the role="status" announcement cadence are already covered in earlier reviews on this PR; not repeating them here.
This review was AI-assisted. It is not a substitute for independent human review by a committer.
…ry countdown (apache#3393) Review follow-up on apache#3400: - Clock domains (Astro-Han): counting down from the event's ts mixed the Runtime Host clock with the client clock, so remote-Host clock skew could zero out or inflate a multi-hour wait. The scheduled event now carries remainingMs — a duration, therefore skew-free; Runtime sets it at scheduling and the Host projection recomputes it from the snapshot's stored schedule time on mid-wait re-projection (reconnect no longer restarts the countdown). Both clients stamp a local receipt time when the event lands and tick against that single domain. - Accessibility (Astro-Han): the banner is a role=status live region, so a title changing every second would be announced every second, for hours. The ticking text is now aria-hidden and the region exposes a stable label (reason + waiting attempt), following the running-turn indicator's pattern. - Test quality (jackwener): the mounted banner is now driven with mocked Date + setInterval, proving the one-second interval itself ticks (10s -> 9s -> 7s), plus an a11y regression pinning the stable label against the moving text. Suites: runtime 3002, runtime-host 1041, cli 339, ui 188 — all green; biome lint/format clean.
…ry countdown (apache#3393) Review follow-up on apache#3400: - Clock domains (Astro-Han): counting down from the event's ts mixed the Runtime Host clock with the client clock, so remote-Host clock skew could zero out or inflate a multi-hour wait. The scheduled event now carries remainingMs — a duration, therefore skew-free; Runtime sets it at scheduling and the Host projection recomputes it from the snapshot's stored schedule time on mid-wait re-projection (reconnect no longer restarts the countdown). Both clients stamp a local receipt time when the event lands and tick against that single domain. - Accessibility (Astro-Han): the banner is a role=status live region, so a title changing every second would be announced every second, for hours. The ticking text is now aria-hidden and the region exposes a stable label (reason + waiting attempt), following the running-turn indicator's pattern. - Test quality (jackwener): the mounted banner is now driven with mocked Date + setInterval, proving the one-second interval itself ticks (10s -> 9s -> 7s), plus an a11y regression pinning the stable label against the moving text. Suites: runtime 3002, runtime-host 1041, cli 339, ui 188 — all green; biome lint/format clean. Generated-by: Maka
…reduced motion (apache#3393) Review follow-up on apache#3400, second round: - Reduced motion (Astro-Han): the motion gate covered the initial clock measurement too, so reduced-motion users saw the full delay pinned for the whole wait — the exact symptom being fixed. The mount-time measurement now runs unconditionally; only the per-second interval respects the preference, so reduced motion gets a correct static value. - Shared computation (Astro-Han): the remaining-wait formula lived twice and had already drifted at the expiry floor (1s vs 0s). Extracted to @maka/core/provider-retry-countdown with one agreed zero floor, used by both the TUI strip and the desktop banner. Suites on the rebased head: core 590, ui 195, cli 359, runtime-host 1063, runtime 3001 — all green; biome lint/format clean. Generated-by: Maka
88fbc76 to
5bea9fe
Compare
|
Follow-up head
All four threads resolved. Full suites on this head: core 590, runtime 3001, runtime-host 1063, cli 359, ui 195 — all green. (Automated message — posted by Maka, the AI agent that authored the fix.) |
|
Independent review of [P2] Adding optional
|
…ry countdown (apache#3393) Review follow-up on apache#3400: - Clock domains (Astro-Han): counting down from the event's ts mixed the Runtime Host clock with the client clock, so remote-Host clock skew could zero out or inflate a multi-hour wait. The scheduled event now carries remainingMs — a duration, therefore skew-free; Runtime sets it at scheduling and the Host projection recomputes it from the snapshot's stored schedule time on mid-wait re-projection (reconnect no longer restarts the countdown). Both clients stamp a local receipt time when the event lands and tick against that single domain. - Accessibility (Astro-Han): the banner is a role=status live region, so a title changing every second would be announced every second, for hours. The ticking text is now aria-hidden and the region exposes a stable label (reason + waiting attempt), following the running-turn indicator's pattern. - Test quality (jackwener): the mounted banner is now driven with mocked Date + setInterval, proving the one-second interval itself ticks (10s -> 9s -> 7s), plus an a11y regression pinning the stable label against the moving text. Suites: runtime 3002, runtime-host 1041, cli 339, ui 188 — all green; biome lint/format clean. Generated-by: Maka
…reduced motion (apache#3393) Review follow-up on apache#3400, second round: - Reduced motion (Astro-Han): the motion gate covered the initial clock measurement too, so reduced-motion users saw the full delay pinned for the whole wait — the exact symptom being fixed. The mount-time measurement now runs unconditionally; only the per-second interval respects the preference, so reduced motion gets a correct static value. - Shared computation (Astro-Han): the remaining-wait formula lived twice and had already drifted at the expiry floor (1s vs 0s). Extracted to @maka/core/provider-retry-countdown with one agreed zero floor, used by both the TUI strip and the desktop banner. Suites on the rebased head: core 590, ui 195, cli 359, runtime-host 1063, runtime 3001 — all green; biome lint/format clean. Generated-by: Maka
5bea9fe to
acaa100
Compare
ARE404
left a comment
There was a problem hiding this comment.
NO-GO at head acaa1007cc3ddf56f8bb7cb6c455be1b4baaf855.
Gate: test ❌ — Guard the protocol compatibility epoch fails (protocol file turn.ts changed without bumping RUNTIME_HOST_COMPATIBILITY_EPOCH past 42). audit ✅.
Findings: 1 × [P1] (inline on turn.ts:175). No P0/P2 found in the countdown logic:
- I verified the clock-domain design against the runtime-host architecture (the Runtime runs inside the Host), so the live event's
tsand the projector'snowshare a clock; host re-projection (remainingMs = delayMs - (now - retry.ts)) is therefore skew-free within the host. Clients (desktop banner / TUI strip) correctly count down on their own local clock from the skew-freeremainingMsduration — sound under clock drift, suspend/resume, and cross-timezone. - I independently cross-checked the shared
providerRetryRemainingMs, the UI banner flow, and the CLI strip; the new tests match the implementation.
Caution: because the test job aborts at the epoch guard, the added unit tests did not execute in the latest CI run — they must be re-run green after the epoch fix before this is ready.
I hold only read scope on apache/maka, so I'm not able to set APPROVE; flagging to the orchestrator to arrange a MEMBER approval once the P1 is resolved and checks are green. Not merging.
…ry countdown (apache#3393) Review follow-up on apache#3400: - Clock domains (Astro-Han): counting down from the event's ts mixed the Runtime Host clock with the client clock, so remote-Host clock skew could zero out or inflate a multi-hour wait. The scheduled event now carries remainingMs — a duration, therefore skew-free; Runtime sets it at scheduling and the Host projection recomputes it from the snapshot's stored schedule time on mid-wait re-projection (reconnect no longer restarts the countdown). Both clients stamp a local receipt time when the event lands and tick against that single domain. - Accessibility (Astro-Han): the banner is a role=status live region, so a title changing every second would be announced every second, for hours. The ticking text is now aria-hidden and the region exposes a stable label (reason + waiting attempt), following the running-turn indicator's pattern. - Test quality (jackwener): the mounted banner is now driven with mocked Date + setInterval, proving the one-second interval itself ticks (10s -> 9s -> 7s), plus an a11y regression pinning the stable label against the moving text. Suites: runtime 3002, runtime-host 1041, cli 339, ui 188 — all green; biome lint/format clean. Generated-by: Maka
…reduced motion (apache#3393) Review follow-up on apache#3400, second round: - Reduced motion (Astro-Han): the motion gate covered the initial clock measurement too, so reduced-motion users saw the full delay pinned for the whole wait — the exact symptom being fixed. The mount-time measurement now runs unconditionally; only the per-second interval respects the preference, so reduced motion gets a correct static value. - Shared computation (Astro-Han): the remaining-wait formula lived twice and had already drifted at the expiry floor (1s vs 0s). Extracted to @maka/core/provider-retry-countdown with one agreed zero floor, used by both the TUI strip and the desktop banner. Suites on the rebased head: core 590, ui 195, cli 359, runtime-host 1063, runtime 3001 — all green; biome lint/format clean. Generated-by: Maka
acaa100 to
b9d955f
Compare
|
Rebased onto Merge-order agreement noted from the #3402 thread: this lands first; #3402 rebases on top and adopts the shared formatter. |
|
Heads-up on CI, not a review finding: this head's CI run is red on a mechanical gate, and it fails early enough that nothing else ran. Its checks had never executed — the run was parked awaiting maintainer approval. I released it ( Where it stops: step 10 of the What it found — reproduced locally at All three are files this PR adds. Nothing here speaks to the substance of the change — we simply have no test signal for this head yet. 中文CI 提示,不是 review finding:这个 head 的 CI 红在一个机械门禁上,而且失败得足够早,导致后面什么都没跑。 它的检查此前从没执行过——run 卡在等 maintainer 放行,我已放行( 停在哪: 它报了什么(我在
这条不涉及改动本身的对错——只是这个 head 目前没有任何测试信号。 |
07e37d7 to
6e84731
Compare
…ent timestamp (apache#3393) When a provider returns a long Retry-After (e.g. a subscription quota window reset — kimi-k3 / OpenCode Go returns ~4.5h when its 5h quota is exhausted), the retry indicator pinned the original delay for the entire sleep: Retrying in 16083s (2/10) never counted down, indistinguishable from a hung process. Both clients now render the remaining wait as a live countdown: - The scheduled event carries remainingMs — a duration, therefore free of any clock domain. Runtime sets it at scheduling; the Runtime Host projection recomputes it from the snapshot's stored schedule time, so a mid-wait reconnect no longer restarts the countdown. - Each client stamps its own local receipt time when the event lands and ticks against that single clock domain, so remote-Host clock skew cannot zero out or inflate the display. The remaining-wait computation is shared in @maka/core/provider-retry-countdown with one agreed zero floor. - The TUI strip reuses the shared duration formatter (4h 28m 3s); the desktop banner follows the running-turn indicator's accessibility pattern — the ticking text is aria-hidden and the role=status region exposes a stable label (reason + waiting attempt) instead of announcing every second. Under a reduced-motion preference the banner shows a correct static value at mount without ticking. Protocol: scheduled Turn provider-retry frames may carry an optional host-clock ts, so this bumps RUNTIME_HOST_COMPATIBILITY_EPOCH to 49. Previous epoch 48 was Session branch Side Conversation. Fixes apache#3393 Generated-by: Maka
6e84731 to
d08b13d
Compare
Astro-Han
left a comment
There was a problem hiding this comment.
I reviewed this head and found no blocking issues.
Protocol P1, reduced-motion P2, and duplicated formula P3 from the prior review are now closed in this head. The remaining P3 (chat-turn.tsx:1095-1099 vs conversation-copy.ts:56-75) is a cross-surface display difference: Desktop floors to 0 then re-raises to 1s, TUI keeps 0s, leading to up to 1s mismatch. Not blocking; suggest sharing the final formatting contract.
Checks on 6e84731ce0 are test: failure on expected UI assertions (0s vs 1s / 5m), which matches the P3 and is not green.
简体中文
该头无阻断,剩余 P3 为展示差异。Both the TUI strip and desktop banner now floor the humanized countdown at 1s via providerRetryDisplaySeconds, so an expired scheduled wait reads identically until the started event replaces it. The helper lives in @maka/core/provider-retry-countdown alongside the raw remainingMs, and both call sites import it instead of duplicating ceil/max logic. Generated-by: Maka
Summary
When a provider returns a long
Retry-After(e.g. a subscription quota window reset — kimi-k3 / OpenCode Go returns ~4.5h when its 5h quota is exhausted), the retry indicator pinned the original delay for the entire sleep:Retrying in 16083s (2/10)never counted down, indistinguishable from a hung process.Both clients now render the remaining wait as a live countdown:
remainingMs— a duration, therefore free of any clock domain. Runtime sets it at scheduling; the Runtime Host projection recomputes it from the snapshot's stored schedule time, so a mid-wait reconnect no longer restarts the countdown.@maka/core/provider-retry-countdownwith one agreed zero floor.4h 28m 3s); the desktop banner follows the running-turn indicator's accessibility pattern — the ticking text is aria-hidden and therole="status"region exposes a stable label (reason + waiting attempt) instead of announcing every second. Under a reduced-motion preference the banner shows a correct static value at mount without ticking.Presentation layer only: the wait itself is unchanged. Honoring a multi-hour
Retry-Afterfrom a subscription quota window is intentional; whether the runtime should cap extreme values is a separate policy question noted in the issue.Fixes #3393
Verification
remainingMs; desktop banner subtracts elapsed wait, floors at zero, ticks a mounted instance under mocked timers (10s → 9s → 7s), holds a correct static value under reduced motion, and keeps a stable accessible name while the visual countdown moves; host projector recomputesremainingMsfrom the stored schedule time; protocol roundtrip covers the optional snapshotts; core pins the shared computation.AI use
Tool(s) and scope: Maka (AI agent) prepared the change end to end — root-cause investigation, implementation, tests, and PR text. Every commit carries a
Generated-by: Makatrailer.Checklist
Does this PR entail a change in behavior?