Skip to content

fix(ui,cli): count down provider retry wait from the event timestamp - #3400

Open
me2seeks wants to merge 2 commits into
apache:mainfrom
me2seeks:fix/retry-countdown-3393
Open

fix(ui,cli): count down provider retry wait from the event timestamp#3400
me2seeks wants to merge 2 commits into
apache:mainfrom
me2seeks:fix/retry-countdown-3393

Conversation

@me2seeks

@me2seeks me2seeks commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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:

  • 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.

Presentation layer only: the wait itself is unchanged. Honoring a multi-hour Retry-After from 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

  • New regression tests: TUI strip counts down in the client clock domain and from host-authoritative 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 recomputes remainingMs from the stored schedule time; protocol roundtrip covers the optional snapshot ts; core pins the shared computation.
  • Full suites on this head: core 590, runtime 3001, runtime-host 1063, cli 359, ui 195 — all pass; biome lint/format clean.
  • Not run: hosted checks (no CI on fork branches).

AI use

  • Generative tooling made a substantive contribution

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: Maka trailer.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread packages/ui/src/chat-turn.tsx Outdated
Comment thread packages/ui/src/chat-turn.tsx

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread packages/ui/src/chat-turn.tsx Outdated
Comment thread packages/ui/src/chat-turn.tsx Outdated
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 22, 2026
…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.
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 22, 2026
…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
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 22, 2026
…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
@me2seeks
me2seeks force-pushed the fix/retry-countdown-3393 branch from 88fbc76 to 5bea9fe Compare August 22, 2026 14:34
@me2seeks

Copy link
Copy Markdown
Contributor Author

Follow-up head 5bea9fed6 addresses the full review round:

  • @jackwener's test-quality gap: the mounted-banner test now enables mocked Date + setInterval and advances the clock, so the one-second interval itself is pinned (10s → 9s → 7s) — deleting the interval would fail the test.
  • Clock domains (thread r3830020299): remainingMs duration + client receipt stamping.
  • Live-region a11y (thread r3830020302): ticking text aria-hidden, stable aria-label.
  • Reduced motion (thread r3835774695): mount-time measurement outside the motion gate.
  • Shared computation (thread r3835774698): @maka/core/provider-retry-countdown, one zero floor.

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.)

@Astro-Han

Copy link
Copy Markdown
Contributor

Independent review of 5bea9fed63ce66c5895e2e478cc98829ad9d2b6f.

[P2] Adding optional ts to the scheduled retry snapshot is a wire-breaking change for older clients

packages/runtime-host/src/protocol/turn.ts:696-711 widens the accepted key set:

const requiredKeys = ['phase', 'attempt', 'maxAttempts', 'delayMs', 'reason'] as const;
assertExactKeys(
  record,
  'scheduled Turn provider retry',
  record.ts === undefined ? requiredKeys : [...requiredKeys, 'ts'],
);

That tolerance is one-directional. The base version of decodeTurnProviderRetry calls assertExactKeys with the strict 5-key list and nothing else, so:

  • old host → new client: fine, ts is absent and the 5-key branch is taken;
  • new host → old client: the snapshot carries a 6th key and assertExactKeys throws invalidProtocolFrame.

This is reachable on the ordinary staged-upgrade path (host upgraded first, client after). decodeTurnSnapshot is wired as decodeOutput for the turn operations at turn.ts:221, :235, :251, and reached again through session-continuity.ts:512 and message.ts:243 — so an old client hits it on live turn output and on session-continuity restore, not just in a corner. The symptom is not a missing countdown; it is a rejected frame and a dropped subscription.

"Optional field" is a property of the decoder that was updated, not of the wire. In a strict-exact-keys protocol, adding a field is a breaking change in the new→old direction regardless of optionality.

The repository's own guard already agrees, and it is red on this head

test on this exact head is completed / failure, and the failing step is Guard the protocol compatibility epoch (run 32579078311):

Protocol epoch guard: Protocol files changed but RUNTIME_HOST_COMPATIBILITY_EPOCH is still 37,
the current base parent's value. ... rebase onto current main and set the epoch past 37.
Changed files:
  packages/runtime-host/src/protocol/turn.ts

main is now at epoch 39, so the concrete fix is: rebase onto current main, then set RUNTIME_HOST_COMPATIBILITY_EPOCH to 40.

Worth being explicit about why the bump is the right resolution rather than a formality: the epoch is what makes an old client refuse at handshake instead of crashing at decode. Without it the incompatibility still exists — it just surfaces later and less legibly.

