@uzysjung/agent-harness 26.135.0 → 26.136.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +2 -0
- package/dist/trust-tier-drift.js.map +1 -1
- package/package.json +3 -2
- package/templates/rules/doc-governance.md +10 -12
- package/templates/rules/git-policy.md +6 -40
- package/templates/skills/harness-health-audit/SKILL.md +6 -0
- package/templates/skills/recurrence-prevention/SKILL.md +37 -8
package/dist/trust-tier-drift.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DEV_METHOD_SKILL_IDS,
|
|
6
6
|
EXTERNAL_ASSETS,
|
|
7
7
|
INTERNAL_BUNDLED_SKILL_IDS,
|
|
8
|
+
TRACKS,
|
|
8
9
|
TRUST_TIER,
|
|
9
10
|
assetCliSupport,
|
|
10
11
|
assetCostRows,
|
|
@@ -68,6 +69,7 @@ export {
|
|
|
68
69
|
EXTERNAL_ASSETS,
|
|
69
70
|
INTERNAL_BUNDLED_SKILL_IDS,
|
|
70
71
|
STAR_THRESHOLD,
|
|
72
|
+
TRACKS,
|
|
71
73
|
TRUST_TIER,
|
|
72
74
|
assetCliSupport,
|
|
73
75
|
assetCostRows,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/trust-tier-drift.ts"],"sourcesContent":["/**\n * A1 — Trust Tier star-drift 검출 데이터 + 순수 로직.\n *\n * TRUST_TIER 의 star 기반 라벨(vetted ≥ 1000★ / experimental < 1000★)이 실제 GitHub\n * star 와 어긋났는지(drift) 판정한다. `official` 은 star 무관(Anthropic 공식·하네스 자체)\n * 이라 검사 제외.\n *\n * repo 출처 = 각 자산 method (in-code authoritative — 주석이 아니라 실제 설치 source):\n * skill → method.source (\"owner/repo\" 또는 github URL)\n * plugin → method.marketplace (\"owner/repo\")\n * npm → NPM_REPO_OVERRIDE[id] (pkg 는 npm 명이므로 GitHub repo 를 별도 명시)\n *\n * fetch/네트워크는 본 모듈에 없음 — 순수 로직만(테스트 가능). 실 fetch 는\n * `scripts/trust-tier-drift.mjs` 가 담당.\n */\nimport { EXTERNAL_ASSETS, type ExternalAsset, TRUST_TIER } from \"./external-assets.js\";\n\n// v26.79.0 — gen-compatibility 의 카테고리 exhaustiveness 가드용 SSOT (하드코딩 drift 차단).\nexport { CATEGORIES } from \"./categories.js\";\n// v26.116.0 (ADR-043) — context-cost-report.mjs 가 dist 에서 비용 계측기를 읽도록 re-export.\nexport { assetCostRows, estimateTokens, residentCost, resolveBundleRoot } from \"./context-cost.js\";\n// v26.76.0 — gen-compatibility.mjs 가 dist 에서 자산 카탈로그+tier 를 읽도록 re-export.\n// v26.93.0 — DEV_METHOD_SKILL_IDS 추가: gen-compatibility 의 CLI scope override 를\n// 하드코딩 id 목록 대신 SSOT 에서 derive (no-false-ship drift 구조 차단).\n// v26.95.0 — INTERNAL_BUNDLED_SKILL_IDS (dev-method + opt-in gemini-consult) 로 CLI scope derive.\nexport {\n // v26.102.0 (ADR-031) — gen-compatibility 의 CLI 열이 도달 범위를 derive 하도록 re-export.\n assetCliSupport,\n DEV_METHOD_SKILL_IDS,\n EXTERNAL_ASSETS,\n INTERNAL_BUNDLED_SKILL_IDS,\n TRUST_TIER,\n} from \"./external-assets.js\";\nexport { buildManifest } from \"./manifest.js\";\n// v26.102.0 (ADR-031) — 도달 라벨(\"N-CLI\")의 N 을 derive 하기 위한 re-export (매직 넘버 금지).\nexport { CLI_BASES } from \"./types.js\";\n\n/** vetted 경계 (NORTH_STAR / PRD v26-71 D2). */\nexport const STAR_THRESHOLD = 1000;\n\nexport type StarTier = \"vetted\" | \"experimental\";\nexport type DriftVerdict = \"ok\" | \"promote\" | \"demote\";\n\n/**\n * method 가 GitHub repo 를 안 담는 자산(npm.pkg / npx-run.cmd 는 npm 명) → 트러스트 근거가\n * 된 GitHub repo 를 명시 매핑. override 가 method 도출보다 우선.\n */\nconst REPO_OVERRIDE: Record<string, string> = {\n \"vercel-cli\": \"vercel/vercel\", // npm\n \"netlify-cli\": \"netlify/cli\", // npm\n \"supabase-cli\": \"supabase/cli\", // npm\n \"agent-browser\": \"vercel-labs/agent-browser\", // npm\n openspec: \"Fission-AI/OpenSpec\", // npm (v26.75.0)\n \"bmad-method\": \"bmad-code-org/BMAD-METHOD\", // npx-run (v26.75.0)\n};\n\n/** \"https://github.com/owner/repo\" 또는 \"owner/repo[/...]\" → \"owner/repo\". 실패 시 null. */\nexport function normalizeRepo(source: string): string | null {\n const stripped = source.replace(/^https?:\\/\\/github\\.com\\//i, \"\");\n const m = stripped.match(/^([^/\\s]+\\/[^/\\s]+)/);\n return m?.[1] ?? null;\n}\n\n/** 자산의 GitHub owner/repo 도출. override 우선 → skill/plugin method. 도출 불가 시 null. */\nexport function repoForAsset(asset: ExternalAsset): string | null {\n const override = REPO_OVERRIDE[asset.id];\n if (override) return override;\n const m = asset.method;\n if (m.kind === \"skill\") return normalizeRepo(m.source);\n if (m.kind === \"plugin\") return normalizeRepo(m.marketplace);\n return null;\n}\n\nexport interface DriftTarget {\n id: string;\n tier: StarTier;\n repo: string;\n}\n\n/** star 기반(vetted/experimental) 자산만 + repo 도출 가능한 것만 검사 대상. */\nexport function driftTargets(\n assets: ReadonlyArray<ExternalAsset> = EXTERNAL_ASSETS,\n): DriftTarget[] {\n const out: DriftTarget[] = [];\n for (const a of assets) {\n const tier = TRUST_TIER[a.id];\n if (tier !== \"vetted\" && tier !== \"experimental\") continue;\n const repo = repoForAsset(a);\n if (!repo) continue; // 도출 불가 — 테스트가 0건을 강제하므로 정상 경로에선 발생 안 함\n out.push({ id: a.id, tier, repo });\n }\n return out;\n}\n\n/** 정적 tier 가 실제 star 와 어긋났는지 판정. */\nexport function classifyDrift(tier: StarTier, stars: number): DriftVerdict {\n if (tier === \"vetted\" && stars < STAR_THRESHOLD) return \"demote\";\n if (tier === \"experimental\" && stars >= STAR_THRESHOLD) return \"promote\";\n return \"ok\";\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/trust-tier-drift.ts"],"sourcesContent":["/**\n * A1 — Trust Tier star-drift 검출 데이터 + 순수 로직.\n *\n * TRUST_TIER 의 star 기반 라벨(vetted ≥ 1000★ / experimental < 1000★)이 실제 GitHub\n * star 와 어긋났는지(drift) 판정한다. `official` 은 star 무관(Anthropic 공식·하네스 자체)\n * 이라 검사 제외.\n *\n * repo 출처 = 각 자산 method (in-code authoritative — 주석이 아니라 실제 설치 source):\n * skill → method.source (\"owner/repo\" 또는 github URL)\n * plugin → method.marketplace (\"owner/repo\")\n * npm → NPM_REPO_OVERRIDE[id] (pkg 는 npm 명이므로 GitHub repo 를 별도 명시)\n *\n * fetch/네트워크는 본 모듈에 없음 — 순수 로직만(테스트 가능). 실 fetch 는\n * `scripts/trust-tier-drift.mjs` 가 담당.\n */\nimport { EXTERNAL_ASSETS, type ExternalAsset, TRUST_TIER } from \"./external-assets.js\";\n\n// v26.79.0 — gen-compatibility 의 카테고리 exhaustiveness 가드용 SSOT (하드코딩 drift 차단).\nexport { CATEGORIES } from \"./categories.js\";\n// v26.116.0 (ADR-043) — context-cost-report.mjs 가 dist 에서 비용 계측기를 읽도록 re-export.\nexport { assetCostRows, estimateTokens, residentCost, resolveBundleRoot } from \"./context-cost.js\";\n// v26.76.0 — gen-compatibility.mjs 가 dist 에서 자산 카탈로그+tier 를 읽도록 re-export.\n// v26.93.0 — DEV_METHOD_SKILL_IDS 추가: gen-compatibility 의 CLI scope override 를\n// 하드코딩 id 목록 대신 SSOT 에서 derive (no-false-ship drift 구조 차단).\n// v26.95.0 — INTERNAL_BUNDLED_SKILL_IDS (dev-method + opt-in gemini-consult) 로 CLI scope derive.\nexport {\n // v26.102.0 (ADR-031) — gen-compatibility 의 CLI 열이 도달 범위를 derive 하도록 re-export.\n assetCliSupport,\n DEV_METHOD_SKILL_IDS,\n EXTERNAL_ASSETS,\n INTERNAL_BUNDLED_SKILL_IDS,\n TRUST_TIER,\n} from \"./external-assets.js\";\nexport { buildManifest } from \"./manifest.js\";\n// v26.102.0 (ADR-031) — 도달 라벨(\"N-CLI\")의 N 을 derive 하기 위한 re-export (매직 넘버 금지).\nexport { CLI_BASES, TRACKS } from \"./types.js\";\n\n/** vetted 경계 (NORTH_STAR / PRD v26-71 D2). */\nexport const STAR_THRESHOLD = 1000;\n\nexport type StarTier = \"vetted\" | \"experimental\";\nexport type DriftVerdict = \"ok\" | \"promote\" | \"demote\";\n\n/**\n * method 가 GitHub repo 를 안 담는 자산(npm.pkg / npx-run.cmd 는 npm 명) → 트러스트 근거가\n * 된 GitHub repo 를 명시 매핑. override 가 method 도출보다 우선.\n */\nconst REPO_OVERRIDE: Record<string, string> = {\n \"vercel-cli\": \"vercel/vercel\", // npm\n \"netlify-cli\": \"netlify/cli\", // npm\n \"supabase-cli\": \"supabase/cli\", // npm\n \"agent-browser\": \"vercel-labs/agent-browser\", // npm\n openspec: \"Fission-AI/OpenSpec\", // npm (v26.75.0)\n \"bmad-method\": \"bmad-code-org/BMAD-METHOD\", // npx-run (v26.75.0)\n};\n\n/** \"https://github.com/owner/repo\" 또는 \"owner/repo[/...]\" → \"owner/repo\". 실패 시 null. */\nexport function normalizeRepo(source: string): string | null {\n const stripped = source.replace(/^https?:\\/\\/github\\.com\\//i, \"\");\n const m = stripped.match(/^([^/\\s]+\\/[^/\\s]+)/);\n return m?.[1] ?? null;\n}\n\n/** 자산의 GitHub owner/repo 도출. override 우선 → skill/plugin method. 도출 불가 시 null. */\nexport function repoForAsset(asset: ExternalAsset): string | null {\n const override = REPO_OVERRIDE[asset.id];\n if (override) return override;\n const m = asset.method;\n if (m.kind === \"skill\") return normalizeRepo(m.source);\n if (m.kind === \"plugin\") return normalizeRepo(m.marketplace);\n return null;\n}\n\nexport interface DriftTarget {\n id: string;\n tier: StarTier;\n repo: string;\n}\n\n/** star 기반(vetted/experimental) 자산만 + repo 도출 가능한 것만 검사 대상. */\nexport function driftTargets(\n assets: ReadonlyArray<ExternalAsset> = EXTERNAL_ASSETS,\n): DriftTarget[] {\n const out: DriftTarget[] = [];\n for (const a of assets) {\n const tier = TRUST_TIER[a.id];\n if (tier !== \"vetted\" && tier !== \"experimental\") continue;\n const repo = repoForAsset(a);\n if (!repo) continue; // 도출 불가 — 테스트가 0건을 강제하므로 정상 경로에선 발생 안 함\n out.push({ id: a.id, tier, repo });\n }\n return out;\n}\n\n/** 정적 tier 가 실제 star 와 어긋났는지 판정. */\nexport function classifyDrift(tier: StarTier, stars: number): DriftVerdict {\n if (tier === \"vetted\" && stars < STAR_THRESHOLD) return \"demote\";\n if (tier === \"experimental\" && stars >= STAR_THRESHOLD) return \"promote\";\n return \"ok\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAsCO,IAAM,iBAAiB;AAS9B,IAAM,gBAAwC;AAAA,EAC5C,cAAc;AAAA;AAAA,EACd,eAAe;AAAA;AAAA,EACf,gBAAgB;AAAA;AAAA,EAChB,iBAAiB;AAAA;AAAA,EACjB,UAAU;AAAA;AAAA,EACV,eAAe;AAAA;AACjB;AAGO,SAAS,cAAc,QAA+B;AAC3D,QAAM,WAAW,OAAO,QAAQ,8BAA8B,EAAE;AAChE,QAAM,IAAI,SAAS,MAAM,qBAAqB;AAC9C,SAAO,IAAI,CAAC,KAAK;AACnB;AAGO,SAAS,aAAa,OAAqC;AAChE,QAAM,WAAW,cAAc,MAAM,EAAE;AACvC,MAAI,SAAU,QAAO;AACrB,QAAM,IAAI,MAAM;AAChB,MAAI,EAAE,SAAS,QAAS,QAAO,cAAc,EAAE,MAAM;AACrD,MAAI,EAAE,SAAS,SAAU,QAAO,cAAc,EAAE,WAAW;AAC3D,SAAO;AACT;AASO,SAAS,aACd,SAAuC,iBACxB;AACf,QAAM,MAAqB,CAAC;AAC5B,aAAW,KAAK,QAAQ;AACtB,UAAM,OAAO,WAAW,EAAE,EAAE;AAC5B,QAAI,SAAS,YAAY,SAAS,eAAgB;AAClD,UAAM,OAAO,aAAa,CAAC;AAC3B,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,EAAE,IAAI,EAAE,IAAI,MAAM,KAAK,CAAC;AAAA,EACnC;AACA,SAAO;AACT;AAGO,SAAS,cAAc,MAAgB,OAA6B;AACzE,MAAI,SAAS,YAAY,QAAQ,eAAgB,QAAO;AACxD,MAAI,SAAS,kBAAkB,SAAS,eAAgB,QAAO;AAC/D,SAAO;AACT;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uzysjung/agent-harness",
|
|
3
|
-
"version": "26.
|
|
3
|
+
"version": "26.136.0",
|
|
4
4
|
"description": "Curate vetted AI-coding skills & plugins by your tech stack — install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"format": "biome format --write src tests",
|
|
33
33
|
"ci": "npm run typecheck && npm run lint && npm run test:coverage && npm run build",
|
|
34
34
|
"prepare": "[ -d dist ] || npm run build",
|
|
35
|
-
"cost:report": "npm run build && node scripts/context-cost-report.mjs"
|
|
35
|
+
"cost:report": "npm run build && node scripts/context-cost-report.mjs",
|
|
36
|
+
"cost:baseline": "npm run build && node scripts/context-cost-baseline.mjs"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@clack/prompts": "^1.3.0",
|
|
@@ -51,12 +51,12 @@ PR 머지로 작업이 끝난 게 아니다. **머지 직후 같은 작업 단
|
|
|
51
51
|
| 부분 구현 | 잔여분만 task 로 남기고 재추정 |
|
|
52
52
|
| 미구현 · 판정 불가 | 원래 계획대로 진행 — 못 찾았다고 착수를 보류하지 않는다 |
|
|
53
53
|
|
|
54
|
-
- **"완전 구현"
|
|
55
|
-
|
|
56
|
-
안 되는
|
|
54
|
+
- **"완전 구현" 판정에 심볼 존재만 쓰지 않는다** — 실행/테스트로 확인, 애매하면 기본값은
|
|
55
|
+
**부분 구현**. (UI 트랙이면 `benchmark-parity.md` 의 "단순 존재 ≠ 완결"이 같은 기준. 다른
|
|
56
|
+
트랙엔 그 파일이 없어 이 한 줄이 SSOT.) 안 그러면 안 되는 걸 완료로 박제한다.
|
|
57
57
|
- 문서 정정의 승인 범위는 `change-management.md` CR 분류를 따른다.
|
|
58
58
|
- 대조 결과는 해당 항목 줄에 인라인으로 남긴다 — `- [ ] X (baseline 대조 YYYY-MM-DD: 기구현)`.
|
|
59
|
-
**본 절은
|
|
59
|
+
**본 절은 프로즈이고 미준수를 잡는 게이트가 없다** — 스킵이 반복되면 게이트로 승격한다.
|
|
60
60
|
|
|
61
61
|
전례: 로드맵이 여러 PR 동안 미갱신되어 완료분이 미완으로 박제된 사례가 있다 — 상세는 해당 ADR 로 위임한다.
|
|
62
62
|
|
|
@@ -77,11 +77,9 @@ PR 머지로 작업이 끝난 게 아니다. **머지 직후 같은 작업 단
|
|
|
77
77
|
|
|
78
78
|
## 검증 게이트
|
|
79
79
|
|
|
80
|
-
`.claude/hooks/spec-drift-check.sh` 가 SPEC/TODO 의
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
결정론 게이트(훅)는 짝이다 — 규약만으로 안 지켜지는 것이 확인되면 게이트를 넓혀라
|
|
87
|
-
(dev 트랙 설치 시 recurrence-prevention 스킬의 에스컬레이션 사다리 참조).
|
|
80
|
+
dev 트랙 설치 시 `.claude/hooks/spec-drift-check.sh` 가 SPEC/TODO 의 미완 잔존·Status 불일치를
|
|
81
|
+
검출한다 — verify 단계는 경고, ship 단계는 차단.
|
|
82
|
+
|
|
83
|
+
**한계를 알고 써라**: 탐지 경로에 없는 문서 레이아웃은 게이트가 못 본다. 그 경우 본 규약은
|
|
84
|
+
프로즈로만 작동한다 — 즉 안 지켜져도 아무도 안 막는다. 규약만으로 안 지켜지는 것이 확인되면
|
|
85
|
+
게이트 쪽을 넓혀라, 프로즈를 늘리지 말고.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Git Policy
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
프로젝트 레벨 git 규약. 버전 체계는 프로젝트가 정한다 — 여기서 강제하지 않는다.
|
|
4
4
|
|
|
5
5
|
## Commit 메시지
|
|
6
6
|
|
|
@@ -49,15 +49,6 @@ ship 보고 시 두 상태를 **반드시 분리**해서 보여줄 것:
|
|
|
49
49
|
|
|
50
50
|
gate ✓ 만 보고 ship 완료라 단정하지 않는다. open PR 1건이라도 있으면 cycle 미완.
|
|
51
51
|
|
|
52
|
-
### 보고 형식 예
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
gate: build ✓ / verify ✓ / review ✓ / ship ✓
|
|
56
|
-
main: PR #123 merged ✓ / tag vX.Y.Z pushed ✓ / release ✓
|
|
57
|
-
OR
|
|
58
|
-
PR #123 OPEN — CI pass / mergeable / 사용자 결정 대기
|
|
59
|
-
```
|
|
60
|
-
|
|
61
52
|
## Post-Merge Cleanup (필수)
|
|
62
53
|
|
|
63
54
|
PR 머지 직후 stale branch 누적 방지. Session Cleanup 의 "open PR 점검" 과 보완 관계.
|
|
@@ -69,37 +60,12 @@ PR 머지 직후 stale branch 누적 방지. Session Cleanup 의 "open PR 점검
|
|
|
69
60
|
- squash merge 후엔 git 가 "unmerged" 경고 → 같은 변경 내용 확인 후 `-D` 사용 가능
|
|
70
61
|
4. **정기 stale 점검** (선택) — `git branch --merged main | grep -v '^\*\| main$'` 으로 잔존 확인
|
|
71
62
|
|
|
72
|
-
### 보고 형식
|
|
73
|
-
|
|
74
|
-
ship 보고에 branch cleanup 상태 한 줄 추가:
|
|
63
|
+
### 보고 형식 (ship 보고 공통)
|
|
75
64
|
|
|
76
65
|
```
|
|
77
|
-
gate:
|
|
78
|
-
main:
|
|
66
|
+
gate: build ✓ / verify ✓ / review ✓ / ship ✓
|
|
67
|
+
main: PR #123 merged ✓ / tag vX.Y.Z pushed ✓ / release ✓
|
|
79
68
|
branch: fix/foo deleted (local + remote) ✓
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
OR
|
|
70
|
+
main: PR #123 OPEN — CI pass / mergeable / 사용자 결정 대기
|
|
82
71
|
```
|
|
83
|
-
|
|
84
|
-
## Versioning Convention (절대 위반 금지)
|
|
85
|
-
|
|
86
|
-
**형식**: `vMAJOR.MINOR.PATCH`
|
|
87
|
-
|
|
88
|
-
- **Major = `year - 2000`** (CalVer-like)
|
|
89
|
-
- 2025 = `v25.x.x`
|
|
90
|
-
- **2026 = `v26.x.x`**
|
|
91
|
-
- 2027 = `v27.x.x`
|
|
92
|
-
- **Minor**: feature bump (BREAKING change여도 같은 year 내에서는 Minor만 bump)
|
|
93
|
-
- **Patch**: bug fix only
|
|
94
|
-
|
|
95
|
-
**Year 변경 시점에만 Major bump**. SemVer-식 BREAKING → Major 적용 **금지**.
|
|
96
|
-
|
|
97
|
-
### Pre-tag checklist (모든 ship 전)
|
|
98
|
-
|
|
99
|
-
1. `git tag -l | sort -V | tail -5` 마지막 정상 태그 확인
|
|
100
|
-
2. 당해년도 매핑 검증 — `date +%Y` % 100 = 다음 Major
|
|
101
|
-
3. SPEC/ADR/문서 본문에 "v(year+1).x" 같은 미래 태그 텍스트 보이면 **즉시 컨벤션 검증** — 그대로 따르지 말 것
|
|
102
|
-
4. 위반 의심 시 ship 중단 + 사용자 컨펌
|
|
103
|
-
|
|
104
|
-
위반이 누적되면 태그를 일괄 rename 해야 하고, 그때 이미 배포된 버전 참조가 전부 거짓이 된다.
|
|
105
|
-
그래서 사전 체크가 사후 정리보다 훨씬 싸다.
|
|
@@ -247,6 +247,12 @@ The evidence:
|
|
|
247
247
|
**Measure:** length of each always-loaded file; how many discrete instructions the harness asserts in
|
|
248
248
|
total across every always-loaded layer (global + project + directory); how much is irrelevant to a
|
|
249
249
|
typical task (those are the distractors).
|
|
250
|
+
**Also measure the *rate*, not just the level.** Always-loaded surfaces only ever grow — every
|
|
251
|
+
incident adds prose and nothing removes it — so a snapshot always looks defensible while the
|
|
252
|
+
trajectory does not. Compare today's total against a recorded earlier total (a committed baseline,
|
|
253
|
+
or `git show <older-ref>:<file> | wc -c` if there is none). A surface that gained more this month
|
|
254
|
+
than last is already failing, even when no single addition looks unreasonable. If the project keeps
|
|
255
|
+
a resident-cost baseline, this axis reads it instead of re-deriving the numbers.
|
|
250
256
|
**Action:** **correct** by moving detail behind pointers — state what is true every session, link the
|
|
251
257
|
rest. Prefer removing duplication over shortening prose.
|
|
252
258
|
**Honest limit:** Chroma publishes performance *curves*, not a percentage-per-token figure. Do not
|
|
@@ -87,8 +87,11 @@ Two quick discriminators:
|
|
|
87
87
|
|
|
88
88
|
Enter the ladder at the level matching the count. **Never enter above your count** — a gate for a
|
|
89
89
|
first-time slip is gate inflation, and every gate is permanent maintenance + false-positive cost.
|
|
90
|
-
(
|
|
91
|
-
at its own level — a violated Level-1 rule at count 2 legitimately escalates to Level 2.
|
|
90
|
+
(Two exceptions. Downward-honest: a **registered countermeasure that failed** counts that failure
|
|
91
|
+
at its own level — a violated Level-1 rule at count 2 legitimately escalates to Level 2. And
|
|
92
|
+
cost-driven: the Level 1 pre-flight below sends a count-2 slip straight to Level 2 when the wrong
|
|
93
|
+
action is deterministically detectable, because a gate is the *cheaper* artifact, not the stronger
|
|
94
|
+
one.)
|
|
92
95
|
|
|
93
96
|
| Level | When | Countermeasure | Characteristic failure of this level |
|
|
94
97
|
|---|---|---|---|
|
|
@@ -111,10 +114,32 @@ way: five recurrences of one doc-fact drift, each answered by adding one more pe
|
|
|
111
114
|
and a file named as a drift surface in the fourth postmortem still carried zero coverage at the
|
|
112
115
|
fifth.
|
|
113
116
|
|
|
114
|
-
**
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
**Level 1 pre-flight — a 2nd occurrence does not automatically earn a rule.** Per unit of
|
|
118
|
+
enforcement a rule is the most expensive artifact on the ladder: it is read **every session, by
|
|
119
|
+
every install, forever**, while a gate costs CI time and **zero** standing context. Answer three
|
|
120
|
+
questions in order and stop at the first that decides:
|
|
121
|
+
|
|
122
|
+
1. **Can the wrong action be detected deterministically?** — a failing test, a hook that exits
|
|
123
|
+
non-zero, a derive that deletes the duplicated list. If yes, **write the gate instead, even at
|
|
124
|
+
count 2.** This is the one sanctioned way to enter above your count, and it is not gate
|
|
125
|
+
inflation: you are not buying stronger enforcement than the count justifies, you are picking
|
|
126
|
+
the cheaper artifact for the same enforcement. Code answers what code can answer.
|
|
127
|
+
2. **Would the rule change behaviour that would otherwise be wrong?** If the corrective principle
|
|
128
|
+
is something a competent agent does anyway, or it restates a rule that already exists, it buys
|
|
129
|
+
nothing and bills every session. Stay at Level 0.
|
|
130
|
+
3. **Is it general, or is it this project's circumstance?** A project's own incidents belong on
|
|
131
|
+
that project's steering surface — never in a rule set that strangers install.
|
|
132
|
+
|
|
133
|
+
Only what survives all three — **a judgement call no deterministic check can express, that
|
|
134
|
+
changes behaviour, and that generalises** — is a rule candidate. That is the bar for "serious
|
|
135
|
+
enough to be worth permanent context".
|
|
136
|
+
|
|
137
|
+
**Confirm before adding standing cost.** Levels 1 and 2 need explicit user confirmation. For a
|
|
138
|
+
rule the escalation must state, in one block: signature · count with evidence · the proposed text ·
|
|
139
|
+
**its standing cost in tokens and the resulting total** · which of the three questions it survived
|
|
140
|
+
and why the deterministic alternative does not work. **Do not guess the cost — measure the draft**
|
|
141
|
+
(if the project reports context cost, run that report). Level 0 needs no confirmation — recording
|
|
142
|
+
a fact is free and always right.
|
|
118
143
|
|
|
119
144
|
### Rule registration template (Level 1)
|
|
120
145
|
|
|
@@ -186,6 +211,8 @@ would be a false ship. Before closing:
|
|
|
186
211
|
- Classification: 단순 실수 | 복잡한 하네스 문제 (+ the discriminator that decided it)
|
|
187
212
|
- Countermeasure: Level 0 기록 | Level 1 룰 | Level 2 게이트 | 페르소나 설계 → <chosen option>
|
|
188
213
|
- Artifact: <path of memory entry / rule file / test or hook>
|
|
214
|
+
- Standing cost: <rule 이면 측정치 ~N tokens/session + 갱신된 총합 | gate·record 면 0>
|
|
215
|
+
- Pre-flight: <Level 1 3질문 통과 근거 — 결정론 불가 사유 · 행동 변화 · 일반성>
|
|
189
216
|
- Fires-verified: <RED→GREEN output, hook exit code, grep proof — or "룰 프로즈: 미검증" honestly>
|
|
190
217
|
- User confirmation: <obtained for Level 1/2 | not needed (Level 0)>
|
|
191
218
|
```
|
|
@@ -198,8 +225,10 @@ would be a false ship. Before closing:
|
|
|
198
225
|
If the one-line corrective principle wouldn't have prevented *both* occurrences as stated,
|
|
199
226
|
the signature is too broad.
|
|
200
227
|
- **Rule bloat** — every rule is standing context; a harness drowning in rules follows none of
|
|
201
|
-
them. That is why Level 0 exists, why Levels 1-2 need user confirmation, and why
|
|
202
|
-
|
|
228
|
+
them. That is why Level 0 exists, why Levels 1-2 need user confirmation, and why the Level 1
|
|
229
|
+
pre-flight routes anything deterministic to a gate instead. Watch the *rate*, not just the
|
|
230
|
+
count: rules only ever grow, so a steering surface that gained more prose this month than last
|
|
231
|
+
is already on the failing trajectory even if no single rule looks unreasonable.
|
|
203
232
|
- **Gate theater** — a gate that was never seen to fire may be checking nothing (wrong matcher,
|
|
204
233
|
wrong path, dead config). Step 4 is mandatory, not optional polish.
|
|
205
234
|
- **Same-level retry** — responding to a recurrence by rewriting the same rule more emphatically
|