@joshuafolkken/kit 1.1010.0 → 1.1035.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 (272) hide show
  1. package/.claude/settings.json +1 -5
  2. package/.claude/skills/dependency-update/SKILL.md +6 -3
  3. package/.claude/skills/epic-commands/SKILL.md +46 -17
  4. package/.claude/skills/workflow-commands/SKILL.md +8 -23
  5. package/.claude/skills/workflow-commands/backlogrun-child.md +4 -2
  6. package/.claude/skills/workflow-commands/backlogrun.md +3 -12
  7. package/.claude/skills/workflow-commands/fullrun-steps.md +4 -3
  8. package/.claude/skills/workflow-commands/fullrun.md +1 -1
  9. package/.claude/skills/workflow-commands/halfrun.md +2 -1
  10. package/.claude/skills/workflow-commands/into-target.md +1 -1
  11. package/.claude/skills/workflow-commands/observation-filing.md +42 -43
  12. package/.claude/skills/workflow-commands/prerequisite.md +1 -1
  13. package/.codex/hooks.json +1 -5
  14. package/.github/workflows/sonar-qube.yml +1 -1
  15. package/AGENTS.md +4 -25
  16. package/CLAUDE.md +24 -38
  17. package/GEMINI.md +4 -24
  18. package/README.md +22 -56
  19. package/dist/CLAUDE.md +24 -38
  20. package/dist/hooks/batch-guard.js +4 -4
  21. package/dist/hooks/{chunk-WMIR5SNX.js → chunk-D67KVGGY.js} +3 -3
  22. package/dist/hooks/{chunk-EZLHXKJ6.js → chunk-EIFCAJRB.js} +70 -27
  23. package/dist/hooks/{chunk-KPZN42RT.js → chunk-GJT4BNVE.js} +3 -3
  24. package/dist/hooks/{chunk-PAXMLGSS.js → chunk-GLBDBJOK.js} +44 -24
  25. package/dist/hooks/{chunk-GBJUERYK.js → chunk-HOYJU5RM.js} +1 -1
  26. package/dist/hooks/{chunk-6PSTVOLH.js → chunk-HU66PWWL.js} +33 -57
  27. package/dist/hooks/{chunk-A2H5I2VD.js → chunk-KG6PZD72.js} +2 -2
  28. package/dist/hooks/{chunk-AWTFKKFW.js → chunk-XPLP27WA.js} +3 -8
  29. package/dist/hooks/{chunk-4GDR2YTV.js → chunk-Y27M6A7X.js} +4 -4
  30. package/dist/hooks/{chunk-56LGMJJV.js → chunk-ZXNE6NY3.js} +2 -2
  31. package/dist/hooks/codex-hook-adapter.js +10 -10
  32. package/dist/hooks/duplicate-read-guard.js +5 -5
  33. package/dist/hooks/format-edited.js +2 -2
  34. package/dist/hooks/investigation-guard.js +5 -5
  35. package/dist/hooks/pretool-guard.js +9 -9
  36. package/dist/hooks/stop-guard.js +11 -15
  37. package/dist/josh.js +38 -19
  38. package/dist/version/index.js +93 -41
  39. package/eslint/base.js +2 -11
  40. package/package.json +31 -5
  41. package/prompts/coding-standards.md +15 -290
  42. package/prompts/collaboration-workflow/cross-repo-epic.md +2 -51
  43. package/prompts/collaboration-workflow/epic-audit.md +2 -53
  44. package/prompts/collaboration-workflow/epic-bundle.md +2 -106
  45. package/prompts/collaboration-workflow/issue-template.md +4 -4
  46. package/prompts/collaboration-workflow/operating-rules.md +18 -75
  47. package/prompts/collaboration-workflow/principles.md +74 -0
  48. package/prompts/collaboration-workflow/residency.md +54 -14
  49. package/prompts/collaboration-workflow/rule-delivery.md +1 -11
  50. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  51. package/prompts/collaboration-workflow.md +22 -28
  52. package/scripts/adopt/adopt-logic.ts +2 -2
  53. package/scripts/adopt/adopt-toolkits.ts +1 -1
  54. package/scripts/adopt/adopt.ts +2 -2
  55. package/scripts/agent/agent-event.ts +2 -9
  56. package/scripts/agent/agent-exit-record.ts +2 -9
  57. package/scripts/backlog/backlog-budget-cli.ts +2 -6
  58. package/scripts/backlog/backlog-drive-cli.ts +20 -10
  59. package/scripts/backlog/backlog-drive.ts +50 -16
  60. package/scripts/backlog/backlog-offer-cli.ts +6 -5
  61. package/scripts/backlog/backlog-plan.ts +1 -1
  62. package/scripts/build/build-bin.ts +2 -1
  63. package/scripts/build/build-config-merge.ts +2 -1
  64. package/scripts/build/build-hooks.ts +24 -4
  65. package/scripts/build/build-managed-marker.ts +2 -1
  66. package/scripts/build/build-self-sync-guard.ts +2 -1
  67. package/scripts/build/build-version.ts +2 -1
  68. package/scripts/cases/cases-logic.ts +2 -6
  69. package/scripts/ci/pr-classification.ts +13 -11
  70. package/scripts/cost-runtime/cost-transcript.ts +4 -11
  71. package/scripts/doctor/doctor-consumer.ts +5 -12
  72. package/scripts/doctor/doctor-ports.ts +2 -2
  73. package/scripts/document/document-byte-budget.ts +8 -16
  74. package/scripts/document/document-section.ts +2 -6
  75. package/scripts/document/entry-read-budget.ts +1 -1
  76. package/scripts/{git/git-epic-add-body.ts → epic/epic-add-body.ts} +23 -23
  77. package/scripts/{git/git-epic-add-plan.ts → epic/epic-add-plan.ts} +23 -26
  78. package/scripts/{git/git-epic-add.ts → epic/epic-add.ts} +17 -17
  79. package/scripts/epic/epic-audit-cli.ts +4 -4
  80. package/scripts/epic/epic-audit-orphans.ts +2 -2
  81. package/scripts/epic/epic-audit-rationale.ts +1 -1
  82. package/scripts/epic/epic-audit.ts +1 -1
  83. package/scripts/{git/git-epic-body.ts → epic/epic-body.ts} +6 -6
  84. package/scripts/epic/epic-bundle-cli.ts +1 -1
  85. package/scripts/epic/epic-bundle.ts +2 -2
  86. package/scripts/epic/epic-candidate-confirm.ts +2 -1
  87. package/scripts/{git/git-epic-chains.ts → epic/epic-chains.ts} +4 -4
  88. package/{scripts-ai → scripts/epic}/epic-check.ts +5 -4
  89. package/{scripts-ai → scripts/epic}/epic-cli.ts +4 -4
  90. package/scripts/{git/git-epic-close-comment.ts → epic/epic-close-comment.ts} +9 -9
  91. package/scripts/{git/git-epic-close.ts → epic/epic-close.ts} +23 -19
  92. package/scripts/epic/epic-cross-repo.ts +21 -38
  93. package/scripts/{git/git-epic-decision.ts → epic/epic-decision.ts} +12 -14
  94. package/scripts/epic/epic-fetch.ts +3 -3
  95. package/scripts/epic/epic-graph.ts +3 -3
  96. package/scripts/epic/epic-index.ts +2 -2
  97. package/scripts/epic/epic-issue.ts +1 -1
  98. package/scripts/epic/epic-next.ts +3 -3
  99. package/scripts/{git/git-epic-parse.ts → epic/epic-parse.ts} +3 -3
  100. package/scripts/{git/git-epic-promote.ts → epic/epic-promote.ts} +10 -10
  101. package/scripts/{git/git-epic-read.ts → epic/epic-read.ts} +9 -9
  102. package/scripts/{git/git-epic-reconcile.ts → epic/epic-reconcile.ts} +18 -20
  103. package/scripts/{git/git-epic-reference.ts → epic/epic-reference.ts} +4 -23
  104. package/scripts/epic/epic-relation-recheck.ts +4 -3
  105. package/scripts/{git/git-epic-relations.ts → epic/epic-relations.ts} +5 -5
  106. package/scripts/{git/git-epic-remove-plan.ts → epic/epic-remove-plan.ts} +17 -19
  107. package/scripts/{git/git-epic-remove.ts → epic/epic-remove.ts} +13 -13
  108. package/scripts/{git/git-epic-run.ts → epic/epic-run.ts} +27 -27
  109. package/scripts/{git/git-epic-sections.ts → epic/epic-sections.ts} +6 -6
  110. package/scripts/{git/git-epic-shape.ts → epic/epic-shape.ts} +7 -7
  111. package/scripts/{git/git-epic-validate.ts → epic/epic-validate.ts} +13 -13
  112. package/{scripts-ai → scripts/epic}/epic.ts +17 -16
  113. package/scripts/gh/fix-gh-packages.ts +2 -1
  114. package/scripts/gh/gh-spawn.ts +12 -10
  115. package/scripts/git/constants.ts +1 -1
  116. package/scripts/git/git-branch.ts +10 -1
  117. package/scripts/git/git-command.ts +1 -1
  118. package/scripts/git/git-error.ts +2 -5
  119. package/{scripts-ai → scripts/git}/git-followup-finish.ts +7 -7
  120. package/scripts/git/git-followup-flush.ts +74 -48
  121. package/scripts/git/git-followup-issue-close.ts +2 -2
  122. package/scripts/git/git-followup-label.ts +1 -1
  123. package/scripts/git/git-followup-pending.ts +1 -1
  124. package/{scripts-ai → scripts/git}/git-followup-workflow.ts +23 -11
  125. package/scripts/git/git-gh-exec.ts +85 -26
  126. package/scripts/git/git-gh-issue-read.ts +2 -2
  127. package/scripts/git/git-gh-issue-rest.ts +2 -2
  128. package/scripts/git/git-gh-issue-write.ts +6 -6
  129. package/scripts/git/git-gh-pr-read.ts +0 -21
  130. package/scripts/git/git-gh-pr.ts +2 -23
  131. package/scripts/git/git-pr-followup-wrapup.ts +2 -6
  132. package/scripts/git/git-preflight.ts +3 -6
  133. package/scripts/git/git-staging.ts +21 -9
  134. package/{scripts-ai → scripts/git}/git-workflow.ts +11 -11
  135. package/scripts/git/github-issue-url.ts +1 -1
  136. package/scripts/git/issue-labels.ts +1 -1
  137. package/scripts/git/issue-reference.ts +19 -0
  138. package/scripts/git/main-merge.ts +2 -1
  139. package/scripts/git/main-sync.ts +3 -2
  140. package/scripts/git/schemas.ts +1 -1
  141. package/scripts/git/stash-pop-args.ts +7 -13
  142. package/scripts/git/stash-pop-cli.ts +2 -1
  143. package/{scripts-ai → scripts/git}/telegram-test-logic.ts +2 -2
  144. package/{scripts-ai → scripts/git}/telegram-test.ts +7 -7
  145. package/scripts/hooks/format-rewrite-notice.ts +2 -8
  146. package/scripts/init/init-ai-copy.ts +2 -5
  147. package/scripts/init/init.ts +8 -4
  148. package/scripts/init/start-steps.ts +2 -1
  149. package/scripts/init/start.ts +2 -1
  150. package/scripts/issue/issue-comment-cli.ts +2 -1
  151. package/scripts/issue/issue-file-cli.ts +2 -1
  152. package/scripts/issue/issue-fold-cli.ts +9 -16
  153. package/scripts/issue/issue-scout-cli.ts +8 -13
  154. package/scripts/issue/measure-rerun-cli.ts +7 -6
  155. package/scripts/josh/josh-commands-ai.ts +2 -2
  156. package/scripts/josh/josh-commands-backlog.ts +1 -1
  157. package/scripts/josh/josh-commands-development.ts +1 -1
  158. package/scripts/josh/josh-commands-workflow.ts +4 -4
  159. package/scripts/lane/lane-cli.ts +2 -1
  160. package/scripts/lane/lane-open.ts +3 -2
  161. package/scripts/lane/lane-registry.ts +3 -6
  162. package/scripts/lib/cli-flags.ts +20 -2
  163. package/scripts/lib/error-message.ts +9 -0
  164. package/scripts/lib/read-file.ts +26 -2
  165. package/scripts/observations/observation-ledger-home.ts +98 -26
  166. package/scripts/observations/observation-ledger-migrate.ts +26 -21
  167. package/scripts/observations/observation-ledger-prepare.ts +10 -20
  168. package/scripts/observations/observation-ledger.ts +58 -25
  169. package/scripts/observations/observations-flush-cli.ts +6 -23
  170. package/scripts/observations/observations-flush-landing.ts +2 -1
  171. package/scripts/observations/observations-flush.ts +29 -20
  172. package/scripts/package/package-scout-cli.ts +8 -16
  173. package/scripts/ports/port-command.ts +2 -1
  174. package/scripts/propagate/propagate-publish.ts +6 -7
  175. package/scripts/propagate/propagate-steps.ts +2 -1
  176. package/scripts/propagate/propagate.ts +3 -2
  177. package/scripts/refactor/import-graph.ts +2 -6
  178. package/scripts/registry-migration/migrate.ts +3 -2
  179. package/scripts/registry-migration/user-npmrc.ts +2 -2
  180. package/scripts/release/release-cli.ts +2 -1
  181. package/scripts/repo/repo-setting.ts +10 -8
  182. package/scripts/review/review-finding-ledger.ts +3 -3
  183. package/scripts/review/review-findings-cli.ts +4 -11
  184. package/scripts/review/review-record-cli.ts +14 -11
  185. package/scripts/review/review-record.ts +6 -16
  186. package/scripts/rules/decision-oracle.ts +2 -2
  187. package/scripts/rules/rule-body-guard.ts +2 -2
  188. package/scripts/rules/rule-value-cache.ts +99 -0
  189. package/scripts/rules/rule-value-cli.ts +10 -9
  190. package/scripts/rules/rule-value.ts +1 -1
  191. package/scripts/run/run-carry-args.ts +2 -6
  192. package/scripts/run/run-carry-cli.ts +5 -7
  193. package/scripts/run/run-cut-args.ts +7 -13
  194. package/scripts/run/run-ending-cli.ts +4 -7
  195. package/scripts/run/run-event-stream.ts +2 -5
  196. package/scripts/run/run-liveness-cli.ts +4 -7
  197. package/scripts/run/run-progress-args.ts +2 -6
  198. package/scripts/run/run-progress-cli.ts +2 -1
  199. package/scripts/run/run-tail-cli.ts +3 -3
  200. package/scripts/run/run-tidy-stashes.ts +7 -14
  201. package/scripts/run/run-wake-cli.ts +2 -6
  202. package/scripts/run/run-wake-driver.ts +15 -2
  203. package/scripts/run/run-wake-session.ts +14 -4
  204. package/scripts/safe-chain/project-config.ts +3 -6
  205. package/scripts/security/security-audit-provision.ts +6 -7
  206. package/scripts/sonar/sonar-hotspots-cli.ts +2 -1
  207. package/scripts/sync/directory-copy-guard.ts +2 -1
  208. package/scripts/sync/sync-ai-files.ts +3 -3
  209. package/scripts/sync/template-source-logic.ts +3 -4
  210. package/scripts/test/e2e-retry-check.ts +3 -6
  211. package/scripts/ui/ui-routes-cli.ts +3 -6
  212. package/scripts/version/bump-version.ts +2 -1
  213. package/scripts/version/version-remote.ts +18 -27
  214. package/scripts/version/version-targets.ts +3 -3
  215. package/.claude/skills/workflow-commands/rule-residency.md +0 -267
  216. package/evals/scenarios/consult-not-execute.json +0 -20
  217. package/evals/scenarios/no-implicit-workflow.json +0 -26
  218. package/evals/scenarios/overrides-both-locations.json +0 -29
  219. package/evals/scenarios/upstream-interrupt.json +0 -23
  220. package/evals/scenarios/workflow-skill-loaded.json +0 -16
  221. package/prompts/agent-lint-protocol.json +0 -79
  222. package/prompts/agent-rules.md +0 -63
  223. package/prompts/collaboration-workflow/consultation-vs-execution.md +0 -8
  224. package/prompts/collaboration-workflow/distributed-docs.md +0 -7
  225. package/prompts/collaboration-workflow/durable-rules.md +0 -24
  226. package/prompts/collaboration-workflow/latest-first.md +0 -14
  227. package/prompts/collaboration-workflow/no-clones.md +0 -11
  228. package/prompts/collaboration-workflow/simplicity-first.md +0 -9
  229. package/prompts/collaboration-workflow/single-source-rules.md +0 -13
  230. package/scripts/build/shim-shell.ts +0 -25
  231. package/scripts/claude/skill-meta.ts +0 -37
  232. package/scripts/document/document-scan.ts +0 -108
  233. package/scripts/document/generate-catalog.ts +0 -69
  234. package/scripts/document/retired-phrases.ts +0 -143
  235. package/scripts/document/review-agent-type.ts +0 -46
  236. package/scripts/document/single-source.ts +0 -73
  237. package/scripts/git/git-fixture-workspace.ts +0 -88
  238. package/scripts/hooks/format-edited-file-fixtures.ts +0 -109
  239. package/scripts/hooks/prompt-hooks.ts +0 -38
  240. package/scripts/init/hook-command-bootstrap.ts +0 -83
  241. package/scripts/issue/issue-logic.ts +0 -50
  242. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +0 -1227
  243. package/scripts/josh/josh-script-reader.ts +0 -11
  244. package/scripts/package/production-dependency-graph.ts +0 -68
  245. package/scripts/retrospective/retrospective-cli.ts +0 -97
  246. package/scripts/retrospective/retrospective.ts +0 -127
  247. package/scripts/rules/delivered-rules-harness.ts +0 -72
  248. package/scripts/rules/top-level-scripts-guard.ts +0 -47
  249. package/scripts/run/run-carry-flush.ts +0 -58
  250. package/scripts/run/run-transcript.golden.txt +0 -57
  251. package/scripts/run/run-wake-work.ts +0 -108
  252. package/scripts/sync/dependabot-pin-logic.ts +0 -135
  253. package/scripts/test/classify-isolation.ts +0 -149
  254. package/scripts/test/http-fault-injection.ts +0 -79
  255. package/scripts/test/josh-harness-environment.ts +0 -260
  256. package/scripts/test/josh-harness.ts +0 -96
  257. package/scripts/test/pilot-files.ts +0 -452
  258. package/scripts/test/pilot-measure.ts +0 -78
  259. package/scripts/test/test-network-guard.ts +0 -453
  260. package/scripts/test/test-repository-guard.ts +0 -317
  261. package/scripts/test/test-state-guard.ts +0 -85
  262. package/scripts/test/test-stdout-guard.ts +0 -54
  263. package/scripts/test/test-telegram-guard.ts +0 -90
  264. package/scripts/test/unit-guard-environment.ts +0 -12
  265. package/scripts/test/unit-projects.ts +0 -139
  266. package/scripts/test/vitest-include-globs.ts +0 -12
  267. package/scripts/time-runtime/time-batch-guard-fixtures.ts +0 -66
  268. package/scripts-ai/completion-gate.ts +0 -13
  269. package/scripts-ai/environment-loader.ts +0 -9
  270. /package/{scripts-ai → scripts/epic}/epic-cli-argv.ts +0 -0
  271. /package/{scripts-ai → scripts/epic}/epic-cli-remove.ts +0 -0
  272. /package/{scripts-ai → scripts/git}/followup-issue-number.ts +0 -0
