mcpField
R
report-with-html

report-with-html

github.com/daymade设计与 UI1.5k82 次安装今天更新
代码仓库

关于 report-with-html

用于制作以读者问题为核心的 HTML 报告和交互式信息工具。它指导作者从确定受众与证据,到视觉设计、无障碍交互和浏览器验证。

主要功能

  1. 01围绕读者问题规划结构
  2. 02明确受众与证据
  3. 03应用可视化规范
  4. 04构建无障碍交互
  5. 05在浏览器中验证页面

适用场景

  1. 01制作面向客户的数据报告
  2. 02呈现系统或因果关系
  3. 03构建资料集审阅工作台
  4. 04交付 HTML 演示文稿

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/daymade/claude-code-skills --skill report-with-html

安装后在 Claude Code 中输入/report-with-html确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
delivery-gates.json
regen-docs-template.py
report-template.html
assets/components/
citation-drawer.html
lightbox-gallery.html
source-preview.html
sticky-nav.html
assets/examples/
change_report.html
assets/examples/source-preview/
demo-image.html
demo-pdf.html
demo-text.html
references/
approved-examples.md
audience-triage.md
citation-source-preview.md
design-principles.md
independent-review-prompt.md
interaction-components.md
interactive-analysis.md
long-lived-report-maintenance.md
visual-evidence.md
visualization-patterns.md
scripts/
crop_segments.py
delivery_gate.py
reconcile_content_diff.py
render_report.sh
test_reconcile_content_diff.py

详细介绍

report-with-html

创建面向读者的 HTML 成品,其信息架构应遵循读者的问题,而非作者的实现清单。

触发范围

当用户请求的成品本身是可视化 HTML 报告或交互式信息工具时,使用此技能。典型输出包括:

  • 系统、架构、旅程、因果、决策、对比或差距视图;
  • 面向客户的数据报告或单页报告;
  • 数据/档案浏览器或审核工作台;
  • 明确要求的 HTML/网页演示。

普通状态回复、常规审查、代码差异、问题列表或 Markdown 文档不属于触发范围。这些任务可以在聊天中报告,除非用户明确要求将结果制作为可视化 HTML 成品。

默认交付内容是在浏览器中打开并经过验证的 HTML。PNG 是用于 QA 的成品,仅在用户要求图像时才交付。如果用户需要可编辑的 PowerPoint,请先完成并验证 HTML,然后使用 deck-creator(路线 C)。

SSOT 地图

图表设计判断由另一个技能负责——设计任何图表或几何图形前,请先加载它。 data-visualization-discipline:data-visualization-discipline 负责判断哪种形式适合内容、应使用哪种图表类型和汇总统计量、是否可以聚合分段、允许使用多少种类别颜色、跨视图颜色的对应关系、表格规范、反模式清单,以及交付前的自检关卡。本技能不会重复这些规则,重复一份只会导致内容不一致。本技能负责报告页面本身:登记表校准、组件库、已批准范例、页面顺序、决策卡规范、交互规范和浏览器验证。

  • 面向读者的原则、内容边界、决策卡规范、无障碍性: references/design-principles.md
  • 布局密度(铺满画布 / 消灭空洞)、作为叙事节奏的页面顺序、HTML 表格微型规范,以及从形式到组件的实现: references/visualization-patterns.md。 无论是否已经选定形式,都适用——其中大部分内容适用于每个页面,无论你绘制什么。此条目过去以“选定形式 →”开头,容易被理解为前置条件;2026-08 的一次交付将该文件归入“如果要构建这些组件,就查阅实现说明”的类别,没有打开它,最终交付的页面漏掉了其中三条规则。某个步骤隐藏在关卡后面时,该关卡不能要求你先完成尚未执行的步骤。
  • 已批准范例和登记表校准: references/approved-examples.md
  • 可复用交互及其键盘操作规范: references/interaction-components.md
  • 参数探索、选定记录的后续跟进以及可恢复的工作台状态: references/interactive-analysis.md。编写这些交互前请先加载;静态报告仍走常规流程。
  • 编号的悬停 / 焦点来源预览和原始内容适配器: references/citation-source-preview.md(候选 / 试点阶段;引用使用预览时加载)。
  • 照片、屏幕截图和说明性图表:references/visual-evidence.md。 当需要查看对象、实体选择、视觉缺陷或关系时,请在编写前加载;不要等到图片已经选好才加载。
  • 长期维护 / 生成页面: references/long-lived-report-maintenance.md
  • 全新上下文审查材料: references/independent-review-prompt.md
  • 暖纸风格的起始实现: assets/report-template.html

编写前请阅读这些内容——原则、模式文件、最接近的已批准范例,以及 data-visualization-discipline。其余内容根据产物的实际内容按需启用。

不要让“只阅读已启用的内容”来决定是否查阅上述必需资料。该筛选机制只会针对你已知的需求进行判断,因此从结构上就无法发现你不知道其存在的步骤——而且它还会给跳过步骤提供听起来合理的理由,这比单纯忘记更糟。这些资料会告诉你有哪些步骤。

产品规范

先明确读者和证据

在选择组件之前,先写明目标读者、页面必须帮助读者做出的决策或理解,以及权威来源。在本次会话中检索最新事实。每个数字都必须注明单位、日期或时间范围,以及可追溯的来源;未知值应保持未知。

