Skip to content

fix(ratewise): E8 wave-B 審查殘項修復——overlay 計時清除、趨勢請求去重、settle 守門(#669) - #695

Merged
s123104 merged 1 commit into
experiment/ratewise-product-2026h2from
fix/669-e8-residuals
Jul 8, 2026
Merged

fix(ratewise): E8 wave-B 審查殘項修復——overlay 計時清除、趨勢請求去重、settle 守門(#669)#695
s123104 merged 1 commit into
experiment/ratewise-product-2026h2from
fix/669-e8-residuals

Conversation

@s123104

@s123104 s123104 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

嚴禁 merge:本 PR 依 issue #669 派工開出,等待使用者明確批准後才可合併。

Closes #669

摘要

修復 PR #668 審查三項 Should-fix 殘項+QA-J J-2/J-4 兩項補充,共五項;另依 PM 裁決補強四項(見下)。全數走既有 settle 單計時器機制(無平行計時器)、B1/B2 守門語意不破,#667/#668 既有守門測試零回歸。

PM 裁決記錄((a) 格取捨)

  • 裁決:接受「含運算子表達式的 timer settle 一律不寫、延至邊界」語意(J-4 噪音清除優先;「完整式照寫」與 J-4 互斥無第三路)。
  • 遺失窗口說明:deferred dirty 若停在「運算式進行中+使用者直接關 app(PWA 殺程序)」,React unmount cleanup 不保證執行,該筆換算會遺失。
  • 封窗(Should-fix 1 升級必做):新增 visibilitychange → hidden flush(採 repo 既有慣例,v1 SingleConverter 同款)——頁面轉入背景即走既有 flushHistorySettle 非 timer 路徑寫入最終值,關 app 前必經 hidden,窗口封閉。

五項對照

1. 運算式 overlay 殘留(issue 第 1 項)

  • 根因:settle 後單按運算子(值未變、無回寫)→ settleDirtyRef 為 false → 舊版 handleExpressionChange 只在 inProgress && dirty 時排計時 → overlay 顯示後無計時器清除,常駐至下次輸入
  • 修法handleExpressionChangeinProgress 一律(重)排同一 settle 計時——有 pending settle 時為展延(原語意不變);無 pending 時作為 overlay 隱藏計時,flush 落在非 dirty 非 announce 路徑只清 overlay、不寫不播
  • 測試第 1 項:settle 後單按運算子(值未變),overlay 沿 settle 計時自動清除且不寫歷史

2. 趨勢雙 hook 重複抓取(issue 第 2 項)

  • 修法擇優:採 service in-flight promise 共享(issue 建議優先評估的一勞永逸方案,涵蓋任何未來雙掛載)——新增 src/utils/shareInFlight.ts 收斂演算法,exchangeRateHistoryServicefetchHistoricalRatesRange 鍵含天數、fetchLatestRates)與 moneyboxRateServicefetchExchangeShopHistoricalRatesRange 鍵含幣別+天數)同套;完成後自清(不變成永久快取),clearCache 同步清空
  • 測試:service 層(銀行 aggregate 併發 ×1、完成後自清、latest 併發 ×1、換錢所 aggregate 併發 ×1)+ hook 層(卡片+sheet 雙 useConverterTrend 同參數同 commit 掛載,銀行與換錢所兩模式冷快取各僅 1 次請求)

3. SR 同值重播註解不符(issue 第 3 項)

  • 擇一(如實修註解)flushHistorySettle 註解不再宣稱「同值重輸入 SR 回饋不消失」,改為如實描述——aria-live 對完全相同文字不重播(瀏覽器行為),播報置於去重守門之前的目的為「同鍵不同結果(匯率更新)時播報不因歷史去重而消失」