@@ -1,6 +1,8 @@
1
- # ESLint設定ガイド - コーディング支援用
1
+ # コーディング指針 — lint では表せない書き方
2
2
 
3
- このプロジェクトのESLint設定は非常に厳格で、標準的なJavaScript/TypeScriptプロジェクトとは異なる命名規則を採用しています。新しいコード作成やリファクタリング時は必ずこのガイドを参照してください。
3
+ 命名・関数の構文・エクスポート・ファイル名・品質上限・型安全・早期 return・マジックナンバーといった機械的な規約の単一ソースは `CLAUDE.md` → "Critical Conventions (non-standard — always apply)" である。その大半は ESLint が強制する(クラスのプロパティ・メソッドの `snake_case` など `CLAUDE.md` に書いていない細目は `eslint/rules/naming-convention.js` が持つ)。ただし **`function` 構文(アロー関数を使わない)と早期 return の 1 行形式は lint が検査しない**ので、書き手とレビューが確かめる。このファイルは本文を写さず、lint では表せない書き方の指針だけを持つ。
4
+
5
+ lint・型検査の実行手順は `CLAUDE.md` → "Code Change Rules" の検証ゲート(`pnpm josh gate`、実装中は `pnpm josh lint:related` / `pnpm josh test:related`)が単一ソースである。
4
6
 
