constraint-driven-development

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Constraint-Driven Development

约束驱动开发

Overview

概述

Other skills in this pack describe what good looks like.
code-review-and-quality
gives you five axes.
test-driven-development
gives you a cycle.
security-and-hardening
gives you a threat list. All of that lives in prose the agent reads and may or may not follow, and none of it survives the end of the session.
This skill produces something different: a written record of this project's bar, with numbers, that outlives the conversation and can be checked mechanically.
The reason matters. When you wrote the code, reading it told you whether it was any good. An agent writes more in an afternoon than you will read that week, so the judgement moves out of your head and into checks that run around the loop. Those checks need to exist, they need numbers you actually chose, and they need to fire close enough to the work that the agent fixes its own output.
Spec-driven development says what to build. Test-driven development proves it works. Constraint-driven development defines what "good enough to ship" means, before anyone argues about it in a pull request.
此工具包中的其他技能描述了优秀代码的样子。
code-review-and-quality
提供了五个评估维度,
test-driven-development
给出了开发循环,
security-and-hardening
提供了威胁清单。但这些内容都以Agent可读的散文形式存在,它可能遵守也可能不遵守,且会话结束后这些内容就不复存在了。
本技能则会产出不同的成果:一份针对当前项目的书面质量标准记录,包含具体数值,能在会话结束后继续存在,且可通过机械方式进行检查。
背后的原因很重要。当你自己编写代码时,阅读代码就能判断其质量。但Agent一个下午编写的代码量可能超过你一周的阅读量,因此判断工作从你的大脑转移到了循环运行的检查工具中。这些检查工具必须存在,必须有你实际选定的数值,且必须在工作完成后立即触发,让Agent能够自行修正输出内容。
规范驱动开发定义了要构建的内容,测试驱动开发验证功能可用,而约束驱动开发则在任何人在拉取请求中争论之前,就定义了「足够好可以发布」的标准。

When to Use

适用场景

Apply this skill when:
  • Starting a project or a significant feature and no quality bar is written down
  • The user asks to "set up constraints", "add quality gates", "define our standards", or "stop the agent shipping junk"
  • An agent is producing volume nobody is reading line by line
  • CI has checks but nobody can say which ones block a merge and which ones are decoration
  • Coverage, performance, or accessibility numbers get argued about per-PR instead of decided once
  • You're about to run
    /build auto
    or any autonomous loop, and the only thing standing between it and main is a test suite the agent also wrote
When NOT to use:
  • The project already has a
    CONSTRAINTS.md
    and the user isn't changing it — read it and follow it instead
  • One-off scripts, spikes, throwaway prototypes
  • The user wants a code review right now (
    code-review-and-quality
    ) or a CI pipeline built (
    ci-cd-and-automation
    )
  • Pre-product-market-fit code with a two-week expected lifetime — the floor below is still worth it, the rest isn't
在以下情况应用本技能:
  • 启动新项目或重要功能,但尚未书面定义质量标准
  • 用户要求「设置约束」「添加质量门禁」「定义我们的标准」或「阻止Agent输出垃圾代码」
  • Agent产出的代码量过大,无人能逐行审阅
  • CI有检查,但没人能说清哪些检查会阻止合并,哪些只是装饰
  • 覆盖率、性能或可访问性数值在每个PR中都引发争论,而非一次性确定
  • 你即将运行
    /build auto
    或任何自主循环,而阻止它合并到主分支的唯一障碍是Agent自己编写的测试套件
不适用场景:
  • 项目已有
    CONSTRAINTS.md
    且用户不打算修改——此时应直接读取并遵循该文件
  • 一次性脚本、探索性代码、临时原型
  • 用户现在就需要代码评审(使用
    code-review-and-quality
    )或构建CI流水线(使用
    ci-cd-and-automation
  • 产品市场适配前的代码,预期生命周期仅两周——基础标准仍有价值,但其他约束无需设置

Loading Constraints

加载约束

The interview needs a live user. Don't run it in non-interactive contexts (CI,
/loop
, autonomous runs). If constraints are missing and you're in one of those, apply the Floor below, note that you did, and flag the rest for a human.
访谈需要真实用户参与。不要在非交互式环境中运行(CI、
/loop
、自主运行)。如果缺少约束且处于上述环境,应应用下方的基础标准,记录操作并将其余部分标记为需要人工处理。

The Process

流程

Step 1: Detect before you ask

步骤1:先检测再询问

