tdesign-component-align-review
Review TDesign Flutter 组件的公开 Demo、API 收敛、Flutter 设计模式、主题、测试和 Golden 证据。以小程序公开 Demo 作为可见效果参考,但不机械映射其 props/events;适用于组件对齐和 PR Review。
Source facts
- Repository
- Tencent/tdesign-flutter
- Last source activity
- October 13, 2026 at 17:07
- Detected SKILL.md language
- Chinese
- Stars
- 1,215
- Forks
- 186
Install options
The review-first prompt is selected by default. You can switch to a direct command or download a local copy.
Review the source files
Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.
Showing SKILL.md
SKILL.md
Source instructions · Read-only preview- name
- tdesign-component-align-review
- description
- Review TDesign Flutter 组件的公开 Demo、API 收敛、Flutter 设计模式、主题、测试和 Golden 证据。以小程序公开 Demo 作为可见效果参考,但不机械映射其 props/events;适用于组件对齐和 PR Review。
# TDesign Flutter 组件 Review
依据当前 PR 的实际源码、运行结果和测试进行 Review。仅请求 Review 时只审查;已获授权的修复或 PR 更新按约定范围继续执行,不重复索取许可,也不从 Review 请求推导修改权限。
本 skill 只补充组件对齐专项规则。分支、Spec、更新日志、双版本兼容、lint 和 PR 模板仍以仓库 `CONTRIBUTING.md`、`specs/README.md` 与 `tdesign-flutter-general` 为准。仓库 `.agents/skills/tdesign-component-align-review/SKILL.md` 是唯一维护源,外部安装副本只做镜像,不得独立演化。
使用外部镜像时,文中的仓库文件和相邻 skill 引用均从目标仓库对应路径解析,不从本机安装目录寻找仓库规范。
## 1. 冻结证据
记录实际 checkout、Flutter PR 的 base、head、commit 和改动文件。涉及跨端 Demo 时,同时记录小程序版本或 commit、公开 Demo 入口及直接使用的模板、样式和脚本;不要把本地过期分支或单个截图当成当前基准。
区分实现事实与对齐目标:当前 Flutter 源码、运行和测试用于判断实际行为;目标以用户指定的设计稿、版本或契约为准,未指定时参考小程序公开 Demo。两者不一致时记录偏差,不以现状替代目标。跨端参考的取证顺序:
1. 已确定目标的完整 Demo、设计节点及其版本;
2. Demo 直接依赖的上游源码;
3. API 文档仅用于解释语义,不能单独证明 Flutter 需要新增 API。
单张截图、首屏、测试覆盖率或 API 列表不能证明 Demo 完整性。无法运行或测量的内容标为未验证,不得写“完全一致”。
## 2. 公开 Demo 契约
按第 1 节确定的目标逐实例核对;默认采用小程序公开页面顺序:
- 页面分组、标题、说明、元素数量和顺序;
- 初始值、禁用/加载/错误状态和操作结果;
- 页面背景、间距、尺寸、对齐、颜色及深浅色表现;
- 滚动、溢出、SafeArea、键盘和手势等实际适用边界。
以官方公开页面中的 Demo 块为契约边界:`ExampleModule` / `ExampleItem` 表达公开分组、标题、描述和示例顺序,不按每个内部 Widget 机械拆分。Flutter 多余示例应删除;仍有测试价值的场景移入聚焦 Widget 测试。同步 Demo 源码、生成示例、页面测试和必要 Golden。
### 组件选择与布局职责
Demo 展示组件能力,不替组件补实现或修复默认样式:
- 有对应 TD 组件时优先使用,如 `TButton`、`TText`、`TPopupHeader`、`TPopup`;不以 Material 控件的默认视觉替代。Demo 自行编写的布局使用 `Row`、`Column`、`Padding`、`SizedBox`、`Expanded` 等基础原语,只负责外部排列和合理约束。
- 组件内部背景、字体、颜色、选中态、圆角、间距和对齐由组件与主题负责;不得在 Demo 中添加 `Material` 包装、装饰、位移或样式覆盖来掩盖缺陷。明确展示自定义样式的示例可用已有 API 或 Theme,但不能替代默认样式验收。
- Demo 管理示例状态和外部组合,例如 `TPopup + TPicker` 的草稿、确认、取消和可用高度;状态/API 的归属遵循第 3 节。此规则不禁止导入 `material.dart` 或使用 Flutter 基础机制;显式主题覆盖遵循第 4 节。
### Demo“假组件符合”检查
“假组件符合”是指 Demo 通过外层样式或约束修正组件本应自己负责的视觉,导致截图看似对齐、但组件脱离该 Demo 或换用正常约束后仍不符合。逐个公开 Demo 检查组件的直接参数和祖先 Widget,并将每个外层样式归类为以下三种:
1. **允许的外部布局**:`Row`、`Column`、`Expanded`、`Padding`、`SizedBox`、滚动容器等仅用于排列组件与示例内容,或提供页面所需的合理约束;右侧内容的背景、分隔线、图片尺寸和文本排版属于内容自身,不是组件样式补丁。
2. **允许的显式自定义**:明确标注为“自定义样式”的 Demo,通过组件公开参数或组件 Theme 展示逐实例 / 子树级定制;它不能代替默认 Demo 的样式验收。
3. **疑似样式补丁**:在组件外层使用 `Material`、`DecoratedBox`、`Container` 装饰、`DefaultTextStyle`、`IconTheme`、`Theme`、`MediaQuery`、`Transform`、透明度、阴影、圆角、颜色、位移,或特殊 padding / 尺寸来复制组件内部背景、字体、选中态、指示器、边框、圆角、间距和对齐,或掩盖溢出、状态和交互缺陷。此类用法应定位为 Demo 缺陷或组件内部缺陷,不能以截图“看起来一致”通过 Review。
默认样式 Demo 必须直接使用组件默认参数 / 组件 Theme,并在相同页面约束下检查组件实际解析出的样式;发现疑似补丁时,记录组件调用、祖先布局、运行表现和最小修复归属。不能仅凭 Golden 或首屏截图判断无补丁,也不能把合法的外部内容布局误报为组件样式覆盖。
默认 Demo 中确认会改变组件视觉契约的外层样式补丁属于阻塞问题:应优先修复组件 / 组件 Theme,或移除错误的 Demo 样式;只有明确的自定义样式示例才可保留这类覆盖,并且不能替代默认 Demo 验收。
页面壳及可复制示例按以下规则处理:
- 页面采用“页面底色 + 组件容器背景”的紧凑布局时,先检查并复用 `ExamplePage.compactDemo`;不要在每个 builder 中重复绘制背景,也不要仅为单个组件扩展 `ExampleItem`。
- 连续 Cell 使用 `TCellGroup` 管理背景、分隔线和末项边界,不在 Demo 中重复编写 `Column + Divider`。状态子标题仍按官方页面层级放置,不能为了代码短而改变背景层级。
- Demo builder 只展示用户可复制的组件组合,Example 页面基础设施不得进入生成代码片段;生成片段的校验见第 5 节。
- 只有现有 Example 页面模式无法表达,并且职责归属与复用证据表明能力应由公共页面基础设施承担时,才考虑扩展通用 Example API;不得仅按受影响组件数量作判断,也不得用一次 Demo 修复制造新的公共抽象。
先判断缺口层级,再决定修改方式:
| 层级 | 判断 | 优先处理 |
|---|---|---|
| Demo 缺口 | 组件已有能力,但父布局约束或组合错误 | 修正 Example;如弹层未给标题预留高度 |
| 内部缺口 | 公开契约足够,但组件在合理约束下仍异常 | 修复组件并补组件测试;如 TD 标题继承错误装饰,不在 Demo 包装补救 |
| API 缺口 | 公开 Demo 或已验证的 Flutter 真实用例无法由组合、Theme 或现有 API 合理表达 | 提出最小公开 API;仅在超出既有授权或需要用户决策时确认 |
| 无缺口 | Flutter 已有等价表达 | 不修改 API |
| 候选能力 | 仅见于上游 API 表,公开 Demo 未使用且没有已验证的 Flutter 真实用例 | 只记录,不实现 |
禁止为了 API 一一对应、缩短 Demo 代码或补齐上游 props/events 而扩大 Flutter 公共面。
## 3. API 收敛与 Flutter 模式
不能只检查本次新增字段。结合组件当前全部公开构造参数、字段、回调、枚举、Controller 和 ThemeData,回答“API 是否已收敛”,并列出证据:
| API/组合 | 状态源和实际语义 | 重叠或冲突 | Flutter 惯用表达 | 结论 |
|---|---|---|---|---|
| 示例 | 默认值、空值和生效条件 | 独立/重复/别名/冲突 | 参数、nullable callback、Widget、builder、Theme 或 Controller | 保留/合并/改名/删除/待确认 |
必须检查:
- 同一状态、启停条件、完成事件或错误结果只有一个权威入口;
- 名称、dartdoc、默认值、空值语义、Theme 默认值和运行逻辑一致;
- 不存在不同名称表达同一能力,或参数可由另一个参数直接推导;
- callback、统一状态回调和 Controller 不重复通知或形成双完成源;
- 业务编排、Demo 状态、子组件 ThemeData、第三方类型和内部适配对象不泄漏到公共 API;
- 声明式状态优先使用不可变参数和 nullable callback;内容扩展使用 Widget/builder;可复用的样式默认值优先来自语义 token 或组件 Theme,实例 API 保留有真实逐实例配置需求的参数、必要语义选择器或完整样式逃逸入口;Controller 只处理无法由声明式重建表达的跨树命令或生命周期协调;
- 名称优先采用 Flutter、Material/Cupertino 和仓库同类组件的惯用语义,不机械沿用小程序名称。
### 状态所有权优先于 token 化
先确定公开 API 的单一状态源,再决定内置默认样式从哪里取得;不得反过来为了 token 化扩大公共面:
- 样式 token 化不得制造第二公开状态源;组件已有必要实例参数时,默认值可以在内部引用语义 token,但 ThemeExtension 不再暴露同义字段。
- 连续尺寸、进度等确有逐实例配置需求的值可以保留为实例参数;“属于可见样式”本身不是迁入 Theme 或删除实例参数的充分理由。
- 只有存在已验证的子树批量默认需求时,才评估由 Theme 提供默认值。实例参数必须允许未指定,不得同时保留非空实例默认值和同义 Theme 默认值形成两个默认源;视觉字段完整解析链见第 4 节,语义选择器见下节。
### `variant`、`colorPreset`、`status` 与 Theme 的判定模型
`TButton` 只提供职责拆分参考,不是所有组件枚举取值的命名模板。Web / 小程序的 `theme`、`type` 等名称不能机械映射;必须根据调用者意图和运行效果判断维度,再记录枚举全部取值、默认值、空值语义、有效组合和公开字段类型。
| 维度 | 判定标准 | 示例 | 所有权 |
|---|---|---|---|
| `variant` | 改变结构、布局、边框或填充/描边等绘制处理;不是任意色相切换 | fill / outline / text / ghost、solid / tinted、linear / circular | 实例 API;满足严格条件时 Theme 可提供 `defaultVariant` |
| `colorPreset` | 业务含义和绘制处理不变,只选择一组协调的内置预设颜色,不传入实际 Material `ColorScheme` | defaultTheme / primary / danger,以及组件确有需要的其他调色预设 | 仅实例 API;Theme 不保存该选择器 |
| `status` / `state` | 表达组件、内容或数据当前所处的业务或生命周期状态 | normal / info / success / warning / error、ready / uploading | 实例、数据模型或 Controller 中唯一合适的一处;Theme 不拥有状态 |
| `style` / 具体样式字段 | 完整或局部覆盖最终呈现 | `ButtonStyle`、颜色、文字样式、间距 | 实例完整 style 或组件 Theme;不得再造同义选择器 |
按以下顺序判定,不能只看枚举成员名称:
1. 值是否描述“当前发生了什么”,或会决定默认图标、提示语、无障碍语义、交互和生命周期?是则属于 `status` / `state`,即使当前实现暂时只改变颜色。
2. 值是否改变填充、描边、文本、层级、布局或绘制处理?是则属于 `variant`。例如同一组件的实色、浅色填充和描边可以是不同 variant。
3. 前两项都不成立,只在相同状态和相同绘制处理中替换内置配色预设,才属于 `colorPreset`。
因此 `info / success / warning / error` 既不能一律判为状态,也不能一律判为配色:输入框校验、上传进度或公告状态属于 `status`;Tag 或 Popover 若只是由调用者选择内置配色、没有状态行为和默认内容语义,可以属于 `colorPreset`。`light` 也不是固定维度:表示浅色填充处理时属于 `variant`,表示一套独立配色时才属于 `colorPreset`。dartdoc 必须写清实际语义,不能让调用者依赖猜测。
Theme 与默认值遵循以下所有权规则:
- 组件不得公开 `colorTheme`,也不得在组件 ThemeExtension 中保存组件枚举型 `colorPreset`、`defaultColorPreset`、`status` 或 `defaultStatus`。Flutter 官方 `ThemeData.colorScheme` 与类型 `ColorScheme` 是 Material 实际调色板,不受此限制;内部私有/常量形式的内置默认配色也不是 Theme 选择器。
- ThemeExtension 可以保存具体 `Color`、`TextStyle`、`ButtonStyle`、布局值和按状态派生的样式。`resolve(context, status: instanceStatus)` 接收实例状态计算样式不表示 Theme 拥有状态;Theme 不得自行选择或覆盖当前状态。
- Theme 仅在 variant 是稳定的呈现偏好、存在真实的子树批量默认需求、且实例 `variant` 为 nullable 时,才可提供 `defaultVariant`。解析顺序必须是 `instance.variant ?? theme.defaultVariant ?? builtInDefault`。实例已经使用非空内置默认值时,不再增加 Theme `defaultVariant` 形成第二默认源。
- `colorPreset` 与 `status` 不提供 Theme 回退,使用实例值或组件内置默认值。枚举成员词汇按组件语义决定;Button 的取值不是强制全集。已发布的 `defaultTheme` 等名称保持兼容,重命名必须按 breaking change 处理。
- 只有 `variant`、`colorPreset`、`status` 彼此独立且至少存在两组有意义的交叉组合时,才同时公开。若组合被禁止、没有真实用例或一个维度可由另一个推导,则合并或只保留权威入口。
- 新增或正在修改的契约必须遵守本模型。未触及的已发布历史 API 若不符合规则,记录为技术债,不自动阻塞无关 PR,也不能作为复制先例;当同一组件契约进入修改范围时,必须评估迁移。若迁移会造成未授权的范围扩大,则明确记录独立 breaking 方案并停止扩散,而不是悄悄删除或继续新增重复入口。
以下情况默认视为冗余:
- `enableX` 与 `onX != null` 同时控制能力;
- `disabled` 与 nullable callback 重复表达禁用;
- 单项事件回调与统一状态回调重复报告同一事件;
- 实例参数与 ThemeExtension 在没有真实子树默认需求时重复保存同一个状态、选择器或样式标量;完整的 Flutter 样式对象逃逸入口不在此列,但必须有明确覆盖优先级;
- Controller 同时与 Future/callback 决定完成状态;
- 高层组件已表达能力,同时又公开第三方底层配置。
未发布的冗余 API 直接收敛;已发布 API 必须说明 breaking 风险和迁移方式。没有逐项证据时,不得断言“API 已完全收敛”或“符合 Flutter 设计模式”。
### 公开 API 文档覆盖门禁
API Review 不以“字段有一句 dartdoc”为完成。对本次新增、修改或用于表达公开 Demo 的每项公开契约,建立“公开行为 → 实现与测试 → 源码 dartdoc → 生成 API / 可复制示例”的对应关系,并检查用户是否无需阅读实现即可正确使用。至少覆盖:
- 名称、类型、默认值、空值语义和生效条件;
- 状态、`variant`、`colorPreset`、style、Theme 与实例参数各自职责及字段级覆盖优先级;
- 会改变父布局、排列、绘制或交互模式的触发条件,以及混合配置时的行为;
- 参数之间的互斥、依赖、无效组合和断言条件;
- callback、Future、Controller、自动关闭、返回值和生命周期所有权;
- 枚举全部取值、默认映射和有意义的组合;不能要求用户从多个字段注释自行拼出行为矩阵;
- 便捷组件与底层组件的默认映射、能力边界及何时应改用底层组件;
- 一个最小、真实、可复制的典型示例;关键配置不能只隐藏在未展示的私有 helper 中。
源码 dartdoc 是文档事实源,但必须运行仓库 API 生成器并检查实际生成产物;只在 IDE 注释中清楚、生成 API 中丢失仍判为未完成。特别核对生成器选取的是构造参数还是字段注释,避免同一参数的短注释覆盖完整契约。生成成功或产物同步只证明生成链路可用,不证明内容覆盖完整。
文档只描述用户可观察的公开契约,不暴露私有类、内部算法或仅服务 Demo 的常量。本次变更涉及的公开行为若缺少上述说明,或生成示例无法让用户复现,属于阻塞问题;与当前范围无关的历史文档缺口单独登记,不扩大无关 PR。不要用仅匹配关键词或固定文案的测试冒充文档完整性验证。
## 4. Theme 与视觉
TD 内置视觉和行为字段的解析优先级为:实例显式参数或受支持的完整 style > 当前子树的 TD 组件 ThemeExtension 显式字段 > TDesign 语义 token / 已文档化的内置默认值。外部 Material/M2/M3 默认及显式主题不作为 TD 视觉或行为入口;实例 style 可以复用 Flutter 样式类型,但不因此开放 Material 主题继承。child、prefix、suffix、builder 等调用方内容保留自身的主题行为,内部隔离不得覆盖用户内容树。原生选择与编辑、Tooltip、反馈及焦点、键盘、无障碍能力继续支持,但其可配置行为和视觉由 TD 明确,不透传外部 Material 主题;不将其使用 Material 实现本身判为样式泄漏。亮暗模式、字体缩放、平台输入、焦点、键盘、方向与无障碍机制继续支持。第 3 节的语义选择器不套用视觉解析链。
- token 是最终兜底,不应预填到高优先级 TD ThemeExtension 并遮蔽组件的显式配置;
- ThemeData 只承载视觉、布局和稳定的呈现默认值,不承载内容、业务状态、回调、Controller 或业务流程开关;动画时长等运动视觉参数可以进入 Theme,但是否启用业务能力仍由组件状态或回调表达;
- 组合组件应让 `TText`、`TLoading` 等子组件继承当前 Theme 子树,不接收子组件 ThemeData;
- 比较视觉时固定视口、DPR、字体缩放、主题、语言和状态;页面壳的合理平台差异不机械对齐。
### 显式主题字段与自动补全
视觉优先级按字段生效;样式对象非空不表示全部字段均为显式覆盖。Flutter 默认主题生成、`copyWith` / `apply` 补全、TDesign Theme 投影和继承链带入的值仍属于默认来源。
- 局部配置只覆盖实际配置字段,不得顺带改写选中、未选中、禁用、错误等状态的默认样式;
- 组件内部产生的默认样式不能通过实例 `style`、便利参数或其他高优先级入口回传给子组件,否则会把默认值伪装成实例显式覆盖;
- 组合组件使用共享解析器或明确的字段级合并,不在各消费组件复制近似判断;无法区分显式值与补全值时修正共享解析边界,不增加公开参数规避。
- 聚焦测试覆盖局部主题配置和最终布局或绘制结果;共享消费者、token 与 Golden 证据按本节及第 5 节既有规则执行。
### ThemeExtension 默认值与插值
ThemeExtension 的配置值、运行时有效值和插值值必须使用同一默认语义。nullable 字段以 `null` 表示内置默认值时,`lerp` 使用运行时有效默认值,不能把 `null` 当作 `0`、空颜色或其他无关初值;两侧均为 `null` 时保持 `null`。
- 连续字段按有效值插值,离散字段采用明确切换点;中间结果满足构造和布局、绘制约束;
- 默认值变更同步消费端回退、`copyWith`、`lerp`、dartdoc 和测试;
- 测试覆盖显式值、双向 nullable、两侧 `null`、端点与中间值,以及动态 Theme 切换后的实际呈现。
### 默认样式值与 token
默认值优先复用 TDesign 语义 token;无匹配 token、无子树默认需求且共享 token 缺少复用证据时,可保留单一、已文档化且有契约证据的内置默认值。不得借用无关 token 或只为消除字面量新增 Theme 字段。公开字段归属仍按第 3 节判断。
- Review 新增或修改的颜色、字体、行高、字重、圆角、阴影、间距、内边距、宽高、指示器尺寸、边框和描边;默认实现不得散落多个直接决定同一可见样式的常量。单一、已文档化且有契约证据的内置默认值不等于散落硬编码。
- 尺寸能由同一语义下的字体、行高和间距自然计算时可以组合;数值相等不代表语义相同。
- `0`、数量、最大行数、枚举值和无量纲绘制比例不属于样式 token。固定路径坐标或数值一旦决定可见尺寸、间距、圆角或描边,仍按样式值审查;几何比例应从画布、控件尺寸或 token 派生。
- 修改共享视觉原语时,列出全部消费组件并验证默认视觉和自定义主题路径,不能只证明当前 Demo 正确。
- token 化修复至少补两类证据:自定义相关 token 后实际布局或绘制值随之变化;默认 token 下 Flutter 3.32.0 Linux Golden 无意外差异。仅把数字改写为 token 名称不算完成。
## 5. 测试、覆盖率与 Golden 门禁
### Widget 与交互测试
- Demo Widget 测试逐项断言公开分组、文案、实例数量、顺序、关键参数、初始状态和操作结果;不能只断言某种组件类型曾出现。
- 可滚动页面必须遍历完整 scroll extent,覆盖首屏外实例;动态、受控、禁用、加载、错误和主题切换场景按真实调用流验证。
- 聚焦组件测试覆盖根因、普通路径、边界、回调次数、Controller 所有权和生命周期。Demo 测试验证公开组装,不能替代组件测试。
### “查看代码”的完整性与真实性
组件整体 Review 必须同时检查运行中的 Demo 和用户实际打开的“查看代码”内容。仓库里存在完整源码,不等于代码面板已展示完整示例;此项适用于所有公开示例,不只适用于弹层组件。生成机制与命令以通用 skill 第七节为准。
**检查路径**:逐个公开 Demo 确认 `ExampleItem` / builder → 实际代码入口(含 `methodName` 等覆盖配置)→ 生成片段 → 面板呈现内容,再追踪片段引用的辅助方法、数据和状态。不能假定生成器递归收集调用依赖,也不能只检查 `@ExampleCode` 是否存在。仅改变入口名称或给辅助方法加注解,不代表依赖已经齐全。
**完整性边界**:示例应让用户理解并复现它声称演示的能力,允许采用以下两种明确形式:
- 完整示例:包含必要导入、数据、状态宿主、触发入口、组件组合、回调和适用的生命周期清理,可在声明的依赖与最小应用壳中编译运行。
- 核心片段:可省略通用应用壳和无关页面基础设施,但必须标明省略内容、参数来源、接入方式,必要内容由当前项目实际运行的源码生成并在面板内展示,不添加外部源码地址指引来补充缺失实现。不得把核心片段标为“直接复制即可运行”。
无论采用哪种形式,当前演示能力的关键逻辑不能只藏在链接或未展示的私有方法中:
- 展示所用数据的结构及有代表性的初始值;长数据集可展示代表性数据及其结构,不要求逐段复制。
- 展示状态由谁持有、如何传入组件、如何接受回调并重建。只给 `value` / `onChanged` 参数名,不能证明受控示例可复现。
- 操作后才出现内容的示例,应展示触发方式及实际组件组合;确认、取消、草稿提交、异步完成或资源释放等仅在该示例涉及时检查,不强加给静态组件。
- 私有辅助方法允许使用,但其必要实现或明确的公共替代调用必须可获得;不能留下来源不明的 `_cell`、`_showPicker`、`_values` 等引用。参数化方法必须说明调用处如何提供数据和回调,不能只把隐藏状态改为未说明的参数。
- 代码必须来源于实际运行的 Demo,保持 API、默认值、主题和行为一致;不手工维护一份只用于展示的平行实现。不得为拼接片段而重复运行逻辑、扩增组件 API 或仅服务单个组件的示例框架 API。
例如,Picker 面板仅展示 `TCellGroup(cells: [_cell(...)])` 时缺少核心能力;仅改为展示 `_showPicker(items, value, onConfirm)`,却未说明触发入口、数据和状态回传,也仍不完整。应展示真实的触发与 `TPopup + TPicker` 组合,以及草稿、确认和取消的状态关系;这不要求 Picker 自身拥有 Popup。
**验证与记录**:
1. 修改源示例后运行生成器及 `--check`;生成片段不得手工修改。`--check` 只证明源码与产物同步,不证明依赖完整、能编译或行为正确。
2. 实际打开各代码入口,核对是否错绑、空白、缺失、陈旧或只包含外层包装;多个示例复用同一片段时,确认各自的数据、配置与差异均有说明。无法打开时可以先核对映射和产物,但须记录面板未验证,不宣称完整验收。
3. 对新增或修改且声称可运行的示例,在最小宿主中编译并复现关键操作;核心片段连同其声明的接入代码验证。复用现有组件和 Demo 测试,不机械复制整套测试;入口易失配时补充面板到实际片段的回归,不能仅断言文件名或关键词存在。源码地址指引等示例编写规范由 Review 检查,不为此添加 URL 禁用或文案匹配断言;测试聚焦入口加载和实际行为。
4. 记录“公开示例 → 展示入口/片段 → 必要依赖 → 编译与关键操作证据 → 缺口”。组件整体审查覆盖所有公开示例;局部 PR 审查覆盖受影响入口及共享映射,不扩大到无关组件。
**缺陷判定**:按第六节的严重性规则,当前范围内的错绑、缺失、核心行为隐藏、无法解析的必要依赖、源码与展示行为不一致,或声称可运行却不能编译/复现,属于示例交付缺陷。组件整体验收或本次修改的示例不得以“仓库以前也这样写”为理由降为建议;与局部 PR 无关的历史示例缺陷单独登记,不阻塞无关改动。合理省略通用壳、已说明的数据集引用和纯排版改进不自动构成阻塞。缺陷应定位到源示例或映射配置,并明确是示例展示问题还是组件运行问题,不能从展示不完整推导组件 API 有缺口。
### CI 回归登记
新增或修改组件测试、Demo 功能测试与 Golden 后,按 [`tdesign-flutter-general` 第八节](../tdesign-flutter-general/SKILL.md) 核对登记、自测与真实 CI 入口。区分已登记、本地已通过和远端 CI 已通过,不以 job 名称代替执行证据。
当前 PR 新增或修改的组件测试、覆盖率目标或 Demo Golden 未登记到仓库已有 CI 调度入口时,属于测试门禁缺失,Review 判定为阻塞问题;不得降级为仓库既有基础设施建议。
共享测试文件可能被多个组件清单重复调度。失败归因以实际测试文件、测试名称、失败像素和差异图为准,不以调度器的组件标签或汇总名称推断多个组件同时回归;报告时区分真实受影响组件与重复呈现的同一失败。
### 覆盖率
- 覆盖率按改动所有权过滤并分别报告:组件生产源码、Demo 页面源码和其他依赖不能混为一个总数。
- 修改生产组件源码时,执行通用 skill 第八节登记的覆盖率门禁,以当前脚本阈值为准。报告过滤后的 LCOV 分子、分母和比例,Demo 页面覆盖率不能替代组件生产源码达标。
- 覆盖率只证明代码行执行,不能替代交互、视觉、真机或跨版本证据。测试失败时不得仅凭已生成的 LCOV 宣称门禁通过。
### 验证分层与执行门禁
验证以“变更批次”和当前源码指纹为单位,不按每次保存文件或每个小改动自动重复运行。先根据 `git diff --name-only` 和实际影响判断门禁范围:
| 变更范围 | 实现阶段优先验证 | 稳定后是否需要 Golden |
|---|---|---|
| 逻辑、状态、回调、API、测试或注释 | 受影响的聚焦功能 / Widget 测试,必要时 analyze 和生成器 `--check` | 不涉及视觉时跳过 |
| 组件绘制、Theme、Demo 布局、字体、图标或资源 | 先完成上行的功能门禁,再运行受影响的非视觉回归 | 仅在视觉确实受影响时运行 |
| 依赖、SDK、公共 Theme 或共享基础设施 | 按依赖链扩大到对应包 / 双版本门禁 | 由实际视觉影响决定 |
遵循以下执行顺序:
1. **实现循环**:可以合并多个相关编辑后一次运行聚焦测试;出现 analyze、编译或功能失败时先停止,不启动 Golden。只改变逻辑且不影响绘制时,不为“保险”重复生成或比对快照。
2. **稳定检查点**:实现者确认本批次代码已基本定型后,先检查 `git diff --check`、生成产物 `--check`(若适用)和受影响功能测试,再一次性运行本次范围所需的完整非视觉门禁。把测试结果关联到当前源码 / diff 指纹;指纹至少包含验证基线到当前提交的二进制 diff(可用 `git diff --binary --no-ext-diff <base>...HEAD -- <受影响路径> | shasum -a 256` 记录)以及 Flutter SDK、依赖、字体/资源、主题环境和测试命令。上述任一项变化都会使检查点失效,必须重新走对应层级。
3. **Golden 比对**:只有稳定检查点通过且变更确实影响视觉时,先在**不带更新参数**的情况下运行既有 Golden,检查实际图、基线图和差异图。测试失败、实现仍在调整或差异原因不明时不得生成 / 更新基线。
4. **Golden 更新**:仅当差异来自已确认且有意的最终视觉变更,并得到当前任务授权时才运行更新命令;更新只执行一次,随后立即用不带更新参数的同一命令复跑,确认可复现。更新命令不得作为修复失败测试或掩盖未完成实现的手段。
5. **结果复用**:同一源码 / diff 指纹、同一 Flutter 版本、同一测试命令和同一环境下已有成功结果可以直接引用;仅查看、解释或更新 Review 文案时不得重跑测试或 Golden。环境、SDK、依赖、生成产物或相关源码变化时,按失效规则重新验证。
变更范围可先用 `git diff --name-only <base>...HEAD` 分流:命中 `tdesign-component/lib/src/` 或 `test/components/` 时跑受影响组件 Widget 测试及组件回归;命中 `example/lib/` 或 `example/test/` 时跑对应 Demo 功能测试与生成器 `dart run tool/generate_example_code.dart --check`;命中 `tool/component_test_manifest.dart`、视觉测试或 Golden/字体资源时,再纳入对应 visual runner。组件源码、Demo、Theme、字体或 Golden 变化稳定前只跑功能门禁,稳定后才执行一次无参 Golden 比对;清单登记、本地通过和远端 CI 通过分别记录,不能互相替代。
本地验证是分层证据,不替代远端 CI;报告必须写明实际运行的层级、命令、版本和是否跳过 Golden 的原因。Golden 不是所有代码变更的必经步骤,但对已确认的视觉变更也不能用功能测试替代。
### Golden
- 建立可审计的 Golden 覆盖矩阵,逐项记录“公开 `ExampleItem` / 场景 → 初始或操作后稳定可见状态 → 真实触发步骤 → 是否存在实质视觉差异 → light/dark Golden → 功能测试 → 未单独截图时的等价覆盖依据”。场景清单从实际公开页面和目标设计取得,不能只从现有 Golden 文件反推。
- 主页或初始页面 Golden 不能替代点击、选择、翻页、展开、滚动、输入、加载完成等操作后才出现的稳定视觉状态。每个存在实质视觉差异且属于当前验收范围的稳定状态都必须有对应 Golden;仅回调结果、不可稳定捕获的瞬时动画或没有视觉差异的交互用功能测试覆盖,并在矩阵中说明。
- 多个场景只有在使用相同渲染路径、关键配置和布局结果时才可共用代表性 Golden,并记录“被代表场景 → 代表 Golden → 等价依据”。文案长度、图标、状态、按钮模式、分页、溢出或尺寸会改变布局时不得视为等价。不要为了数量机械复制相同快照,也不能以“看起来接近”省略差异场景。
- 将公开场景集合、Golden 登记集合和功能测试集合做集合核对。新增、删除或改名公开场景时同步更新矩阵与登记;无解释的缺失场景、操作后状态或孤立基线属于阻塞问题。只有矩阵无遗漏、等价关系有证据且登记测试实际执行时,才能宣称 Golden 覆盖完整;否则明确报告为代表性或部分覆盖。
- 功能断言与像素比较必须解耦;混合文件应拆分或用标签分流。执行平台见下方“执行环境”,不能因 Golden 的平台限制缩减功能测试矩阵。
- Golden 固定 viewport、device pixel ratio、字体缩放、语言和主题,同时覆盖 light / dark;加载确定性的中文字体和实际使用的图标字体,基线中不得保留缺字方框。
- Golden 边界包含真实 Demo 页面背景、标题、描述、组间距和组件容器。长页面按稳定 `ExampleItem` / 分组边界分别截图,或生成完整滚动页面证据;仅覆盖首屏不能宣称整页齐备。
- 对弹窗、操作面板、下拉层、消息等“操作后才可见”的状态,必须先通过真实点击、选择、翻页或关闭操作触发目标状态,再断言目标内容可见并保存 Golden;初始隐藏状态或仅渲染触发按钮不能替代操作后快照。
- 首次生成或有意更新前,先与当前官方 Demo 和真机渲染核对。检查实际图、基线图和差异图,确认变化来自预期源码;不得直接运行更新命令消除失败。
- 更新基线后,立即在不带更新参数的情况下重跑同一测试,证明基线可复现。报告比较器容差、实际 diff 比例及仍未覆盖的平台风险。
- 以仓库实际 Golden comparator 和 CI 配置为准;未配置容差时默认要求精确一致。配置了容差也必须报告来源和实际差异比例;结构、数量、顺序、关键尺寸、缺字、裁切和未覆盖区域不得通过面积容差豁免。
### 执行环境
- Flutter 3.32.0 与 latest 均运行严格 analyze 和非视觉功能/交互测试;自动 Golden 与其他像素比较测试仅在 Flutter 3.32.0 Linux 执行和更新基线。其他平台允许真机运行、截图与人工核对,但不能写回 Golden 基线。区分本地与 CI 证据,清理本次无关产物,不处理用户已有文件。
## 6. Review 结论与交付
Review 输出按严重程度列出问题,每项包含文件行号、可复现行为、根因、影响、最小修复和应补测试。明确区分:
- **阻塞问题**:行为、API、兼容性、视觉契约或测试证据不满足;Review 不通过;
- **非阻塞问题**:不影响当前契约的风险或后续建议;单独列出,不伪装成缺陷;
- **未验证项**:缺少运行、截图、版本或环境证据。
先判断缺失证据是否属于本次验收范围:完成当前行为、API、视觉或兼容性契约所必需的证据缺失时,必须列为阻塞问题;只有明确超出本次范围,或不影响当前契约且因环境限制无法补充的证据,才列为非阻塞的未验证项。不得用“未验证”绕过本 skill 的完成条件。
当 Review **没有阻塞问题**时,结论为通过;除非用户明确要求,不修改 PR。用户明确要求创建或更新 PR 时,PR 模板、更新日志和 breaking 格式遵循仓库 `CONTRIBUTING.md`、PR 模板及 `tdesign-flutter-general`,本 skill 只补充以下对齐 Review 专项要求:
1. 标题遵循 Conventional Commits,概括当前源码实际产生的用户可见或工程变更;
2. 描述根据当前 diff、最终行为、API 影响和测试证据填写;
3. 标题和描述不得把“对齐小程序”“参考小程序”或跨端比较过程当作变更内容;小程序只属于 Review 证据,不属于 PR 实现说明;
4. 不写源码未实现的能力,不沿用过时标题或计划;平台专属的 Issue 关联规则按仓库规范执行;
5. 更新后同时检查正文原始 Markdown 和渲染结果,再核对 title、body、base/head、commit 和文件范围。
CI 自动修复、合并冲突、生成产物回写或机器人提交都会产生新的 Review head。旧 head 上的 CodeBuddy、人工 Review、CI 或本地验证不能直接作为新 head 的通过证据;先检查自动提交的真实 diff,再对最终 head 重跑受影响门禁并重新请求所需 Review。autofix 显示成功时仍须确认它没有删除或回退本次公开契约。
当 Review 有阻塞问题时,不得用改标题、正文、Golden 容差或更新基线规避问题;仅审查任务报告问题,已授权修复的任务继续修复。修复后基于最新代码及验证证据重新判断,不能沿用旧结论。
按本次任务范围判断完成:公开 Demo 契约有证据;缺口分层正确;API 无重复状态源且符合 Flutter 模式;Theme 继承合理;相关非视觉测试、必要的 Golden(仅视觉影响时)以及双版本 analyze 和必要覆盖率按执行门禁通过。涉及 PR 时还需核对标题与描述是否准确;存在未获授权的修改需求应报告,不能据此自行修改远端。
View on GitHub