@holmes-lab/holmes-kit 0.17.0 → 0.19.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +6 -0
  3. package/dist/.build-id +1 -1
  4. package/dist/holmes/cli/release-docs.d.ts +27 -0
  5. package/dist/holmes/cli/release-docs.js +68 -0
  6. package/dist/holmes/cpg/arch-observe.d.ts +15 -0
  7. package/dist/holmes/cpg/arch-observe.js +19 -0
  8. package/dist/holmes/cpg/cpg-scanner.d.ts +10 -36
  9. package/dist/holmes/cpg/cpg-scanner.js +27 -3
  10. package/dist/holmes/cpg/cycle-detect.d.ts +87 -0
  11. package/dist/holmes/cpg/cycle-detect.js +251 -0
  12. package/dist/holmes/cpg/scan-cache.d.ts +1 -1
  13. package/dist/holmes/cpg/scanned-file.d.ts +36 -0
  14. package/dist/holmes/cpg/scanned-file.js +2 -0
  15. package/dist/holmes/governance/autonomy.js +1 -0
  16. package/dist/holmes/governance/constitution.d.ts +20 -0
  17. package/dist/holmes/governance/constitution.js +17 -0
  18. package/dist/holmes/governance/ledger-store.d.ts +9 -0
  19. package/dist/holmes/governance/ledger-store.js +47 -0
  20. package/dist/holmes/governance/provenance-chain.d.ts +16 -1
  21. package/dist/holmes/governance/provenance-chain.js +5 -3
  22. package/dist/holmes/hooks/pre-tool-use.js +3 -1
  23. package/dist/holmes/hooks/stop.d.ts +14 -0
  24. package/dist/holmes/hooks/stop.js +73 -0
  25. package/dist/holmes/mcp/defuse-bound.d.ts +1 -0
  26. package/dist/holmes/mcp/defuse-bound.js +8 -0
  27. package/dist/holmes/mcp/handlers.d.ts +23 -0
  28. package/dist/holmes/mcp/handlers.js +173 -6
  29. package/dist/holmes/mcp/history-admission.d.ts +15 -0
  30. package/dist/holmes/mcp/history-admission.js +37 -0
  31. package/dist/holmes/mcp/maintenance-analyze.d.ts +11 -0
  32. package/dist/holmes/mcp/maintenance-analyze.js +64 -8
  33. package/dist/holmes/mcp/spec-id-guard.d.ts +0 -8
  34. package/dist/holmes/mcp/spec-id-guard.js +10 -1
  35. package/dist/holmes/review/evaluation-metrics.d.ts +6 -0
  36. package/dist/holmes/review/evaluation-metrics.js +18 -1
  37. package/dist/holmes/review/paired-power.d.ts +14 -0
  38. package/dist/holmes/review/paired-power.js +57 -0
  39. package/dist/holmes/review/replay-corpus.d.ts +11 -0
  40. package/dist/holmes/review/replay-corpus.js +34 -0
  41. package/dist/holmes/review/run-replay.js +60 -4
  42. package/dist/holmes/review/symbol-truth.d.ts +14 -0
  43. package/dist/holmes/review/symbol-truth.js +23 -0
  44. package/dist/holmes/rtm/decision-context.d.ts +23 -0
  45. package/dist/holmes/rtm/decision-context.js +47 -0
  46. package/dist/holmes/rtm/defuse-symbols.d.ts +17 -0
  47. package/dist/holmes/rtm/defuse-symbols.js +91 -0
  48. package/dist/holmes/rtm/incremental.js +5 -0
  49. package/dist/holmes/rtm/localize.js +4 -2
  50. package/dist/holmes/rtm/rtm-builder.d.ts +8 -0
  51. package/dist/holmes/rtm/rtm-builder.js +34 -5
  52. package/dist/holmes/rtm/rtm-graph.d.ts +11 -0
  53. package/dist/holmes/rtm/rtm-graph.js +13 -0
  54. package/dist/holmes/spec/legacy-fields.d.ts +2 -0
  55. package/dist/holmes/spec/legacy-fields.js +9 -0
  56. package/dist/holmes/spec/legacy-format.d.ts +1 -1
  57. package/dist/holmes/spec/legacy-format.js +4 -1
  58. package/dist/holmes/spec/spec-parser.js +5 -3
  59. package/dist/holmes/spec/spec-types.d.ts +1 -1
  60. package/dist/holmes/spec/spec-types.js +14 -1
  61. package/package.json +1 -1
  62. package/playbooks/author-slice/PLAYBOOK.md +33 -0
  63. package/playbooks/publish/PLAYBOOK.md +32 -0
  64. package/playbooks/tdd-slice/PLAYBOOK.md +19 -0