Never ask what you can read. Before the first question, gather:
WhatWhere to look
Language and stack
package.json
,
pyproject.toml
,
go.mod
,
Cargo.toml
Test runnerdev dependencies,
test
script, existing test files
Existing linters
eslint.config.*
,
biome.json
,
.ruff.toml
Coverage today
coverage/
output, or run the suite once
CI
.github/workflows/
,
.gitlab-ci.yml
Agent harness
.claude/
,
.codex/
,
AGENTS.md
Report what you found in two lines, then ask only what's left.
永远不要询问可以通过读取获取的信息。在提出第一个问题前,先收集以下信息:
内容查找位置
语言和技术栈
package.json
,
pyproject.toml
,
go.mod
,
Cargo.toml
测试运行器开发依赖、
test
脚本、现有测试文件
现有代码检查工具
eslint.config.*
,
biome.json
,
.ruff.toml
当前覆盖率
coverage/
输出,或运行一次测试套件
CI配置
.github/workflows/
,
.gitlab-ci.yml
Agent工具配置
.claude/
,
.codex/
,
AGENTS.md
用两行文字汇报发现的内容,然后只询问剩余的信息。

Step 2: Four questions, each with a default

步骤2:四个问题,每个都有默认值

Follow the one-question-at-a-time discipline from
interview-me
, with one change: every question here has a default, so "I don't know" is a complete answer that still produces a working config.
Q1: Beyond the floor, which of these do you want enforced?
    (a) Test coverage on new code
    (b) Security scanning
    (c) Performance budgets
    (d) Accessibility
    (e) Architecture boundaries
GUESS: (a) and (b) — you have a test runner already and you're handling user input.
DEFAULT if unsure: (a) and (b).
Say what each pick costs: (c) and (d) need a running URL, (e) needs a rules file written.
Q2: When a check fails while the agent is mid-task, should it block or warn?
GUESS: Block. You're running agents unattended and a warning nobody reads is a warning.
DEFAULT if unsure: Block on the floor, warn on everything else for the first two weeks.
Q3: Do you have target numbers in mind, or should I measure where you are today and hold that line?
GUESS: Measure. Most teams don't have a number, and an invented one gets ignored.
DEFAULT if unsure: Measure and hold. See "Ratchets" below.
Q4: What's the slowest check you'll tolerate before the agent hands work back?
GUESS: About 90 seconds. Longer and you'll stop running it.
DEFAULT if unsure: 90 seconds at task end, unlimited in CI.
Stop at four. A twelve-question intake produces a config nobody understands and a user who regrets starting.
遵循
interview-me
的逐个提问原则,但有一点变化:这里的每个问题都有默认值,因此「我不知道」也是完整答案,仍能生成可用配置。
问题1:除基础标准外,你希望强制执行以下哪些维度?
    (a) 新代码的测试覆盖率
    (b) 安全扫描
    (c) 性能预算
    (d) 可访问性
    (e) 架构边界
推测:(a)和(b)——你已有测试运行器且正在处理用户输入。
不确定时的默认值:(a)和(b)。
说明每个选项的成本:(c)和(d)需要可访问的URL,(e)需要编写规则文件。
问题2:当Agent执行任务时检查失败,应该阻止任务还是仅发出警告?
推测:阻止。你在无人值守情况下运行Agent,无人阅读的警告等同于无效。
不确定时的默认值:基础标准触发阻止,其他维度在前两周仅发出警告。
问题3:你有目标数值吗?还是我应该测量当前状态并保持该标准?
推测:测量。大多数团队没有明确数值,凭空设定的数值会被忽略。
不确定时的默认值:测量并保持。详见下方「棘轮机制」。
问题4:你能容忍的最慢检查耗时是多少,超过后Agent应交付工作?
推测:约90秒。耗时更长的话大家就不会运行它了。
不确定时的默认值:任务结束时最多90秒,CI中无限制。
最多只问四个问题。十二个问题的导入流程会生成没人能理解的配置,还会让用户后悔启动这个流程。

Step 3: Write CONSTRAINTS.md

步骤3:编写CONSTRAINTS.md

One file at the repo root. Any agent on any harness can read it, and a change to it shows up in review where it belongs.
markdown
undefined
在仓库根目录创建一个文件。任何工具中的Agent都能读取它,对它的修改会出现在评审中,这才是正确的位置。
markdown
undefined

Constraints

约束

Last reviewed: 2026-08-08 by @addy
最后评审时间:2026-08-08 by @addy

Floor (always enforced, no setup required)