屏幕文案可以包含事实性结论,但同一页面必须通过数据、机制或一手证据直观地支持该结论。删除缺乏依据的价值判断、口号、格言、最高级表述和未经证实的因果主张。像 不是.*是 这样的 grep 模式只能找出候选项;仅仅出现该模式绝不代表有问题。按照 design-principles.md 第 3 节中的测试逐一判断每个候选项——删掉这句话,看看读者失去的是一个可以在本页核实的事实,还是仅仅一个观点。前者保留,后者删除。

使用完整且易于目标读者理解的语言。内部代码、私下使用的缩写、没有上下文的算法评分,以及未作解释的缩略语都不应出现在页面上。

让问题决定页面骨架
  • “它如何运作?”→ 流程、架构或机制。
  • “我们应该做什么决定?”→ 选项、权衡、关键未知项和建议。
  • “为什么会发生?”→ 带时间戳的因果链,以及可证伪该因果链的证据。
  • “哪个更好?”→ 在共同基准下比较实体 × 标准。
  • “让我查看这个集合。”→ 列表/详情、搜索/筛选、状态、来源信息、深层链接,以及返回审核结果的路径。

实现状态只是页面骨架上的徽标,而不是页面骨架本身。缺失的依赖项、未经验证的结果或未知项必须保持可见。

对于技术选型或采购比较,在安排各个部分之前,遵循 references/visualization-patterns.md 中针对具体方案的阅读顺序。区分选择下一步调查什么,与批准采购或部署。

几何呈现与真实证据

使用位置和长度呈现重要的定量比较。颜色用于表示类别或状态,而不是第二个独立度量。几何编码必须配有明确的编码说明,并由数据支持读数。

不要用多种装饰形式重复绘制同一组实体。每个部分都必须回答不同的子问题。审查 UI 或视觉产品时,真实截图是一手证据:精确裁剪缺陷区域,同时保留足够的周边上下文,并确保前后对比图的裁剪范围完全一致。

统计图表应使用已安装的成熟图表工具,或当前项目声明的图表技术栈。如果两者都没有,应先调研并选择一个仍在维护的库,再开始实现;不要手动构建图表引擎。

交互与无障碍

对于会基于读者的参数或选择继续操作的计算器或工作台,在实现控件、状态恢复或返回对话前,先加载 references/interactive-analysis.md。请区分上下文准备、状态保存和显式发送消息;在独立浏览器中使用手动交接。

证据应呈现给读者,而不是让读者前往证据所在处。 当页面引用条款、截图或来源段落时,请在引用位置嵌入内容——使用原位叠加层或抽屉,让读者关闭后返回原处。将读者抛到页面其他位置、再要求其自行返回的锚点是禁止的,而不只是“不推荐”;design-principles.md §13 说明了这条规则及用户本人的原话。用于导航和外部深层链接的哈希锚点仍然合适:禁止的是强迫读者在阅读过程中离开。

请从 assets/components/ 复制已批准的交互组件,不要重新构建。行为属于组件契约的一部分;可以调整特定注册表的样式。复制每个组件时,必须遵循其完整契约:

  1. 阅读组件文件自身的头部契约——其中列出了注册表未重复说明的前置条件(必需的 CSS 令牌、必需的 DOM 结构、会扫描哪些元素类型)。例如,citation-drawer 只会在 <section> 元素内将文本转换为链接,并且需要由生成器生成的 #s9。
  2. 确保页面满足这些前置条件。
  3. 交付前,在真实浏览器中点击组件的主要交互。 组件可能已经存在,ID 唯一、标签成对,却完全无法使用——所有静态检查都能通过,但功能毫无作用。只有点击才能区分这两种情况。

每项交互都必须在没有指针的情况下正常工作:

  • 有原生按钮、链接和对话框时,优先使用;
  • 为模态界面提供可见的关闭控件,并支持按 Escape 键关闭;
  • 打开的模态界面应保持焦点在其内部,并在关闭时将焦点还原到触发控件;
  • 使用语义化 HTML 和 ARIA 呈现名称、状态和关联关系;
  • 保留可见的焦点样式、符合逻辑的 Tab 顺序,以及适用于窄屏的可用布局。

