☰
从不误吵醒 Agent 的被动检测:lavish-axi iframe 布局审计实现深解
2026/9/26 8:37:38 网站建设 项目流程

从不误吵醒 Agent 的被动检测:lavish-axi iframe 布局审计实现深解

【免费下载链接】lavish-axiHTML is the new markdown. Lavish is the new editor for your HTML artifacts.项目地址: https://gitcode.com/gh_mirrors/la/lavish-axi

lavish-axi是一款面向人与 AI Agent 协作的本地优先HTML 编辑器:Agent 写好 HTML 产物,用户在本地浏览器里审阅,可以点选元素、选中文字,把反馈发回给 Agent。其中最精巧的设计是它的iframe 布局审计——一套被动检测机制,能发现文字被裁切、按钮被剪掉、内容跑出视口等严重布局故障,但永远不会因为"发现了问题"就去吵醒 Agent 🤫。

什么是"被动检测"?先看两种思路

Agent 生成的 HTML 经常"看着能跑、实际有伤":一段标题溢出了卡片、一个按钮被容器剪掉一半。传统思路是检测到问题就立刻通知 Agent 修复,但这会带来两个麻烦:

  • 误报即骚扰:检测逻辑稍有噪音,Agent 就会被反复唤醒去"修"并不存在的问题;
  • 浪费轮次:用户可能只是扫一眼,根本不想修。

lavish-axi 选择了另一条路:检测永远是被动发生的。审计在 iframe 里静默运行,发现的结果只落进顶部的Layout issues收件箱;只有当用户手动勾选问题并点击Queue selected fixes时,Agent 才会通过常规的长轮询通道收到一条layout-warnings提示。源码里把这个原则写得很直白:

检测从不返回lavish-axi poll,从不唤醒 Agent;只有用户排队修复才会。

这个约定见 src/layout-warnings.js 文件头部的注释,也是整个模块的设计基石。

审计盯住哪 6 类严重布局故障?

审计只报告"有直接渲染证据"的严重失败,规则与用户看到的大白话描述在 src/layout-warnings.js 中一一对应:

规则含义用户看到的描述
page-horizontal-overflow页面整体横向溢出页面比视口宽,内容跑到了屏幕外
clipped-text文字片段越过容器裁剪边界文字被容器裁掉了
clipped-control必要控件被容器剪掉一部分按钮的一部分无法使用
viewport-unreachable-control必要控件在视口之外控件够不到
viewport-unreachable-content文字片段在视口之外这段文字读不到
overlapping-text文字被不透明兄弟元素大面积遮挡文字被盖住读不了

只有severity: "error"的发现才会入箱(见 src/layout-warnings.js),轻微抖动一律忽略——宁可漏报小瑕疵,不可误报。

审计如何等到"稳定时刻"再出手?

浏览器里做布局测量最大的坑是"测得太早":字体还没加载完、动画还没结束、响应式布局还没算完。审计入口 auditLayout() 之前有一整串"稳压器",全部位于注入到沙盒 iframe 的 SDK 中(src/artifact-sdk.js):

  1. 等字体:document.fonts.ready——字体切换会显著改变文字几何;
  2. 等尺寸稳定:用ResizeObserver监听前 800 个元素,180ms 无变化才算稳定,最多等 2 秒;
  3. 等有限动画结束:入场动画、过渡最多等 4 秒;无限动画(如持续旋转的装饰)则放行,但动画关联的元素会被整体排除在检测之外;
  4. 采样两到三轮:先测一遍,间隔 120ms 再测一遍,若 DOM 仍在"水合"(MutationObserver 观察到变化)则等其静止后再测第三轮,最后只发布两轮都稳定存在的发现(findStableLayoutFindings)。

审计会在load、resize、animationend、transitionend等事件后自动重排(startLayoutAudit),所以用户手动缩小窗口触发的响应式塌陷也会被捕获。

如何避免误报?一份精心设计的"豁免清单"

这是该模块最见功力的部分——大量看起来"越界"的布局其实是作者意图,审计会主动豁免(src/artifact-sdk.js):

  • ✂️显式省略号 / line-clamp:作者想截断,就不算事故;
  • 🙈标准 visually-hidden 无障碍文本(2px 裁剪的 sr-only 写法);
  • 🎠有意的横向滚动容器(轮播、横向列表)及其后代;
  • 🎭蒙版 / 圆角裁剪(mask、clip-path、带圆角的 overflow 容器)属于装饰手法;
  • 🖼️装饰性重叠(海报式叠字)不产生文本遮挡发现;
  • 🎬正在运动的元素:动画未结束时的中间态不算证据。