基础标准(始终强制执行,无需额外设置)

  • No new suppression comments:
    @ts-ignore
    ,
    eslint-disable
    ,
    # noqa
    ,
    # type: ignore
  • No unimplemented stubs:
    throw new Error("Not implemented")
    , empty
    catch {}
  • No skipped or deleted tests without a reason in the commit message
  • No secrets in source
  • This file does not get weakened to make a change pass
  • 禁止新增抑制注释:
    @ts-ignore
    ,
    eslint-disable
    ,
    # noqa
    ,
    # type: ignore
  • 禁止未实现的存根:
    throw new Error("Not implemented")
    , 空
    catch {}
  • 禁止跳过或删除测试,除非提交信息中说明原因
  • 源代码中禁止包含密钥
  • 不得为了让变更通过而弱化本文件的内容

Enforced with numbers

带数值的强制执行项

DimensionRuleChecked byRuns at
TypesZero type errors
tsc --noEmit
every edit
LintZero errors from our config
biome check
every edit
SecretsNo secrets in source
gitleaks detect --redact
every edit
CoverageChanged lines ≥ 80% covered
vitest run --coverage
+ git diff
task end, CI
Security: codeNo high findings
semgrep scan --config p/default
CI
Security: depsNothing at high or above
osv-scanner scan source -r .
CI
AccessibilityZero critical or serious
axe $PREVIEW_URL --tags wcag2a,wcag2aa,wcag21aa
preview deploy
PerformanceLCP ≤ 2500ms, CLS ≤ 0.1
lighthouse $PREVIEW_URL --output=json
preview deploy
Every row names the command that produces the verdict. A dimension with a number and no command in this column is an aspiration, not a constraint.
维度规则检查工具运行时机
类型检查零类型错误
tsc --noEmit
每次编辑后
代码检查零配置错误
biome check
每次编辑后
密钥检查源代码中无密钥
gitleaks detect --redact
每次编辑后
覆盖率修改行覆盖率≥80%
vitest run --coverage
+ git diff
任务结束时、CI中
代码安全无高危发现
semgrep scan --config p/default
CI中
依赖安全无高危及以上风险
osv-scanner scan source -r .
CI中
可访问性零严重或极严重问题
axe $PREVIEW_URL --tags wcag2a,wcag2aa,wcag21aa
预览部署时
性能LCP ≤ 2500ms, CLS ≤ 0.1
lighthouse $PREVIEW_URL --output=json
预览部署时
每一行都标注了生成判断结果的命令。带有数值但本列无命令的维度只是目标,而非约束。

Measured, not yet enforced

已测量但暂未强制执行

MetricTodayDirection
Project coverage62.4%must not fall
Bundle size (main)184 kBmust not grow
指标当前值要求方向
项目覆盖率62.4%不得下降
主包大小184 kB不得增长

Exceptions

例外情况