工作流

  1. 定义成功标准。 记录受众、问题、来源集、所需证据、交付形式,以及会导致产物失败的情况。关卡模板(第 5 步)还必须始终包含 读者已知清单 一栏——当声明的受众范围窄于“任何读者”(即内部且已有相关知识的读者,而非陌生读者)时,填写该受众应当已经了解的具体术语、脚本或系统,并使用反引号标记,以便核查。若受众确实是陌生读者,则填写 不适用: <why>——这一栏仍必须填写,只是填入该答案。请在第 9 步首次审查前填写,而不是等收到审查意见后再填写——有关为何此顺序至关重要,以及第 9 步如何使用此清单,请参阅 references/audience-triage.md。 从原始请求、后续更正和当前项目契约中确定实际的读者与预期用途。区分可发布的草稿与真正的外部发布。为该用途设定证据精度:对于私下调查,保留可追溯的原始标识符、路径和日志,而不是静默替换为公开的脱敏版本。遵循已授权项目现有的交付目录或文档库;临时目录是工作位置。若未确定目标位置,选择一个可逆的本地默认值并加以说明。只询问那些对结果有实质性影响且无法合理默认的缺失输入。对于调查,将完整的可读性与核心因果主张的证明记录为两项独立的验收结果。可读的报告并不能终结调查,只要必要的、已授权的行动仍能推进该主张;无法获取的历史证据仍属未知。

  2. 校准。 阅读必读来源 —— design-principles.md、 references/visualization-patterns.md、approved-examples.md 中最接近的条目,以及 data-visualization-discipline —— 然后阅读该产物所激活的任何组件参考。 使用最接近的已批准登记方式;不要盲目照搬外观。(这一步以前写的是 "被激活的模式参考",这让模式文件被归为尚未需要而被跳过;上面的 SSOT 映射解释了为什么该过滤条件在这里行不通。)

  3. 规划视觉证据与 造量纲 —— 在写下一行 HTML 之前。 首先遵循 references/visual-evidence.md,用于处理关于具体对象、物理选择、 视觉缺陷或关系的章节。将代表性图片放在相关选项 旁,并用图表解释关联;明确标识不可获取的证据。 将选定的视觉内容记录在现有的页面意图中,而不是另建一份清单。 逐节指明内容中哪些是 有序的 / 有量级的 / 有方向的 / 有对应物的,并把那个量 写下来。每种几何图形随后在标记中承载它:

    <div data-geometry="退款家数刻度轴"
         data-derived-from="退款家数(0–30 家线性,共同基线;位置=家数÷30)"> … </div>
    

    没有受支持的量或关系,就不要凭空发明几何图形。 将该 内容保留为散文;经过核实的照片或截图仍可展示该对象或证据。 把一句话包在彩色方框里并不会让它成为图表。

    一个数字与编码它的坐标出自同一个脚本。 一旦 任何几何图形由计算值定位 —— 一个条形的长度、位于 left:30.80% 的刻度、 一个坐标轴标签、一条线的端点 —— 就编写一个小型无依赖脚本,打印出 既是发现结果又是坐标,从它的输出中粘贴,并把该脚本随 页面一起交付。在散文中计算该值,然后手工编写 SVG 属性,是一个 有两份副本、没有任何 grep 能捕捉其漂移的事实:这正是同一个量在两个 章节中以两种不同方式取整的原因,也是一个坐标轴标签落在 较小数字的位置上的原因 —— 一个由恰恰在反对谎言因子的页面所制造的谎言因子。 交付该脚本还使绘图可审计:读者重新运行它并做差异比对。 第 5 步的关卡要求该脚本的路径并对该文件执行 stat,因此这条规则有一个机器 消费者,而不只是又一个只有你来裁决的东西。(它恰好有一个版本 仅是散文形式,一次独立审计将其列为下一个最可能被跳过的规则 —— 决定一个步骤能否存活的变量不是"它是否产出一个产物",而是 "是否有任何下游消费者消费该产物"。视觉纪律关卡 在被跳过时早已是产物步骤。) 为什么这是一个编号步骤而不是一条原则:这条规则已经存在于 design-principles.md §2 以及 data-visualization-discipline 中,并且在一次交付前 于这两处都被读到,而那次交付发布了八个散文章节和一个几何图形。 一个唯一的裁判是其作者的判断步骤会被理解而不是执行。 正是这两个属性让脚本能够看出该步骤是否发生。

  4. 创作。 如果调用的 Skill 提供了一个经用户批准的本地报告形式,且该形式仍然 符合本报告的输出契约,就以该形式为起点。否则 从 assets/report-template.html 或一个已批准的示例开始。模板的批准与存储归调用的 Skill 所有;本 Skill 负责报告的生成与视觉 QA。 让客户事实与结论紧扣当前证据,并且不要把 调用方的模板复制进本 Skill 由更新所拥有的 assets/。使用实际的 shelf 组件。如果页面嵌入了可变的源文档,请遵循长期存续报告 参考,并将生成区域与撰写区域分开。

  5. 运行交付门禁 —— 它会产出那些判断步骤否则会跳过的产物。

    uv run <skill-dir>/scripts/delivery_gate.py init  page.html [--height 9600]
    #   → renders page.png AND page--masked.png (all text transparent — the squint test,
    #     headless; see the script header for the technique's provenance)
    #   → scans for ≥120 CSS px whitespace voids (visualization-patterns.md 版面填充纪律)
    #   → writes page.html.gate.md: the delivery gates + the stage-1 questions
    #     (`STAGE1` in delivery_gate.py owns the exact list), every slot empty
    # Read the masked PNG segment by segment, fill every slot, then:
    uv run <skill-dir>/scripts/delivery_gate.py check page.html   # exit 1 until it passes
    

    check 会在以下情况失败:缺失或过期的遮罩渲染(因此若无 证据就不能声称完成遮字自测)、一个由百分比驱动但没有 data-geometry/data-derived-from 的视觉元素(因此 不能跳过造量纲 —— 纯布局盒子通过 data-layout 可见地选择退出)、任何 未填充的槽位,以及一个比页面更旧的 gate 文件(因此“填完了清单,然后继续 编辑”无法通过)。它断言这些步骤确实发生了;它并不说明结论是否正确 —— 那仍然是第 9 步和第 10 步。

  6. 渲染一份新的产物。 第 5 步已经按你传入的高度产出了 page.png; 只有在你此后修改过页面时才在此处重新渲染,并且传入相同的高度 —— render_report.sh 会原地覆盖,因此较短的 H 会悄悄地把一份好的渲染替换成 被截断的渲染。

    <skill-dir>/scripts/render_report.sh page.html page.png 1300 2400   # H is an example, not a default
    

    <skill-dir> 是本 skill 自己的目录 —— 它的绝对路径会在 skill 加载时提供给你。像 report-with-html/scripts/… 这样的裸相对路径只能从 某一个特定的父目录解析,在其他任何地方都会以退出码 127 失败。

    渲染器若没有产出新的有效 PNG 就会失败,并且从不把已存在的输出当作 成功。在 CI 或共享浏览器环境中,将 CHROME_BIN 设置为一个明确受管理的 Chrome/Chromium 可执行文件; 无效的覆盖会导致硬失败。

    然后将其切分并读取每一段 —— 一张很高的 PNG 超出了一次 Read 所能解析的范围:

    uv run <skill-dir>/scripts/crop_segments.py page.png --segments 5
    

    这一步也是捕获截断的地方。 Chrome 会严格按照你传入的 --window-size 截图,并且永远不会增大以适应内容,而渲染器的 PNG 检查只 能证明这些字节是有效图像 —— 因此高于你的 H 的页面会悄悄丢失其尾部, 而 design-principles.md 的 §6 把最强的结论放在最后。当内容延伸到画布最后一行时, 切分器会发出警告,这意味着画布截断了页面,而不是页面在画布内结束。 它在此处而不是在渲染器中检查,因为测量页面高度的唯一非变更方式是第二次 调用 --dump-dom,而后者在某些页面上会挂起 —— 一个永远无法测量的门禁就是一个 永远跳过的门禁。 该警告有一个误报,而且它看似显而易见的解决办法在这种情况下不会终止——因此重新渲染前,请先阅读警告中的两个分支。 如果页面有任何尺寸使用 vh(常见情况是 max-height:78vh 的滚动面板),那么无头模式下的 1vh 等于 H/100,因此增大 H 也会扩大该元素,内容在任何 H 下都会固定在画布底部。只需通过在一个明显不同的 H 下渲染一次来判断,并比较报告的内容底部位置:位置不变,说明之前确实被截断,现在已修复;位置仍约等于新的画布高度,说明陷入了 vh 循环。不要继续把 H 加倍——如果操作人员在 3000 和 40000 下看到相同的警告,就会开始忽略它;被训练成噪声的门禁,也就无法再捕捉它原本要发现的真正截断问题。

    还要使用真实设备模拟测试窄屏布局,并测量溢出情况。这里特意要求使用设备模拟:无头 Chrome 会将 --window-size 限制为约 500 CSS px 的最小宽度(2026-09-17 测量结果:请求 390 时得到 innerWidth=500;--force-device-scale-factor 也不会缩小 CSS 视口)。对于 390 级别的手机宽度,请使用 Playwright/CDP Emulation.setDeviceMetricsOverride(或 Ego)——绝不要把 --window-size=390 的运行结果报告为手机宽度测试。

    为比例门禁测量绘制出的条形范围时:以容器为锚点(先找到轨道框,再测量其中的深色像素),切勿在全局范围内对内容像素进行聚类——边缘抗锯齿会产生虚假的聚类,而长条本身会遮住所在的轨道行(这是 2026-09-17 出现的两个真实故障)。

  7. 走完整个流程。 在真实浏览器中,沿着读者的路径进行操作,而不只是逐项点击。测试理解顺序、明显的下一步操作、键盘访问、模态框焦点、深层链接、筛选器以及错误和空状态。使用 frontend-visual-qa 进行微观、宏观和意图审查。你嵌入的每个架子组件,都要在此处点击其主要交互,并记录观察结果——“抽屉已打开,并高亮显示第 7 条条款”是证据;“组件已存在”则不是。检查实际图片能否加载、重要细节是否清晰可读、说明文字是否紧邻对应视觉内容,以及交付的本地文件是否缺少资源。

  8. 核对并验证。

    对于合并或当前状态更新,请按照 references/long-lived-report-maintenance.md §6.1 中的语义验收约定执行。将信息点映射与门禁证据一起保存;来源链接索引并不是所要求的综合整理。

    • 对于重写或合并,运行:

      uv run --python 3.12 python <skill-dir>/scripts/reconcile_content_diff.py old.html new.html
      

      它会在 Chrome 中打开这两个页面,并比较页面初始状态下计算得出的、读者可见的文本。它不会遍历标签页、折叠面板或其他由交互创建的状态;这些状态应在 Journey/浏览器测试框架中覆盖。

    • 对于生成的长期页面,运行页面生成器,然后运行其 --check 模式。锚点缺失或重复、输出过时都属于失败。

    • 搜索过时信息、简写、缺乏依据的说法、错误的文件路径,以及重复的版本/状态值。

  9. 独立读者审查——并留下记录文件。 审查者必须从未继承任何对话或作者推理的状态开始:在 Codex 中使用 fork_turns: "none";在 Claude Code 中启动一个单独的非 fork general-purpose Agent,并在提示词中提供所有必要的读者背景信息。将 HTML 和渲染后的截图交给审查者——除此之外什么都不要给(下表写着“只有页面,不要给其他内容”;截图就是页面,纯文本审查者会通过阅读源代码回答视觉问题,在书面记录中无法分辨他是否真的看过页面),并逐字使用 references/independent-review-prompt.md。读者理解方面的问题都属于缺陷——但有一个例外:下文的 读者已知清单,页面不能声称其狭窄受众以外的读者都已知相关信息。将建议的实现更改视为假设,并在修改产物前复现问题。

    将页面交给审查者之前,先确认审查者确实能打开浏览器——有几个审查问题涉及焦点、Escape 和键盘顺序,纯文本审查者会通过阅读源代码来回答。你无法在启动子 Agent 之前查看其能力,因此应将这项检查设为审查者的第一个操作:要求它尝试执行浏览器步骤;如果无法执行,就在输出中注明 “browser unavailable — items 7 and 8 answered from source”。未注明的源代码阅读答案才是失败;已注明的答案则是一个已知缺口,你可以通过其他方式弥补。在书面记录中,这种答案与点击页面得出的答案无法区分,而它恰好会落入此技能警告的盲区:所有静态检查都通过,功能却完全不起作用。

    在页面旁边(或审查档案中)写入一份文件,记录审查结果:如何启动审查者(Agent 类型,以及它不是 fork)、你提供的提示词、每项发现的处理方式及理由,以及哪些内容无法检查。记录启动详情,因为 fork 的书面记录看起来与独立审查完全相同——两者唯一的区别在于启动方式,而如果从未记录下来,包括你在内的任何人都无法验证上述独立性要求。这份文件本身就是重点:没有留下任何记录的审查,与打算开展但最终未开展的审查无法区分;这正是此步骤真正的失效模式。问题不在于作者不同意此步骤,而在于交付压力之下,它是最容易被悄悄省略的一项。 在将任何“我看不懂”发现计入之前,先根据 读者已知清单 进行暂定分流; 第 10 步会独立重新推导,这并非自我检查。 审阅者的零背景设定是刻意为之,不会改变——但 清单中第 1 步已列出的术语属于虚构问题(Sauro,MeasuringU):审阅者确实无从知晓该术语,而声明的受众实际上并不会因此困惑。将 审阅者的发现逐字引用,并放在与之对应的清单条目旁—— “可归结为一个已知术语”是一种解释性主张,并非检查文件是否存在;引用原话才能让你以外的人判断这种归结是否诚实。将 处理结果记录为 audience-declared-known,并附上该引用和原因;此结果不计入下文的同一维度重复出现测试。被标记的术语若不在清单中, 要么作为真实发现保留,处理方式与目前相同;要么现在加入清单——这种情况下,要在门槛文件中直接写在对应条目旁注明 (补记于 cycle N 审阅之后),不要悄悄将它混入原清单。不要倒填日期:init --force 保留的“上一轮的答案”附录已经记录了本轮开始前的清单内容,因此, 将新增条目悄悄混入清单,只需对比当前清单和该附录就能轻易发现——请坦诚说明,而不是指望有人去做这种对比。完整机制以及为何此轮是暂定而非最终判断的依据,见 references/audience-triage.md。

    是否需要再次执行,应以观察为依据,而非自我评估。 请问: 自上次记录的审阅以来,页面的骨架、组件、决策卡片 内容、任何数字,或审阅者需要解读的任何术语或标签是否有所变化? 只要有一项为是 → 就需要新的审阅者,因为上一位审阅者看到的是不同的页面。术语重命名值得单独提及:这是修复审阅者“无法理解的词语”这一发现的标准方法,而且很容易被归入措辞调整——但新词除了你以外还没有任何人读过,而这正是本次审阅要消除的情况。错别字和标点修正 → 无需重新审阅;在结项说明中写明即可。不要通过自问这次改动“感觉上是否属于结构性变更”来做决定。有记录在案的失败案例是:先把页面作为文字审阅,随后又将其重制为图形——每次重制都感觉像是在润色一份已经审阅过的页面,结果连续三个版本发布时都没有任何人读过。

    这一触发条件本身没有上限——必须配上预算,否则“任何实质性编辑都需要审阅”会不断催生新的审阅轮次。 每一项真正的修复,按定义都恰好属于上述触发条件要求重新请审阅者审阅的变更,因此,从单轮审阅中无法区分一个逐渐收敛的审阅流程和一个失控的流程——这种失败既出现在小规模场景(为解决一项低风险修正,完整进行了三轮审阅),也出现在大规模场景(一个真实决策文档经历了 21 轮审阅,直到有人类询问原因才停止)。这是 claude-code-hooks 的 SKILL.md 规则 7 中的 Loop Contract——“如果钩子要求整改,就证明循环会终止” (daymade-claude-code/claude-code-hooks/SKILL.md (daymade/claude-code-skills),可在此阅读通用框架及其失败案例详解)——在此步骤中的具体应用,而非钩子:

    LOOP KEY: this delivery's lineage (the HTML frozen at round 1 plus every descendant
              edit) + one failure axis: can a fresh, uninformed reader use this page?
    FIRE T:   after audience triage (above), a review still answers review-prompt item 9
              "no" — or surfaces any finding that amounts to the same thing (the reader
              could not actually make the decision this page exists to produce) — on that
              same axis, using only findings that survived triage
    REMEDIATION R: reproduce the finding, apply one bounded fix, re-run the review once
    VARIANT V: 2 - completed review cycles for this lineage
    BUDGET:   2 cycles total — the initial review plus one narrowly scoped re-review.
              A third reviewer on this lineage is never automatic.
    SUCCESS EXIT: the re-review answers item 9 "yes" on that same axis, with nothing else
              reopening it
    AUDIENCE-MISMATCH EXIT: EVERY SINGLE post-triage reason behind a cycle's "no" disposes as
              audience-declared-known — ship, log the disposition table, do not report this
              to the user as blocked. "Every" means every: a "no" with two reasons, one
              audience-related and one a genuine unrelated defect (a chart missing a unit, a
              broken cross-reference), is not this exit — the unrelated reason alone routes
              through ordinary REMEDIATION/CAPPED EXIT, same as if it had appeared by itself.
              This can fire after cycle 1 alone: if nothing survived triage, there is no
              finding for REMEDIATION to reproduce and fix, so a mandatory cycle 2 would just
              re-review an unchanged page for a second phantom verdict.
              (see `references/audience-triage.md`)
    CAPPED EXIT: at least one post-triage finding is real and recurring across two cycles —
              stop, report the remaining findings as a backlog, do not ship silently, and do
              not dispatch a third reviewer on your own authority
    

    这项技能自身的评审输出没有可供判断的严重程度词汇——评审提示词(references/independent-review-prompt.md)返回的是已回答的问题,而不是标有 BLOCKER/MAJOR 等级的问题发现;第 10 步的验收词汇也是 PASS / FAIL / CANNOT-CHECK——因此,上面的 FIRE T 和 SUCCESS EXIT 依据的是评审提示词第 9 项的“最后一问”的回答(读者能否不需要其他解释就根据此页面采取行动?),而不是规则 7 中的严重程度标签示例。后者描述的是另一种评审,并未在这项技能的其他地方出现。

    同一维度上再次出现的问题,与新出现的无关问题,在第 2 轮中要区别处理——把两者混为一谈,就会让有界循环不断扩张。首先,对每一轮的问题发现应用上文的受众分类;以下内容只涉及经过分类后仍保留的问题。如果第 1 轮的问题发现经处理后全部归为受众已知,则应立即走 AUDIENCE-MISMATCH EXIT——第 2 轮没有需要重新评审的内容。

    • 第 2 轮再次发现第 1 轮已指出的同一维度上的理解障碍(即使具体措辞有所变化,读者仍然无法使用此页面)→ 只有当该问题发现通过分类后仍保留时,才属于上文的 CAPPED EXIT。如果两轮的问题原因经处理后都全部归为受众已知,则应走 AUDIENCE-MISMATCH EXIT——直接交付,不要报告为受阻。如果确实有问题在分类后仍保留并再次出现:停止。报告为 blocked。不要以“但这个问题确实存在”为由再触发第 3 轮——缺少的从来不是问题是否真实,而是一个获得用户授权、且预算预先设定的新任务;只有用户才能开启这样的任务。
    • 第 2 轮发现确实全新且无关的问题(第 1 轮关注决策卡是否清晰;第 2 轮顺带指出一个无关的颜色问题)→ 将其记录为单独的待办事项,交由单独的任务处理。它不会占用本次任务链的预算,也不能仅凭这一点成为在本任务链上启动第 3 轮的理由——交付已趋于一致的内容;如果用户希望立即跟进,就将新事项作为独立评审开启,并为其设定单独的预算。 如果这条谱系此前已经通过步骤 10,同样的越界问题仍然适用。 正式验收并非不会被重新开启;这与上述问题是不同的失败——即使沿途的每项发现都是真实的,并且涉及全新的维度,它仍会再次发生(同一条谱系上的三次独立验收均通过,且每次都确有依据,是有记录的最坏情况)。如果步骤 10 已为这条谱系给出无问题的判定,而现在又要启动新一轮步骤 9/10,那么这一越界本身——在判断新发现是否属实之前——就是停止并询问用户的信号,而不是悄悄重新开启。
  10. 独立验收。 将以下验收清单、页面及其来源,以及原始请求、后续更正、输出契约和必需的验收标准,交给另一位全新上下文的 Agent——必须与步骤 9 中的审阅者分开,因为两者要回答不同的问题(见该清单下方的表格)。它会为每项给出判定和证据。它判定为 FAIL 的项目是需要你复现并修复的问题,与步骤 9 的问题完全一样;只有它判定为 PASS,项目才算关闭。

  11. 评审后定稿。 应用已接受的修复,重新渲染,重复浏览器操作流程,并且重新运行交付门禁——在填写门禁文件后编辑页面会有意使其失效,因此此时 check 显示红色是设计如此,并非故障。重新运行 init --force(它会将先前的答案附加在末尾,方便你复核后移回,而不必重新输入),重新阅读新的遮罩渲染版本,仅在确认答案仍然成立后才将其移回,然后再次运行 check。只有完成这些步骤后,才能为用户打开最终 HTML。不要把评审前的草稿作为交付成果。