Everything else we raised, we withdrew

  • Cross-machine clock skew. providerRetryRemainingMs takes remainingMs ?? delayMs as a duration and the client measures elapsed from its own receivedAtMs. Host time never enters the client's arithmetic. This is the strongest design decision in the PR and it is the thing Provider retry countdown never ticks: 'Retrying in 16083s' stays frozen for the whole wait #3393 was actually about. Withdrawn.
  • A late-arriving event restarting the countdown. receivedAtMs is stamped when the event enters projection, so a delayed event makes the displayed remainder longer, never shorter. Errs safe. Withdrawn.
  • Host re-projection recomputing remainingMs from ts - retry.ts. Both timestamps are host-clock; the difference is same-domain. Withdrawn.
  • Re-projection resetting the countdown on reconnect. receivedAtMs resets, but the host has recomputed remainingMs over the same interval, so the two cancel. Withdrawn.
  • isDeepStrictEqual on the retry object now being ts-sensitive, so re-projection re-emits an event for an unchanged wait. Confirmed as behavior; the re-emitted event carries a correctly recomputed remainder, so it costs one extra event and nothing else. Withdrawn as a defect.
  • Reduced-motion showing a static value. isTimeDrivenMotionEnabled === false measures once and does not tick, which is pinned by an explicit test. That is a deliberate accessibility trade-off, not a regression. Withdrawn.
  • TUI refresh cadence. The 1 s turn-elapsed ticker is alive for the whole turn and provider retry happens inside the turn, so the strip re-renders. Withdrawn.

On entropy

+513/−31. The 31 deleted lines are the two private countdown implementations — one in the TUI activity strip, one in the desktop banner — each independently computing Math.max(1, Math.ceil(delayMs / 1000)). Two authorities for "how much longer" become one, in packages/core. That is a real concept disappearing, not a relocation, and it is exactly the drift that produced the symptom #3393 describes. The added protocol field is the honest price of that consolidation.

Net: the direction is right and the clock-domain reasoning is careful. The protocol epoch is the one thing standing in the way.

Gate state

  • exact head 5bea9fed, non-draft, MERGEABLE / BLOCKED (blocked by CI, not by conflict).
  • check-runs on this head: audit = completed/success, test = completed/failure.
  • Existing review endpoints read separately: jackwener 1 comment and Astro-Han 2, all bound to the older head 5eb038d3; the author has 2 comments plus an issue comment on the current head stating the follow-up addresses the round. Nothing above duplicates those.

No overall verdict offered. Reviewed 2026-08-23 13:15 UTC.

me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 23, 2026
…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
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 23, 2026
…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
@me2seeks
me2seeks force-pushed the fix/retry-countdown-3393 branch from 5bea9fe to acaa100 Compare August 23, 2026 14:56

@ARE404 ARE404 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ts and the projector's now share 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-free remainingMs duration — 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.

Comment thread packages/runtime-host/src/protocol/turn.ts

@ARE404 ARE404 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge-ordering pointer (echoing the #3402 thread): #3402 must be rebased onto this PR and reuse the shared formatter once this lands.

Comment thread packages/ui/src/conversation-copy.ts
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 24, 2026
…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
me2seeks added a commit to me2seeks/maka-agent that referenced this pull request Aug 24, 2026
…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
@me2seeks
me2seeks force-pushed the fix/retry-countdown-3393 branch from acaa100 to b9d955f Compare August 24, 2026 03:53
@me2seeks

Copy link
Copy Markdown
Contributor Author

Rebased onto main (c79e9eb4) and the epoch now moves 44 → 45 (b9d955fb8) for the optional host-clock ts on scheduled retry frames — strict exact-key decoders on older peers reject the added key, so a bump (not a compatible-change declaration) is required. Epoch guard passes against the new base, which also un-blocks the test job so this PR's countdown tests get their first real CI run.

Merge-order agreement noted from the #3402 thread: this lands first; #3402 rebases on top and adopts the shared formatter.

@Astro-Han

Copy link
Copy Markdown
Contributor

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 (32687999762), so the result you see now is real, not a new regression.

Where it stops: step 10 of the test job, Check ASF source headers (npm run check:asf-headers). That step runs before npm install, so no build, lint, typecheck or test ran on this head at all.

What it found — reproduced locally at b9d955fb820d666686b50995f6433943a28dc45c:

3 file(s) are missing the ASF license header. Run `npm run write:asf-headers`:
  packages/core/src/__tests__/provider-retry-countdown.test.ts
  packages/core/src/provider-retry-countdown.ts
  packages/ui/src/__tests__/provider-retry-countdown.test.tsx

All three are files this PR adds. npm run write:asf-headers fixes it; commit the result and the rest of the pipeline will finally get a chance to run.

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 放行,我已放行(32687999762),所以你现在看到的红是真实结果,不是新回归。

停在哪test job 的第 10 步 Check ASF source headersnpm run check:asf-headers),这一步在 npm install 之前,所以这个 head 上 build / lint / typecheck / 测试一个都没跑

它报了什么(我在 b9d955fb 上本地复现):三个文件缺 ASF license header,全是本 PR 新增的文件 —— packages/core/src/__tests__/provider-retry-countdown.test.tspackages/core/src/provider-retry-countdown.tspackages/ui/src/__tests__/provider-retry-countdown.test.tsx

npm run write:asf-headers 可以直接修好,提交之后流水线才有机会跑到后面。

这条不涉及改动本身的对错——只是这个 head 目前没有任何测试信号

@me2seeks
me2seeks force-pushed the fix/retry-countdown-3393 branch 3 times, most recently from 07e37d7 to 6e84731 Compare August 25, 2026 02:16
…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
@me2seeks
me2seeks force-pushed the fix/retry-countdown-3393 branch from 6e84731 to d08b13d Compare August 25, 2026 02:37

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provider retry countdown never ticks: 'Retrying in 16083s' stays frozen for the whole wait

4 participants