@@ -37,7 +37,9 @@ exports.parseDependsOn = parseDependsOn;
37
37
  exports.parseSpec = parseSpec;
38
38
  exports.serializeSpec = serializeSpec;
39
39
  const yaml = __importStar(require("js-yaml"));
40
- const legacy_format_1 = require("./legacy-format");
40
+ // @implements A-SPEC-574.3 — from the shared module, not from `legacy-format`, which imports
41
+ // this file's `Spec` type. That pair was a cycle over one string constant.
42
+ const legacy_fields_1 = require("./legacy-fields");
41
43
  /**
42
44
  * Read `depends_on` in every spelling the corpus contains, keeping what cannot be represented.
43
45
  *
@@ -121,8 +123,8 @@ function parseSpec(input) {
121
123
  const deps = parseDependsOn(fm.depends_on);
122
124
  // @implements A-SPEC-221 — never overwrite an existing preservation: a second round trip must not
123
125
  // chew up what the first one saved, the same rule `legacy_status` follows.
124
- if (deps.legacy !== null && fm[legacy_format_1.LEGACY_DEPENDS_FIELD] === undefined) {
125
- fm[legacy_format_1.LEGACY_DEPENDS_FIELD] = deps.legacy;
126
+ if (deps.legacy !== null && fm[legacy_fields_1.LEGACY_DEPENDS_FIELD] === undefined) {
127
+ fm[legacy_fields_1.LEGACY_DEPENDS_FIELD] = deps.legacy;
126
128
  }
127
129
  return {
128
130
  id: String(fm.id ?? ''),
@@ -1,4 +1,4 @@
1
- export type SpecType = 'REQ' | 'H-SPEC' | 'A-SPEC' | 'C-SPEC' | 'T-SPEC';
1
+ export type SpecType = 'REQ' | 'H-SPEC' | 'A-SPEC' | 'C-SPEC' | 'T-SPEC' | 'ADR';
2
2
  export declare const SPEC_STATUSES: readonly ["draft", "review", "approved", "outdated"];
3
3
  export type SpecStatus = (typeof SPEC_STATUSES)[number];
4
4
  export interface SpecTypeDef {
@@ -12,7 +12,9 @@ exports.parentRuleText = parentRuleText;
12
12
  // its test's CANON, and the type itself — so adding a status compiled clean while spec_list kept
13
13
  // flagging it legacy.
14
14
  exports.SPEC_STATUSES = ['draft', 'review', 'approved', 'outdated'];
15
- exports.SPEC_ORDER = ['REQ', 'H-SPEC', 'A-SPEC', 'C-SPEC', 'T-SPEC'];
15
+ // @implements A-SPEC-571.1 — ADR trails the functional chain: spec_next serves the REQ→…→T-SPEC
16
+ // order first, and a decision is off that critical path.
17
+ exports.SPEC_ORDER = ['REQ', 'H-SPEC', 'A-SPEC', 'C-SPEC', 'T-SPEC', 'ADR'];
16
18
  /**
17
19
  * Where a requirement came from.
18
20
  *
@@ -102,6 +104,17 @@ exports.SPEC_TYPES = {
102
104
  requiredFields: ['coverage'],
103
105
  requiredSections: ['Normal Cases', 'Corner Cases', 'Negative Cases', 'Boundary Cases'],
104
106
  },
107
+ // @implements A-SPEC-571.1
108
+ // A DECISION, not a functional contract: a root type (no parent, like REQ) that records why a
109
+ // choice was made and inherits the store's authoring governance (stub → validate → seal → ledger
110
+ // → tamper-block). It carries NO T-SPEC/anchor/FtT duty — that is the No-Spec-No-Code chain, a
111
+ // separate axis. Its number space is its own (see spec-id-guard), so jarvis's ADR-0001 does not
112
+ // collide with the functional chain's max. 4-digit zero-padded ids are accepted (ADR-0001).
113
+ 'ADR': {
114
+ type: 'ADR', idRegex: /^ADR-\d{3,}$/, example: 'ADR-0001', folder: '06_adr', parents: [],
115
+ requiredFields: ['decided', 'decider'],
116
+ requiredSections: ['Context', 'Decision', 'Consequences', 'Alternatives'],
117
+ },
105
118
  };
106
119
  // @implements A-SPEC-100.1
107
120
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "@implements A-SPEC-209",
3
3
  "name": "@holmes-lab/holmes-kit",
4
- "version": "0.17.0",
4
+ "version": "0.19.0",
5
5
  "description": "Holmes-Kit — deterministic Agentic Software Engineering (ASE) harness with causal traceability (spec chain + D-CPG + RTM + phase guardrail)",
6
6
  "main": "dist/holmes/mcp/server.js",
7
7
  "types": "dist/holmes/mcp/server.d.ts",
@@ -82,6 +82,25 @@ Criteria · Non-Functional · Assumptions · Open Questions.** 필수 필드: `r
82
82
  부모 REQ의 Success Criteria가 이 설계로 어떻게 달성되는지가 본문이다. Open Questions는 비워두는
83
83
  칸이 아니다 — 아직 결정하지 않은 것을 결정하지 않았다고 적는 곳이고, 닫을 때는 근거와 함께 닫는다.
84
84
 
85
+ ## Files to Touch를 확정하기 전에 — 설계-시점 영향 범위 읽기
86
+
87
+ A-SPEC의 Files to Touch는 **스코프 선언**이고, 그래프는 그 선언이 무엇을 빠뜨리는지 이미 안다.
88
+ `approval_status(id)`를 부르면 `graphPreview`가 온다:
89
+
90
+ - `impact` — 선언한 FtT **밖**에서 그 안으로 호출해 들어오는 파일들(1-hop). 각 파일의 앵커 옆에
91
+ 그 스펙의 **의도 문장**이 붙으므로, "무슨 의도가 걸려 있는지"를 스토어를 열지 않고 읽는다.
92
+ - `density` — FtT 안의 **앵커-과밀** 파일(live 앵커가 분포 상위이며 절대치도 큰 것). 새 로직을
93
+ 거기 더할지, 새 파일로 뺄지 판단하는 근거다.
94
+
95
+ 읽고 나서 셋 중 하나를 **선택**한다: ①지목된 밖-파일을 FtT에 넣는다 ②스코프를 좁혀 그 파급이
96
+ 생기지 않게 설계를 바꾼다 ③근거를 갖고 그대로 둔다. 어느 쪽이든 선언은 이제 **알고 한 선언**이다.
97
+
98
+ > [!NOTE]
99
+ > **게이트는 이것을 막지 않는다** — 규율이지 차단이 아니다(하드 게이트 승격은 관측 원장이
100
+ > 오탐률을 답한 뒤의 별도 결정). 다만 읽지 않고 확정하면, 같은 소견이 봉인 뒤에 같은 말을
101
+ > 반복한다 — 실사고 기록: 봉인 소견이 지목한 파일 클러스터에서 회귀 3건이 났고, 그 소견은
102
+ > 설계가 끝난 뒤에야 읽혔다.
103
+
85
104
  ## A-SPEC / T-SPEC에 쓰는 것
86
105
 
87
106
  A-SPEC 필수 섹션: **Objective · Inputs / Outputs · Behavior · Test Points · Files to Touch · Done
@@ -117,3 +136,17 @@ T-SPEC 필수 섹션은 4분면 그대로다: **Normal · Corner · Negative ·
117
136
  번호가 A-SPEC과 T-SPEC에 한정되는 것, 그리고 스펙 폴더 밑 `.ts`가 author 게이트로 강등되지 않는다는 사실. 번호
118
137
  상속 관습은 엔진이 강제하지 않으므로 테스트도 고정하지 않는다 — 관습은 관습이라 말한다. 변이
119
138
  검사로 판별력을 증명한 뒤 신뢰한다.
139
+
140
+ ### 순환 의존을 만들지 않는다
141
+
142
+ 두 모듈이 서로를 import 하면 순환이다. **설계 단계에서 피하는 것이 유일하게 값싼 시점이다** ——
143
+ 코드가 쓰인 뒤에는 공유 타입 추출이나 지연 `require()` 워크어라운드로만 풀 수 있고, 후자는
144
+ 순환을 숨길 뿐 없애지 않는다.
145
+
146
+ - **공유 타입은 별도 모듈로 뺀다.** A 와 B 가 같은 타입을 필요로 하면 그 타입은 A 도 B 도 아닌
147
+ 세 번째 모듈에 있어야 한다.
148
+ - **타입만 필요하면 `import type` 을 쓴다.** TypeScript 가 방출에서 지우므로 런타임 순환이 되지
149
+ 않는다. 값 import 로 두면 타입만 쓰면서도 순환을 만든다.
150
+ - **지연 `require()` 로 순환을 우회하지 않는다.** 그것은 수리가 아니라 청구서 이연이다.
151
+
152
+ 이 저장소는 **스펙 그래프의 무순환을 ART-2 로 집행**한다. 코드 그래프도 같은 기준을 향한다.
@@ -96,6 +96,38 @@ npm publish --access public
96
96
 
97
97
  ---
98
98
 
99
+ ### 6단계: 외부 문서 표면 (External Docs Reach) — 발행이 닿는 곳까지 정직하게
100
+
101
+ npm 만 갱신하고 끝나면, 사람들이 실제로 읽는 문서는 낡은 채로 남는다. **사고 이력**: 이 저장소에는
102
+ GitHub 리모트가 없어(origin 이 로컬 gitea) 0.16.0·0.17.0·0.18.0 **세 릴리스 동안** GitHub README 가
103
+ 한 번도 갱신되지 않았고, `package.json` 의 `homepage` 가 바로 그 문서를 가리킨다.
104
+
105
+ **발행이 성공한 뒤에만** 실행한다 — 실패한 릴리스의 문서를 최신이라고 주장하지 않는다.
106
+
107
+ 1. **대상 파생 (하드코딩 금지)**: `package.json` 의 `repository` 에서 `<owner>/<repo>` 를 얻는다
108
+ (`repoTargetFrom`). 이 플레이북은 **소비 프로젝트에도 설치**되므로 특정 저장소를 박아 두면 남의
109
+ 릴리스가 그 저장소를 덮어쓴다. 파생 실패 → **SKIP(사유: `repository` 필드 없음/비-GitHub)**.
110
+ 2. **덮어쓸 것을 먼저 본다**: `gh api repos/<owner>/<repo>/contents/README.md` 로 원격을 읽어
111
+ 로컬과의 차이를 **보고**한다. 원격이 분기했다면 동기화는 남의 편집을 지우는 행위다 — 사람이
112
+ 알고 결정해야 한다.
113
+ 3. **동기화**: 로컬 `README.md` 를 `gh api --method PUT` 으로 올린다(`sha` 는 2 에서 읽은 값).
114
+ 4. **재조회 검증**: 다시 읽어 로컬과 일치하는지 확인한다. **쓴 것과 남은 것은 다를 수 있다** —
115
+ 검증 없는 "갱신했다"는 주장이지 사실이 아니다.
116
+ 5. **profile README drift 감지 (자동 수정 금지)**: `<owner>/.github` 의 `profile/README.md` 를 읽어
117
+ `profileDriftFindings` 로 주장-현실 불일치를 **보고만** 한다. 포지셔닝 문안은 오너 결정이며
118
+ 릴리스 절차가 정할 것이 아니다.
119
+ 6. **SKIP 은 값이지 침묵이 아니다**: `gh` 미설치 / 미인증(`gh auth status` 실패) / 권한 없음 /
120
+ `repository` 부재 — 각각 **무엇을 하지 않았는지 명시**하고 다음으로 간다. 소비 프로젝트의 발행을
121
+ 우리 편의로 막지 않는다. 다만 **조용한 성공은 금지** — 아무 말 없이 넘어가면 그것은 3단계
122
+ 전부를 한 것처럼 읽힌다.
123
+
124
+ > [!CAUTION]
125
+ > 2.5단계가 로컬 문서에 적용하는 규율("drift 도 누락도 거짓 주장이다")은 **외부 표면에도** 적용된다.
126
+ > 다른 점은 하나뿐이다: repo README 는 로컬의 사본이라 **동기화**하고, profile README 는 독립
127
+ > 문서라 **감지·보고**한다. 무엇이 정본인가가 처방을 정한다.
128
+
129
+ ---
130
+
99
131
  ## 플레이북 트리거 조건
100
132
  - "npm publish"
101
133
  - "release to npm"
@@ -69,6 +69,11 @@ holmes는 기계적으로 판별한다: `red-error`로는 red→green 시퀀스
69
69
 
70
70
  ## 절차
71
71
 
72
+ 0. **FtT 확정 전** `approval_status(<A-SPEC id>)`의 `graphPreview`로 영향 범위를 읽는다 —
73
+ `impact`(선언 밖에서 들어오는 1-hop 호출자, 의도 문장 병기)와 `density`(앵커-과밀 파일). 지목된
74
+ 것을 FtT에 넣을지, 스코프를 좁힐지, 근거를 갖고 둘지 **정하고 나서** 아래로 간다. 게이트가
75
+ **게이트는 이것을 막지 않는다** — 규율이지 차단이 아니다. 다만 읽지 않으면
76
+ 같은 소견을 봉인 뒤에 다시 듣는다(실사고 기록).
72
77
  1. `promote-slice`로 대상 A-SPEC과 그 T-SPEC을 승인한다(`[ART-1]` 게이트를 연다).
73
78
  2. 커버 테스트를 **먼저** 쓴다. 심볼이 없어 컴파일이 깨지면 틀린-값 스텁을 넣는다.
74
79
  3. `test_run` — **red-assertion**을 본다. `red-error`면 그건 아직 RED가 아니다; 스텁으로 고쳐라.
@@ -80,3 +85,17 @@ holmes는 기계적으로 판별한다: `red-error`로는 red→green 시퀀스
80
85
 
81
86
  `src/holmes/playbooks/tdd-slice.test.ts` — 이 스킬이 집행 태그(ART-1/4/8)와 red-assertion/red-error
82
87
  구별을 담고, 설치기가 이를 발견함을 고정한다. 상시 스위트 포함.
88
+
89
+ ### 순환 의존을 만들지 않는다
90
+
91
+ 두 모듈이 서로를 import 하면 순환이다. **설계 단계에서 피하는 것이 유일하게 값싼 시점이다** ——
92
+ 코드가 쓰인 뒤에는 공유 타입 추출이나 지연 `require()` 워크어라운드로만 풀 수 있고, 후자는
93
+ 순환을 숨길 뿐 없애지 않는다.
94
+
95
+ - **공유 타입은 별도 모듈로 뺀다.** A 와 B 가 같은 타입을 필요로 하면 그 타입은 A 도 B 도 아닌
96
+ 세 번째 모듈에 있어야 한다.
97
+ - **타입만 필요하면 `import type` 을 쓴다.** TypeScript 가 방출에서 지우므로 런타임 순환이 되지
98
+ 않는다. 값 import 로 두면 타입만 쓰면서도 순환을 만든다.
99
+ - **지연 `require()` 로 순환을 우회하지 않는다.** 그것은 수리가 아니라 청구서 이연이다.
100
+
101
+ 이 저장소는 **스펙 그래프의 무순환을 ART-2 로 집행**한다. 코드 그래프도 같은 기준을 향한다.