新经验应该放在哪里——在将其写入本技能之前,先按顺序回答以下两个问题。

首先:失败是因为“我忘了做”,还是因为*“我做了,却没看出哪里有问题”*?** 前者属于上述工作流;提醒就能解决。后者必须变成由他人提出的问题,因为作者并非跳过了检查——他们明明仔细看过,却认为没有问题。颜色、术语、图表是否能支撑自己的说明文字、决策卡是否缺少选项:都属于第二类。把这些内容列成由作者自行回答的清单,恰恰会让规则虽然写了下来,却依然被违反——这正是本技能中每条不得不艰难重学的规则都曾发生过的事。

然后,如果问题要由他人提出:能否仅凭页面作答? 能 → 使用审阅者提示词(references/independent-review-prompt.md)。不能 → 使用下面的验收清单。第二个问题能防止两份清单彼此重复;下表从另一个角度说明了同一条界线。

交付验收——此清单由独立 Agent 执行,而非你自己

审阅者评审和验收共同完成交付,二者没有重叠:每项检查恰好只属于其中一方,因此不存在职责逐渐分化的问题。

步骤 9 · 审阅者评审步骤 10 · 验收
获取内容仅页面,不含其他内容(截图也算页面)页面加上原始请求和更正、输出契约及必需的验收标准、你的来源、命令、评审文件,以及门禁产物
要回答的问题你能读懂它吗?你能依据它作出判断吗?它是否交付了所请求的结果?页面之外的内容是否与页面上的内容一致?
问题列于references/independent-review-prompt.md——所有问题均须原样使用以下各项
判定依据页面上所有可见内容原始任务要求、来源依据和流程
**拆分规则,确保未来新增内容只落在一处,而不是两处:**回答这个问题是否需要页面以外的信息?不需要 → 这是读者问题;将其加入审查提示词。**需要 → 应放在这里。**颜色、措辞、图表是否能支撑自身的标题说明、决策卡片是否缺少一个选项、各级标题是否构成论证——这些都能在页面上看到,都是读者的问题。以下检查需要读者无法获取的信息。

