mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Daily pushes should catch policy and path-aware local failures without making every contributor wait for full coverage. The hook now runs a new quality:push entrypoint that reuses the PR quality gate while skipping coverage; verify, quality:pr, and CI still retain the full coverage gate for PR readiness. Constraint: Forks and local contributors need a faster default push path Rejected: Remove coverage from quality:pr | PR readiness and CI still need the ratcheted coverage signal Confidence: high Scope-risk: narrow Directive: Keep pre-push on quality:push; use verify or quality:pr when coverage evidence is required Tested: bun test scripts/pr/quality-contract.test.ts scripts/git-hooks/install.test.ts Tested: bun run check:policy Tested: bun run quality:push Not-tested: Live provider smoke; intentionally remains opt-in
71 lines
4.1 KiB
TypeScript
71 lines
4.1 KiB
TypeScript
import { describe, expect, test } from 'bun:test'
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
describe('feature quality contract', () => {
|
|
test('keeps the agent-facing implementation contract explicit', () => {
|
|
const agents = readFileSync('AGENTS.md', 'utf8')
|
|
|
|
expect(agents).toContain('## Feature Quality Contract')
|
|
expect(agents).toContain('## Persistent Storage Compatibility')
|
|
expect(agents).toContain('Any change to local JSON, `localStorage`, or app config persistence formats must ship with a forward migration')
|
|
expect(agents).toContain('`~/.claude/settings.json` is user-owned shared state')
|
|
expect(agents).toContain('persistence upgrade gate')
|
|
expect(agents).toContain('Production code changes under `desktop/src`, `src/server`, `src/tools`, `src/utils`, or `adapters` must include a same-area test file')
|
|
expect(agents).toContain('Coverage is part of the feature, not an afterthought.')
|
|
expect(agents).toContain('changed executable production line must meet the changed-line coverage gate')
|
|
expect(agents).toContain('E2E is required when the feature crosses process boundaries')
|
|
expect(agents).toContain('AI agents must include this evidence')
|
|
expect(agents).toContain('Unified local entrypoint: `bun run verify`')
|
|
expect(agents).toContain('If `bun run verify` fails, do not stop at reporting the failure')
|
|
})
|
|
|
|
test('keeps PR authors accountable for tests, coverage, E2E, and risk', () => {
|
|
const template = readFileSync('.github/pull_request_template.md', 'utf8')
|
|
|
|
expect(template).toContain('## Feature Quality Contract')
|
|
expect(template).toContain('Changed surface:')
|
|
expect(template).toContain('Tests added or updated:')
|
|
expect(template).toContain('Coverage evidence:')
|
|
expect(template).toContain('changed-line coverage')
|
|
expect(template).toContain('E2E / live-model evidence:')
|
|
expect(template).toContain('Known risk / rollback:')
|
|
expect(template).toContain('I added or updated same-area tests')
|
|
})
|
|
|
|
test('keeps the one-command verification entrypoint documented', () => {
|
|
const packageJson = JSON.parse(readFileSync('package.json', 'utf8')) as {
|
|
scripts?: Record<string, string>
|
|
}
|
|
const prePushHook = readFileSync('scripts/git-hooks/pre-push', 'utf8')
|
|
const contributing = readFileSync('docs/guide/contributing.md', 'utf8')
|
|
const englishContributing = readFileSync('docs/en/guide/contributing.md', 'utf8')
|
|
const rootContributing = readFileSync('CONTRIBUTING.md', 'utf8')
|
|
|
|
expect(packageJson.scripts?.verify).toBe('bun run quality:pr')
|
|
expect(packageJson.scripts?.['quality:verify']).toBe('bun run quality:pr')
|
|
expect(packageJson.scripts?.['quality:push']).toBe('bun run quality:gate --mode pr --skip coverage')
|
|
expect(packageJson.scripts?.['check:persistence-upgrade']).toBe('bun run scripts/quality-gate/persistence-upgrade.ts')
|
|
expect(prePushHook).toContain('bun run quality:push')
|
|
expect(prePushHook).not.toContain('\nbun run quality:pr\n')
|
|
expect(contributing).toContain('bun run verify')
|
|
expect(contributing).toContain('bun run quality:push')
|
|
expect(contributing).toContain('AI Coding Agent 修复循环')
|
|
expect(englishContributing).toContain('bun run verify')
|
|
expect(englishContributing).toContain('bun run quality:push')
|
|
expect(englishContributing).toContain('AI Coding Agent Fix Loop')
|
|
expect(rootContributing).toContain('bun run verify')
|
|
expect(rootContributing).toContain('bun run quality:push')
|
|
})
|
|
|
|
test('keeps general AI coding tools pointed at the same quality bar', () => {
|
|
const instructions = readFileSync('.github/copilot-instructions.md', 'utf8')
|
|
|
|
expect(instructions).toContain('Follow the repository contract in `AGENTS.md`')
|
|
expect(instructions).toContain('Add same-area tests with the production change')
|
|
expect(instructions).toContain('Preserve or improve the coverage ratchet')
|
|
expect(instructions).toContain('changed-line coverage threshold')
|
|
expect(instructions).toContain('E2E or agent-browser smoke')
|
|
expect(instructions).toContain('include changed files, tests added, coverage report path')
|
|
})
|
|
})
|