cx-pr-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCultureX PR Review
CultureX PR审查
How to use this skill
如何使用本技能
You are the reviewer; this skill is a companion, not a substitute for judgment. This file holds everything universal — process, TS/JS/Express-level lenses, router rows, and framework-agnostic traps. Repo-specific mechanics live in per-repo supplements (§0 dispatch): , , and future repo files following the same pattern.
saas-server.mdcreator-services.mdOperating rules:
- Checklists are a floor, not a ceiling. Reason from first principles about this change, then cross-check the lists. The best findings are edge cases no checklist covers yet.
- The trap library is examples, not the whole job. A PR can dodge every listed trap and still be broken. New recurring bug class → add it (§9).
- Adapt to the diff. Spend effort where the risk is — a docs-only PR needs no SQL generator; a cron PR needs idempotency thinking beyond the table's hints.
- Adapt to the repo. Confirm the base branch (§0a), identify the repo (§0), load its supplement, and apply only checks that match. Never apply another repo's mechanics — e.g. don't flag a missing in a repo without tenancy; find that repo's equivalent scoping and check that.
agencyId - Flag real bugs, risks, design problems — don't nit style (§8 What to skip).
你作为审查者,本技能是辅助工具,不能替代独立判断。本文件包含所有通用规则——流程、TS/JS/Express层面的分析视角、路由检查项、与框架无关的陷阱库。仓库专属的规则在各仓库补充文档(§0 调度)中:、,以及后续遵循相同模式的仓库文档。
saas-server.mdcreator-services.md操作规则:
- 检查清单是基础,而非上限。从第一性原理出发分析本次变更,再对照清单验证。最有价值的发现往往是清单未覆盖的边缘场景。
- 陷阱库是示例,而非全部工作。PR可能避开所有列出的陷阱,但仍存在问题。若发现新的重复Bug类型,请添加到陷阱库(§9)。
- 适配差异内容。将精力放在风险点上——仅修改文档的PR无需检查SQL生成逻辑;定时任务PR需要思考清单提示之外的幂等性问题。
- 适配目标仓库。确认基准分支(§0a)、识别仓库(§0)、加载对应补充文档,仅应用匹配的检查项。切勿应用其他仓库的规则——例如,在无租户模式的仓库中不要标记缺失,而是找到该仓库对应的范围限制规则并检查。
agencyId - 标记真实Bug、风险、设计问题——不要纠结风格细节(§8 可忽略内容)。
0a. Confirm the base branch (ASK before checking anything)
0a. 确认基准分支(检查任何内容前先询问)
Ask the user which branch the PR merges into before any / — every diff, log, and re-review delta is computed against it (stale base → reviewing already-merged commits; wrong base → missing or phantom changes). Don't assume . Detect candidates, then confirm:
gitgrepmainbash
gh pr view --json baseRefName 2>/dev/null # if a PR exists this IS the base — still confirm
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null # repo default branch
git branch -r # what exists (main? master? develop? release?)- found → state it, ask confirm/override (devs sometimes branch off a feature/release branch, not the PR base).
baseRefName - No PR → ask explicitly, presenting the detected default as the suggestion.
- Record as ; use it in every command below (
<base>). For a re-review, also pin the last-reviewed SHA (§6).<base>..HEAD
Use AskUserQuestion (or a plain question) — don't proceed to §0/§1 until confirmed.
在执行任何/命令前,询问用户PR将合并到哪个分支——所有差异、日志和重新审查的增量都是基于该分支计算的(基准分支过时→审查已合并的提交;基准分支错误→遗漏或出现虚假变更)。不要默认是分支。先检测候选分支,再确认:
gitgrepmainbash
gh pr view --json baseRefName 2>/dev/null # 若PR已存在,这就是基准分支——仍需确认
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null # 仓库默认分支
git branch -r # 现有分支(main? master? develop? release?)- 找到→告知用户,询问是否确认/覆盖(开发者有时会从功能分支/发布分支创建分支,而非PR基准分支)。
baseRefName - 无PR→明确询问,将检测到的默认分支作为建议。
- 记录为;在以下所有命令中使用(格式为
<base>)。若为重新审查,还需记录上次审查的SHA(§6)。<base>..HEAD
使用AskUserQuestion(或直接提问)——在确认前不要进入§0/§1。
0. Identify the repo & load its supplement (once, first)
0. 识别仓库并加载补充文档(首次执行一次)
| Repo | Fingerprint | Supplement |
|---|---|---|
| cx-saas-server | | read |
| cx-creator-services | | read |
| cx-analytics-backend | package name | read |
| cx-worker | package name | no supplement yet — SQS consumer, no DB; calls back to saas-server/creator-services via axios. Review = message-contract both sides (§4 Cross-repo), idempotency on redelivery, §5 stuck-task trap |
| cx-pdf-generation | package name | no supplement yet — Express+Puppeteer React-SSR PDF service, no DB; universal checks only |
| cx-partners / saas-super-admin / cx-saas-dashboard | React frontends ( | frontend — this skill's backend mechanics don't apply; §3 lenses + §5 agnostic traps only |
| any other repo | fingerprint below | no supplement yet — use the mapping table below + universal checks; propose a new supplement file (§9) |
bash
undefined| 仓库 | 特征标识 | 补充文档 |
|---|---|---|
| cx-saas-server | | 阅读 |
| cx-creator-services | | 阅读 |
| cx-analytics-backend | 包名为 | 阅读 |
| cx-worker | 包名为 | 暂无补充文档——SQS消费者,无数据库;通过axios调用saas-server/creator-services。审查需注意:消息契约双向一致性(§4 跨仓库)、重投递时的幂等性、§5 任务阻塞陷阱 |
| cx-pdf-generation | 包名为 | 暂无补充文档——基于Express+Puppeteer的React-SSR PDF服务,无数据库;仅应用通用检查项 |
| cx-partners / saas-super-admin / cx-saas-dashboard | React前端( | 前端项目——本技能的后端规则不适用;仅应用§3 分析视角 + §5 通用陷阱 |
| 其他任意仓库 | 特征标识如下 | 暂无补充文档——使用下方映射表 + 通用检查项;建议新增补充文档(§9) |
bash
undefinedORM / DB driver — the fleet only uses sequelize+mysql2 (saas-server) and mongoose (creator-services); anything else is a red flag to investigate, not a stack to accommodate
ORM / 数据库驱动——当前仅使用sequelize+mysql2(saas-server)和mongoose(creator-services);其他任何情况需调查,而非适配
grep -iE '"(sequelize|mongoose|mongodb|mysql2?)"' package.json 2>/dev/null
ls migrations 2>/dev/null
grep -iE '"(sequelize|mongoose|mongodb|mysql2?)"' package.json 2>/dev/null
ls migrations 2>/dev/null
Tenancy / auth convention (what plays the role of a tenant key / rbac config)
租户/认证约定(租户标识/权限配置的对应字段)
grep -rIlE 'agencyId|tenantId|orgId|workspaceId|accountId' src 2>/dev/null | head
grep -rIl 'rbac|checkRBAC|authorize|can(' src middleware 2>/dev/null | head
For a repo with no supplement, map what fingerprinting finds — the **principle** is constant, only the mechanism changes. The fleet has exactly two DB stacks:
| Concept | Sequelize + MySQL (saas-server) | Mongoose + Mongo (creator-services) | No DB (analytics-backend, cx-worker, cx-pdf-generation) |
|---|---|---|---|
| Schema change | `migrations/*.js` | none — shape lives in the model file; check back-compat of reads on old docs | N/A — check payload contract vs the owning repo |
| Tenant scoping | `agencyId` in every `where:` | `platform`+`username`/`profile_id` | social identifiers / message fields — never `agencyId` |
| Negation + NULL | `NOT IN (NULL,…)` → zero rows (saas-server.md) | `$ne`/`$nin` with `null` semantics | N/A |
| Soft delete | `paranoid` + `deleted_at` | no global convention — check per-model | N/A |
| Partial indexes | MySQL silently drops them | `partialFilterExpression` quirks (creator-services.md) | N/A |
| Query verification | regenerate SQL (saas-server.md) | reason about aggregation pipeline / `$match` | read the outbound HTTP payload vs the consumer's schema |
With no supplement, the review is §3 lenses + §2 universal rows + §5 agnostic traps. Still thorough — the universal lenses carry it.grep -rIlE 'agencyId|tenantId|orgId|workspaceId|accountId' src 2>/dev/null | head
grep -rIl 'rbac|checkRBAC|authorize|can(' src middleware 2>/dev/null | head
对于无补充文档的仓库,根据特征标识映射对应规则——**核心原则不变,仅实现机制不同**。当前共有三种数据库架构:
| 概念 | Sequelize + MySQL(saas-server) | Mongoose + Mongo(creator-services) | 无数据库(analytics-backend, cx-worker, cx-pdf-generation) |
|---|---|---|---|
| Schema变更 | `migrations/*.js` | 无——结构定义在模型文件中;检查旧文档读取的向后兼容性 | 不适用——检查负载契约与所属仓库的一致性 |
| 租户范围限制 | 每个`where:`条件中包含`agencyId` | `platform`+`username`/`profile_id` | 社交标识/消息字段——绝不会是`agencyId` |
| 非空判断 + NULL | `NOT IN (NULL,…)` → 返回0行(saas-server.md) | `$ne`/`$nin`的NULL语义处理 | 不适用 |
| 软删除 | `paranoid` + `deleted_at` | 无全局约定——需按模型检查 | 不适用 |
| 部分索引 | MySQL会静默丢弃 | `partialFilterExpression`的特性(creator-services.md) | 不适用 |
| 查询验证 | 生成SQL语句(saas-server.md) | 分析聚合管道 / `$match`逻辑 | 对比出站HTTP负载与消费者的Schema |
无补充文档时,审查内容为§3 分析视角 + §2 通用检查项 + §5 通用陷阱。仍需全面审查——通用分析视角已覆盖核心要点。1. Scope the diff & understand intent
1. 确定差异范围并理解变更意图
Run in parallel ( = branch confirmed in §0a):
<base>bash
git log <base>..HEAD --oneline
git diff <base>..HEAD --stat
git status --short
gh pr view --json title,body,number 2>/dev/null || trueBefore reading code line-by-line, answer:
- What is this PR trying to do? (title/body/commits/ticket) — you can't judge correctness without intent.
- Blast radius? One-module feature vs. shared middleware/model/config/cron — the latter breaks unrelated features.
- Which categories does it touch? Classify each changed file: Migration/Schema · Model · Repository · Service/Helper · Controller/Route/Validation · Auth/Middleware · Cron/Background job · Cross-repo contract (SNS/SQS, service-to-service calls) · Config/Infra · Docs · Data backfill/DML · Spec-implementing code (formula/PRD → aggregation/ranking) · Test. The repo supplement maps concrete paths to these categories; the category determines which checklists and §2 rows apply.
并行执行以下命令( = §0a中确认的分支):
<base>bash
git log <base>..HEAD --oneline
git diff <base>..HEAD --stat
git status --short
gh pr view --json title,body,number 2>/dev/null || true逐行阅读代码前,先回答以下问题:
- 本次PR的目标是什么?(标题/描述/提交记录/工单)——脱离意图无法判断正确性。
- 影响范围? 单模块功能 vs 共享中间件/模型/配置/定时任务——后者可能破坏无关功能。
- 涉及哪些类别? 对每个变更文件分类:迁移/Schema · 模型 · 仓储层 · 服务/工具 · 控制器/路由/校验 · 认证/中间件 · 定时/后台任务 · 跨仓库契约(SNS/SQS、服务间调用) · 配置/基础设施 · 文档 · 数据回填/DML · 规范实现代码(需求文档→聚合/排名逻辑) · 测试。仓库补充文档会将具体路径映射到这些类别;类别决定适用的检查清单和§2检查项。
2. Universal router — deeper checks by what you see
2. 通用路由规则——根据变更内容深入检查
Scan the diff for these signals; when present, run the linked checks. The repo supplement adds its own rows. Ordered by how often they bite.
| If the diff contains… | Then also verify |
|---|---|
an ID from | The entity belongs to the caller's tenant/scope (supplement defines the key — |
| Success counts reflect actual writes (dedupe/ignore options skip silently); rejections surfaced not swallowed; field shape consistent across paths. (§5) |
an | Move to a queue (SNS→cx-worker) or respond |
| a new/changed route | Input validation (Zod) on body/query/params; authZ wired per the repo's convention; standard response shape ( |
| a change to shared middleware/config | Blast radius across all consumers of that key/module. |
| an update call followed by returning a previously-fetched object | Stale in-memory data — re-fetch, mutate, or assert the affected count. (§5) |
| a controller→service refactor / extraction | Side-effect gating drift: analytics/audit events still gated behind the old early-return? (§5) |
| JSON-key typos hidden by |
| file upload / Multer | DB payload column actually written (not the Multer field object); validation schema includes the column. (§5) |
| money / credits / payments / webhooks | Idempotency keys, transaction boundaries, no double-charge on retry, correct unit, webhook signature verified. Reason hard — the trap table only hints. |
| a new external API call (another CultureX service / 3rd-party) | Rate limits, timeouts, error handling, caching, N+1 (one call per item in a list endpoint → batch). (§5) |
| LLM prompt + a mapping/enum of its output | Prompt category strings exactly match mapping keys; accept both defensively. (§5) |
| date/time, timezone, or cron schedule | TZ assumptions, DST, cron overlap/re-entrancy, "today" server-side vs. tenant-side. |
| a spec/formula/scoring doc the code must implement | Reproduce the doc's worked examples against the code; check denominator per segment and distributions sum to ~100%; fix landed on every parallel branch. (§5 symmetric-fix gap) |
| a raw DML backfill / data migration (esp. prod / large table) | Normalization parity with the app's matching logic, batching, soft-delete filter, idempotent/resumable, tenant key in the join, query plan checked. Mechanics per supplement. |
Signal not in the table (or the supplement's) → expected; fall through to §3 and reason it out.
扫描差异内容,若出现以下信号,则执行对应的检查。仓库补充文档会添加专属检查项。按出现问题的频率排序。
| 若差异中包含… | 则需额外验证 |
|---|---|
使用 | 该实体属于调用者的租户/范围(补充文档定义对应标识—— |
| 成功计数反映实际写入数量(去重/忽略选项会静默跳过数据);需暴露拒绝错误而非吞掉;各路径的字段结构一致。(§5) |
HTTP处理器内包含 | 移至队列(SNS→cx-worker)或返回 |
| 新增/修改路由 | 对body/query/params进行Zod输入校验;按仓库约定配置授权;使用标准响应格式( |
| 修改共享中间件/配置 | 检查该键/模块的所有消费者的影响范围。 |
| 更新调用后返回先前获取的对象 | 内存数据过时——需重新获取、修改或断言受影响的计数。(§5) |
| 控制器→服务的重构/提取 | 副作用控制漂移:分析/审计事件是否仍受旧的提前返回逻辑限制?(§5) |
| |
| 文件上传 / Multer | 数据库负载列已实际写入(而非Multer字段对象);校验Schema包含该列。(§5) |
| 金额/积分/支付/Webhook | 幂等键、事务边界、重试时不重复扣费、单位正确、Webhook签名已验证。需仔细分析——陷阱表仅提供提示。 |
| 新增外部API调用(其他CultureX服务 / 第三方) | 速率限制、超时、错误处理、缓存、N+1问题(列表接口中每个条目发起一次调用→需批量处理)。(§5) |
| LLM提示词 + 输出映射/枚举 | 提示词分类字符串与映射键完全匹配;需兼容两种写法。(§5) |
| 日期/时间、时区或定时任务调度 | 时区假设、夏令时、定时任务重叠/重入、服务器端与租户端的“今日”差异。 |
| 代码需实现的规范/公式/评分文档 | 用文档中的示例代码验证实现;检查各分段分母和分布总和约为100%;修复已应用到所有并行分支。(§5 对称修复遗漏陷阱) |
| 原始DML回填 / 数据迁移(尤其是生产环境 / 大表) | 与应用的匹配逻辑保持标准化一致、分批处理、软删除过滤、幂等/可恢复、连接条件包含租户标识、已检查查询计划。具体机制参考补充文档。 |
若信号不在本表(或补充文档)中→属正常情况;继续执行§3并自行分析。
3. Independent analysis lenses (EVERY PR)
3. 独立分析视角(所有PR必查)
Checklists are memory aids for known traps; these lenses find the unknown ones. Trace each meaningful change through them — out loud in your notes:
- Correctness / intent — does it do what the PR says? Happy path, then empty/zero/null/one/many. Off-by-one, empty array, key?
undefined - Data integrity — inconsistent DB possible? Partial writes without a transaction? Orphans? Lost updates? Wrong counts reported?
- Multi-tenancy / scoping — every query scoped to the repo's tenant/scope key? Can caller A reach caller B's data via a guessed ID/slug/UUID?
- AuthZ / security — authZ on the route? Privilege escalation path? Input validated (Zod)? Injection (raw SQL, NoSQL, path, SSRF on a URL param)? Secrets/PII in logs or responses?
- Concurrency / idempotency — run twice (retry, double-click, redelivered SQS)? Read-modify-write race? Unique constraint or transaction protecting it?
- Performance / scale — N+1 queries or service calls? Unbounded list in request/response? Missing index for a new filter/sort? Sync work that should be async?
- API contract / back-compat — response shape changed for existing clients? Field renamed without migrating callers? Nullable became required?
- Error handling / observability — failures swallowed (,
catch {})? Success reported when work silently didn't happen? Errors actionable?.filter('fulfilled') - Blast radius — shared model/middleware/config/cron: what else consumes it? Did fixing path A regress symmetric path B?
End each lens with: "What's the worst input or timing that breaks this, and is it handled?" That question, not the checklist, is where critical bugs come from.
检查清单是已知陷阱的记忆辅助工具;这些视角能发现未知问题。逐一跟踪每个有意义的变更,并在审查记录中明确说明:
- 正确性 / 意图——是否实现了PR描述的功能?验证正常路径,再验证空值/零值/空值/单个/多个场景。是否存在差一错误、空数组、键?
undefined - 数据完整性——是否可能出现数据库不一致?无事务的部分写入?孤立数据?更新丢失?计数错误?
- 多租户 / 范围限制——每个查询是否都限定在仓库的租户/范围标识内?调用者A能否通过猜测ID/别名/UUID访问调用者B的数据?
- 授权 / 安全——路由是否配置授权?是否存在权限提升路径?输入是否已校验(Zod)?是否存在注入风险(原生SQL、NoSQL、路径、URL参数导致的SSRF)?日志或响应中是否包含密钥/PII?
- 并发 / 幂等性——执行两次(重试、双击、SQS重投递)会怎样?是否存在读-改-写竞争?是否有唯一约束或事务保护?
- 性能 / 扩展性——是否存在N+1查询或服务调用?请求/响应中是否存在无界列表?新的过滤/排序是否缺少索引?是否有应异步处理的同步工作?
- API契约 / 向后兼容性——现有客户端的响应格式是否变更?字段重命名但未迁移调用方?可空字段变为必填?
- 错误处理 / 可观测性——是否吞掉错误(、
catch {})?工作未执行却报告成功?错误是否可排查?.filter('fulfilled') - 影响范围——共享模型/中间件/配置/定时任务:还有哪些消费者使用?修复路径A是否导致路径B回归?
每个视角结束时需思考:“什么最坏的输入或时序会破坏这个逻辑,是否已处理?” 这个问题(而非检查清单)是发现关键Bug的核心。
4. Universal checklists (the floor)
4. 通用检查清单(基础要求)
Run the ones matching §1. The repo supplement replaces/extends these with stack mechanics (migrations, models, repositories, auth).
执行与§1分类匹配的检查项。仓库补充文档会用架构机制(迁移、模型、仓储、认证)替换/扩展这些内容。
Service / Helper
服务 / 工具
- Field-shape consistency across paths — path A pushes strings, path B objects → downstream yields
.map(x => x.name)sundefined - No sync LLM/external/heavy calls in the request path — queue (SNS→cx-worker) or + background
202 - Idempotency on retry-prone work (LLM, payments, webhooks, SQS consumers)
- Side-effect gating preserved across controller→service refactors
- Services take specific params (/
agencyId/userIdor the repo's equivalents), not wholerole/user objectsreq
- 字段结构一致性——路径A传入字符串,路径B传入对象→下游会返回
.map(x => x.name)undefined - 请求路径中无同步LLM/外部/重型调用——移至队列(SNS→cx-worker)或返回+ 后台处理
202 - 易重试工作(LLM、支付、Webhook、SQS消费者)的幂等性
- 控制器→服务重构时保留副作用控制逻辑
- 服务接收特定参数(/
agencyId/userId或仓库对应标识),而非完整的role/用户对象req
Controller / Route / Validation
控制器 / 路由 / 校验
- Zod on ,
req.body,req.queryreq.params - Field names match what they store (shouldn't hold a Mongo
postUUID)_id - Caller identity/scope (/tenant key/role) forwarded from
type/req.paramsinto the serviceres.locals - AuthZ wired per repo convention (supplement has specifics)
- Standard response
{ success, message?, result? } - Public routes (declared before the auth middleware) intentionally public
- 对、
req.body、req.query使用Zod校验req.params - 字段名与存储内容匹配(不应存储Mongo
postUUID)_id - 调用者身份/范围(/租户标识/角色)从
type/req.params传递到服务层res.locals - 按仓库约定配置授权(补充文档有具体规则)
- 使用标准响应格式
{ success, message?, result? } - 公开路由(在认证中间件前声明)为有意设置
Cron / Background job
定时 / 后台任务
- Re-entrancy/overlap — previous run not finished?
- Tenant iteration scoped; one tenant's failure doesn't abort the rest
- Idempotent; time/timezone assumptions explicit
- Heavy work batched/chunked; no unbounded in-memory accumulation
- 重入/重叠——前一次运行是否未完成?
- 租户遍历范围受限;单个租户失败不会终止整个任务
- 幂等性;时间/时区假设明确
- 重型工作分批处理;无内存中无界累积
Cross-repo contract (SNS/SQS, service-to-service)
跨仓库契约(SNS/SQS、服务间调用)
- Payload shape matches the consumer (cx-worker message types, …) on both sides
- Field names/types align with the other store's schema (e.g. MySQL Creator ↔ Mongo)
- Timeouts, retries, rate limits, error handling; N+1 batched
- Versioning/back-compat if the message or API shape changed
- 负载格式与消费者(如cx-worker消息类型)双向匹配
- 字段名/类型与另一方存储的Schema对齐(如MySQL Creator ↔ Mongo)
- 超时、重试、速率限制、错误处理;N+1问题已批量处理
- 消息或API格式变更时的版本控制/向后兼容性
Data backfill / one-off DML (principles; DB mechanics per supplement)
数据回填 / 一次性DML(原则;数据库机制参考补充文档)
- Normalization parity — the backfill's match/join mirrors exactly how the app matches (case, trimming, prefixes), normalized on the driving side so the indexed side stays usable
- Batched — no single unbounded write on a hot table
- Soft-delete filter applied to match app behavior
- Idempotent / resumable — re-run safe, killed run resumes
- Tenant key in the join/filter
- Query plan checked before running
- 标准化一致性——回填的匹配/连接逻辑与应用完全一致(大小写、修剪、前缀),在驱动端标准化以保持索引端可用
- 分批处理——热表上无单次无界写入
- 应用软删除过滤以匹配应用行为
- 幂等/可恢复——可安全重跑,中断后可恢复
- 连接/过滤条件包含租户标识
- 运行前已检查查询计划
5. Framework-agnostic traps (learned the hard way — examples, not exhaustive)
5. 与框架无关的陷阱库(从实际问题中总结——示例,非全部)
Reach for these by name when the pattern matches; the library grows (§9). Stack-specific traps live in the repo supplements.
| Trap | Where it bites | Fix |
|---|---|---|
| Sync LLM / external job inline | Handler | Queue (SNS→cx-worker), or |
| Logs rejection but still reports | Split |
| Field-shape inconsistency between paths | | Normalize at source; one shape everywhere |
| Misleading field name | | Rename to match what's stored |
| N+1 to another service | One | Batch endpoint, or precompute/cache the flag |
| Unbounded id list in HTTP body | Filter-by-label sends all matching mongo ids in the POST body | Chunk, or push the join into the owning service |
| LLM key mismatch with mapping | Prompt says "Educational Content", mapping has "Educational Content & How-To Guides" → silent drop | Align prompt + JSON output; accept both keys defensively |
| Side-effect gating drift on extraction | Old controller returned early before Mixpanel/audit; new one fires unconditionally → double-count | Re-gate with the old early-return condition (e.g. |
JSON-key typo hidden by | | Audit every |
| Multer field vs DB column mismatch | | Write to the DB payload; validation schema includes the column |
| Symmetric-fix gap (parallel branches) | Fix lands on one sibling only — city/country denominator fixed to | Apply + re-verify ALL parallel branches; distributions must sum to ~100% |
| Stuck background task with no recovery | Worker chunk never calls back (crash/DLQ/lost SQS) → task | Wire a stuck-task sweep (terminal-state / re-publish); fail the message if the SNS publish throws |
当匹配到对应模式时,参考这些陷阱;陷阱库会持续扩充(§9)。架构专属陷阱在仓库补充文档中。
| 陷阱 | 触发场景 | 修复方案 |
|---|---|---|
| 处理器内同步LLM/外部任务 | 处理器 | 移至队列(SNS→cx-worker),或返回 |
| 日志记录拒绝但仍报告 | 拆分 |
| 路径间字段结构不一致 | 一个路径返回 | 在源头标准化;统一使用一种结构 |
| 字段名误导 | | 重命名以匹配存储内容 |
| 对其他服务的N+1调用 | 列表接口中每个用户发起一次 | 批量接口,或预计算/缓存标识 |
| HTTP请求体中的无界ID列表 | 按标签过滤时在POST请求体中发送所有匹配的Mongo ID | 分块处理,或让所属服务执行连接逻辑 |
| LLM输出键与映射不匹配 | 提示词为"Educational Content",映射为"Educational Content & How-To Guides"→静默丢弃 | 对齐提示词+JSON输出;兼容两种键 |
| 提取时副作用控制漂移 | 旧控制器提前返回,未触发Mixpanel/审计;新控制器无条件触发→重复计数 | 用旧的提前返回条件重新控制(如 |
| | 检查所有 |
| Multer字段与数据库列不匹配 | | 写入数据库负载;校验Schema包含该列 |
| 对称修复遗漏(并行分支) | 修复仅应用到一个分支——城市/国家分母改为 | 应用并重新验证所有并行分支;分布总和需约为100% |
| 无恢复机制的后台任务阻塞 | 工作进程块从未回调(崩溃/死信队列/丢失SQS消息)→任务永远处于 | 配置阻塞任务清理(终端状态 / 重新发布);若SNS发布失败则标记消息为失败 |
6. Re-review protocol
6. 重新审查流程
"The dev fixed X, re-review" → re-read the actual files (/). Never trust commit messages, prior memory, or your own prior findings — re-verify each against resolved source (§8 evidence gate); a prior pass can be wrong. If new commits double down on something you flagged, re-check your claim, not escalate.
Readgrep- Previously flagged issue actually resolved in code?
- Fix regress the symmetric/other path?
- Fix itself introduce a new bug? e.g. →
[Op.not]: ""turned a partial filter into "zero rows on MySQL".[Op.notIn]: [null, ""] - New files/commits since last review?
- Any query fix → regenerate and read the actual query (supplement's generator/one-liners).
Pin the delta. Record the last-reviewed SHA; re-review = + , not a fresh . The start-of-session snapshot and commit-message claims are not ground truth — reconcile with the PR's remote head (): the dev may have committed locally (your HEAD advanced) or pushed (your checkout stale). Establish the real delta, then verify each prior finding against it.
git diff <last-sha>..HEADgit log <last-sha>..HEAD<base>..HEADgitStatusgh pr view <n> --json headRefOidMost common re-review miss: a fix applied to one of several parallel branches. Confirm every sibling case got it, and invariants still hold (distribution sums to ~100%). See §5 symmetric-fix gap.
“开发者已修复X,重新审查”→重新读取实际文件(/)。永远不要信任提交信息、先前记忆、或你自己之前的发现——需针对已修复的源码重新验证(§8 证据验证);之前的审查可能有误。若新提交强化了你标记的问题,请重新检查你的结论,而非直接升级问题。
Readgrep- 之前标记的问题是否已在代码中实际修复?
- 修复是否导致对称/其他路径回归?
- 修复本身是否引入新Bug? 例如→
[Op.not]: ""将部分过滤变为“MySQL返回0行”。[Op.notIn]: [null, ""] - 自上次审查后是否有新文件/提交?
- 任何查询修复→生成并读取实际查询语句(补充文档的生成器/单行命令)。
锁定增量范围。记录上次审查的SHA;重新审查范围为 + ,而非重新执行。会话开始时的快照和提交信息并非事实——需与PR的远程头()核对:开发者可能已本地提交(你的HEAD已更新)或推送(你的检出版本过时)。确定真实增量后,针对每个先前发现的问题进行验证。
git diff <last-sha>..HEADgit log <last-sha>..HEAD<base>..HEADgitStatusgh pr view <n> --json headRefOid重新审查最常见的遗漏:修复仅应用到部分并行分支。确认所有关联场景都已修复,且不变量仍保持(分布总和约为100%)。见§5 对称修复遗漏陷阱。
7. Verification
7. 验证
Don't reason about generated queries or call graphs from memory — verify cheaply with greps and query generators. Each repo supplement carries its stack's one-liners (saas-server.md: Sequelize→SQL generator, tenancy greps; creator-services.md: index-drift script, payload-index greps).
不要凭记忆推断生成的查询或调用图——用grep和查询生成器快速验证。每个仓库补充文档包含对应架构的单行命令(saas-server.md:Sequelize→SQL生成器、租户grep;creator-services.md:索引漂移脚本、负载索引grep)。
8. Categorize findings & output
8. 分类发现并输出结果
Severity labels (plain words, no emoji/icons):
- Blocker — data loss, authZ/tenant bypass, security hole, production timeout, silent data corruption
- High — perf regression, edge-case correctness, broken UX path, back-compat break
- Lower priority — naming, structure, minor inconsistency
- Verified OK — what you checked and confirmed (gives the dev confidence in the rest)
严重程度标签(纯文字,无表情/图标):
- 阻塞——数据丢失、授权/租户绕过、安全漏洞、生产环境超时、静默数据损坏
- 高优先级——性能回归、边缘场景正确性、用户路径断裂、向后兼容性破坏
- 低优先级——命名、结构、轻微不一致
- 验证通过——你已检查并确认的内容(给开发者信心)
Evidence gate — clear before writing ANY Blocker/High
证据验证——标记任何阻塞/高优先级问题前必须确认
A false blocker is worse than a missed bug — it burns trust and can launch a regression. Any absolute claim ("always null", "never called", "dead/unused", "field doesn't exist", "returns zero rows", "this regresses X") must clear:
- Never infer a structure's full shape or a symbol's call graph from a diff hunk. Diffs are windowed — other keys, an line, another caller routinely sit just outside the shown context. A
exportsblock cut off beforereturn {is not the full object. (Real case:}mislabeled "always undefined" —cxScore.attributessat three lines below the hunk, onattributes: payloadall along.)main - Verify against resolved source, cheaply: grep where the symbol is assigned/returned/exported (not just read), then Read the full enclosing block. "X doesn't exist" → grep the producer side; "never called" → grep callers repo-wide; "zero rows" → regenerate the query (§7).
- A finding that contradicts shipped behavior flags your own premise first. If
mainalready reads that field and shipped, disprove yourself before writing it. Dev "doubling down" → re-verify your claim.main - Can't verify → can't assert. Downgrade to Lower-priority phrased as a question — "suspected X; verify by ". Confidence must match evidence.
<exact grep/read>
Write findings to at repo root.
<TOPIC>_REVIEW.mdOutput style: plain, tight, scannable. No emoji, no bold/decorative headers — plain severity labels only. No TL;DR padding, no empty "none" sections. One finding per line; write only what the dev needs to act. Applies to the chat summary too.
Re-review: append-only file — new section on top stamped with the delta range (), fixed vs. still-open; don't rewrite earlier rounds.
<last-sha>..HEADmarkdown
undefined虚假阻塞比遗漏Bug更糟——会破坏信任,甚至导致回归。任何绝对断言(如“始终为null”、“从未调用”、“已废弃/未使用”、“字段不存在”、“返回0行”、“此变更导致X回归”)必须满足:
- 切勿从差异片段推断结构的完整形态或符号的调用图。差异是局部的——其他键、行、其他调用者通常在显示范围之外。
exports块在return {前被截断并不代表完整对象。(真实案例:}被错误标记为“始终未定义”——cxScore.attributes位于差异片段下方3行,一直存在于attributes: payload分支。)main - 基于已解析源码快速验证:grep符号的赋值/返回/导出位置(而非仅读取位置),然后读取完整的封闭块。“X不存在”→grep生产者端;“从未调用”→全仓库grep调用者;“返回0行”→生成查询语句(§7)。
- 若发现与已上线分支行为矛盾的问题,先质疑自己的假设。若
main分支已读取该字段并上线,先推翻自己的结论再记录。开发者“坚持己见”→重新验证你的结论。main - 无法验证→无法断言。降级为低优先级,以问题形式表述——如“怀疑存在X;请通过验证”。信心需与证据匹配。
<具体grep/读取操作>
将发现写入仓库根目录的。
<TOPIC>_REVIEW.md输出风格:简洁、紧凑、易扫描。无表情、无加粗/装饰性标题——仅使用纯文字严重程度标签。无TL;DR冗余内容,无空的“无”章节。每个发现单独一行;仅记录开发者需要处理的内容。聊天摘要也需遵循此风格。
重新审查:文件采用追加模式——在顶部添加新章节,标记增量范围()、已修复vs仍未解决的问题;不要重写之前的审查记录。
<last-sha>..HEADmarkdown
undefined<PR topic> — review (<base>..<head>)
<PR主题> — 审查记录 (<base>..<head>)
Verdict: <one line — good to merge, or the one thing blocking it>.
Blockers (must fix before merge)
- <headline>. (
file:line) — symptom → root cause → fix.identifier
High
- …
Lower priority
- …
Verified OK
- <what you checked and confirmed>
Deferred (per author)
- <anything the user told you to ignore>
Each line: `- [ ]` checkbox (GitHub-pasteable) · `file:line` + offending identifier in backticks · symptom → cause → fix. State confidence honestly; if suspected-not-verified, say so with the exact check.结论:<一句话——可合并,或阻塞合并的核心问题>.
阻塞问题(合并前必须修复)
- <标题>. (
file:line) — 症状 → 根本原因 → 修复方案.标识符
高优先级
- …
低优先级
- …
验证通过
- <你已检查并确认的内容>
延期处理(按开发者要求)
- <用户要求忽略的内容>
每行格式:`- [ ]` 复选框(可粘贴到GitHub) · `file:line` + 反引号包裹的问题标识符 · 症状 → 原因 → 修复方案。如实记录信心;若为怀疑未验证的问题,需说明具体检查方式。What to skip
可忽略内容
- Style/formatting, comment typos (unless semantic), LSP-safe renames
- "Pre-existing in " issues — note, don't block
main - Anything explicitly deferred (track under "Deferred per author")
- 风格/格式、注释拼写错误(除非语义错误)、LSP安全重命名
- 分支已存在的问题——记录但不阻塞合并
main - 明确延期处理的内容(记录在“按开发者要求延期处理”下)
9. Keep the skill learning
9. 持续优化本技能
The skill improves by accumulating real traps, not theory.
- New recurring bug class → one-line trap row (+ a router row if file-type-triggered): trap → where it bites → fix. Framework-agnostic → this file's §5; stack-specific → the repo's supplement.
- Reviewing a repo with no supplement and finding repo-specific conventions worth encoding → propose a new supplement (fingerprint + stack mapping + checks by diff signal + one-liners, like the existing two) and add its row to the §0 dispatch table.
<repo>.md - Trap stops applying (pattern removed, framework upgraded) → prune it.
- Don't encode one-offs or anything lint/types/tests already enforce.
本技能通过积累实际陷阱而非理论来改进。
- 新的重复Bug类型→添加一行陷阱记录(若为文件类型触发,需同时添加路由规则):陷阱→触发场景→修复方案。与框架无关的陷阱→添加到本文件的§5;架构专属陷阱→添加到对应仓库的补充文档。
- 审查无补充文档的仓库时,若发现值得固化的仓库专属约定→建议新增补充文档(包含特征标识 + 架构映射 + 差异信号检查项 + 单行命令,参考现有文档),并添加到§0调度表中。
<repo>.md - 陷阱不再适用(模式已移除、框架已升级)→删除。
- 不要添加一次性问题或已被lint/类型检查/测试覆盖的内容。