将此列表、页面及其门控材料(page.html.gate.md、page--masked.png)、原始请求和后续修正及其来源坐标、现有输出契约和必需的验收标准、关键事实背后的来源、你运行过的命令,以及第 9 步审查文件,一并交给一个具有全新上下文的 Agent(非 fork)。你可以先自行检查——这样能以较低成本发现明显遗漏——但你不能宣布这些项已通过。

明确说明为何不能自查,因为越接近交付,越容易想跳过这一步:此列表的早期版本要求作者“能够指出”每一项,作者总能真心实意地声称自己做到了。改写后要求粘贴证据,解决了一半的问题——现在证据确实存在了——但另一半问题依然存在,因为作者仍要判断自己的证据是否充分。这些项目背后的失败都属于同一种情况:作者觉得图表足够清晰,作者考虑并认可过的配色方案,作者从未注意到缺少不利因素的建议。这些都不是忘了某个步骤。提醒无法纠正这类错误;需要另一双眼睛。

要求提供:项目编号、PASS / FAIL / CANNOT-CHECK,以及具体证据——引用的原文、计数或命令输出。无法检查的项目应如实报告,不得标记为通过。

  1. 请求的结果——现有验收 Agent 首先逐一对应每项必需的读者问题或输出,指出其在交付页面中的答案和证据,并引用要求原文和页面位置。缺少答案,或以样本/原型替代必需报告,即使交互、渲染和门控都通过,也判定为 FAIL。若请求仅要求样本,则按该范围评判;不得要求提供请求中从未要求的完整报告。缺少原始要求时,判定为 CANNOT-CHECK;不得根据作者范围更窄的契约推断。此项是语义验收,并非交付门控脚本能够确立的内容。

  2. 来源追溯——每项关键事实都能追溯到页面之外的来源,并注明截至日期:不仅包括数字,还包括引用的条款、关于某人同意了什么的说法,以及关于依赖项状态的陈述。读者可以拿页面与其自身内容核对;只有这项检查才能将页面与现实核对。无法追溯的内容应从页面中删除,或明确标记为未知。 对于有来源的图片,将实际文件与其原始发布者及确切的对象/变体匹配,然后检查标题说明的限制以及预期交付用途是否获准。 对于图表,将关键节点、连接和尺寸追溯到来源;用于解释的绘图不能证明系统已组装或部署。

  3. 最新渲染——渲染的 PNG 文件时间晚于页面最后一次编辑。替换为实际文件名:

    [ page.png -nt page.html ] && echo FRESH || echo STALE
    

    使用这种写法,而不是 find page.png -newer page.html:当 PNG 缺失或文件名拼错时,find 会向 stderr 输出错误,而“有输出”随后会被判定为通过。-nt 会将过期、缺失和文件名错误合并为一个 STALE。

  4. 内容完整性 — 如果页面经过重写或合并,必须提供 reconcile_content_diff.py 的输出;如果页面由生成器生成,则必须提供生成器的 --check 输出。这些检查可以发现文本遗漏或生成输出偏差;但都不能证明语义完整、矛盾已协调或业务状态为最新。 对于合并或更新当前状态,还应检查信息点映射,以及交付门禁中 合并与现行事实验收 要求的证据。遵循长期报告参考的 §6.1:拒绝将归档索引冒充为综合总结、将历史快照冒充为当前状态,或将已存储的证据冒充为生产环境采纳情况。 如果作者声明两者均不适用(手动编写、第一版),请按原样记录该答复——明确跳过可审计,擅自假定则不可审计。 阅读这两项输出时应正确解读,而不是一带而过。协调器会打印实际比较的片段数量;数量接近零表示“没有可比较的内容”,而不是“没有内容丢失”——它的提取器会抽取以中文字符开头的连续文本,因此非中文页面几乎不会有结果。如果发生超时——Chrome 在时限内未能生成完整 DOM——应将该项记录为未完成协调,绝不能记为通过。生成器的 --check 也有自己的盲点,现在已对此加以防护——它比较的是自洽性,因此两边都没有子句锚点时,看起来会完全一致;所以它会单独断言锚点数量,并在数量为零时以非零状态码退出。

  5. 审阅完成情况——打开第 9 步的审阅文件,逐字引用一条审阅者自己的发现,并记录该审阅者是如何启动的。路径只能证明文件存在且作者写了该文件;只有审阅者自己的原话和启动详情,才能证明审阅确实运行过。然后检查每条发现是否都有处理结论,并询问此后做过的每项改动:如果改动不止措辞——包括框架、组件、决策卡内容、任何数字,或任何需要审阅者解读的术语——第 9 步就要求重新邀请审阅者,因此要确认是否进行过重新审阅。如果页面声明了 读者已知清单(第 1 步),那么作者对每条 audience-declared-known 发现所作的处理,属于暂定的初步判断,而非最终结论——要让它真正成立,必须独立重新推导,而不是再次审视作者自己的结论:阅读审阅者引用的发现及其对应处理的清单条目,并在不先阅读作者所述理由的情况下,独立判断自己是否会作出相同分类。如果某条发现只是顺带提及清单中的术语,而实际问题是其他内容(图表的主张、失效的交叉引用、颜色冲突),就不能仅因术语在清单中便判定已处理——要检查审阅者的句子实际在批评什么,而不是其中出现了哪些词。不同意作者的分类 → 该项就尚未处理,不能算通过,无论作者写了什么。还要确认声明的术语确实是页面的读者会接触到的内容——把术语塞进注释、alt 文本、aria-hidden 内容或 display:none 标记中,虽然从技术上说满足“出现在页面上”,但读者不可能在阅读此页面时就已了解该术语;据此处理发现,正是 references/audience-triage.md 所指出的钻空子方式。最后,检查清单本身的历史记录:如果某个已处理的术语不在本次审阅周期之前、门禁文件“上一轮的答案”附录中保留的 读者已知清单 版本里,且门禁文件没有在该条旁边明确说明(例如 补记于 cycle N 审阅之后 或类似表述),这就是未标注的事后补录——应视为尚未处理,而非通过。带有标注的后续补录不会自动失去资格;应像评估其他条目一样,判断读者是否确实早已了解该术语。

  6. 交付门禁已运行,且其答案描述的是此页面——要求提供三项内容,因为前两项很容易伪造,而第三项才赋予它们实际意义: (a) page.html.gate.md 和 page--masked.png 确实存在,且 check 此刻退出码为 0 (粘贴输出)。非零退出码表示此项不通过,不是让作者趁你等候时重新运行 init --force 再试一次;页面交到你手上之前,门禁就应该是绿色的;(b) 先数出遮罩 PNG 中可见的不同几何图形,记下数量,然后再打开门禁表——先读表会让你去寻找表中列出的形状,这就是方向已知的确认偏误。然后比较两个数量——此处以遮罩渲染图为准。判定不匹配之前要先考虑两点:长页面需要先运行 crop_segments.py(19000px 的 PNG 无法在一次 Read 中读清),而且一个复合几何图形合理地会呈现为多个形状——例如带有主轴和嵌入图的时间线,或成对的前后对比柱;因此,要数两次之前,先查看对应门禁行自己的 data-derived-from。真正的不匹配意味着扫描器漏掉了某个视觉元素(它只读取静态标记:少数属性上的内联百分比样式,以及 <svg>/<canvas> 元素——通过 CSS 类设置的宽度、渐变色标、transform 百分比,或 JS 库在运行时注入的图表,扫描器都看不到;注意,<canvas> 元素能被捕捉,但它绘制的内容不能),或者某个包装项将多个图形算作一个;(c) 随机挑选 两个已填写的行,亲自对照遮罩 PNG 检查每行的“遮字后读出的关系”。一行太少——伪造单行内容能以 1/N 的抽查概率蒙混过关。还要评判正确的对象:问题不是“这句话是否属实”,而是**“不打开那张图片,能否仅凭源内容写出这句话?”** 仅仅复述标记内容的说法(“六根柱子从左向右逐渐升高”)通过了第一项测试,却过不了第二项;如果你得到的只有这种说法,就要明确指出。遮罩 PNG 的来源也很重要——它由作者自行运行生成,因此如果有任何地方看起来不对,就在副本上自行运行 delivery_gate.py init --force 重新渲染并进行比较。

    坦率说明此项存在的原因,因为这是作者最有理由省略的一项:没有它,第 3 步和第 5 步就是可选项。对 2026-08 版本的一次独立审查发现,整个门禁可以零成本跳过——没有任何下游角色要求提供其产物,因此作者可以跳过第 3 步和第 5 步,完整执行第 6 步到第 11 步,而无人察觉。没有人负责检查的门禁,只对原本就会完成这些工作的人有意义。

