Cursor 建议不符合仓库约定

Tab 补全和 Composer 改的命名 / 格式 / 模式都和仓库不一样——训练 prior 压过了检索信号,需要显式锚定。

仓库里全是 snake_case,Cursor Tab 补出 camelCase;现有组件都用 function declaration,Composer 给你 arrow function;测试都用 vitest,AI 写出 jest 语法。问题不是模型蠢,而是它的预训练 prior 见过的 “标准写法” 比你这个仓库的实际约定信号更强——retrieval 没给够反向证据时 prior 就赢。

修法是把约定从”隐含在代码里”变成”显式告诉模型”。

常见原因

1. 没 .cursorrules 或写得太泛

只有 “Follow project conventions” 这种空话,模型解析不出可执行规则。

如何判断cat .cursorrules 看是不是 < 20 行的空泛宣言。

2. 仓库本身约定混杂

老代码 snake_case、新代码 camelCase,retrieval 抽到的样本两边都有。模型按训练 prior 偏好 camelCase 就给你 camelCase。

如何判断

rg "function [a-z]+_[a-z]+" --type ts -c | head
rg "function [a-z]+[A-Z]" --type ts -c | head

两个数都大 = 混杂。

3. 目标模式的参考文件没进上下文

你想让新组件按 ProductCard.tsx 的风格写,但 retrieval 没把 ProductCard 拉进 prompt,模型只能凭训练记忆。

如何判断:Composer context 面板有没有你心里的标杆文件。

4. .cursorrules 过时

仓库 6 个月前从 pnpmbun、从 jestvitest,但 rules 没更新。

如何判断:rules 里写的工具 / 包管理器 vs package.json / lock 文件是否一致。

5. Tab 补全的上下文窗口小

Cursor Tab 是低延迟自动补全,只看光标附近上下文,不读全仓 rules。你 .cursorrules 写得再好它都看不见。

如何判断:Tab 经常出错而 Composer / chat 准 = Tab 上下文不够。

6. 模型训练 prior 比你的约定更强

约定本身就是少数派(如 interface I_FooState,匈牙利命名)。模型见过百万个 React 仓库,几乎没人这样命名,prior 占绝对优势。

如何判断:你的约定是否罕见、是否反 industry 主流。

动手前先确认

  • 区分是 Tab / Composer / Cmd+K 哪种入口在违反约定——Tab 上下文有限,治理路径不同。
  • .cursorrules 前 commit 一次。
  • 记下 Cursor 版本和当前模型——某些模型遵循 rules 比另一些好。

需要收集的信息

  • 一段 AI 给的代码 + 你期望它怎么写的对比。
  • .cursorrules / .cursor/rules/*.mdc 全部内容。
  • 仓库一份标杆文件路径(你希望它效仿的)。
  • 当前 Composer context 面板截图。

最短修复路径

按”立刻修 + 让规则更易遵循”。

Step 1:写一份具体的 .cursorrules

少用形容词,多写”应该 / 不应该”+ 例子:

# .cursorrules
- Use snake_case for function and variable names (project convention).
- Use function declarations for top-level functions, NOT arrow functions.
- Use vitest for tests, NEVER jest. Tests live next to source as *.test.ts.
- Imports order: 1) node built-ins, 2) external, 3) @/aliases, 4) relative.
- Prefer `interface` over `type` for object shapes; use `type` only for unions.

Example of correct style:
```ts
function parse_invoice(payload: InvoicePayload): Invoice \{
  return \{ ... \};
\}

Example of WRONG style (do not output):

const parseInvoice = (payload) => \{ ... \};

50-150 行最合适,太长稀释自己。

### Step 2:用 @File 锚定标杆

每次 Composer 任务里 `@<canonical-file>`,让模型直接看一份"正确写法"。

Composer prompt: Implement function X following the exact style of @src/services/parseOrder.ts (naming, import order, error handling pattern).


### Step 3:发现偏移立刻 push back

Your output uses camelCase but this repo uses snake_case. Rewrite, matching the style of @src/utils/parse_date.ts exactly.


回话里持续这样纠正几次,本次 chat 里效果立竿见影。

### Step 4:迁移期混杂约定要二选一

如果仓库正在从 jest → vitest 迁移,rules 里写明:
  • All NEW tests use vitest. Do NOT add new jest tests.
  • When editing existing jest tests, leave them as jest (separate PR will migrate).

不要让模型自己猜在哪一边。

### Step 5:用 CI lint 兜底

`.cursorrules` 是软约束,CI lint 是硬约束。配 eslint / biome / ruff 规则把约定校验自动化,AI 漏的能被 lint 拦下。

```json
// .eslintrc.json 示例
{
  "rules": {
    "@typescript-eslint/naming-convention": [
      "error",
      { "selector": "variableLike", "format": ["snake_case"] }
    ]
  }
}

Step 6:罕见约定考虑改回主流

如果你的约定罕见且没强 buy-in,可以重新评估。模型遵循 industry standard 几乎免费,对抗 prior 要持续投入。能改成主流的约定,长期最划算。

怎么确认已经修好

  • 用同一 prompt 重跑 Composer,确认代码风格符合 rules。
  • 让队友打开同一 workspace 跑相同 prompt,结果一致。
  • 跑 CI lint 全过,没有约定违规。

如果还是没修好

  • 把 prompt 缩到最小:单文件 + 显式 @ 一个标杆。
  • 回滚最近一次 .cursorrules 改动,确认是哪一条没起效。
  • 在 forum.cursor.com 搜 “ignores conventions”;附 rules 内容 + 输出 vs 期望对比。
  • 抓 View → Output → Cursor 日志贴 Bug Reports。

预防建议

  • .cursorrules commit 到仓库,跟约定变化同步更新,季度 audit 一次。
  • 每个 package 一份 .cursorrules,写本包独有规则。
  • 标杆文件 pin 在 workspace tabs,让 retrieval 优先看到。
  • CI 用 lint / formatter 自动化约定,不依赖 AI 自觉。
  • 罕见约定考虑改成主流,省得长期对抗模型 prior。

相关阅读

标签: #排查 #Cursor #排查 #约定