@erclx/canon 5.45.0 → 5.47.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 (158) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/api-design/REQUIREMENT.md +15 -31
  3. package/claude/skills/auto-ship/REQUIREMENT.md +14 -25
  4. package/claude/skills/backlog-triage/REQUIREMENT.md +12 -23
  5. package/claude/skills/build-in-slices/REQUIREMENT.md +15 -25
  6. package/claude/skills/canon-cli/REQUIREMENT.md +15 -27
  7. package/claude/skills/canon-feedback/REQUIREMENT.md +10 -18
  8. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +10 -15
  9. package/claude/skills/canvas-board/REQUIREMENT.md +14 -28
  10. package/claude/skills/ci-workflow/REQUIREMENT.md +12 -21
  11. package/claude/skills/code-craft/REQUIREMENT.md +14 -28
  12. package/claude/skills/codebase-layout/REQUIREMENT.md +14 -31
  13. package/claude/skills/context-fold/REQUIREMENT.md +15 -39
  14. package/claude/skills/context-fold/references/context.md +3 -3
  15. package/claude/skills/create-rule/REQUIREMENT.md +10 -24
  16. package/claude/skills/create-rule/SKILL.md +3 -0
  17. package/claude/skills/create-skill/REQUIREMENT.md +10 -21
  18. package/claude/skills/decision-escalate/REQUIREMENT.md +12 -24
  19. package/claude/skills/deploy-app/REQUIREMENT.md +12 -22
  20. package/claude/skills/deprecation-migration/REQUIREMENT.md +14 -42
  21. package/claude/skills/design-identity/REQUIREMENT.md +14 -20
  22. package/claude/skills/design-taste/REQUIREMENT.md +16 -57
  23. package/claude/skills/docs-sync/REQUIREMENT.md +14 -23
  24. package/claude/skills/document-health/REQUIREMENT.md +15 -29
  25. package/claude/skills/document-health/SKILL.md +2 -2
  26. package/claude/skills/document-repair/REQUIREMENT.md +32 -0
  27. package/claude/skills/document-repair/SKILL.md +76 -0
  28. package/claude/skills/document-repair/references/batches.md +44 -0
  29. package/claude/skills/draft-and-pick/REQUIREMENT.md +4 -3
  30. package/claude/skills/draft-doc/REQUIREMENT.md +4 -3
  31. package/claude/skills/draft-figure/REQUIREMENT.md +4 -3
  32. package/claude/skills/draft-identity/REQUIREMENT.md +4 -3
  33. package/claude/skills/draft-ready/REQUIREMENT.md +4 -3
  34. package/claude/skills/draft-screencast/REQUIREMENT.md +4 -3
  35. package/claude/skills/draft-slides/REQUIREMENT.md +4 -3
  36. package/claude/skills/draw-figure/REQUIREMENT.md +15 -39
  37. package/claude/skills/git-branch/REQUIREMENT.md +12 -26
  38. package/claude/skills/git-commit/REQUIREMENT.md +11 -15
  39. package/claude/skills/git-followup/REQUIREMENT.md +11 -22
  40. package/claude/skills/git-followup/SKILL.md +1 -0
  41. package/claude/skills/git-issue/REQUIREMENT.md +9 -15
  42. package/claude/skills/git-pr/REQUIREMENT.md +13 -32
  43. package/claude/skills/git-pr/SKILL.md +11 -2
  44. package/claude/skills/git-pr/references/closing-issues.md +47 -0
  45. package/claude/skills/git-pr/references/pr.md +62 -7
  46. package/claude/skills/git-ship/REQUIREMENT.md +13 -26
  47. package/claude/skills/git-split/REQUIREMENT.md +10 -17
  48. package/claude/skills/git-stage/REQUIREMENT.md +12 -18
  49. package/claude/skills/git-worktree/REQUIREMENT.md +15 -19
  50. package/claude/skills/make-deck/REQUIREMENT.md +13 -21
  51. package/claude/skills/markdown-craft/REQUIREMENT.md +9 -3
  52. package/claude/skills/plan-feature/REQUIREMENT.md +15 -24
  53. package/claude/skills/plan-groundwork/REQUIREMENT.md +12 -28
  54. package/claude/skills/plan-groundwork/SKILL.md +5 -2
  55. package/claude/skills/plan-groundwork/references/output.md +47 -1
  56. package/claude/skills/plan-intake/REQUIREMENT.md +11 -26
  57. package/claude/skills/plan-intake/references/intake.md +2 -2
  58. package/claude/skills/plan-intake-answer/REQUIREMENT.md +14 -29
  59. package/claude/skills/plan-intake-answer/SKILL.md +7 -1
  60. package/claude/skills/plan-ready/REQUIREMENT.md +17 -36
  61. package/claude/skills/pr-evidence/REQUIREMENT.md +11 -17
  62. package/claude/skills/read-frames/REQUIREMENT.md +3 -8
  63. package/claude/skills/record-screencast/REQUIREMENT.md +14 -17
  64. package/claude/skills/review-address/REQUIREMENT.md +14 -38
  65. package/claude/skills/review-address/SKILL.md +18 -6
  66. package/claude/skills/review-address/references/post-review-findings.md +4 -1
  67. package/claude/skills/review-address/references/rebase-only.md +14 -2
  68. package/claude/skills/review-craft/REQUIREMENT.md +14 -32
  69. package/claude/skills/review-pr/REQUIREMENT.md +15 -34
  70. package/claude/skills/review-pr/SKILL.md +9 -2
  71. package/claude/skills/review-pr/references/body-variants.md +29 -8
  72. package/claude/skills/review-pr/references/post.md +29 -10
  73. package/claude/skills/review-ui/REQUIREMENT.md +14 -39
  74. package/claude/skills/review-ui/SKILL.md +1 -0
  75. package/claude/skills/review-ui/references/post.md +2 -0
  76. package/claude/skills/review-ui/references/tick.md +3 -0
  77. package/claude/skills/role-orchestrator/REQUIREMENT.md +2 -2
  78. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +5 -0
  79. package/claude/skills/role-orchestrator/references/orchestrator-review-dispatch.md +9 -0
  80. package/claude/skills/role-reviewer/REQUIREMENT.md +15 -65
  81. package/claude/skills/role-reviewer/SKILL.md +8 -1
  82. package/claude/skills/role-worker/REQUIREMENT.md +2 -2
  83. package/claude/skills/role-worker/SKILL.md +3 -0
  84. package/claude/skills/script-screencast/REQUIREMENT.md +10 -16
  85. package/claude/skills/search-craft/REQUIREMENT.md +12 -36
  86. package/claude/skills/search-craft/SKILL.md +1 -1
  87. package/claude/skills/search-craft/references/adopted.md +2 -2
  88. package/claude/skills/session-compact/REQUIREMENT.md +13 -23
  89. package/claude/skills/session-map/REQUIREMENT.md +13 -29
  90. package/claude/skills/session-relay/REQUIREMENT.md +14 -58
  91. package/claude/skills/session-relay/SKILL.md +6 -0
  92. package/claude/skills/session-resume/REQUIREMENT.md +13 -27
  93. package/claude/skills/session-worktree/REQUIREMENT.md +14 -43
  94. package/claude/skills/systematic-debugging/REQUIREMENT.md +13 -34
  95. package/claude/skills/target-check/REQUIREMENT.md +16 -23
  96. package/claude/skills/target-setup/REQUIREMENT.md +11 -34
  97. package/claude/skills/task-board/REQUIREMENT.md +13 -22
  98. package/claude/skills/task-board/SKILL.md +7 -0
  99. package/claude/skills/task-board/references/decline.md +2 -2
  100. package/claude/skills/task-board/references/tasks.md +1 -1
  101. package/claude/skills/task-complete/REQUIREMENT.md +11 -24
  102. package/claude/skills/task-complete/references/archive.md +4 -2
  103. package/claude/skills/teach-workspace/REQUIREMENT.md +14 -45
  104. package/claude/skills/test-craft/REQUIREMENT.md +15 -46
  105. package/claude/skills/test-first/REQUIREMENT.md +14 -20
  106. package/claude/skills/ui-checklist/REQUIREMENT.md +14 -29
  107. package/claude/skills/ui-checklist/SKILL.md +3 -3
  108. package/claude/skills/ux-audit/REQUIREMENT.md +3 -7
  109. package/claude/skills/ux-measure/REQUIREMENT.md +14 -28
  110. package/claude/skills/video-craft/REQUIREMENT.md +14 -27
  111. package/claude/skills/write-doc/REQUIREMENT.md +14 -24
  112. package/claude/skills/write-human/REQUIREMENT.md +15 -27
  113. package/claude/skills/youtube-transcripts/REQUIREMENT.md +9 -15
  114. package/docs/agents/context-audit.md +19 -12
  115. package/docs/agents/markdown-audit.md +15 -10
  116. package/docs/target/projects.md +2 -0
  117. package/docs/workflow/skill-map.md +6 -5
  118. package/docs/workflow/zshrc-aliases.md +3 -0
  119. package/governance/renames.toml +0 -2
  120. package/governance/rules/claude/output.md +5 -1
  121. package/governance/rules/code/routing.md +5 -1
  122. package/governance/stacks/base.toml +0 -1
  123. package/package.json +1 -1
  124. package/scripts/core/bootstrap.sh +1 -0
  125. package/src/claude/cases/workflow.ts +12 -0
  126. package/src/commands/context.ts +57 -3
  127. package/src/commands/labels.ts +149 -4
  128. package/src/commands/markdown.ts +188 -21
  129. package/src/commands/pr.ts +113 -4
  130. package/src/commands/sessions.ts +58 -11
  131. package/src/commands/tasks.ts +182 -0
  132. package/src/commands/worktrees.ts +2 -0
  133. package/src/context/coverage.ts +210 -0
  134. package/src/context/gate.ts +12 -3
  135. package/src/gate/stages.ts +1 -1
  136. package/src/init/steps.ts +45 -0
  137. package/src/intake/items.ts +14 -0
  138. package/src/labels/closing.ts +46 -0
  139. package/src/labels/density.ts +363 -0
  140. package/src/markdown/gated.ts +250 -0
  141. package/src/markdown/scope.ts +115 -2
  142. package/src/migrate/rename.ts +6 -0
  143. package/src/pr/evidence.ts +1 -1
  144. package/src/pr/rest.ts +2 -0
  145. package/src/pr/tick.ts +89 -0
  146. package/src/sessions/claim.ts +7 -0
  147. package/src/sessions/live.ts +79 -6
  148. package/src/sessions/registry.ts +11 -0
  149. package/src/sessions/resolve.ts +85 -7
  150. package/src/tasks/archive.ts +15 -4
  151. package/src/tasks/closes.ts +136 -0
  152. package/src/tasks/record.ts +1 -1
  153. package/src/worktrees/reclaim.ts +16 -1
  154. package/tooling/base/configs/scripts/verify.ts +1 -1
  155. package/tooling/base/seeds/.github/pull_request_template.md +1 -1
  156. package/tooling/claude/seeds/.claude/hooks/board-validate.sh +1 -1
  157. package/tooling/claude/seeds/CLAUDE.md +2 -2
  158. package/governance/rules/canon/task-scope.md +0 -12
