@haposoft/cafekit 0.13.2 → 0.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haposoft/cafekit",
3
- "version": "0.13.2",
3
+ "version": "0.13.3",
4
4
  "description": "Claude Code-first spec-driven workflow for AI coding assistants. Bundles CafeKit hapo: skills, runtime hooks, agents, and installer scaffolding.",
5
5
  "author": "Haposoft <nghialt@haposoft.com>",
6
6
  "license": "MIT",
@@ -132,6 +132,28 @@ function validateTaskSections(taskPath, content, errors) {
132
132
  }
133
133
  }
134
134
 
135
+ /**
136
+ * Task files are created from the scaffold template (the scaffold-guard hook
137
+ * forces creation through it), so every task starts as a stub full of `{{...}}`
138
+ * placeholders. The hook guarantees the stub is CREATED via scaffold, but
139
+ * nothing guaranteed the model FILLED it. An unfilled `{{...}}` is an
140
+ * incomplete task — SKILL.md: "Leave NO {{...}} placeholder ... fails DoCT" —
141
+ * so it is a hard error here. A `.../` path fragment is a not-yet-resolved path
142
+ * placeholder; it is only a warning, because it usually survives in prose Steps
143
+ * while the Related Files table (which spec-ground.cjs does verify) is already
144
+ * concrete. Matching `\.\.\.\/` (three dots + slash) avoids flagging a relative
145
+ * `../` path or a prose ellipsis.
146
+ */
147
+ function validateTaskPlaceholders(taskPath, content, errors, warnings) {
148
+ const stub = content.match(/\{\{[^}\n]+\}\}/);
149
+ if (stub) {
150
+ errors.push(`${taskPath}: unfilled scaffold placeholder ${stub[0]} — task stub was not completed`);
151
+ }
152
+ if (/\.\.\.\//.test(content)) {
153
+ warnings.push(`${taskPath}: contains a '.../' path placeholder — replace with a concrete path`);
154
+ }
155
+ }
156
+
135
157
  /**
136
158
  * Each phase completion must carry its own timestamp. Reusing `timestamps.init`
137
159
  * for a later phase is forbidden (SKILL.md spec.json Update Rules). This used to
@@ -344,6 +366,7 @@ function validateSpec(specDir) {
344
366
  const fullPath = path.join(specDir, taskFile);
345
367
  const content = fs.readFileSync(fullPath, 'utf8');
346
368
  validateTaskSections(taskFile, content, errors);
369
+ validateTaskPlaceholders(taskFile, content, errors, warnings);
347
370
 
348
371
  const idRe = /\b((?:REQ-\d+)|(?:R\d+))\b/gi;
349
372
  let match;
@@ -335,7 +335,7 @@ Rules:
335
335
  - Load `references/ask-user-question-gates.md`; if scoring reveals unapproved scope expansion or an unresolved user-owned choice, pause before writing task files.
336
336
  - **Scaffold is mandatory — raw `Write` to a task file is blocked.** A PreToolUse hook (`task-scaffold-guard.cjs`) rejects any `Write` whose path matches `specs/<feature>/tasks/task-*.md`. The only path to a task file is scaffold → Edit. Once the task list is decided, generate the stubs:
337
337
  `node .claude/scripts/spec-scaffold.cjs <feature> --tasks "R0-01-slug,R1-01-slug,..." --tasks-only`
338
- This creates each `tasks/task-R*.md` from `templates/task.md` and merges `task_files` + `task_registry` into the existing `spec.json` (pending, no overwrite of already-filled tasks). Then **Edit-fill** the `{{...}}` placeholders in each stub (`Edit`/`MultiEdit` are allowed; `Write` is not). Hand-writing whole task files is the single biggest output-token cost — scaffold + fill cuts it. (The guard fails open if the scaffold script is absent, and can be disabled via `"spec": { "scaffold_guard": false }` in `.claude/runtime.json`.)
338
+ This creates each `tasks/task-R*.md` from `templates/task.md` and merges `task_files` + `task_registry` into the existing `spec.json` (pending, no overwrite of already-filled tasks). Then **Edit-fill** the `{{...}}` placeholders in each stub (`Edit`/`MultiEdit` are allowed; `Write` is not). (The guard fails open if the scaffold script is absent, and can be disabled via `"spec": { "scaffold_guard": false }` in `.claude/runtime.json`.)
339
339
  - Each task file follows template `templates/task.md` (scaffold already applies it). **Leave NO `{{...}}` placeholder unfilled** — a stub with placeholders is an incomplete task.
340
340
  - `Related Files` and test plans must inherit paths, contracts, and test targets from the codebase scout. If exact files/tests cannot be named for an enhancement, run targeted inspect before generating tasks. Every `Related Files` path will be grounded (Layer 2) at Step 8.5 — phantom paths hard-fail, so cite real paths.
341
341
  - Each task file MUST include `Completion Criteria` and `Evidence` sections detailed enough that a downstream quality gate can prove the task is truly done. Existing specs may use `Task Test Plan & Verification Evidence` or legacy `Verification & Evidence`.