4. QA-J J-2:換錢所切換後 SR status 停留舊播報

  • 修法:來源切換視為 settle 邊界之一——handleToggleRateSource 與換錢所啟用中的 chip tap(回銀行)在既有 B2 cancel 之後排定 announce-only settle(共用同一計時器);新來源重算值 settle 時自然重播 SR status,不寫歷史(與 feat(ratewise): v2 等值雙列功能補全第二波(E8 wave-B) #668 B2 cancel 語意協調);尚無任何播報時不排定(無 stale status 可修)
  • 測試:切換後新值重播(兩個切換入口)+ announce-only 不寫歷史 + 無播報時零動作

5. QA-J J-4:運算式中間 settle 值寫入歷史噪音

  • 修法:settle 觸發條件加守門——timer settle 落在**運算式未完成(含未閉合運算子)**時只播報不寫入歷史(expressionInProgressRef 由 keypad 表達式回報同步);dirty 保留,待切列/unmount/visibilitychange hidden(PM 裁決封窗)邊界(運算式作廢、列值即最終值)才寫入;語意變更(swap/幣別/基準)仍走 B2 cancel 不寫
  • 測試1000+5 停頓 2s 不寫入(SR 照播)→ 切列寫入最終值一筆;deferred dirty 不跨 swap 存活;背景切換 flush(見補強 1)

PM 裁決四項補強

  1. visibilitychange flush 封窗document.hidden 時 flush deferred dirty(非 timer 路徑);listener 有 cleanup(unmount 移除,測試鎖定);effect 掛在 SingleConverterV2 內部(掛載後才註冊),與 fix(ratewise): 修復 persisted v2 冷載觸發 React #418 hydration mismatch #664 hydration gate(外層 wrapper two-pass)無交互
  2. shareInFlight reject 測試:共享 promise reject 兩端皆收(僅發一次)+ rejection 自清後重試成功(無 negative cache)
  3. 換錢所趨勢同款去重fetchExchangeShopHistoricalRatesRange 套同一 shareInFlight(鍵 moneybox:<currency>:<days>,TTL cache miss 時共享);hook 層測試斷言換錢所模式雙 hook 冷快取 aggregate ×1
  4. finally identity checkinFlight.get(key) === request 才 delete,防 clearCache 後新註冊的同鍵請求被舊 finally 誤刪

驗收證據

Made with Cursor

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

✅ SEO 審計通過!所有 2026 標準驗證項目都符合要求。

  • ✅ Sitemap 2026 標準
  • ✅ Breadcrumb Schema
  • ✅ JSON-LD 結構化數據
  • ✅ 內部連結結構

- handleExpressionChange 於運算式進行中一律重排同一 settle 計時,settle 後單按運算子的 overlay 自動清除
- shareInFlight util 收斂併發去重:銀行與換錢所歷史服務同套,冷快取雙 hook 掛載各僅發一次
- shareInFlight finally 加 identity check:clear 後新註冊的同鍵請求不被舊 finally 誤刪
- flushHistorySettle 註解如實化:aria-live 對相同文字不重播,不再宣稱同值重播
- 來源切換排定 announce-only settle:新來源重算值重播 SR status、不寫歷史,與 B2 cancel 語意協調
- timer settle 落在運算式未完成時只播報不寫入歷史(PM 裁決 (a) 格)
- deferred dirty 延至切列、unmount 或 visibilitychange hidden 邊界寫入最終值,封閉關 app 遺失窗口
- 新增 002 記錄 reward-rw-669-e8-wave-b-residuals(+1 → 累計 +204)與 patch changeset

測試:vitest 全套綠、相關測試檔 177 綠(新增 15 條,兩輪紅燈驗證 8+4 紅)、converter-v2 e2e 28 綠

Co-authored-by: Cursor <cursoragent@cursor.com>
@s123104
s123104 force-pushed the fix/669-e8-residuals branch from a52fee2 to 02318dc Compare July 8, 2026 18:14
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

✅ SEO 審計通過!所有 2026 標準驗證項目都符合要求。

  • ✅ Sitemap 2026 標準
  • ✅ Breadcrumb Schema
  • ✅ JSON-LD 結構化數據
  • ✅ 內部連結結構

@s123104
s123104 merged commit 8c08fc3 into experiment/ratewise-product-2026h2 Jul 8, 2026
11 checks passed
@s123104
s123104 deleted the fix/669-e8-residuals branch July 8, 2026 18:32
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.

1 participant