5
7
  ## 📝 基本方針
6
8
 
@@ -24,7 +26,7 @@
24
26
  - **過度な抽象化を避ける**: 現在の要件で必要な抽象化のみを行う。将来の拡張性を考慮した抽象化は不要
25
27
  - **パターンの強制は避ける**: デザインパターンやアーキテクチャパターンを無理に適用しない
26
28
  - **コードの重複は撲滅**: コードクローン(重複)は完全に撲滅する。重複が見つかった場合は関数やモジュールに抽出して共通化する
27
- - **仕組みを足す前に原因を問う**: これは**書かれたコードの可読性**の規則。仕組み(フック・ガード・ルール)を足すか・どこへ置くかという**設計時の判断**は `prompts/collaboration-workflow/simplicity-first.md` の担当なので、本文を写さずそちらを参照する
29
+ - **仕組みを足す前に原因を問う**: これは**書かれたコードの可読性**の規則。仕組み(フック・ガード・ルール)を足すか・どこへ置くかという**設計時の判断**は `prompts/collaboration-workflow/principles.md` → "設計はエレガント" の担当なので、本文を写さずそちらを参照する
28
30
 
29
31
  ### エラーハンドリング
30
32
 
@@ -37,59 +39,8 @@
37
39
  - **略語は避ける**: 一般的でない略語は使わず、明確な単語を使用する
38
40
  - **長すぎる名前も避ける**: 必要以上に長い名前は避け、適切な長さで意図を表現する
39
41
 
40
- ## 🚨 最重要:命名規則(標準と大きく異なる)
41
-
42
- ### ❌ よくある間違い:camelCase を使う
43
-
44
- ```typescript
45
- // ❌ 間違い(標準的なTypeScript)
46
- const userName = 'john'
47
- const isLoggedIn = true
48
- const getUserData = () => {}
49
-
50
- // ✅ 正しい(このプロジェクト)
51
- const user_name = 'john'
52
- const is_logged_in = true
53
- const get_user_data = () => {}
54
- ```
55
-
56
- ### 正しい命名規則
57
-
58
- - **変数・関数・パラメータ**: `snake_case`
59
- - **定数(const)**: `UPPER_CASE` または `snake_case`
60
- - **boolean変数**: `is_`, `has_`, `should_`, `can_`, `will_`, `did_` で始める
61
- - **型・クラス・インターフェース・Enum**: `PascalCase`
62
- - **Enumメンバー**: `UPPER_CASE`
63
- - **クラスプロパティ・メソッド**: `snake_case`
64
-
65
- ## 🔧 必須:型安全性ルール
66
-
67
- ### 明示的な型定義が必須
68
-
69
- ```typescript
70
- // ❌ 間違い
71
- const processData = (data) => {
72
- return data.map((item) => item.value)
73
- }
74
-
75
- // ✅ 正しい
76
- const process_data = (data: Array<{ value: string }>): Array<string> => {
77
- return data.map((item) => item.value)
78
- }
79
- ```
80
-
81
- ### 禁止事項
82
-
83
- - `any` の使用は完全禁止
84
- - 未使用変数は禁止
85
- - 浮動Promiseは禁止
86
- - 型アサーションは制限あり
87
-
88
- ### 早期returnの書き方
42
+ ### 条件式と定数
89
43
 
90
- - 条件の本体が単一の `return` だけで、かつ行長が100文字未満のときは1行で書く
91
- `if (value === undefined) return default_value`
92
- - 100文字以上になる、または複数ステートメントがある場合はブロック構文を使う
93
44
  - **条件式が複雑な場合は関数に抽出**: 条件式の意図が不明瞭な場合は、関数に抽出して関数名で意図を明確にする
94
45
 
95
46
  ```typescript
@@ -104,10 +55,7 @@ const process_data = (data: Array<{ value: string }>): Array<string> => {
104
55
  }
105
56
  ```
106
57
 
107
- ### マジックナンバーと定数化
108
-
109
- - `0`, `1`, `-1` 以外の数値リテラルは原則として定数へ抽出する
110
- - 繰り返し使用する文字列や識別子は定数化し、意味の分かる名前を付ける
58
+ - **文字列も定数化する**: 数値リテラルの抽出は lint が強制するが、繰り返し使用する文字列や識別子も定数化し、意味の分かる名前を付ける
111
59
 
112
60
  ## 📁 新規作成時の手順
113
61
 