@@ -36,12 +36,27 @@ const DENSITY_SCOPE = [
36
36
  /^(?:README|CONTRIBUTING)\.md$/,
37
37
  ]
38
38
 
39
+ /**
40
+ * The roots `canon init` gates in a new project when each passes at init time:
41
+ * every density surface a target authors itself, leaving out the toolkit's own
42
+ * `claude/skills/` and `tooling/` trees.
43
+ */
44
+ export const GATED_SCOPE_ROOTS: readonly string[] = [
45
+ 'canon/context/',
46
+ 'docs/',
47
+ '.claude/skills/',
48
+ 'wiki/',
49
+ 'README.md',
50
+ 'CONTRIBUTING.md',
51
+ ]
52
+
39
53
  /**
40
54
  * The path prefixes whose density findings fail a run, each added by the
41
55
  * rewrite batch that brought its folders to zero.
42
56
  *
43
57
  * It describes this repository's rewrite progress and nothing about a target's
44
- * corpus, which is why the audit reads it only inside a canon checkout.
58
+ * corpus, which is why the audit reads it only inside a canon checkout. A
59
+ * target keeps its own list in the file `src/markdown/gated.ts` reads.
45
60
  */
46
61
  export const GATED_PATHS: readonly string[] = [
47
62
  'canon/context/surfaces/',
@@ -50,8 +65,10 @@ export const GATED_PATHS: readonly string[] = [
50
65
  'canon/context/features/',
51
66
  'canon/context/context-model.md',
52
67
  'canon/context/index.md',
68
+ 'claude/skills/api-design/REQUIREMENT.md',
53
69
  'claude/skills/api-design/SKILL.md',
54
70
  'claude/skills/api-design/references/adopted.md',
71
+ 'claude/skills/auto-ship/REQUIREMENT.md',
55
72
  'claude/skills/auto-ship/SKILL.md',
56
73
  'claude/skills/auto-ship/references/draft-mark.md',
57
74
  'claude/skills/auto-ship/references/failure-recovery.md',
@@ -60,33 +77,45 @@ export const GATED_PATHS: readonly string[] = [
60
77
  'claude/skills/auto-ship/references/ui-checklist.md',
61
78
  'claude/skills/auto-ship/references/verb-absent.md',
62
79
  'claude/skills/auto-ship/references/worktree-name.md',
80
+ 'claude/skills/backlog-triage/REQUIREMENT.md',
63
81
  'claude/skills/backlog-triage/SKILL.md',
64
82
  'claude/skills/backlog-triage/references/apply.md',
83
+ 'claude/skills/build-in-slices/REQUIREMENT.md',
65
84
  'claude/skills/build-in-slices/SKILL.md',
66
85
  'claude/skills/build-in-slices/references/adopted.md',
86
+ 'claude/skills/canon-cli/REQUIREMENT.md',
67
87
  'claude/skills/canon-cli/SKILL.md',
88
+ 'claude/skills/canon-feedback-triage/REQUIREMENT.md',
68
89
  'claude/skills/canon-feedback-triage/SKILL.md',
90
+ 'claude/skills/canon-feedback/REQUIREMENT.md',
69
91
  'claude/skills/canon-feedback/SKILL.md',
70
92
  'claude/skills/canon-feedback/references/template.md',
93
+ 'claude/skills/canvas-board/REQUIREMENT.md',
71
94
  'claude/skills/canvas-board/SKILL.md',
72
95
  'claude/skills/canvas-board/references/canvas.md',
73
96
  'claude/skills/canvas-board/references/design.md',
97
+ 'claude/skills/ci-workflow/REQUIREMENT.md',
74
98
  'claude/skills/ci-workflow/SKILL.md',
75
99
  'claude/skills/ci-workflow/references/workflows.md',
100
+ 'claude/skills/code-craft/REQUIREMENT.md',
76
101
  'claude/skills/code-craft/SKILL.md',
77
102
  'claude/skills/code-craft/references/adopted.md',
103
+ 'claude/skills/codebase-layout/REQUIREMENT.md',
78
104
  'claude/skills/codebase-layout/SKILL.md',
79
105
  'claude/skills/codebase-layout/references/adopted.md',
80
106
  'claude/skills/codebase-layout/references/frontend.md',
81
107
  'claude/skills/codebase-layout/references/tests.md',
108
+ 'claude/skills/context-fold/REQUIREMENT.md',
82
109
  'claude/skills/context-fold/SKILL.md',
83
110
  'claude/skills/context-fold/references/classify.md',
84
111
  'claude/skills/context-fold/references/completion-report.md',
85
112
  'claude/skills/context-fold/references/context-refresh.md',
86
113
  'claude/skills/context-fold/references/context.md',
87
114
  'claude/skills/context-fold/references/unusable-baseline.md',
115
+ 'claude/skills/create-rule/REQUIREMENT.md',
88
116
  'claude/skills/create-rule/SKILL.md',
89
117
  'claude/skills/create-rule/references/rule.md',
118
+ 'claude/skills/create-skill/REQUIREMENT.md',
90
119
  'claude/skills/create-skill/SKILL.md',
91
120
  'claude/skills/create-skill/references/skill-disclosure.md',
92
121
  'claude/skills/create-skill/references/skill-frontmatter.md',
@@ -95,12 +124,16 @@ export const GATED_PATHS: readonly string[] = [
95
124
  'claude/skills/create-skill/references/skill-reference.md',
96
125
  'claude/skills/create-skill/references/skill-requirement.md',
97
126
  'claude/skills/create-skill/references/skill.md',
127
+ 'claude/skills/decision-escalate/REQUIREMENT.md',
98
128
  'claude/skills/decision-escalate/SKILL.md',
129
+ 'claude/skills/deploy-app/REQUIREMENT.md',
99
130
  'claude/skills/deploy-app/SKILL.md',
100
131
  'claude/skills/deploy-app/references/cloudflare.md',
101
132
  'claude/skills/deploy-app/references/vercel.md',
133
+ 'claude/skills/deprecation-migration/REQUIREMENT.md',
102
134
  'claude/skills/deprecation-migration/SKILL.md',
103
135
  'claude/skills/deprecation-migration/references/adopted.md',
136
+ 'claude/skills/design-taste/REQUIREMENT.md',
104
137
  'claude/skills/design-taste/SKILL.md',
105
138
  'claude/skills/design-taste/references/adopted.md',
106
139
  'claude/skills/design-taste/references/craft.md',
@@ -109,14 +142,27 @@ export const GATED_PATHS: readonly string[] = [
109
142
  'claude/skills/design-taste/references/systems.md',
110
143
  'claude/skills/design-taste/references/tells.md',
111
144
  'claude/skills/design-taste/references/vocabulary.md',
145
+ 'claude/skills/docs-sync/REQUIREMENT.md',
112
146
  'claude/skills/docs-sync/SKILL.md',
113
147
  'claude/skills/docs-sync/references/docs.md',
114
148
  'claude/skills/docs-sync/references/readme.md',
149
+ 'claude/skills/document-health/REQUIREMENT.md',
115
150
  'claude/skills/document-health/SKILL.md',
116
151
  'claude/skills/document-health/references/axes.md',
152
+ 'claude/skills/document-repair/REQUIREMENT.md',
153
+ 'claude/skills/document-repair/SKILL.md',
154
+ 'claude/skills/document-repair/references/batches.md',
155
+ 'claude/skills/draft-and-pick/REQUIREMENT.md',
156
+ 'claude/skills/draft-doc/REQUIREMENT.md',
157
+ 'claude/skills/draft-figure/REQUIREMENT.md',
158
+ 'claude/skills/draft-identity/REQUIREMENT.md',
159
+ 'claude/skills/draft-ready/REQUIREMENT.md',
160
+ 'claude/skills/draft-screencast/REQUIREMENT.md',
161
+ 'claude/skills/draft-slides/REQUIREMENT.md',
117
162
  'claude/skills/pick-by-eye/REQUIREMENT.md',
118
163
  'claude/skills/pick-by-eye/SKILL.md',
119
164
  'claude/skills/pick-by-eye/references/live-arms.md',
165
+ 'claude/skills/write-doc/REQUIREMENT.md',
120
166
  'claude/skills/write-doc/SKILL.md',
121
167
  'claude/skills/write-doc/references/context.md',
122
168
  'claude/skills/write-doc/references/docs.md',
@@ -129,76 +175,102 @@ export const GATED_PATHS: readonly string[] = [
129
175
  'claude/skills/write-doc/references/requirements.md',
130
176
  'claude/skills/write-doc/references/wiki-kind.md',
131
177
  'claude/skills/write-doc/references/wiki.md',
178
+ 'claude/skills/draw-figure/REQUIREMENT.md',
132
179
  'claude/skills/draw-figure/SKILL.md',
133
180
  'claude/skills/draw-figure/references/architecture-set.md',
134
181
  'claude/skills/draw-figure/references/figures.md',
135
182
  'claude/skills/draw-figure/references/hand-drawn.md',
136
183
  'claude/skills/draw-figure/references/mermaid-path.md',
137
184
  'claude/skills/draw-figure/references/mermaid.md',
185
+ 'claude/skills/design-identity/REQUIREMENT.md',
138
186
  'claude/skills/design-identity/SKILL.md',
139
187
  'claude/skills/design-identity/references/card-route.md',
188
+ 'claude/skills/plan-ready/REQUIREMENT.md',
140
189
  'claude/skills/plan-ready/SKILL.md',
141
190
  'claude/skills/plan-ready/references/assembly.md',
142
191
  'claude/skills/plan-ready/references/ready.md',
192
+ 'claude/skills/script-screencast/REQUIREMENT.md',
143
193
  'claude/skills/script-screencast/SKILL.md',
144
194
  'claude/skills/script-screencast/references/beats-template.md',
195
+ 'claude/skills/make-deck/REQUIREMENT.md',
145
196
  'claude/skills/make-deck/SKILL.md',
146
197
  'claude/skills/make-deck/references/deck.md',
198
+ 'claude/skills/git-branch/REQUIREMENT.md',
147
199
  'claude/skills/git-branch/SKILL.md',
148
200
  'claude/skills/git-branch/references/branch.md',
149
201
  'claude/skills/git-branch/references/slug.md',
202
+ 'claude/skills/git-commit/REQUIREMENT.md',
150
203
  'claude/skills/git-commit/SKILL.md',
151
204
  'claude/skills/git-commit/references/commit.md',
152
205
  'claude/skills/git-commit/references/versioning.md',
206
+ 'claude/skills/git-followup/REQUIREMENT.md',
153
207
  'claude/skills/git-followup/SKILL.md',
208
+ 'claude/skills/git-issue/REQUIREMENT.md',
154
209
  'claude/skills/git-issue/SKILL.md',
155
210
  'claude/skills/git-issue/references/issue.md',
211
+ 'claude/skills/git-pr/REQUIREMENT.md',
156
212
  'claude/skills/git-pr/SKILL.md',
157
213
  'claude/skills/git-pr/references/final-command.md',
158
214
  'claude/skills/git-pr/references/labels.md',
159
215
  'claude/skills/git-pr/references/pr.md',
160
216
  'claude/skills/git-pr/references/publish.md',
161
217
  'claude/skills/git-pr/references/task-number.md',
218
+ 'claude/skills/git-ship/REQUIREMENT.md',
162
219
  'claude/skills/git-ship/SKILL.md',
163
220
  'claude/skills/git-ship/references/ci-watch.md',
221
+ 'claude/skills/git-split/REQUIREMENT.md',
164
222
  'claude/skills/git-split/SKILL.md',
165
223
  'claude/skills/git-split/references/independent.md',
166
224
  'claude/skills/git-split/references/stacked.md',
225
+ 'claude/skills/git-stage/REQUIREMENT.md',
167
226
  'claude/skills/git-stage/SKILL.md',
227
+ 'claude/skills/git-worktree/REQUIREMENT.md',
168
228
  'claude/skills/git-worktree/SKILL.md',
169
229
  'claude/skills/git-worktree/references/cleanup.md',
230
+ 'claude/skills/markdown-craft/REQUIREMENT.md',
170
231
  'claude/skills/markdown-craft/SKILL.md',
171
232
  'claude/skills/markdown-craft/references/markdown.md',
233
+ 'claude/skills/plan-feature/REQUIREMENT.md',
172
234
  'claude/skills/plan-feature/SKILL.md',
173
235
  'claude/skills/plan-feature/references/batches.md',
174
236
  'claude/skills/plan-feature/references/plan-lifecycle.md',
175
237
  'claude/skills/plan-feature/references/plan.md',
238
+ 'claude/skills/plan-groundwork/REQUIREMENT.md',
176
239
  'claude/skills/plan-groundwork/SKILL.md',
177
240
  'claude/skills/plan-groundwork/references/groundwork-spikes.md',
178
241
  'claude/skills/plan-groundwork/references/groundwork.md',
179
242
  'claude/skills/plan-groundwork/references/output.md',
243
+ 'claude/skills/plan-intake-answer/REQUIREMENT.md',
180
244
  'claude/skills/plan-intake-answer/SKILL.md',
245
+ 'claude/skills/plan-intake/REQUIREMENT.md',
181
246
  'claude/skills/plan-intake/SKILL.md',
182
247
  'claude/skills/plan-intake/references/intake.md',
248
+ 'claude/skills/pr-evidence/REQUIREMENT.md',
183
249
  'claude/skills/pr-evidence/SKILL.md',
184
250
  'claude/skills/pr-evidence/references/evidence.md',
251
+ 'claude/skills/read-frames/REQUIREMENT.md',
185
252
  'claude/skills/read-frames/SKILL.md',
253
+ 'claude/skills/record-screencast/REQUIREMENT.md',
186
254
  'claude/skills/record-screencast/SKILL.md',
255
+ 'claude/skills/review-address/REQUIREMENT.md',
187
256
  'claude/skills/review-address/SKILL.md',
188
257
  'claude/skills/review-address/references/post-review-findings.md',
189
258
  'claude/skills/review-address/references/rebase-conflicts.md',
190
259
  'claude/skills/review-address/references/rebase-only.md',
191
260
  'claude/skills/review-address/references/rest-reads.md',
261
+ 'claude/skills/review-craft/REQUIREMENT.md',
192
262
  'claude/skills/review-craft/SKILL.md',
193
263
  'claude/skills/review-craft/references/adopted.md',
194
264
  'claude/skills/review-craft/references/security.md',
195
265
  'claude/skills/review-craft/references/ui.md',
266
+ 'claude/skills/review-pr/REQUIREMENT.md',
196
267
  'claude/skills/review-pr/SKILL.md',
197
268
  'claude/skills/review-pr/references/body-variants.md',
198
269
  'claude/skills/review-pr/references/close-out.md',
199
270
  'claude/skills/review-pr/references/key-changes.md',
200
271
  'claude/skills/review-pr/references/post.md',
201
272
  'claude/skills/review-pr/references/scope.md',
273
+ 'claude/skills/review-ui/REQUIREMENT.md',
202
274
  'claude/skills/review-ui/SKILL.md',
203
275
  'claude/skills/review-ui/references/close-out.md',
204
276
  'claude/skills/review-ui/references/driving.md',
@@ -225,38 +297,51 @@ export const GATED_PATHS: readonly string[] = [
225
297
  'claude/skills/role-orchestrator/references/orchestrator-watch.md',
226
298
  'claude/skills/role-planner/REQUIREMENT.md',
227
299
  'claude/skills/role-planner/SKILL.md',
300
+ 'claude/skills/role-reviewer/REQUIREMENT.md',
228
301
  'claude/skills/role-reviewer/SKILL.md',
229
302
  'claude/skills/role-worker/REQUIREMENT.md',
230
303
  'claude/skills/role-worker/SKILL.md',
304
+ 'claude/skills/search-craft/REQUIREMENT.md',
231
305
  'claude/skills/search-craft/SKILL.md',
232
306
  'claude/skills/search-craft/references/adopted.md',
307
+ 'claude/skills/session-compact/REQUIREMENT.md',
233
308
  'claude/skills/session-compact/SKILL.md',
234
309
  'claude/skills/session-compact/references/handoff-note.md',
310
+ 'claude/skills/session-map/REQUIREMENT.md',
235
311
  'claude/skills/session-map/SKILL.md',
236
312
  'claude/skills/session-map/references/session.md',
313
+ 'claude/skills/session-relay/REQUIREMENT.md',
237
314
  'claude/skills/session-relay/SKILL.md',
315
+ 'claude/skills/session-resume/REQUIREMENT.md',
238
316
  'claude/skills/session-resume/SKILL.md',
317
+ 'claude/skills/session-worktree/REQUIREMENT.md',
239
318
  'claude/skills/session-worktree/SKILL.md',
240
319
  'claude/skills/session-worktree/references/install-command.md',
241
320
  'claude/skills/session-worktree/references/main-root-writes.md',
321
+ 'claude/skills/systematic-debugging/REQUIREMENT.md',
242
322
  'claude/skills/systematic-debugging/SKILL.md',
243
323
  'claude/skills/systematic-debugging/references/adopted.md',
324
+ 'claude/skills/target-check/REQUIREMENT.md',
244
325
  'claude/skills/target-check/SKILL.md',
245
326
  'claude/skills/target-check/references/domains.md',
327
+ 'claude/skills/target-setup/REQUIREMENT.md',
246
328
  'claude/skills/target-setup/SKILL.md',
247
329
  'claude/skills/target-setup/references/detect.md',
248
330
  'claude/skills/target-setup/references/indexes.md',
249
331
  'claude/skills/target-setup/references/verify.md',
332
+ 'claude/skills/task-board/REQUIREMENT.md',
250
333
  'claude/skills/task-board/SKILL.md',
251
334
  'claude/skills/task-board/references/board.md',
252
335
  'claude/skills/task-board/references/create-report.md',
253
336
  'claude/skills/task-board/references/decline.md',
254
337
  'claude/skills/task-board/references/tasks-decline.md',
255
338
  'claude/skills/task-board/references/tasks.md',
339
+ 'claude/skills/task-complete/REQUIREMENT.md',
256
340
  'claude/skills/task-complete/SKILL.md',
257
341
  'claude/skills/task-complete/references/archive.md',
258
342
  'claude/skills/task-complete/references/receipt-sweep.md',
259
343
  'claude/skills/task-complete/references/unusable-baseline.md',
344
+ 'claude/skills/teach-workspace/REQUIREMENT.md',
260
345
  'claude/skills/teach-workspace/SKILL.md',
261
346
  'claude/skills/teach-workspace/references/glossary.md',
262
347
  'claude/skills/teach-workspace/references/lesson-build.md',
@@ -266,23 +351,43 @@ export const GATED_PATHS: readonly string[] = [
266
351
  'claude/skills/teach-workspace/references/promotion.md',
267
352
  'claude/skills/teach-workspace/references/revisit.md',
268
353
  'claude/skills/teach-workspace/references/teach.md',
354
+ 'claude/skills/test-craft/REQUIREMENT.md',
269
355
  'claude/skills/test-craft/SKILL.md',
270
356
  'claude/skills/test-craft/references/adopted.md',
271
357
  'claude/skills/test-craft/references/component.md',
272
358
  'claude/skills/test-craft/references/e2e.md',
273
359
  'claude/skills/test-craft/references/unit.md',
360
+ 'claude/skills/test-first/REQUIREMENT.md',
274
361
  'claude/skills/test-first/SKILL.md',
275
362
  'claude/skills/test-first/references/adopted.md',
363
+ 'claude/skills/ui-checklist/REQUIREMENT.md',
276
364
  'claude/skills/ui-checklist/SKILL.md',
365
+ 'claude/skills/ux-audit/REQUIREMENT.md',
277
366
  'claude/skills/ux-audit/SKILL.md',
367
+ 'claude/skills/ux-measure/REQUIREMENT.md',
278
368
  'claude/skills/ux-measure/SKILL.md',
369
+ 'claude/skills/video-craft/REQUIREMENT.md',
279
370
  'claude/skills/video-craft/SKILL.md',
280
371
  'claude/skills/video-craft/references/adopted.md',
372
+ 'claude/skills/write-human/REQUIREMENT.md',
281
373
  'claude/skills/write-human/SKILL.md',
282
374
  'claude/skills/write-human/references/adopted.md',
283
375
  'claude/skills/write-human/references/density.md',
284
376
  'claude/skills/write-human/references/machine-tells.md',
377
+ 'claude/skills/youtube-transcripts/REQUIREMENT.md',
285
378
  'claude/skills/youtube-transcripts/SKILL.md',
379
+ '.claude/skills/internal-canvas/REQUIREMENT.md',
380
+ '.claude/skills/internal-claude/REQUIREMENT.md',
381
+ '.claude/skills/internal-docs/REQUIREMENT.md',
382
+ '.claude/skills/internal-governance/REQUIREMENT.md',
383
+ '.claude/skills/internal-rule-audit/REQUIREMENT.md',
384
+ '.claude/skills/internal-sandbox-check/REQUIREMENT.md',
385
+ '.claude/skills/internal-scripts/REQUIREMENT.md',
386
+ '.claude/skills/internal-shipped-reference/REQUIREMENT.md',
387
+ '.claude/skills/internal-teach/REQUIREMENT.md',
388
+ '.claude/skills/internal-tooling/REQUIREMENT.md',
389
+ '.claude/skills/internal-upstream-digest/REQUIREMENT.md',
390
+ '.claude/skills/internal-web/REQUIREMENT.md',
286
391
  '.claude/skills/internal-',
287
392
  'docs/',
288
393
  'tooling/',
@@ -307,15 +412,23 @@ export function inDensityScope(rel: string): boolean {
307
412
  return DENSITY_SCOPE.some((pattern) => pattern.test(rel))
308
413
  }
309
414
 
310
- /** Whether a density finding of this kind on this path fails the run. */
415
+ /**
416
+ * Whether a density finding of this kind on this path fails the run.
417
+ *
418
+ * `alwaysGated` is off for a target's list, since no stage of a target's ever
419
+ * failed a push on a bullet run, and gating one unlisted would fail an older
420
+ * project's push on prose it has not touched since the limit landed.
421
+ */
311
422
  export function densityGates(
312
423
  rel: string,
313
424
  kind: DensityKind,
314
425
  gated: readonly string[] = GATED_PATHS,
426
+ alwaysGated = true,
315
427
  ): boolean {
316
428
  if (!inDensityScope(rel)) return false
317
429
  if (REQUIREMENT_SCOPE.test(rel)) return gated.includes(rel)
318
430
  if (
431
+ alwaysGated &&
319
432
  ALWAYS_GATED.includes(kind) &&
320
433
  BULLET_RUN_SCOPE.some((pattern) => pattern.test(rel))
321
434
  )
@@ -12,6 +12,12 @@
12
12
  * sweeps sharing a module constant would have to agree on a single map, and
13
13
  * the second rename this repository needed shares nothing with the first
14
14
  * except the scanning discipline above.
15
+ *
16
+ * Two misses survive a clean run. The sweep reads spelled text only, so a path
17
+ * assembled as `join('.claude', ...)` is never joined back into a token and
18
+ * keeps its old spelling. And rewriting a test's fixtures can collapse a
19
+ * fallback test into a copy of its neighbor, which keeps passing while it
20
+ * covers nothing, so read the rewritten fixtures rather than trusting the run.
15
21
  */
16
22
 
17
23
  /**
@@ -5,7 +5,7 @@ const EVIDENCE_SEGMENT = 'evidence'
5
5
  const EVIDENCE_OPEN_LIMIT = 6
6
6
 
7
7
  /** Length of the commit names the visible line shows, the width `git` abbreviates to. */
8
- const SHORT_SHA_LENGTH = 7
8
+ export const SHORT_SHA_LENGTH = 7
9
9
 
10
10
  /** Prefix of the trailing marker this module writes and reads back. */
11
11
  const MARKER_PREFIX = '<!-- pr-evidence:'
package/src/pr/rest.ts CHANGED
@@ -42,6 +42,7 @@ export interface PullIdentity {
42
42
  readonly head?: string
43
43
  readonly base?: string
44
44
  readonly mergeState?: string
45
+ readonly body?: string
45
46
  }
46
47
 
47
48
  export type BranchPull =
@@ -70,6 +71,7 @@ export function identityOf(row: RestPull): PullIdentity {
70
71
  ...(row.head?.sha !== undefined && { head: row.head.sha }),
71
72
  ...(row.base?.ref !== undefined && { base: row.base.ref }),
72
73
  ...(mergeState !== undefined && { mergeState }),
74
+ ...(typeof row.body === 'string' && { body: row.body }),
73
75
  }
74
76
  }
75
77
 
package/src/pr/tick.ts CHANGED
@@ -3,9 +3,98 @@ import {
3
3
  CHECKLIST_START,
4
4
  parseBoxLine,
5
5
  readChecklistBoxes,
6
+ SHORT_SHA_LENGTH,
6
7
  writeBoxLine,
7
8
  } from '@/pr/evidence'
8
9
 
10
+ const UI_PASS_MARKER = '<!-- pr-ui-pass -->'
11
+ const TESTING_HEADING = /^## Testing\s*$/
12
+ const SECTION_HEADING = /^## /
13
+ const REVIEWER_HEADING = /^## For the reviewer\s*$/
14
+ const UI_PASS_HEAD = /at `([0-9a-f]+)`/
15
+
16
+ /** What the UI pass line reports, either a pass or a reset to a head nobody has driven. */
17
+ export type UiPassSummary =
18
+ | {
19
+ readonly kind: 'passed'
20
+ /** Driven boxes ticked, taste boxes excluded. */
21
+ readonly passed: number
22
+ /** Boxes a driver can run, taste boxes excluded. */
23
+ readonly total: number
24
+ readonly taste: number
25
+ readonly head: string
26
+ }
27
+ | { readonly kind: 'reset'; readonly head: string }
28
+
29
+ /**
30
+ * The one `## Testing` line a UI pass owns. It is ticked only when every box
31
+ * a driver can run passed, so a failed box never reads as done, and taste
32
+ * boxes are counted apart so a full pass never reads as one box failed.
33
+ */
34
+ export function uiPassLine(summary: UiPassSummary): string {
35
+ const at = `\`${summary.head.slice(0, SHORT_SHA_LENGTH)}\``
36
+ if (summary.kind === 'reset') {
37
+ return `- [ ] UI pass, not run at ${at} ${UI_PASS_MARKER}`
38
+ }
39
+ const taste =
40
+ summary.taste === 0
41
+ ? ''
42
+ : `${summary.taste} taste ${summary.taste === 1 ? 'box' : 'boxes'} left to the operator`
43
+ if (summary.total === 0) {
44
+ return `- [ ] UI pass, no box a driver can run, ${taste} at ${at} ${UI_PASS_MARKER}`
45
+ }
46
+ const box = summary.passed === summary.total ? 'x' : ' '
47
+ const tail = taste === '' ? '' : `, ${taste}`
48
+ return `- [${box}] UI pass, ${summary.passed} of ${summary.total} boxes passed at ${at}${tail} ${UI_PASS_MARKER}`
49
+ }
50
+
51
+ /** The short sha the marked line names, absent when the body carries no such line. */
52
+ export function readUiPassHead(body: string): string | undefined {
53
+ const line = body.split('\n').find((row) => row.includes(UI_PASS_MARKER))
54
+ return line === undefined ? undefined : UI_PASS_HEAD.exec(line)?.[1]
55
+ }
56
+
57
+ /**
58
+ * Puts the UI pass line in a pull request body and touches nothing else.
59
+ * The marked line is replaced where it stands, else appended to the end of
60
+ * `## Testing`, which is created ahead of `## For the reviewer` when absent.
61
+ */
62
+ export function writeUiPassLine(body: string, summary: UiPassSummary): string {
63
+ const line = uiPassLine(summary)
64
+ const lines = body.split('\n')
65
+
66
+ const marked = lines.findIndex((row) => row.includes(UI_PASS_MARKER))
67
+ if (marked !== -1) {
68
+ lines[marked] = line
69
+ return lines.join('\n')
70
+ }
71
+
72
+ const heading = lines.findIndex((row) => TESTING_HEADING.test(row))
73
+ if (heading === -1) {
74
+ const reviewer = lines.findIndex((row) => REVIEWER_HEADING.test(row))
75
+ if (reviewer === -1) {
76
+ return `${body.trimEnd()}\n\n## Testing\n\n${line}\n`
77
+ }
78
+ lines.splice(reviewer, 0, '## Testing', '', line, '')
79
+ return lines.join('\n')
80
+ }
81
+
82
+ const next = lines.findIndex(
83
+ (row, index) => index > heading && SECTION_HEADING.test(row),
84
+ )
85
+ let last = next === -1 ? lines.length - 1 : next - 1
86
+ while (last > heading && lines[last]?.trim() === '') last -= 1
87
+
88
+ if (last > heading) {
89
+ lines.splice(last + 1, 0, line)
90
+ } else if (lines[heading + 1] === '') {
91
+ lines.splice(heading + 2, 0, line)
92
+ } else {
93
+ lines.splice(heading + 1, 0, '', line)
94
+ }
95
+ return lines.join('\n')
96
+ }
97
+
9
98
  export type TickRefusal = 'no-checklist' | 'no-box' | 'taste-box'
10
99
 
11
100
  export type TickResult =
@@ -19,6 +19,12 @@ export interface ClaimReport {
19
19
  readonly refs: readonly string[]
20
20
  /** False when the session roster could not be read, so `claimed` covers the readings around it alone and cannot be trusted as a clean "unclaimed". */
21
21
  readonly sessionsReadable: boolean
22
+ /**
23
+ * Foreign-namespace records whose socket is gone. They read dead, so a branch
24
+ * one of them holds can read unclaimed, which a caller with a count above
25
+ * zero should treat as unverified.
26
+ */
27
+ readonly foreignDead: number
22
28
  /** False when the ref read failed, which is the same false clean under a different reading. */
23
29
  readonly refsReadable: boolean
24
30
  }
@@ -80,6 +86,7 @@ export async function checkClaim(
80
86
  sessions,
81
87
  refs: refs.refs,
82
88
  sessionsReadable: report.kind === 'resolved',
89
+ foreignDead: report.kind === 'resolved' ? report.foreignDead : 0,
83
90
  refsReadable: refs.readable,
84
91
  }
85
92
  }
@@ -1,4 +1,5 @@
1
- import { readFileSync } from 'node:fs'
1
+ import { existsSync, readFileSync, readlinkSync } from 'node:fs'
2
+ import { createConnection } from 'node:net'
2
3
  import type { SessionRecord } from '@/sessions/registry'
3
4
 
4
5
  /**
@@ -7,13 +8,19 @@ import type { SessionRecord } from '@/sessions/registry'
7
8
  * `confirmed` means the running process was matched against the start time the
8
9
  * record stamped, so the pid belongs to the session that wrote the file.
9
10
  * `unverified` means the pid answers a signal probe and nothing more, which
10
- * cannot separate the original session from whatever inherited its pid.
11
+ * cannot separate the original session from whatever inherited its pid, or,
12
+ * for a `foreign` row, that its messaging socket still exists.
11
13
  */
12
14
  export type Confidence = 'confirmed' | 'unverified'
13
15
 
14
16
  export interface Liveness {
15
17
  readonly alive: boolean
16
18
  readonly confidence: Confidence
19
+ /**
20
+ * Set only when the record belongs to another pid namespace, so the pid was
21
+ * never probed. Absent rather than false on every other path.
22
+ */
23
+ readonly foreign?: true
17
24
  }
18
25
 
19
26
  export interface LivenessProbes {
@@ -21,6 +28,20 @@ export interface LivenessProbes {
21
28
  readonly procStartOf: (pid: number) => string | null
22
29
  /** Whether the pid answers at all, ignoring which process holds it. */
23
30
  readonly responds: (pid: number) => boolean
31
+ /**
32
+ * The reader's own pid namespace in `pid:[inode]` form, or null where it
33
+ * cannot be read. Optional so a caller with no use for the foreign branch,
34
+ * such as the gate's lock, states nothing and takes the pid path.
35
+ */
36
+ readonly ownDomain?: () => string | null
37
+ /** Whether the messaging socket a foreign record names still exists. */
38
+ readonly socketExists?: (path: string) => boolean
39
+ /**
40
+ * Whether something accepts a connection on the socket within the timeout.
41
+ * Async, so `liveness()` never calls it and a caller with no use for it, such
42
+ * as the gate's lock, states nothing.
43
+ */
44
+ readonly listens?: (path: string, timeoutMs: number) => Promise<boolean>
24
45
  }
25
46
 
26
47
  /**
@@ -51,7 +72,40 @@ function responds(pid: number): boolean {
51
72
  }
52
73
  }
53
74
 
54
- export const SYSTEM_PROBES: LivenessProbes = { procStartOf, responds }
75
+ /** The link target reads `pid:[inode]`, which a record's `pidDomain` ends with. */
76
+ function ownDomain(): string | null {
77
+ try {
78
+ return readlinkSync('/proc/self/ns/pid')
79
+ } catch {
80
+ return null
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Connects and closes without writing, so the peer sees no bytes. The socket is
86
+ * destroyed on connect rather than waited on, since a listener that accepts and
87
+ * never closes would otherwise hold the probe open past its timeout.
88
+ */
89
+ function listens(path: string, timeoutMs: number): Promise<boolean> {
90
+ return new Promise((resolve) => {
91
+ const socket = createConnection(path)
92
+ const settle = (accepted: boolean): void => {
93
+ socket.destroy()
94
+ resolve(accepted)
95
+ }
96
+ socket.setTimeout(timeoutMs, () => settle(false))
97
+ socket.once('connect', () => settle(true))
98
+ socket.once('error', () => settle(false))
99
+ })
100
+ }
101
+
102
+ export const SYSTEM_PROBES: LivenessProbes = {
103
+ procStartOf,
104
+ responds,
105
+ ownDomain,
106
+ socketExists: existsSync,
107
+ listens,
108
+ }
55
109
 
56
110
  /**
57
111
  * Decides whether a record describes a session that is still running.
@@ -62,13 +116,32 @@ export const SYSTEM_PROBES: LivenessProbes = { procStartOf, responds }
62
116
  * probe alone stands, and every surviving row is marked so a caller never reads
63
117
  * a recycled pid as a confirmed identity.
64
118
  *
65
- * It reads two fields and asks for no more, so a record that is not a session,
66
- * such as the gate's machine lock, carries the same proof.
119
+ * A record from another pid namespace is judged first, on its messaging
120
+ * socket, because its pid names nothing in this namespace and either probe
121
+ * would read an unrelated process or none. That answer is always `unverified`,
122
+ * since a crashed session leaves its socket behind.
123
+ *
124
+ * The pid and start time are the only fields the rest needs, so a record that
125
+ * is not a session, such as the gate's machine lock, carries the same proof and
126
+ * takes the pid path for want of a `pidDomain`.
67
127
  */
68
128
  export function liveness(
69
- record: Pick<SessionRecord, 'pid' | 'procStart'>,
129
+ record: Pick<SessionRecord, 'pid' | 'procStart'> &
130
+ Partial<Pick<SessionRecord, 'pidDomain' | 'messagingSocketPath'>>,
70
131
  probes: LivenessProbes = SYSTEM_PROBES,
71
132
  ): Liveness {
133
+ const own = probes.ownDomain?.() ?? null
134
+ if (
135
+ own !== null &&
136
+ record.pidDomain !== undefined &&
137
+ !record.pidDomain.endsWith(own)
138
+ ) {
139
+ const socket = record.messagingSocketPath
140
+ const alive =
141
+ socket !== undefined && (probes.socketExists?.(socket) ?? false)
142
+ return { alive, confidence: 'unverified', foreign: true }
143
+ }
144
+
72
145
  const started = record.procStart
73
146
 
74
147
  if (started !== undefined && started.length > 0) {
@@ -45,6 +45,17 @@ export interface SessionRecord {
45
45
  * been handed to something else.
46
46
  */
47
47
  readonly procStart: string | undefined
48
+ /**
49
+ * The pid namespace the client stamped, ending in the `pid:[inode]` form that
50
+ * `/proc/self/ns/pid` reads as. A reader in another namespace cannot see the
51
+ * record's pid, so this is what tells a foreign row from a dead one.
52
+ */
53
+ readonly pidDomain: string | undefined
54
+ /**
55
+ * The socket the session listens on for messages. It is the only evidence of
56
+ * life a foreign-namespace reader can reach, since the pid is out of sight.
57
+ */
58
+ readonly messagingSocketPath: string | undefined
48
59
  }
49
60
 
50
61
  /**