Product Thinking 是一套运行手册(runbook),用于在改动 React Doctor 任何用户可接触的公共接口(surface)之前,先像产品经理一样进行评审。资料说明,智能体默认会直接构建被要求的东西,而这一遍评审补充了它跳过的产品检查:这项改动是否值得在接口上占据一个永久位置,以及如何知道它确实有效。它既用于推回不合理的改动,而不仅仅是给改动放行。
一、适用范围与触发时机
当一次 diff 触及用户(运行 React Doctor 的开发者,或他们的 CI)所依赖的接口时,就运行这一遍评审。资料指出,每个接口都是一份契约:一旦发布,人们就会在其上构建,无法悄悄收回。因此应先找到接口所在位置,以便改对地方,并在新增之前搜索是否有可复用的东西。
资料列出的接口及其位置与「承重」原因包括:CLI 命令/标志位于 cli/index.ts、cli/commands/*.ts、cli/utils/inspect-flags.ts,因为每个标志都是永久的,必须被解析、文档化、测试并在各版本中保持可用;0–100 评分位于 core/src/calculate-score.ts、core/src/constants.ts,因为这是人们截图并用于 CI 门禁的数字,改动算法会静默改变每位用户的分数;配置项位于 core/src/types/config.ts、core/src/services/config.ts,属于长期契约且与既有优先级交互;JSON 报告字段位于 core/src/schemas.ts、core/src/build-json-report.ts,是其他工具解析的线格式;包 API/退出码位于 react-doctor/src/inspect.ts、api/src/diagnose.ts,程序化使用者会锁定它,因此改动属于 semver 破坏性变更并需要 changeset;GitHub Action 输入/输出位于 action.yml,独立版本化(vN);终端输出/UX 由 cli/utils/ 的渲染器负责,是用户的第一印象与日常体验。
资料特别说明:lint 规则不在本评审范围内,它们走 rule-research → rule-writing → rule-validate 流水线,规则配置走 doctor-explain;本评审针对规则周围的接口,而非规则本身。纯内部改动(引擎、私有核心类型、测试、工具)完全跳过本评审,只需用一行说明为何是内部改动即可。
二、七个步骤
第一步,写清任务与改动(各两行)。任务需说明谁运行 React Doctor、他们真正想完成什么、目前用什么替代做法(现有标志或配置项、其他工具,或什么都没有),并把任务锚定在观察到的行为上,而非假设性需求。改动应是完成该任务的最小接口;若改动大于任务,就是在投机构建。如果无法说出一个当前接口做不到的任务,就应停止,直接把用户指向既有做法。随后要通过两个过滤器:持久性(该能力是否会被更好的模型吸收或被轻易商品化,只有持久、确定性的价值才值得占用接口)与信任(用户不信任的功能比没有更糟;若会产生误报或无法提供证据,先解决信任问题)。
第二步,新增之前先搜索。最便宜的接口是你从未创建的接口。先搜索既有标志、选项或报告字段进行扩展。资料给出的命令示例为:bunx @rayhanadev/truffler "<name or behavior>" packages --kind function,interface,type,constant --limit 20 以及 rg -n "<flag-or-option-name>" packages/react-doctor/src/cli packages/core/src/types。在写任何东西之前先读排名靠前的匹配项。只有当任务确实不同、且没有既有条目能在不造成混淆的情况下承载时,才新增全新接口,并在简报中记录搜索了什么、为什么都不合适。
第三步,恰好接入一个指标。看不见的接口就无法管理,所以改动在发出信号之前都算未完成。应在构建之前确定信号。资料说明 CLI 遥测是匿名化的 Sentry,对 @react-doctor/api 库、测试和 --no-score 已是 no-op,因此只需接入 emit:采用计数(在 cli/utils/constants.ts 的 METRIC 映射中加一个名称,通过 cli/utils/record-metric.ts 发出,用于「人们是否开启了这个标志」)与每次扫描结果(在 cli/utils/build-run-event.ts 的 wide event 上加属性,运行级维度放在 cli/utils/build-sentry-scope.ts,优先使用一个丰富的 wide-event 属性而非一堆窄计数器)。匿名化不可协商:绝不能在属性中放入用户名、路径、密钥或仓库身份,一切都必须经过 scrubSentryEvent / scrubSentryMetric。然后把指标名称与「成功」阈值写进简报。北极星指标是 CI 队列留存(团队几周后是否仍在 CI 中运行 React Doctor);「是否被喜爱而非仅仅使用」的代理指标是 PMF 调查中「非常失望」达到 40% 及以上。
第四步,确定默认值并补齐兼容性产物。默认值是产品决策而非实现细节,大多数用户从不修改它,因此默认值几乎就是对所有人的行为。应选择保持当前行为的默认值,并把有风险的选项设为 opt-in。随后补上防止现有用户被破坏的产物:已发布包行为改变要加 changeset(nr changeset);JSON 报告形状改变要编辑 core/src/schemas.ts,保留既有形状或提升 schemaVersion,并运行 nr smoke:json-report;评分权重或算法改变会同时移动所有用户的数字并可能翻转以阈值为键的 CI 门禁,应视为破坏性变更;action.yml 改变要打 vX.Y.Z 标签并移动浮动的 vN。
第五步,更新文档。没人能发现的接口是浪费,过时的文档是信任缺陷。文档属于「完成」的一部分,包括:新标志或命令旁的 --help / 用法文本;网站页面与 react.doctor/prompts/... 下的规范提示(智能体在运行时获取的内容);当改动改变面向用户的工作流时的分发技能(skills/react-doctor、skills/doctor-explain)。
第六步,记录终止指标。接口会不断累积:每个未使用的标志与失效配置键都是永久维护成本,也是让用户误读的东西。应事先决定如何知道它没保住价值,在简报中写一行——第三步的指标、阈值与时间范围,例如「若 <metric> 在两个版本后仍低于 N 则移除」——并安排检查而非只靠记忆,把删除未使用接口视为胜利而非失败。
第七步,运行检查:nr typecheck && nr test && nr lint,以及仅当改动了 JSON 报告时运行 nr smoke:json-report。
三、简报与停止确认
简报模板字段包括:Job(谁/目标/今天的替代做法)、Change(完成它的最小接口)、Reuse(搜索了什么;扩展了什么,或为何需要新接口)、Metric(METRIC 名称或 wide-event 属性 + 表示成功的数字)、Compat(默认状态;changeset / schemaVersion / action 标签)、Kill(触发移除的指标阈值 + 时间范围),并并入 PR 的「Why」。
资料列出四种应停下来询问而非硬推的时刻:无法说出当前接口做不到的任务;无法为其定义指标;它破坏已发布契约(包行为、JSON schemaVersion、评分或 action I/O);它会将范围扩大到超出要求。评审干净后,落地改动使用 ship(deslop、changeset、PR、babysit)。
四、产品原则
当某一步含糊、两个选项看似都可行时的裁决依据:少而精的发现优于更多发现(开发者真正会处理的十个问题胜过被略过的一百个,应设上限并排序);根因优于单条警告(把同一底层问题的症状合并为一个发现);证据优于断言(展示代码、度量、理由);可操作性优于正确性(有清晰下一步的可修复问题胜过没人知道怎么办的技术完美发现);工作流优于仪表盘(在开发者已工作的地方——CLI、PR、编辑器——接触他们);教育优于诊断(解释为什么是问题,让用户学到东西);信任优于检测覆盖(最好的发现是用户相信并采取行动的,一个误报损失的信任超过漏报损失的覆盖)。
需要指出的是,资料未提供 React Doctor 的具体评分算法数值、完整配置项清单、价格或收费信息,这些内容暂未提供。