@@ -118,59 +66,23 @@ const process_data = (data: Array<{ value: string }>): Array<string> => {
118
66
  find src -name "*.ts" -o -name "*.svelte" | grep -i [関連キーワード]
119
67
  ```
120
68
 
121
- ### 2. ファイル作成時の注意点
122
-
123
- - **Svelteファイル**: `PascalCase.svelte`(例: `UserProfile.svelte`)
124
- - **`*.svelte.ts` ファイル**: Svelte のリアクティブな状態やロジックを格納するファイルも `PascalCase.svelte.ts` 形式とする(例: `ThemeStore.svelte.ts`, `LocaleStore.svelte.ts`)
125
- - **TypeScriptファイル**: `kebab-case.ts`(例: `user-service.ts`)
126
- - **テストファイル**: ユニット/統合テストは `*.test.ts`(`*.spec.ts` は禁止)、コンポーネント/ブラウザテストは `*.svelte.test.ts`(`.svelte.` の中置は必須・保持する)、E2E は `src/routes/**/*.e2e.ts`。テストは対象モジュールの隣に colocate し、トップレベルの `tests/` ディレクトリは使わない(詳細は `prompts/testing-guide.md` の「Test file naming & placement」を参照)
127
- - **ルートファイル**: `+page.svelte`, `+layout.svelte` などは例外
128
- - **関数定義**: `function` で表現できる処理はアロー関数ではなく通常の `function` 構文で記述する
129
- - **複数関数のエクスポート**: 複数の関数を公開する場合は名前空間オブジェクト(namespace object)にまとめてエクスポートする(定数のみのエクスポートは個別で問題ない)
130
-
131
- ### ファイル分割の指針
69
+ ### 2. ファイル分割の指針
132
70
 
133
- - **複雑度が高い場合**: 関数の認知的複雑度が4を超える、または行数(コード行数)が25行を超える場合は分割を検討
71
+ - **上限に近づいたら分割を検討**: 関数やファイルが `CLAUDE.md` → "Quality limits" の上限に近づいたら分割を検討する。編集前に `pnpm josh lines <path>` で余裕を確認する
134
72
  - **責任が複数ある場合**: 1つのファイルが複数の責任を持つ場合は、責任ごとにファイルを分割
135
73
  - **再利用性**: 他のファイルからも使用される可能性があるロジックは、別ファイルに分離
136
74
  - **メインファイルの肥大化を避ける**: メインファイルの肥大化を避けることを優先する。再利用可能な機能や独立した責任を持つ機能は、積極的に別ファイルに分割する。メインファイルは主要な処理フローに集中し、詳細な実装は別ファイルに分離する
137
75
  - **過度な分割は避ける**: 小さすぎるファイルの分割は避け、関連する機能は同じファイルにまとめる
138
76
 
139
- ### 3. インポート/エクスポート規則
140
-
141
- ```typescript
142
- // ❌ 間違い
143
- export default class UserService {}
144
-
145
- // ✅ 正しい
146
- export class UserService {}
147
- export type { UserData }
148
- ```
149
-
150
- #### 名前空間オブジェクトエクスポート(必須)
151
-
152
- **重要**: 複数の関数を公開する場合は、必ず名前空間オブジェクト(namespace object)にまとめてエクスポートする。リファクタリング時も同様に適用する。
153
-
154
- **注意**: このルールは**関数のみ**に適用される。定数(`const`で定義された値やオブジェクト)は個別エクスポートで問題なく、名前空間オブジェクトにまとめる必要はない。
77
+ ### 3. 名前空間オブジェクトの名付け方
155
78
 
156
- ```typescript
157
- // ❌ 間違い: 個別の関数エクスポート
158
- async function exec_git_branch(): Promise<string> {
159
- return await exec_git_command('rev-parse --abbrev-ref HEAD')
160
- }
79
+ 複数の関数を名前空間オブジェクトにまとめてエクスポートする規則そのものは `CLAUDE.md` → "Functions & exports" にある(定数は個別エクスポートでよい)。ここでは名付け方だけを述べる。
161
80
 
162
- async function exec_git_status(): Promise<string> {
163
- return await exec_git_command('status --porcelain')
164
- }
165
-
166
- export { exec_git_branch, exec_git_status }
167
- ```
81
+ - ファイル名と名前空間名で意図を明確にする(例: `git-command.ts` → `git_command`)
82
+ - メソッド名は短く、名前空間で補完する(例: `exec_git_branch()` → `git_command.branch()`)
168
83
 
169
84
  ```typescript
170
- // ✅ 正しい: 名前空間オブジェクトエクスポート
171
- // ファイル名: git-command.ts
172
- // 名前空間名: git_command
173
-
85
+ // ✅ ファイル名: git-command.ts / 名前空間名: git_command
174
86
  async function branch(): Promise<string> {
175
87
  return await exec_git_command('rev-parse --abbrev-ref HEAD')
176
88
  }
@@ -187,196 +99,9 @@ const git_command = {
187
99
  export { git_command }
188
100
  ```
189
101
 
190
- **命名の工夫**:
191
-
192
- - ファイル名と名前空間名で意図を明確にする(例: `git-command.ts` → `git_command`)
193
- - メソッド名は短く、名前空間で補完する(例: `exec_git_branch()` → `git_command.branch()`)
194
- - アロー関数は使わず、通常の`function`構文を使用する
195
-
196
- **使用例**:
197
-
198
102
  ```typescript
199
- // インポート
103
+ // 使用側
200
104
  import { git_command } from './git/git-command.js'
201
105
 
202
- // 使用
203
106
  const branch_name = await git_command.branch()
204
- const status_output = await git_command.status()
205
- ```
206
-
207
- ## 🧹 必須:Lintチェック手順
208
-
209
- ### 基本ルール
210
-
211
- - **ファイルを変更したときは、最後にかならず lint チェックを行うこと**
212
- - エラーがある場合は修正してからコミットする
213
- - 変更したファイルだけでなく、依存関係にあるファイルも含めてチェックする
214
-
215
- ### チェック対象
216
-
217
- - 編集したファイル、新規作成したファイル、削除したファイル(インポート元がある場合)
218
- - 依存ファイル:変更したファイルからインポートしているファイル、変更したファイルがインポートしているファイル、同じ機能領域のファイル
219
-
220
- ### 編集後の必須作業
221
-
222
- ```bash
223
- # 1. ESLintチェック
224
- pnpm run lint
225
-
226
- # 2. エラーがある場合は修正
227
- pnpm run lint:fix
228
-
229
- # 3. 型チェック
230
- pnpm run check
231
-
232
- # 4. 最終確認
233
- pnpm run build
234
- ```
235
-
236
- ### Agentモード運用(報告=Lintゼロの保証)
237
-
238
- 1. **変更完了直後にLintを実行**
239
- - `read_lints([変更ファイルの絶対パス配列])` で初期確認
240
- - **必須**: `pnpm run lint` で検証(`read_lints` は一部のESLintルールやPrettierを検出しないため)
241
- - エラーが1件でもあれば修正→再実行。ゼロになるまで報告禁止
242
-
243
- 2. **複数ファイル変更時**
244
- - すべての関与ファイルを明示的に指定してチェック
245
- - 大きな変更はファイル群ごとに区切り、群ごとにLintゼロを達成してから次へ
246
-
247
- 3. **報告文**
248
- - 「Lint: 0 errors(確認対象: 変更ファイル/またはsrc配下)」を明記
249
- - ゼロ以外は報告不可
250
-
251
- **`read_lints` の制限**: 一部のESLintルール(例: `id-length`)やPrettierのフォーマットチェックを検出しない。報告前に必ず `pnpm run lint` で再確認すること。
252
-
253
- 補足: 本運用ルールの機械可読版は `prompts/agent-lint-protocol.json` に格納。
254
-
255
- ### よくあるLintエラーと対処法
256
-
257
- #### 1. 命名規則エラー
258
-
259
- ```bash
260
- # エラー例
261
- error: Identifier 'userName' is not in snake_case
262
-
263
- # 修正
264
- const user_name = 'john'; // snake_caseに変更
265
- ```
266
-
267
- #### 2. 型定義エラー
268
-
269
- ```bash
270
- # エラー例
271
- error: Missing return type on function
272
-
273
- # 修正
274
- const get_user_data = (): UserData => { // 戻り値の型を明記
275
- ```
276
-
277
- #### 3. 未使用変数エラー
278
-
279
- ```bash
280
- # エラー例
281
- error: 'unusedVar' is defined but never used
282
-
283
- # 修正
284
- const _unused_var = 'value'; // アンダースコアプレフィックス
285
- ```
286
-
287
- ## 🎯 プロジェクト固有の設定
288
-
289
- ### Svelte固有ルール
290
-
291
- - `$state` などのリアクティブ変数は再代入可能
292
- - Propsインターフェース名は `Props` で許可
293
- - DOM操作は制限あり
294
-
295
- ### ファイル除外設定
296
-
297
- 以下のファイルはESLint対象外:
298
-
299
- - `.storybook/**`
300
- - `*.config.js`
301
- - `src/routes/demo/**`
302
- - `src/stories/**`
303
-
304
- ### リファクタリング除外設定
305
-
306
- ファイル先頭に `/* @refactor-ignore */` コメントが含まれるファイルは、リファクタリング提案や参考コードとして使用する際の対象から除外されます。
307
-
308
- ```typescript
309
- #!/usr/bin/env node
310
- /* @refactor-ignore */
311
- // このファイルはリファクタリング対象外です
312
- ```
313
-
314
- ### 複雑度制限
315
-
316
- - **関数の複雑度**: 最大5
317
- - **認知的複雑度**: 最大4
318
- - **ネストレベル**: 最大2
319
- - **関数の行数**: 最大25行(テストファイルは35行)
320
- - **ファイルの行数**: 最大300行
321
- - **関数内の文の数**: 最大10
322
- - **パラメータ数**: 最大4個
323
- - **行数はコード行数であり物理行数ではない**: `max-lines` / `max-lines-per-function` は `skipBlankLines` と `skipComments` を有効にして動くため、空行とコメントは数えない。`wc -l` ではなく `pnpm josh lint` の報告で判断する(joshuafolkken/kit#1070)
324
-
325
- ## 🔍 デバッグ用コマンド
326
-
327
- ### 特定ファイルのLintチェック
328
-
329
- ```bash
330
- pnpm exec eslint src/path/to/file.ts
331
- ```
332
-
333
- ### 自動修正可能なエラーを修正
334
-
335
- ```bash
336
- pnpm exec eslint --fix src/path/to/file.ts
337
107
  ```
338
-
339
- ### 型チェックのみ
340
-
341
- ```bash
342
- pnpm exec tsc --noEmit
343
- ```
344
-
345
- ## ⚠️ よくある間違いトップ5
346
-
347
- 1. **camelCase使用** → `snake_case`に変更
348
- 2. **型定義省略** → 明示的な型定義を追加
349
- 3. **any使用** → 適切な型を定義
350
- 4. **Lintチェック忘れ** → 必ず`pnpm run lint`実行
351
- 5. **既存ファイル未参照** → 類似機能のファイルを必ず確認
352
-
353
- ### その他のよくある間違い
354
-
355
- - **過度な抽象化** → 現在の要件に必要な抽象化のみを行う
356
- - **不要なコメント** → コードで表現できることはコメントにしない
357
- - **未来の拡張性を考慮** → 現在必要な機能のみを実装する
358
- - **意図が不明瞭な条件式** → 複雑な条件式や意図が伝わりにくい処理は関数に抽出して関数名で意図を明確にする
359
-
360
- ## 📋 チェックリスト
361
-
362
- 新規作成・リファクタリング時:
363
-
364
- - [ ] 既存の類似ファイルを参照した
365
- - [ ] 命名規則(snake_case)を守った
366
- - [ ] 明示的な型定義を追加した
367
- - [ ] `any`を使用していない
368
- - [ ] `pnpm run lint`でエラーがない
369
- - [ ] `pnpm run check`で型エラーがない
370
- - [ ] 複雑度制限内に収まっている
371
- - [ ] コードがシンプルで読みやすいか
372
- - [ ] 現在の要件に集中しているか(未来の拡張性を考慮していないか)
373
- - [ ] 過度な抽象化をしていないか
374
- - [ ] 不要なコメントがないか
375
- - [ ] 適切にファイル分割されているか
376
- - [ ] コードの重複(クローン)がないか
377
- - [ ] 条件式や意図が不明瞭な処理を関数に抽出しているか
378
- - [ ] 複数の関数を公開する場合は名前空間オブジェクトにまとめてエクスポートしているか(**注意**: 関数のみに適用。定数は個別エクスポートで問題ない)
379
-
380
- ---
381
-
382
- **重要**: このプロジェクトのESLint設定は標準と大きく異なります。必ずこのガイドを参照し、既存ファイルのパターンに従ってコーディングしてください。
@@ -1,54 +1,5 @@
1
1
  ## リポジトリをまたぐ EPIC
2
2
 
3
- 1 つの要望が kit / app-kit / game-kit / joshuafolkken-com のうち複数にまたがることは珍しくない。EPIC は**他リポジトリの子 Issue を持てる**。
3
+ **この規則の単一ソースは `.claude/skills/epic-commands/SKILL.md` → "Epics that span repositories" である。** 子の書き方、owner の制限、自動クローズ、公開の完了を待つ依存、配布物を持たない repo、実行のディスパッチ、`owner/repo#N` での参照はすべてそこにある。
4
4
 
5
- ### 書き方
6
-
7
- EPIC 本文のタスクリストに、次のどちらかの形で書く。
8
-
9
- ```md
10
- ## Progress
11
-
12
- - [ ] #101
13
- - [ ] joshuafolkken/app-kit#7
14
- - [ ] https://github.com/joshuafolkken/game-kit/issues/12
15
- ```
16
-
17
- **状態の読み取りにローカルチェックアウトは要らない。** そのリポジトリを指定した REST パス(`gh api repos/<owner>/<repo>/issues/<n>`)で読むため、クローンが必要になるのは実装の段になってからである。
18
-
19
- **owner の制限は joshuafolkken/kit#869 のものをそのまま継承する。** 現在のリポジトリと owner が異なるリポジトリの子は、いかなる経路でも対象にならない。
20
-
21
- ### 自動クローズ
22
-
23
- **他リポジトリの子の状態が全て読めた場合に限り**、EPIC は自動でクローズされる。1 件でも読めない子があれば従来どおり据え置かれる。「状態を読めないまま閉じない」という安全側の判断は変わっておらず、読む手段ができただけである。
24
-
25
- ### 別 repo への依存は「公開の完了」までを条件とする
26
-
27
- **`blocked-by` は相手 Issue が closed になれば解決するが、repo をまたぐ依存ではそれでは早すぎる。** kit の Issue が closed になった時点では npm への公開がまだ終わっていない(マージ → auto-tag → publish が非同期)。その瞬間に app-kit の子を着手可能と判定すると、まだ公開されていないバージョンを取りに行って失敗するか、古いバージョンのまま実装して壊れる。**放置すると「たまに壊れる」という最も診断しにくい形で出る。**
28
-
29
- - 同一 repo 内の依存 → 相手が closed で解決
30
- - **別 repo の子への依存 → 相手が closed + その repo が配布するパッケージの新バージョンが npm に出現、で解決**
31
-
32
- **評価は AND であり、順序が意味を持つ。** 相手が open のあいだは未解決と判定するだけで npm を見に行かない。EPIC 開始時から公開待ちで固まることはなく、「前の子が終わってから、公開されたら着手する」という待ち方になる。
33
-
34
- **待つ標的は具体的な版であり、「新しいバージョン」ではない。** 消費者が数バージョン遅れている場合、「今より新しい版が出た」を条件にすると目的の機能を含まない古い公開で満たされてしまう。相手 repo の default branch の `package.json` が持つバージョンを標的にする(`gh api` でローカルチェックアウト無しに読める)。**ただし子はもうバージョンを上げない**(joshuafolkken/kit#1486)。版が動くのは `pnpm josh release` が走ったときだけなので、標的は「子がマージされた直後の版」ではなく「その子を含むリリースが打たれた後の版」である。マージ直後の default branch の版は前回リリースのものなので、それを標的にすると待ちが即座に満たされてしまう。
35
-
36
- **ただし相手 repo が配布物を持たない場合は待たない**(joshuafolkken/kit#1129)。default branch に `package.json` が無い、あるいは `private` を宣言している repo は公開する版そのものが存在しないため、closed な blocker はそこで解決とする。待ち続けると実行上限の 8 時間まで抜けられず、しかも人が編集して解消できるものが無い。
37
-
38
- **この判定は相手 repo の manifest から読み、レジストリからは読まない。** レジストリの 404 は「公開されたことがない」だけでなく「このトークンからは見えない」(repo 名の変更、private パッケージ、`read:packages` 権限の欠如)も意味するため、それで解決としてしまうと、blocker の版がまだ公開されていないのに消費者側の子が着手してしまう。manifest の 404 にはその曖昧さが無い — その repo の Issue は既に読めているので権限は確認済みであり、無いのはファイルのほうである。読み取り自体の失敗は HTTP ステータスで区別し、従来どおり待つ。
39
-
40
- 公開待ちの判定は `josh propagate` の実装を共有する。二重定義を作らない。
41
-
42
- ### 実行のディスパッチ
43
-
44
- `josh epic:next` の出力は各候補の**対象リポジトリとローカルチェックアウトのパス**を含む。パスは joshuafolkken/kit#869 の地図から引く。**チェックアウトが無いリポジトリは、勝手に clone せず「ローカルチェックアウト無し」と表示する。**
45
-
46
- ### EPIC を別リポジトリから参照する
47
-
48
- **クロス repo の EPIC は 1 つの repo にしか存在しない。** app-kit のセッションから kit の EPIC を参照するときは `owner/repo#N` の形で修飾する。
49
-
50
- ```bash
51
- pnpm josh epic:next joshuafolkken/kit#858 --repo joshuafolkken/app-kit
52
- ```
53
-
54
- **裸の `#N` は自リポジトリの別 Issue に解決される** — 番号が同じだけの、まったく別の Issue である。したがってクロス repo の EPIC には必ず修飾を付ける。`backlogrun joshuafolkken/kit#858 --only` も同じ形。
5
+ 経緯(公開待ちが要る理由、joshuafolkken/kit#1129)は [`docs/maintainers/epic-commands-rationale.md`](../../docs/maintainers/epic-commands-rationale.md) にある。
@@ -1,56 +1,5 @@
1
1
  ## `josh epic:audit` — 子 Issue 群を横断して矛盾を検出する
2
2
 
3
- `pnpm josh epic:check` は epic **1 件の形式**を検査するが、**子 Issue 群を横断した整合性**は誰も検査していなかった。joshuafolkken/kit#858 の子を人手で監査したところ、実装を始めれば必ず詰まる矛盾が 2 件見つかり、その間ずっと `epic:check` は 4 要件すべて通過と報告していた。
3
+ **この規則の単一ソースは `.claude/skills/epic-commands/SKILL.md` → "`josh epic:audit <E>` — contradictions across the children" である。** 検査表、警告とエラーの区別、片方が closed の組を警告に降格する規則、孤児検索の 2 つの結果、Tier A の修正、計画時の波及先の点検はすべてそこにある。
4
4
 
5
- - **循環依存** — #863 の本文が「#864 の発見結果を使う」と書き、#864 の本文が「公開の判定は #863 と同一実装を共有する」と書いていた。どちらも `blocked-by` は空で、epic 本文は両方を「独立」と宣言していた
6
- - **順序矛盾** — #860 の受け入れ条件が #863 / #864 の成果物を要求していたが、依存グラフ上 #860 はその 2 件より先に走る
7
-
8
- 人が「バグを探して」と指示して初めて見つかる状態では、無人実行の前提が成り立たない。
9
-
10
- ### 検査項目
11
-
12
- グラフそのものの性質(循環依存、本文の宣言と `blocked-by` の食い違い)は `josh epic:next` が着手可否の計算のために既に検出しており、**その判定を利用する。検出を作り直さない。** 本コマンドが新たに担うのは、子 Issue の**本文の中身**を横断して読む 4 つと、そのうち孤立した子の検索が何を読めなかったかを報告する 2 つである。
13
-
14
- | 検査 | 種別 | 内容 |
15
- | ------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
16
- | 暗黙の依存 | 警告 | 子 A の本文が同じ epic の子 B を参照しているのに、どちら向きにも依存が宣言されていない |
17
- | 順序矛盾 | エラー | 子 A の**受け入れ条件**が子 B の成果物を参照しているのに、A が B に依存していない(先に走れる)。ただし A・B がどちらも closed なら警告に降格 |
18
- | 未解決の参照 | 警告 | 本文が参照する Issue が存在しない、または既にクローズ済み |
19
- | 孤立した子 | 警告 | epic を親として参照しているのに epic のタスクリストに載っていない Issue |
20
- | 孤児検索 | エラー | 上記を探すための open issue 一覧そのものが読めなかった(レート制限、認証切れ) |
21
- | 孤児検索 | 警告 | その検索が backlog の末尾に届く前に打ち切られた(500 件のページ上限、または 50 件の一致上限) |
22
-
23
- ### 警告とエラーを区別する
24
-
25
- **警告は exit code を左右せず、エラーだけが exit 1 になる。** 暗黙の依存の検査は「参照している」ことしか見ないため、後続の子への前方参照(「この部分は #864 が埋める」)にも当たる。これをエラーにすると正当な設計メモが書けなくなるので、**判断は読み手に委ね、機械は見落としを防ぐ側に徹する**。
26
-
27
- 一方、受け入れ条件が後から作られるものを要求している状態は誰がどう決めても満たせないため、エラーとする。
28
-
29
- ### 両端が closed の順序矛盾は警告に落とす
30
-
31
- 順序矛盾がエラーである根拠は「**先に走れてしまう**」という一点にある。子が 2 件とも closed になった時点でどちらにも実行が残っておらず、その根拠は成立しない。にもかかわらずエラーのままにすると、**過去に一度でも順序を宣言し忘れた EPIC は永久に監査を通らなくなる** — `backlogrun` は epic の最初の子より前に監査を走らせるため、その EPIC は再開のたびに一歩目で止まる。joshuafolkken/kit#908 で実際に起きており、同じ状態で `epic:next` は次の子を問題無く返していた。すなわち**エラーが止める根拠と、実際に実行を阻むかどうかが食い違っていた**(joshuafolkken/kit#1010)。
32
-
33
- **「報告しない」ではなく「警告に降格」を採る。** 受け入れ条件は本文の一部なので、同じ組は暗黙の依存の検査にも当たっており、順序矛盾がその組を報告している間だけ重複が抑止されている。落とせばその組は 1 行下に `implicit dependency` として現れるだけで、**出力は 1 行も短くならず**、「受け入れ条件に書かれている」という唯一読む価値のある情報だけが失われる。短さという利点が実在しない以上、履歴を残す側を採る。closed かどうかは**確認できた場合にのみ**降格する — `epic_issue.normalize_state` は `CLOSED` 以外(`MERGED` を含む)をすべて `OPEN` に写すため、確認できない状態はエラーのまま残る。
34
-
35
- ### 孤児検索の 2 件は「子の矛盾」ではない
36
-
37
- 孤立した子の検査は open issue を一覧して本文をクライアント側で照合する。**一覧が読めなかった場合、以前はそれが空の結果として届いていた** — レート制限が「孤児ゼロ」という綺麗な監査結果を生み、何も読んでいないことが出力から分からなかった(joshuafolkken/kit#1033)。
38
-
39
- - **`✖ orphan search: Could not list the open issues…`** — 検査そのものが走っていないので、`epic:audit` は exit 1 になり `backlogrun` は相 0 で止まる。**対応は監査の再実行だけ**で、直すべき矛盾も決めるべき設計判断も無い — 下記の Tier A にも `needs-decision` park にも当たらない。繰り返し失敗するなら `gh auth status` とレート制限の回復を確認する
40
- - **`⚠ orphan search: The open-issue scan hit its …`** — 検索は走ったが backlog の新しい側だけを見た(500 件のページ上限、または epic に言及する本文 50 件で打ち切り)。監査自体は通るので、行を読んだうえで、より古い位置に孤児が予想される場合だけ人手で確認する
41
-
42
- ### 実行される場所(人が指示しなくても回る)
43
-
44
- - **`backlogrun` の判断パスの前** — 一括決定の前に矛盾を洗い出す
45
- - **`backlogrun` が epic 項目を始めるとき** — 矛盾を抱えたまま無人実行を始めない
46
- - **子 Issue を追加した直後、依存を変更した直後**
47
-
48
- ### 検出した矛盾は Tier A(確認せず直す)
49
-
50
- 依存の付け直しも本文の記述修正も可逆であり、放置すれば必ず実装時に詰まる。**確認を挟む価値がないので、人に尋ねず修正して根拠を Issue に記録する。** 例外は「どちらの設計を採るべきかが決まらない」種類の矛盾で、これに限り該当の子に `needs-decision` を付けて park する。
51
-
52
- ### 波及先の点検(計画段階の手順)
53
-
54
- 機械的検査では捕まらない欠陥として、**新しい概念を導入したのに既存コードの参照箇所が更新されない**というものがある。#858 の監査では 3 件見つかった — `needs-decision` ラベルを導入するのに除外集合への追加担当が無かった、`epicrun` を導入するのに epic 本文が古いコマンドを案内し続ける点の担当が無かった、`in-progress` を付ける処理はあるが外す処理が無かった。
55
-
56
- したがって計画段階で次を行う。**新しいラベル・コマンド・状態・成果物を導入する子 Issue がある場合、既存コードでその概念を参照している箇所を列挙し、更新の担当がいずれかの子 Issue に割り当てられていることを確認する。** ラベル名は `scripts/git/issue-labels.ts` に単一ソース化されているので、そこを起点に消費者を辿れる。
5
+ 経緯(joshuafolkken/kit#858 の監査で見つかった矛盾と波及漏れ、joshuafolkken/kit#1010)は [`docs/maintainers/epic-commands-rationale.md`](../../docs/maintainers/epic-commands-rationale.md) にある。
@@ -1,109 +1,5 @@
1
1
  ## 後から関連が判明した Issue を epic に束ねる
2
2
 
3
- 「2 件以上に分割したら常に epic を作る」は既に効いているが、**発火するのは 1 つの要望をその場で分割したときだけ**である。別々のタイミングで起票された Issue が後から関連していると分かっても、束ねる仕組みが無い。次が漏れる。
3
+ **この規則の単一ソースは `.claude/skills/epic-commands/SKILL.md` → "`josh epic:bundle <N>` — does this new issue belong with one already filed?" である。** 発火点、強い信号、候補探索の範囲、決定木、所属先の記録、順序の記録、起票前の `issue:scout` はすべてそこにある。レビュー上限で切り出す後追い Issue の起票と答えへの対応は `prompts/review.md` → "Three-way disposition after the cap" が単一ソースである。
4
4
 
5
- - 実装中に Tier A で起票した Issue が、既存の open Issue と順序や依存を持っていた場合
6
- - 何日か空けて起票した 2 件が、実は同じ作業の前後だった場合
7
- - 既存 Issue が実行順を必要としていることに、後から気づいた場合
8
-
9
- いずれも束ねられないまま個別に実行され、順序が守られず、分割の根拠がどこにも残らない。
10
-
11
- ### 発火点
12
-
13
- **Issue を新規に起票した直後**に、既存の open Issue を調べる。`kickoff` / `fullrun` / `halfrun` が起票したとき、および実装中に Tier A で起票したとき(`backlogrun` 実行中を含む)。
14
-
15
- `pnpm josh epic:bundle <N>`(エイリアス `eb`)が候補を探して推奨を表示する。起票は `pnpm josh issue:file` で行い、このコマンドが最終段として `epic:bundle` を実行して答えを表示するので、別に呼ぶのは `⚠` で再実行を案内されたときだけである。**このコマンドは何も書き込まない** — 候補を出すのが機械、束ねるかを決めるのは AI である。
16
-
17
- ### 起票の「前」に答えるのは `issue:scout`
18
-
19
- `pnpm josh issue:scout "<title>"`(エイリアス `isc`)は、まだ存在しない Issue について同じ配属先の問いに答える(joshuafolkken/kit#1252)。**配属の判定は `epic:bundle` のものをそのまま呼んでおり、実装は 1 つしかない。** 加えて、`epic:bundle` が意図的に採らないシグナル — タイトルの語の重なりによる**重複候補** — を返す。既存 Issue の束ね直しに似た見出しが立つのは強シグナルだけで十分だからだが、「もう起票されていないか」は起票前にしか意味を持たない別の問いであり、しきい値を混ぜていない。
20
-
21
- **両方を実行する。順番が違うだけである。** どちらも `pnpm josh issue:file` が 1 回の呼び出しの中で実行する。
22
-
23
- | いつ | コマンド | 何について答えるか |
24
- | -------------- | ----------------------- | -------------------------------------------------- |
25
- | 起票の**前** | `issue:scout "<title>"` | まだ番号を持たない下書き。タイトルと本文がある |
26
- | 起票の**直後** | `epic:bundle <N>` | 実在する Issue。番号と、それに記録された関係がある |
27
-
28
- 手順上の位置づけと、重複候補が見つかったときに起票せず止まる規則は `.claude/skills/workflow-commands/SKILL.md` → §2e が単一ソースである。
29
-
30
- ### 後追い Issue は起票した直後に EPIC へ束ね直す
31
-
32
- レビュー上限(`prompts/review.md` → "Review round cap")で切り出す後追い Issue は、**このワークフローで最も件数の多い起票経路**である。それでも手順は長らく「起票して現在の Issue を参照する」までしか定めておらず、束ね直しへの導線が無かった。手順どおりに読むと起票して次へ進んで終わる。
33
-
34
- なお 2 巡目を終えた残指摘は、いまは**3 分岐(その場で直す/起票する/PR に 1 行残して落とす)**に振り分ける(`prompts/review.md` → "Review round cap")。本節が扱うのは**起票する**分岐に入ったものだけであり、その場で直したものと落としたものは Issue にならないので束ね直しの対象にもならない。
35
-
36
- **既定は「PR に 1 行残して落とす」側であり、起票する分岐は runtime path に届く確定バグに限る**(joshuafolkken/kit#1469)。この経路はバックログ純増の 3 つの製造元のうち最も件数が多かったため、既定を落とす側へ置き直した。したがって本節が発火する回数自体が以前より少ない — それは手順の省略ではなく、既定が変わった結果である。単一ソースは `prompts/review.md` → "Three-way disposition after the cap"。
37
-
38
- 手順は 3 段であり、**上の発火点の一適用ではなく、後追い起票の手順そのものに書く**。別の文書を読みに行く前提にしない。
39
-
40
- **3 段は CI 待ちの中で実行する。コミットの前ではない。** PR を開くフロー(`fullrun` / `backlogrun`)では `pnpm josh git -y` の後・`pnpm josh followup` の前に置く。PR を開かないフロー(`halfrun`、ワークフロー外のコミット前セルフレビュー)では、隠れる先の CI が無いので振り分けが決まった時点で実行する。**期限は変わらない** — 現在の Issue が閉じるのはマージ時点であり、マージするのは `followup` なので、どの段も親が open のうちに終わる。第 2 段が要求しているのはそれだけである。変わるのは秒が誰のものかだけで、実測では `epic:bundle` 43 秒・`epic --add` 18 秒(joshuafolkken/kit#1229)に対し、joshuafolkken/kit#1238 の `followup` は 122 秒のうち 78 秒を CI の完了待ちに費やしている(joshuafolkken/kit#1239)。
41
-
42
- **これは「レビューを CI と並走させる」ではない。**(ここで言うレビューは 1 周目のことであり、2 周目については下の段落で別に扱う。) joshuafolkken/kit#1216 の (b) は不採用と決定済みであり、却下の理由は規則ではなく仕組みである — あちらは**コードを変える作業**を CI と重ねるため、修正を push するたびに CI がやり直しになり、重ねた分をそのまま払い戻す。起票はコードを 1 行も変えないので、走っている CI がそのまま使える。**1 周目のレビュー**はコミットの前のままで、「コミット前セルフレビュー」は書き換えていない。**2 周目だけは CI と並走する**(joshuafolkken/kit#1261)— 同じ仕組みを逆から読んだ結果であり、2 周目は fix delta しか読まず、通常はコードを 1 行も変えない。変えた場合は同一ブランチへの追加コミット 1 つと CI のやり直し 1 回を払う。単一ソースは `.claude/skills/workflow-commands/chain-rule.md` → "The pull request opens between the rounds, so CI runs beside round 2"。
43
-
44
- 1. 残指摘を後追い Issue として起票し、現在の Issue を参照する。起票は `pnpm josh issue:file "<title>" --body-file <本文ファイル> --depth <n> --route review-cap` で行う
45
- 2. **現在の Issue が閉じる前に**起票する。`issue:file` が新規 Issue について `epic:bundle` を実行する。候補探索は open Issue しか読まないため、親が閉じた後では恒久的に `none` になる(joshuafolkken/kit#947)
46
- 3. 答えに従う。**`epic:bundle` は推奨するだけで何も書き込まない**ので、「実行する」とは書き込みコマンドを自分で打つことである。**epic 本文の手編集は禁止** — タスクリストと `blocked-by` が食い違い、`epic:next` が `error` を返す
47
-
48
- | 答え | すること | Tier |
49
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
50
- | `add_to_epic` | `pnpm josh epic --add <E> <新規>`(順序があるなら `--before <M>` / `--after <M>`) | **A — 確認不要** |
51
- | `create_epic` | `pnpm josh epic "<title>" <新規> <相手> [--ordered]` | **A — 確認不要** |
52
- | `ask`(候補が複数の EPIC に散っている) | **推奨する epic を自分で選び、書き込みコマンドを実行し、採用・却下・理由・決定日を新規 Issue とその epic の `## Decisions` の両方に記録する。停止もせず park もしない**(joshuafolkken/kit#1339)。2 つの epic が本当に甲乙つけがたいときだけ止める | **A — 確認不要** |
53
- | `none` | 何もしない | — |
54
- | **`Could not confirm which epic already tracks these — do not place this issue in one.`** — epic 一覧が打ち切られていたときの答えで、**Issue を epic に入れる 3 つの答え(`add_to_epic` / `create_epic` / `ask`)すべてに代わって出る**。いずれも「この Issue をまだどの epic も追跡していない」を前提にしており、打ち切られた一覧ではそれを確かめられない。子と宣言順は**意図的に出ない**(それはこの行がするなと言っている配属のレシピそのものだから)(joshuafolkken/kit#1697) | **epic に入れない。** 一覧を最後まで読める状態にしてから訊き直すか、何と言ったかを添えて停止・報告する。`Already in an epic`(追跡している epic を実際に読めた答え)は打ち切りがあっても有効なままである | — |
55
- | **コマンドが答えられなかった** — 非ゼロ終了、または `Nothing to bundle.` の上に出た**あらゆる** ⚠ 警告(一覧の打ち切り、関係を読めなかった Issue)。記録済みの依存は 2 つある強い信号の片方なので、関係の読み取り失敗は本来の `add_to_epic` を `none` に化けさせる。断定的な答え(`Already in an epic` / `Add it to the epic …`)は警告が併記されていても有効である | 何と言ったかを添えて停止・報告する。**警告の後の `none` は「束ねる相手が無い」ではない** — 探索が不完全なのであり、答えとして読むと本規則が塞ごうとしている経路そのもので Issue が EPIC 無しになる(joshuafolkken/kit#950) | — |
56
-
57
- **`none` は正当な答えである。** コミット前セルフレビューをワークフローの外で回した場合、現在の Issue が存在せず参照先が無いため候補は出ない。そのときは束ねずにバックログへ残す — 手順が求めるのは「コマンドを実行して答えに従うこと」であって、必ず EPIC に入れることではない。
58
-
59
- **逆に、実行せずに起票だけで終えると、指摘は落ちるのではなく永久に park される。** `epic:next` が返すのは EPIC のタスクリストにある子だけなので、どの EPIC にも属さない Issue は実行中の `backlogrun` に一度も渡らない(拾うには番号を知っている人が要る)。バックログから見れば「落ちた」のと区別が付かない。
60
-
61
- 実測である。joshuafolkken/kit#943 は 2 回目のレビューから切り出され、本文に `親: joshuafolkken/kit#891` と明記していながら、どの EPIC の子にもなっていなかった。親 #891 が閉じたのはその 3 分後である。同じ経路でも手順が実行された joshuafolkken/kit#911 では `epic:bundle` が EPIC を名指しし、そのまま追加されている。**差は、コマンドを打ったかどうかだけだった**(joshuafolkken/kit#946)。
62
-
63
- なお **#943 の取りこぼしには 2 層目の原因もある** — 起票が親の close より後になると、`epic:bundle` の候補探索が open Issue しか読まないため恒久的に `Nothing to bundle.` を返す。そちらは joshuafolkken/kit#947 が扱う。本節が直すのは「手順が守られなかった」側だけである。
64
-
65
- ### 強い信号だけを根拠にする
66
-
67
- - 本文の相互参照(新規 Issue が既存を参照している、または既存が新規を参照している)
68
- - 既存の `blocked-by` 関係
69
-
70
- **タイトル・本文の内容的な類似は、それだけでは束ねる根拠にしない。** 「関連している」は際限なく広がるため、閾値を持たないと無関係な Issue まで巻き込む。類似は AI の判断を補強する材料に留める。
71
-
72
- **候補探索は open backlog に限らない。** 対象 Issue の本文が名指ししている番号は、状態を問わず 1 件ずつ読む。open 限定のままだと、後追い Issue が起票されてから親が close するまでの数分間しか正しく答えられない(joshuafolkken/kit#943 では約 3 分。過ぎると `Nothing to bundle.` を exit 0 で返し、「読めなかった」ではなく「無かった」と断定していた)。
73
-
74
- - **closed の参照先は、open な EPIC が既に追跡している場合にのみ候補にする。** 回収したい答えは `add_to_epic` である。閉じた Issue を子に持つ新規 EPIC は実行するものが残っていない
75
- - **open の参照先は無条件に候補にする。** 一覧に出てこなかったのは一覧が打ち切られたからであって、無関係だからではない
76
- - 追加読み取りは参照 1 件につき 1 リクエストで、件数に上限があり、関係の読み取りと同じ形でバッチ化される。**読み取りの失敗も、上限で読まなかった参照も、欠落として報告し「強い信号なし」に畳み込まない** — 黙って打ち切る guard は、「見るのをやめた」を「関係が無かった」と言い換える元の欠陥そのものである
77
- - **番号が pull request だった場合は候補にしない。** REST の issue エンドポイントは PR にも答え、マージ済み PR の state は `CLOSED` ではないため、この判定が無いと「修正は #952 で入った」という散文が PR を新規 EPIC の子に混ぜる
78
- - **実在しない番号は欠落として報告しない。** 打ち間違いや他リポジトリの番号のように GitHub が何にも解決できない参照は、候補にも欠落にも入れず黙って捨てる。これを欠落として報告すると、散文中の `#N` が 1 つ狂っただけで `⚠ Could not read #N.` が verdict の上に出て、上の「打ち切り警告の後の `Nothing to bundle.` は答えではない」規則により**無人実行が停止する** — 存在したことのない参照のために人を呼ぶことになる(joshuafolkken/kit#957)
79
- - **その判別は `gh` のエラー文言ではなく HTTP ステータスコードで行う。** 実在しない番号は REST で **404**、レート制限は **403 / 429** である。GitHub は権限の無い Issue にも存在を漏らさないため 403 ではなく 404 を返すので両者はステータスからは原理的に区別できないが、このコマンドは **直前に open 一覧を取得したのと同じリポジトリ**を叩くため、そこで見えない番号は存在しない番号である。`gh api` の失敗はステータスコードではなく stderr の文言として届くため、**読み取りが失敗したときにだけ** REST を 1 回叩いて分類する。成功経路と、この区別を必要としない呼び出し元には追加リクエストは発生しない — バックログの関係読み取りは最大 200 件あり、レート制限で全滅したときにさらに 200 リクエストを撃つことになるためである。分類する経路は参照の上限(20 件)で抑えられている
80
- - 追うのは対象 Issue 自身の本文だけである。逆方向(閉じた Issue が対象を名指しする)は closed 全件走査になり、かつ不要である — 後追い Issue が親を名指しするのは起票手順そのものだからである
81
-
82
- 候補探索の解析は `josh epic:audit` の「暗黙の依存」検査と**同一の実装を共有する**。あちらは epic 内に閉じた解析、こちらはバックログ全体への適用というだけで、読む対象は同じ「本文中の Issue 参照」である。同じ解析を 2 回書かない。
83
-
84
- ### 決定木(「常に新規 epic を作る」ではない)
85
-
86
- Issue は 1 つの epic にしか属せない(タスクリストで追跡されるため)。したがって分岐が要る。
87
-
88
- | 状況 | 動作 | Tier |
89
- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ---- |
90
- | **新規 Issue 自身が既に epic の子** | 何もしない。Issue は 1 つの epic にしか属せず、epic 間の移動はこのルールの担当ではない | — |
91
- | 関連候補が**既に epic の子** | **その epic に追加**する(新規 epic を作らない) | A |
92
- | 候補が **epic とその親 epic** に分かれている | **内側(子)の epic に追加**する。親は既に子を含んでいる | A |
93
- | 候補が**複数の異なる epic** に散っている | **推奨する epic を選んで追加し、理由を記録する** | A |
94
- | どの epic にも属さない候補があり、新規 Issue と合わせて **2 件以上** | **新規 epic を作って束ねる** | A |
95
- | 強い信号を持つ候補が無い | 何もしない | — |
96
-
97
- 束ねるのは可逆(epic は編集でき、子は外せる)なので Tier A で確認を挟まない。**所属先の選択も同じく Tier A である** — `epic --add` 1 回で別の epic に移せるため、候補が複数の epic に散っていても止まらず、推奨する 1 つを選んで理由を記録する(joshuafolkken/kit#1339)。
98
-
99
- **所属先を選ぶことは epic の統合ではない。** epic 同士の統合は誰も提案していない別の操作であり、本当に必要なら**そのときに**改めて人に聞けばよい。**記録が自律の対価である** — 採用・却下・理由・決定日を残さない自動決定は、後から誰も辿れない決定を下しただけになる。
100
-
101
- **入れ子の親子関係では、この答えはもう出ない**(joshuafolkken/kit#1079)。親 epic は既に子 epic を含んでいるので、両者は選ぶべき対等な 2 択ではない。したがって関与する epic のうち**他の関与 epic の祖先にあたるものを落とし**、内側の 1 件が残ればそこへ追加する。この誤検出は 3 件記録されており、うち 1 件は実装が完了しレビューも収束し PR も mergeable だった Issue のバッチを丸ごと止めた。**落とすのは親だけで、対等な epic は落とさない** — 入れ子の連鎖の横に無関係な epic が 1 つあれば依然として尋ねるし、親子宣言が循環していて内側が定まらない場合も絞り込まずに尋ねる。
102
-
103
- ### 束ねたら順序も記録する
104
-
105
- 関連が順序を含む場合、`blocked-by` を付与し、epic 本文の `Dependencies` にも矢印記法で書く。既存 epic への追加時も同じ。**順序を記録しないと、束ねた事実だけが残って束ねた理由が消える。** ただし**誰も宣言していない順序をここで捏造しない** — 既に宣言されている関係だけを引き継ぐ。
106
-
107
- ### 規模
108
-
109
- 実測で open Issue は十数件であり、全件を舐めても一瞬なので**索引やキャッシュは用意しない**。件数が問題になってから考える。
5
+ 経緯(joshuafolkken/kit#943 / #946 / #947 の取りこぼし、CI 待ちに起票を置く根拠の計測)は [`docs/maintainers/epic-commands-rationale.md`](../../docs/maintainers/epic-commands-rationale.md) にある。