Compare commits

...

2 Commits

Author SHA1 Message Date
Jesse_Chen 421ec0f9bf docs: record BUG-326 fix SHA
Independent Staging Quality Gate / validate (push) Successful in 9m23s
Independent Staging Quality Gate / publish (push) Successful in 12m51s
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 16:21:01 +08:00
Jesse_Chen dbbcb71b6a fix(ci): stop writing dialog close refs during render
eslint-plugin-react-hooks forbids updating ref.current in render, which failed staging lint after the compact rectification board landed.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 16:20:39 +08:00
3 changed files with 21 additions and 4 deletions
+16
View File
@@ -4906,3 +4906,19 @@
- 相关记录:BUG-291、BUG-320、BUG-323
- 复发自:BUG-320(财务/健康进入方法轮询是当时的产品决定,本记录故意改回经典八方法);BUG-323(KP 政策跳过只解决提出门,没有做出真实观察)
- 修复版本:84e6191f
## BUG-326 | 窄屏盘面对话框在 render 里写 refstaging ESLint 失败
- 状态:resolved
- 首次发现:2026-08-20
- 最近更新:2026-08-20
- 影响面:Gitea `backend-quality-gate``npm run lint --prefix frontend``frontend/src/components/rectification-board.tsx`
- 用户现象:staging 推送后质量门禁失败。摘要为 `✖ 11 problems (1 error, 10 warnings)`
- 触发条件:向 `staging` 推送含窄屏 `<dialog>` 盘面的提交后跑 frontend lint。
- 根因:`react-hooks/refs` 禁止在 render 期间更新 `ref.current`。窄屏盘面用 `onCloseRef.current = onClose` 保存最新关闭回调,触发 `Cannot update ref during render`。另外 10 条是既有 unused-vars / exhaustive-deps warning,不构成这次失败。
- 修复:关闭监听改为在 effect 里直接调用 `onClose`,并把 `onClose` 放进依赖。
- 验证:`npx eslint src/components/rectification-board.tsx``npx tsx --test tests/rectification-agentic-entry.test.ts`
- 防复发:盘面对话框不得在 render 里写 `ref.current`;源码合同锁定 close 监听只出现在 effect。
- 相关记录:BUG-322
- 复发自:无
- 修复版本:dbbcb71b
@@ -208,8 +208,6 @@ export function RectificationBoard({
onClose: () => void;
}>) {
const dialogRef = useRef<HTMLDialogElement>(null);
const onCloseRef = useRef(onClose);
onCloseRef.current = onClose;
const body = (
<RectificationBoardBody
result={result}
@@ -235,10 +233,10 @@ export function RectificationBoard({
if (!compact) return;
const node = dialogRef.current;
if (!node) return;
const handleClose = () => onCloseRef.current();
const handleClose = () => onClose();
node.addEventListener("close", handleClose);
return () => node.removeEventListener("close", handleClose);
}, [compact]);
}, [compact, onClose]);
if (compact) {
return (
@@ -363,6 +363,9 @@ test("the natal house table is a live board beside the chat, not a message", ()
assert.match(board, /aria-live="polite"/);
assert.match(board, /groupWindowTransitions/);
assert.match(board, /<dialog/);
assert.doesNotMatch(board, /onCloseRef\.current = onClose/);
assert.match(board, /node\.addEventListener\("close", handleClose\)/);
assert.match(board, /}, \[compact, onClose\]\);/);
assert.match(chat, /RectificationBoardPeek/);
assert.match(houseTable, /当前本命宫位/);
assert.match(houseTable, /补充经历后会按新线索重算/);