如果某项无法回答,就应如实记录这一缺口,而不是宣布页面已完成。坦诚说明的缺口能让读者采取行动;一张涵盖了从未执行过的检查的绿色清单则不能。

依赖项

  • 如果可用,使用 content-writing-discipline 获取用户的写作/语体规则;
  • 使用 frontend-visual-qa 进行浏览器和视觉检查——它随同级的 claude-code-skills 套件提供,不属于本套件,因此在某些会话中可能无法加载。 如果不可用,请直接进行检查,不要跳过:逐段阅读渲染后的 PNG,检查微观层面 (排版、对齐、对比度)、宏观层面(页面节奏、章节平衡)和意图(每个视图是否 回答了相应的子问题);
  • 使用 Google Chrome 或 Chromium 进行渲染——第 5 步的门槛检查也需要它,此外还需 uv(它会从 PEP 723 头部安装 delivery_gate.py 所需的 pillow)。旧工作流 仅使用标准库即可从头运行到尾;新工作流不行,因为门槛检查的全部目的就是生成 产物。如果缺少这些依赖,请在验收项 5 中说明无法检查及其原因——不要将该项 报告为已通过,也不要悄悄跳过第 3 步和第 5 步;
  • 使用 Python 3.10+ 进行 PNG 验证和内容核对——reconcile_content_diff.py 仅使用 标准库;delivery_gate.py 通过 PEP 723 声明了 pillow,uv run 会自动安装它—— reconcile_content_diff.py 使用的 X | None 注解在 Python 3.9 中会引发错误;
  • 可选:使用 d2 绘制自动布局图表;
  • 仅在 HTML 设计获批且需要可编辑 PPTX 时,才使用 deck-creator(路线 C)。

评论

支持 Markdown