IDRulePathReasonOwnerExpires
W1
no-explicit-any
src/legacy/**
Rewrite tracked in ENG-441@addy2026-11-01

Then add one line to `AGENTS.md` and `CLAUDE.md`: `Read CONSTRAINTS.md before writing code. Do not weaken it to make a change pass.`
ID规则路径原因负责人到期时间
W1
no-explicit-any
src/legacy/**
重构进度跟踪在ENG-441@addy2026-11-01

然后在`AGENTS.md`和`CLAUDE.md`中添加一行:`编写代码前请阅读CONSTRAINTS.md。不得为了让变更通过而弱化其内容。`

Step 4: Install what each dimension needs

步骤4:安装各维度所需工具

Picking a dimension means installing something. Don't leave the user with a number and no mechanism, and don't invent your own checker when a de facto one exists — these tools are listed because their rule formats and thresholds are what everything else in the ecosystem targets, so the team's existing config keeps working.
DimensionToolInstallRunGate on
Types (TS)tscalready there
tsc --noEmit
any error
Types (Python)mypy
pip install mypy
mypy .
any error
Lintyour existing configalready there
eslint .
/
biome check
/
ruff check
any error
Coverage (JS)your test runneralready there
vitest run --coverage
(or
jest --coverage
)
coverage of changed lines
Coverage (Python)pytest-cov
pip install pytest-cov
pytest --cov --cov-report=lcov
same
Security: codeSemgrep
pipx install semgrep
semgrep scan --config p/default --config p/owasp-top-ten
any high finding
Security: secretsgitleaks
brew install gitleaks
gitleaks detect --redact --no-banner
any finding
Security: dependenciesosv-scanner
brew install osv-scanner
osv-scanner scan source -r .
high or above
Performance: pageLighthouse
npm i -D lighthouse
lighthouse $URL --output=json --quiet
LCP, CLS, performance score
Performance: bundlesize-limit
npm i -D size-limit
size-limit --json
per-entry byte budget
Accessibilityaxe-core
npm i -D @axe-core/cli
axe $URL --tags wcag2a,wcag2aa,wcag21aa
zero critical or serious
Architecturedependency-cruiser
npm i -D dependency-cruiser
depcruise --validate src
any violation
Assertion qualityStryker
npm i -D @stryker-mutator/core
stryker run --mutate <changed files>
mutation score
Five things that will bite you if you skip them:
  1. --redact
    on gitleaks is not optional.
    Without it the matched secret lands in the agent's transcript, which is how a leaked key ends up in a log, a summary, or a commit message. Report the rule and the location, never the value.
  2. Lighthouse and axe need a URL. They only work against a running app, so they belong in the runtime stage against a preview deploy or a local server you start first. If the project has no URL to hit — a CLI, a library, a desktop app — say so and drop the dimension rather than inventing a check that can't run.
  3. Scope the expensive ones to the diff.
    stryker run --mutate
    on the whole repo takes hours and gets turned off; on the files a change touched it takes under a minute. Same for Semgrep, which takes a path list.
  4. Coverage needs no second test run. Read the lcov your suite already writes and intersect it with
    git diff
    . Running the suite twice to get a number is the fastest way to make people hate this.
  5. Semgrep's registry rules are free to run; check the licence before redistributing them.
    opengrep
    is a drop-in fork with the same rule format and JSON output if that matters to your legal team.
Add each one to the project's own script so it's reproducible without an agent:
json
{
  "scripts": {
    "check:fast": "tsc --noEmit && eslint . && gitleaks detect --redact --no-banner",
    "check:task": "npm run check:fast && vitest run --coverage",
    "check:full": "npm run check:task && semgrep scan --config p/default && osv-scanner scan source -r ."
  }
}
That mapping matters more than the tools.
check:fast
is what runs after an edit,
check:task
when the agent thinks it's done,
check:full
in CI.
The commands now live in two places — the
Checked by
column in
CONSTRAINTS.md
and these scripts.
CONSTRAINTS.md
is the canonical source: it carries the reason alongside each command and it shows up in review. The scripts are convenience wrappers that must mirror it, not a second source of truth; if they drift, the file wins.
选择某个维度意味着要安装对应的工具。不要让用户只得到数值却没有执行机制,且不要在已有行业标准工具时自行编写检查器——列出这些工具是因为它们的规则格式和阈值是生态系统的通用标准,团队现有配置可以继续使用。
维度工具安装方式运行命令门禁条件
类型检查(TS)tsc已存在
tsc --noEmit
任何错误
类型检查(Python)mypy
pip install mypy
mypy .
任何错误
代码检查现有配置已存在
eslint .
/
biome check
/
ruff check
任何错误
覆盖率(JS)现有测试运行器已存在
vitest run --coverage
(或
jest --coverage
修改行覆盖率
覆盖率(Python)pytest-cov
pip install pytest-cov
pytest --cov --cov-report=lcov
同上
代码安全Semgrep
pipx install semgrep
semgrep scan --config p/default --config p/owasp-top-ten
任何高危发现
密钥安全gitleaks
brew install gitleaks
gitleaks detect --redact --no-banner
任何发现
依赖安全osv-scanner
brew install osv-scanner
osv-scanner scan source -r .
高危及以上风险
页面性能Lighthouse
npm i -D lighthouse
lighthouse $URL --output=json --quiet
LCP、CLS、性能评分
包性能size-limit
npm i -D size-limit
size-limit --json
每个入口的字节预算
可访问性axe-core
npm i -D @axe-core/cli
axe $URL --tags wcag2a,wcag2aa,wcag21aa
零严重或极严重问题
架构检查dependency-cruiser
npm i -D dependency-cruiser
depcruise --validate src
任何违规
断言质量Stryker
npm i -D @stryker-mutator/core
stryker run --mutate <修改的文件>
突变评分
如果跳过以下五点,你会遇到麻烦:
  1. gitleaks的
    --redact
    参数是必须的。
    没有它,匹配到的密钥会出现在Agent的记录中,可能导致密钥泄露到日志、摘要或提交信息中。只需报告规则和位置,永远不要泄露密钥值。
  2. Lighthouse和axe需要URL。 它们只能针对运行中的应用工作,因此应在运行阶段针对预览部署或本地启动的服务器执行。如果项目没有可访问的URL——比如CLI、库、桌面应用——应说明情况并移除该维度,而非编写无法运行的检查。
  3. 将耗时的检查范围限定在差异代码中。 对整个仓库运行
    stryker run --mutate
    需要数小时,最终会被停用;而仅针对修改的文件运行耗时不到一分钟。Semgrep同理,只需指定路径列表。
  4. 覆盖率无需运行两次测试。 读取测试套件已生成的lcov文件,并与
    git diff
    结果交叉对比。为了获取数值而运行两次测试套件是让大家反感的最快方式。
  5. Semgrep的注册表规则可免费运行;重新分发前请检查许可证。 如果法务团队有要求,
    opengrep
    是一个兼容的替代方案,具有相同的规则格式和JSON输出。
将每个检查添加到项目自身的脚本中,确保无需Agent也能重现:
json
{
  "scripts": {
    "check:fast": "tsc --noEmit && eslint . && gitleaks detect --redact --no-banner",
    "check:task": "npm run check:fast && vitest run --coverage",
    "check:full": "npm run check:task && semgrep scan --config p/default && osv-scanner scan source -r ."
  }
}
这种映射比工具本身更重要。
check:fast
在每次编辑后运行,
check:task
在Agent认为任务完成时运行,
check:full
在CI中运行。
命令现在存在于两个地方——
CONSTRAINTS.md
的「检查工具」列和这些脚本中。
CONSTRAINTS.md
是权威来源:它为每个命令附带了原因,且会出现在评审中。脚本只是方便的包装器,必须与文件内容保持一致;如果两者出现偏差,以文件内容为准。

Step 5: Wire it to the lifecycle

步骤5:与生命周期关联

The single biggest mistake is running everything everywhere. A check that stalls the agent gets switched off, and a gate people switched off is worse than no gate, because the bar still looks like it exists.
PhaseCommandWhat runsBudget
BUILD
/build
Types, lint, secrets, the floorunder 5s, changed file only
VERIFY
/test
Related tests, coverage on changed linesunder 90s
REVIEW
/review
Everything, plus the guards belowminutes
SHIP
/ship
Direction checks, no regressionsCI
Two rules that keep this tolerable:
  1. Scope to the diff. Check the lines this change touched, not the whole repo. Coverage of changed lines is a number the agent can move; project coverage is one it inherited.
  2. Cost decides placement. Anything over a few seconds moves out of the edit loop. Mutation testing on a whole repo takes hours; on the files a change touched it takes under a minute, which is the difference between a check people run and one they don't.
最大的错误是在所有地方运行所有检查。让Agent停滞的检查会被停用,而被停用的门禁还不如没有门禁,因为表面上看起来标准仍然存在。
阶段命令运行内容时间预算
构建
/build
类型检查、代码检查、密钥检查、基础标准5秒以内,仅针对修改的文件
验证
/test
相关测试、修改行覆盖率90秒以内
评审
/review
所有检查,加上下方的门禁检查数分钟
发布
/ship
方向检查,无回归CI中
以下两条规则让流程保持可接受:
  1. 范围限定在差异代码中。 检查本次变更涉及的行,而非整个仓库。修改行覆盖率是Agent可以改变的数值;项目覆盖率是它继承的数值。
  2. 成本决定位置。 任何耗时超过几秒的检查都要移出编辑循环。对整个仓库进行突变测试需要数小时;而针对修改的文件运行耗时不到一分钟,这决定了检查是否会被大家使用。

Step 6: Guard the bar itself

步骤6:守护标准本身

Someone will point out that if the agent writes the code and the checks, the checks prove nothing. Half right, and worth engineering around.
Agents don't craft clever loopholes. They hit a red check and take the cheapest road to green. Watch for these five moves in the diff, at review time:
  1. The threshold moved. A budget lowered, a severity dropped, a check removed from the fast stage. Compare
    CONSTRAINTS.md
    against its state at the branch point.
  2. A test got easier.
    .skip
    added, a test file deleted, assertions pulled out of tests that stayed.
  3. A checker got silenced. New
    @ts-ignore
    or
    eslint-disable
    . Four suppressions deserve special attention because they switch off a check you're relying on:
    istanbul ignore
    drops code from coverage instead of testing it,
    Stryker disable
    hides a surviving mutant,
    nosemgrep
    and
    gitleaks:allow
    do it for security findings.
  4. Work is unfinished. A stub that throws, an empty
    catch
    turning a failure into silence, a
    TODO
    standing where the implementation should be.
  5. An exception appeared. A new row in the Exceptions table nobody discussed.
None of this needs tooling beyond
git diff
. Tightening the bar should be silent; loosening it should be loud.
Unlike the numbered dimensions, the floor has no de facto tool of its own, so an agent asked to enforce it tends to write a checker from scratch, and two agents write two different ones. A reference implementation of these five checks ships with this skill in references/floor-guard.md (diff-scoped, exit
0
/
1
/
2
, patterns adaptable per ecosystem). Adapt that rather than reinventing it, for the same reason every dimension names a de facto tool: so the mechanism is the same across runs and stacks.
Not all checks are equally circular. Rank them by one question: can the agent make this pass by writing code that doesn't work?
  • External — axe-core encodes WCAG,
    osv-scanner
    reads a vulnerability database, Lighthouse measures a real browser. The agent can't argue with these.
  • Project — your lint rules, your layer boundaries. A human owns the file.
  • Suite — your own tests. Most useful, and the only genuinely circular one.
A bar made entirely of the third kind is worth less than one with an outside opinion in it. Check that at least one external constraint is present.
有人会指出,如果Agent既编写代码又编写检查,那么检查毫无意义。这话只对了一半,值得我们针对性设计避免。
Agent不会制造巧妙的漏洞。它们遇到检查失败时会选择最省事的方式通过。在评审时,监控差异中的以下五种操作:
  1. 阈值被修改。 预算被调低、严重等级被降低、检查从快速阶段移除。将
    CONSTRAINTS.md
    与分支起点的版本进行对比。
  2. 测试被简化。 添加
    .skip
    、删除测试文件、移除保留测试中的断言。
  3. 检查器被静默。 新增
    @ts-ignore
    eslint-disable
    。有四种抑制需要特别注意,因为它们会关闭你依赖的检查:
    istanbul ignore
    将代码从覆盖率统计中排除而非测试它,
    Stryker disable
    隐藏存活的突变体,
    nosemgrep
    gitleaks:allow
    会关闭安全检查。
  4. 工作未完成。 抛出异常的存根、将失败转为静默的空
    catch
    块、本应是实现代码的
    TODO
    注释。
  5. 新增例外。 例外情况表中出现无人讨论过的新行。
所有这些都不需要
git diff
之外的工具。收紧标准可以静默进行;但放宽标准必须公开。
与带编号的维度不同,基础标准没有现成的行业工具,因此被要求强制执行的Agent往往会自行编写检查器,不同的Agent会写出不同的版本。本技能附带了这五项检查的参考实现,位于references/floor-guard.md(限定在差异代码中,返回
0
/
1
/
2
,模式可适配不同生态系统)。应基于此修改而非重新发明,原因与每个维度都选择行业标准工具相同:确保不同运行和技术栈中的机制一致。
并非所有检查都是同等循环验证的。 通过一个问题对它们进行排序:Agent是否可以通过编写无效代码来通过检查?
  • 外部检查 — axe-core遵循WCAG标准,
    osv-scanner
    读取漏洞数据库,Lighthouse测量真实浏览器的性能。Agent无法反驳这些结果。
  • 项目检查 — 你的代码检查规则、层级边界。由专人负责维护配置文件。
  • 套件检查 — 你自己的测试。最有用,但也是唯一真正循环验证的检查。
完全由第三类检查构成的标准价值低于包含外部意见的标准。确保至少存在一项外部约束。

Step 7: Ratchets, when you don't have a number

步骤7:棘轮机制,当你没有数值时

Set 80% coverage on a codebase at 62% and you get a red build forever, then a team that learns to ignore red builds.
The alternative asks for no decision: record where you are, then refuse to get worse. Put it in the "Measured, not yet enforced" table with today's number and a direction. Every check compares against the recorded value, not an aspiration. When a number improves, update it; when it drops, that's the finding.
This also answers a fair objection to training. Models are rewarded for passing tests, which you can evaluate in seconds. Architectural rot shows up over months and never reaches the weights. A ratchet is the missing penalty, written down where the build can see it.
在覆盖率为62%的代码库中设置80%的覆盖率要求,会导致构建永远失败,进而让团队学会忽略失败的构建。
替代方案无需决策:记录当前状态,然后拒绝恶化。将其放入「已测量但暂未强制执行」表格,包含当前数值和要求方向。每次检查都与记录的值对比,而非目标值。当数值提升时更新记录;当数值下降时,将其视为问题。
这也解决了一个关于模型训练的合理异议:模型会因通过测试而获得奖励,这可以在几秒内评估。但架构腐化会在数月内显现,永远不会影响模型权重。棘轮机制就是缺失的惩罚,它被记录在构建可以读取的位置。

Sane Defaults

合理默认值

When the user has no opinion, use these. They're chosen to be met by most codebases on day one.
ConstraintDefaultWhy this number
Coverage of changed lines≥ 80%High enough to force a test, low enough to allow a config line
Project coveragetoday's value, must not fallNo argument needed to adopt
Mutation score (if used)≥ 60% to startTypical for a suite never mutated before; 80% is mature
Dependency vulnerabilitiesnothing at high or aboveBelow that is mostly noise
LCP≤ 2500 msCore Web Vitals "good" threshold
CLS≤ 0.1Same
Accessibilityzero critical or serious axe violationsModerate and minor are often debatable
Exception lifetime90 daysLong enough to plan the fix, short enough to remember
Ratchet tolerance0.5%Absorbs drift when an unrelated file moves the number
State the number and the reason together. A threshold without a rationale gets deleted by the next person who hits it.
当用户没有意见时,使用以下默认值。这些数值选择为大多数代码库在第一天就能达到的标准。
约束默认值数值原因
修改行覆盖率≥ 80%高到足以强制编写测试,低到允许配置行存在
项目覆盖率当前值,不得下降采用无需争论
突变评分(若使用)初始≥60%从未进行突变测试的套件的典型值;80%为成熟水平
依赖漏洞无高危及以上风险以下大多是噪音
LCP≤ 2500 msCore Web Vitals「良好」阈值
CLS≤ 0.1同上
可访问性axe检查零严重或极严重问题中等和轻微问题常存在争议
例外有效期90天足够规划修复,也足够短以便记住
棘轮容差0.5%当无关文件导致数值变化时吸收波动
同时说明数值和原因。没有理由的阈值会被下一个遇到它的人删除。

Escalation Path

升级路径

Constraints work at three levels of teeth. Start at the first.
  1. Written only.
    CONSTRAINTS.md
    exists and agents read it. Costs nothing, catches the honest mistakes, relies on the agent complying.
  2. Scripted. An
    npm run check
    (or
    make check
    ) that runs the fast checks, wired into your agent's post-edit hook and your CI. Deterministic, no new dependency.
  3. Tool-backed. A dedicated runner that handles diff scoping, budgets, ratchets, and the guard checks. Use when the config outgrows a shell script. The floor-guard reference in references/floor-guard.md is the starting point for the guard-checks half of this.
Most projects should stop at 2. Move to 3 when you're maintaining more than about thirty lines of check-running shell.
A first run can be floor-only. The floor guard is diff-only and needs no installs, so you can enforce the floor on day one and add numbered dimensions as you install each tool, rather than standing up every checker before the first commit is protected. Security tools that install machine-wide (gitleaks, osv-scanner) can also run CI-only if you'd rather keep laptops clean; declare where each dimension runs in the
Runs at
column.
约束有三个严格程度级别。从第一个级别开始。
  1. 仅书面记录。
    CONSTRAINTS.md
    存在且Agent会读取它。无成本,能捕捉无心之失,依赖Agent遵守。
  2. 脚本化。
    npm run check
    (或
    make check
    )运行快速检查,关联到Agent的编辑后钩子和CI。确定性强,无新依赖。
  3. 工具支持。 专用运行器处理差异范围、预算、棘轮机制和门禁检查。当配置超出shell脚本能力时使用。references/floor-guard.md中的基础门禁参考实现是门禁检查部分的起点。
大多数项目应停留在第2级。当你维护的检查shell脚本超过约30行时,再升级到第3级。
首次运行可仅启用基础标准。 基础门禁仅针对差异代码,无需安装,因此你可以在第一天就强制执行基础标准,然后在安装每个工具时添加带编号的维度,而非在保护第一个提交前就搭建好所有检查器。如果希望保持电脑整洁,可在CI中仅运行机器全局安装的安全工具(gitleaks、osv-scanner);在「运行时机」列中声明每个维度的运行位置。

Common Rationalizations

常见借口

ExcuseReality
"We'll add constraints once the code settles"Code settles around whatever was allowed while it was moving
"The tests are the constraints"Tests you wrote prove you agree with yourself; they say nothing about coverage of new code, dependency risk, or bundle growth
"We can't hit 80% coverage"Then don't set 80%. Set today's number and hold it
"This will slow the agent down"Only if you put slow checks in the fast loop. That's a placement error, not an argument against constraints
"I'll remember what our standards are"The agent won't, and it's writing most of the code
"Constraints will block us shipping"An exception with an owner and a date unblocks you. Deleting the constraint unblocks everyone forever
借口实际情况
"等代码稳定后我们再添加约束"代码会围绕变动期间允许的内容稳定下来
"测试就是约束"你编写的测试只能证明你自洽;它们无法说明新代码的覆盖率、依赖风险或包大小增长情况
"我们无法达到80%的覆盖率"那不要设置80%。设置当前数值并保持它
"这会拖慢Agent的速度"只有当你把慢检查放在快速循环中才会如此。这是位置错误,而非反对约束的理由
"我会记住我们的标准"Agent不会,而且它编写了大部分代码
"约束会阻止我们发布"带有负责人和日期的例外情况可以解除阻止。删除约束会永久解除所有人的限制

Red Flags

危险信号

Stop and reconsider if you notice:
  • The interview ran past four questions, or produced a config the user can't explain
  • A budget was set that the codebase fails today, with no plan to reach it
  • A dimension was written into CONSTRAINTS.md with a number but no tool behind it
  • A checker was hand-rolled when a de facto one exists, so the team's existing config is ignored
  • Every constraint is checked by the project's own test suite, with no external opinion
  • CONSTRAINTS.md
    changed in the same commit as the feature that was failing
  • An exception has no owner, or an expiry more than a year out
  • The agent proposed relaxing a threshold instead of fixing the code
  • Slow checks landed in the edit loop and someone has started passing
    --no-verify
  • Nobody has opened
    CONSTRAINTS.md
    since it was written
如果注意到以下情况,请停止并重新考虑:
  • 访谈超过四个问题,或生成用户无法解释的配置
  • 设置的预算是当前代码库无法达到的,且没有实现计划
  • CONSTRAINTS.md
    中写入了带数值但无对应工具的维度
  • 已有行业标准工具时仍自行编写检查器,导致团队现有配置被忽略
  • 所有约束都由项目自己的测试套件检查,无外部意见
  • CONSTRAINTS.md
    与失败的功能变更在同一个提交中被修改
  • 例外情况没有负责人,或有效期超过一年
  • Agent提议放宽阈值而非修复代码
  • 慢检查被放在编辑循环中,有人开始使用
    --no-verify
    跳过检查
  • 自编写以来无人打开过
    CONSTRAINTS.md

Verification

验证

The skill was applied correctly when:
  • CONSTRAINTS.md
    exists, and every number in it has a stated reason
  • The floor is enforced and passes on the current codebase without changes
  • Every dimension the user picked has a tool installed and a command that runs today
  • Each constraint says where it runs, and the fast stage stays under a few seconds
  • At least one constraint is external (not judged by this project's own tests)
  • Measured-only metrics record today's value and a direction
  • Exceptions have an owner and an expiry date
  • AGENTS.md
    or
    CLAUDE.md
    points at the file
  • A trial run on the current branch produces no failures the user disagrees with
当满足以下条件时,技能被正确应用:
  • CONSTRAINTS.md
    存在,且其中每个数值都有说明理由
  • 基础标准已强制执行,且当前代码库无需修改即可通过
  • 用户选择的每个维度都已安装工具,且命令当前可运行
  • 每个约束都说明了运行时机,且快速阶段耗时保持在几秒以内
  • 至少存在一项外部约束(不由项目自己的测试判断)
  • 仅测量的指标记录了当前值和要求方向
  • 例外情况有负责人和到期时间
  • AGENTS.md
    CLAUDE.md
    指向该文件
  • 在当前分支上试运行未产生用户不同意的失败结果

See Also

另请参阅

  • interview-me
    — the one-question-at-a-time discipline this skill's intake borrows
  • code-review-and-quality
    — how to review; this skill decides what the review enforces
  • ci-cd-and-automation
    — building the pipeline these constraints run in
  • test-driven-development
    — the suite that coverage and mutation constraints measure
  • security-and-hardening
    — what the security dimension should contain
  • performance-optimization
    — where the performance numbers come from
  • interview-me
    — 本技能导入流程采用的逐个提问原则
  • code-review-and-quality
    — 如何进行评审;本技能决定评审要强制执行的标准
  • ci-cd-and-automation
    — 构建运行这些约束的流水线
  • test-driven-development
    — 覆盖率和突变约束测量的测试套件
  • security-and-hardening
    — 安全维度应包含的内容
  • performance-optimization
    — 性能数值的来源