阈值也经过校准:文本要"越过裁剪边界 1px 以上且中心点在界外,或超过 20%"才算严重(classifySevereTextOverflow);页面级横向溢出必须同时满足"有真实内容逃出"且超出max(24px, 视口宽度 5%)(isMaterialPageOverflow)。遮挡检测则是对文字片段取 9 个采样点做elementFromPoint,不透明遮挡占比 ≥90% 且样本 ≥5才报(isNearTotalOcclusion)。

为什么告警不会"误消",也不会"重复刷屏"?

发现落库后,applyDiagnosticPass 按一套刻意保守的生命周期来维护记录:

  • 稳定指纹:规则 + 归一化目标 + 视口档位(layoutWarningFingerprint)生成 16 位哈希,同一个问题反复检测只会更新同一条记录,绝不虚增计数——溢出量甚至被刻意排除在指纹之外;
  • 视口隔离:mobile / compact / desktop三档视口互不干扰,桌面端的通过永远不能清除手机端的告警;
  • 只有正向证据能解决:Resolved要求"更新的产物加载 + 同一视口的一轮完整审计不再检出"。审计失败、页面没加载完、换了一个视口,统统只会把记录标成Unverified(未验证)而非清除;
  • 状态机:Open → Queued for fix → Still present / Returned,外加Unverified / Dismissed / Obsolete / Resolved(完整枚举见 src/layout-warnings.js),每次状态迁移都写入有界的历史轨迹,方便回看"这条告警是怎么来的"。

这套规则有完整的单测覆盖:test/layout-warnings.test.js 里的用例名本身就是一份需求文档,例如"a different viewport class can never clear a warning"、"a newer complete matching-viewport pass without the finding resolves it"。

用户视角:从徽章到 Agent 修复的完整链路

  1. 审计完成后,顶栏出现Layout issues按钮与未解决计数;没有问题时按钮直接隐藏;
  2. 打开抽屉,每条问题展示严重程度、大白话解释、受影响视口、组件标识、最后出现时间与状态,并提供Reveal(在产物中高亮定位)与Dismiss(仅对当前产物版本生效);
  3. 勾选若干条(或Select all),点击Queue selected fixes——整批问题合并成一条普通排队提示,标签为layout-warnings,随用户下次发送走常规反馈通道;
  4. Agent 收到的是结构化载荷:每条带选择器、轴方向、溢出像素、视口档位(layoutWarningPromptPayload),并要求"一次修完、保存一次",让审阅页只刷新一次。

交互细节可见 test/layout-warning-inbox.browser.test.js。

打开时的布局闸门:只挡一瞬间

打开审阅页时,产物会先被遮罩盖住,只等第一轮真实的 iframe 审计完成就立刻揭开——无论查到什么问题。第一次完成的客户端检查即放行,绝不让网络往返或修复请求"绑架"审阅;超时有兜底超时自动放行,用户还能随时点Show anyway。用--no-gate可以跳过这层幕布(见 README.md 的Open-time layout gate一节)。

靠什么保证"不误报、不吵人"?真实浏览器回归测试

项目用真浏览器对一整组夹具页做回归(test/layout-audit-browser.test.js),夹具就在 test/fixtures/layout-audit/:

  • control-broken-*四类故意做坏的页面(溢出、裁切、可达性、遮挡)必须在桌面 + 移动视口下各报出预期条数;
  • real-*-clean一组真实但健康的页面(产品计划、仪表盘、杂志排版、轮播、动画入场)必须保持沉默;
  • 断言里有一行点睛之笔:detection alone must never wake an agent——检测到问题后执行 poll 仍然返回waiting;
  • 修复后的产物重新加载并通过完整审计,计数归零——全程 Agent 从未被唤醒。

小结

lavish-axi 的 iframe 布局审计把"检测"和"修复"彻底解耦:

  • 对 Agent 安静:检测永不触发轮询返回,只有用户排队修复才产生提示;
  • 对用户有用:每条告警都有大白话解释、可定位、可忽略、可批量修复;
  • 对状态诚实:只有正向证据能清除告警,失败与不确定一律显式标记。

如果你也在做"AI 生成 HTML + 人工审阅"的产品,这套 src/layout-warnings.js + src/artifact-sdk.js 的"被动检测 + 保守生命周期"设计,值得完整读一遍源码。

【免费下载链接】lavish-axiHTML is the new markdown. Lavish is the new editor for your HTML artifacts.项目地址: https://gitcode.com/gh_mirrors/la/lavish-axi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询