判据要用真值而非代理

判据要用真值而非代理

# 判据要用真值而非代理

你反复踩的坑不是「判断写错了」,而是判断用的那个量根本不是你要问的东西。 「第几次事件」「滚了多远」「动画转到第几帧」「这次会话缓存过没有」「多久没结束」「字符串变了没有」—— 它们都只是真值的代理,在边界条件下会和真值分叉,而且不报错。 解法统一:把判据换成真值本身(内容是否变化、元素是否可见、真实进度、真实加载状态)。

十处证据:每一处都是「用代理当判据」

出处代理(错的判据)真值(对的判据)分叉后的症状
首次内容事件不能无条件跳过事件序号(第 1 次就跳过)内容是否仍等于初始内容空正文第一次粘贴图片被整个丢掉 → 保存不了
显示阈值应按元素可见性而非固定像素固定滚动距离(scrollTop > 18)标题元素是否已滚出覆盖区字号/行高不同 → 标题提前或延后出现
进度条要由真实进度驱动无限循环动画 / 帧间隔计时真实加载状态或经过时间条件永不成立 → 进度条卡在假进度上
图片加载失败要可重试并升级到HTTPS「这场会话加载失败过」的缓存标记本次请求的实际结果一次失败被会话级永久记住 → 整场不再重试
缓存命中率命中率数字(0 就以为坏了)「是不是每次都是新会话首请求」测量动作本身绕过了被测对象 → 误判实现有 bug
编辑器显示不能脱离真实光标状态固定的渲染规则 / 滞后的 selection真实光标位置源码与渲染同时出现;「看起来正常」但输入落到错误位置
编辑器初始化会触发假保存字符串 diff(编辑器 round-trip 后变了)内容语义是否真的变化 / 是否是用户输入打开即保存 → updatedAt 变新 → 列表跳位
长任务不要用固定超时判定固定 RUN_TIMEOUT_MS(10 分钟)turn/completed 等结构化事件长任务被误杀;超时被当成「已停止」
终端画面同步Agent状态不稳定「终端画面几秒没变」app-server 的结构化事件turn 结束判断早或晚;输出夹杂 UI 文本
两条写入路径要用内容判重id(本地 id / 镜像 id)内容 + 会话 + 时间窗同一条消息被插两次
共享历史不等于共享活会话(懒加载反模式)「用户点进会话才拉」会话是否真的有更新电脑端在跑,手机端不更新也不通知

综合判断

  1. 代理量在「典型输入」下与真值一致,只在边界处分叉。 这正是它们难被发现的原因: 日常使用完全正常,只在「第一次」「刚好滚动到临界」「刚好那一次失败」时出错 —— 所以第一反应永远是「偶发」,而不是「判据错了」。

  2. 代理量往往比真值更「好拿」,所以会被顺手用上:事件序号比内容比较便宜, 固定像素比测量元素位置便宜,循环动画比接真实进度便宜,字符串 diff 比语义比较便宜, 数秒画面静止比接结构化事件便宜。省下的那点成本,全部以「静默错误」的形式还回来。

    顺带一个识别信号:代理量几乎总是「单点」的(一个 id、一个序号、一个数字、一个时间), 而真值往往需要多点或结构化信息(内容 + 会话 + 时间窗、内容前后对比、事件类型 + 状态)。 判据越依赖单点,越可能在边界处分叉。

  3. 可迁移的动作:写下任何一个条件判断时,追问一句 —— 「这个量和我真正要问的东西,在所有情况下都等价吗?」 只要答案不是「是」,就换成真值:内容比较、元素可见性、真实状态、显式记录。 配套:真值若不可得,就显式记录它(对照 更新时序要由本地最新状态决定)。

与既有 synthesis 的关系

为什么这是 synthesis

单看每一页,都是某个功能的一个具体 bug(粘贴丢图、标题时机、进度条、图片重试、缓存命中、 光标显示、打开即保存、长任务误杀、终端画面判结束、重复插入、懒加载不推送)。 并排之后才看得出它们共享同一个失败形状:用可得的代理量代替了要问的真值。 这个形状与框架、业务无关,可以直接带走。

相关