@jenga-ai/agent 1.3.0 → 3.0.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 (175) hide show
  1. package/README.md +93 -256
  2. package/agents/developer.md +9 -8
  3. package/agents/scrum-master.md +57 -23
  4. package/agents/tester.md +51 -5
  5. package/hooks/on_session_end.sh +13 -1
  6. package/lib/generate-agent-context.js +18 -1
  7. package/lib/generate-copilot-instructions.js +18 -1
  8. package/lib/generate-skill-allow-list.js +197 -0
  9. package/lib/skill-allow-list.json +42 -0
  10. package/package.json +17 -13
  11. package/scripts/apply-j-prefix.sh +243 -0
  12. package/scripts/consume-context-digest.sh +103 -0
  13. package/scripts/generate-j-alias.sh +333 -0
  14. package/scripts/postinstall.js +25 -0
  15. package/scripts/sweep-stale-context-digests.sh +132 -0
  16. package/scripts/validate-board.sh +5 -0
  17. package/scripts/write-context-digest.sh +230 -0
  18. package/skills/{brainstorm → j-brainstorm}/SKILL.md +9 -2
  19. package/skills/{btw → j-btw}/SKILL.md +9 -2
  20. package/skills/{clearify → j-clearify}/SKILL.md +9 -2
  21. package/skills/{close-story → j-close-story}/SKILL.md +92 -13
  22. package/skills/j-close-story/scripts/check-privatized.sh +345 -0
  23. package/skills/{close-story → j-close-story}/scripts/check-story-closeable.sh +1 -1
  24. package/skills/{close-story → j-close-story}/scripts/extract-task-diff-stats.sh +1 -1
  25. package/skills/{commit → j-commit}/SKILL.md +9 -2
  26. package/skills/j-continue/SKILL.md +36 -0
  27. package/skills/{deep-dive → j-deep-dive}/SKILL.md +9 -8
  28. package/skills/{dev-done → j-dev-done}/SKILL.md +11 -4
  29. package/skills/{dev-done → j-dev-done}/scripts/classify-commit-outcome.sh +4 -4
  30. package/skills/{distribute → j-distribute}/SKILL.md +17 -10
  31. package/skills/{distribute → j-distribute}/scripts/distribute-changes.sh +1 -1
  32. package/skills/{do → j-do}/SKILL.md +111 -14
  33. package/skills/j-doc/README.md +155 -0
  34. package/skills/{doc → j-doc}/SKILL.md +55 -18
  35. package/skills/j-doc/authoring-notes.md +72 -0
  36. package/skills/j-doc/scripts/resolve_last_update.py +149 -0
  37. package/skills/{doc-sync → j-doc-sync}/SKILL.md +9 -2
  38. package/skills/{dooo → j-dooo}/SKILL.md +9 -2
  39. package/skills/j-error/SKILL.md +36 -0
  40. package/skills/{evaluate → j-evaluate}/SKILL.md +9 -2
  41. package/skills/j-examplify/SKILL.md +49 -0
  42. package/skills/{help → j-help}/SKILL.md +9 -2
  43. package/skills/{idea → j-idea}/SKILL.md +10 -3
  44. package/skills/{idea → j-idea}/assets/idea_handoff_template.md +1 -1
  45. package/skills/{improve → j-improve}/SKILL.md +9 -2
  46. package/skills/{init → j-init}/SKILL.md +21 -8
  47. package/skills/j-init/assets/scope-thresholds_template.json +7 -0
  48. package/skills/j-jbp/SKILL.md +32 -0
  49. package/skills/j-lgtm/SKILL.md +28 -0
  50. package/skills/{pi-plan → j-pi-plan}/SKILL.md +10 -3
  51. package/skills/{proceed → j-proceed}/SKILL.md +9 -2
  52. package/skills/{publish → j-publish}/SKILL.md +47 -40
  53. package/skills/{publish → j-publish}/adapters/droplet.md +1 -1
  54. package/skills/{publish → j-publish}/adapters/mobile-ios.md +3 -3
  55. package/skills/{publish → j-publish}/adapters/npm-ci.md +29 -7
  56. package/skills/{publish → j-publish}/adapters/npm.md +8 -8
  57. package/skills/{publish → j-publish}/assets/ci-contract.md +2 -2
  58. package/skills/{publish → j-publish}/schemas/publish.schema.json +1 -1
  59. package/skills/{publish → j-publish}/scripts/npm_ci_pipeline.sh +21 -1
  60. package/skills/{publish → j-publish}/scripts/npm_stage_inspect.sh +34 -1
  61. package/skills/{publish → j-publish}/scripts/npm_stage_pipeline.sh +9 -4
  62. package/skills/{publish → j-publish}/scripts/publish_deploy.sh +4 -4
  63. package/skills/{publish → j-publish}/scripts/validate_npm_stage_env.sh +1 -1
  64. package/skills/{publish → j-publish}/wizards/droplet.md +1 -1
  65. package/skills/{publish → j-publish}/wizards/mobile-ios.md +1 -1
  66. package/skills/{publish → j-publish}/wizards/npm-ci.md +1 -1
  67. package/skills/{publish → j-publish}/wizards/npm.md +1 -1
  68. package/skills/{reconcile → j-reconcile}/SKILL.md +12 -5
  69. package/skills/{reconcile → j-reconcile}/scripts/detect-unlinked-code.sh +2 -2
  70. package/skills/{reconcile → j-reconcile}/scripts/resolve-reconcile-scope.sh +3 -3
  71. package/skills/{reconcile-origin → j-reconcile-origin}/SKILL.md +13 -6
  72. package/skills/{redo → j-redo}/SKILL.md +9 -2
  73. package/skills/{skillify → j-skillify}/SKILL.md +10 -3
  74. package/skills/{spinoff → j-spinoff}/SKILL.md +9 -2
  75. package/skills/{status → j-status}/SKILL.md +9 -2
  76. package/skills/j-todo/SKILL.md +92 -0
  77. package/skills/{todo → j-todo}/assets/todo_handoff_template.md +1 -1
  78. package/skills/j-todo/scripts/add_trivial_task.sh +216 -0
  79. package/skills/j-todo/scripts/update_story_tasks.py +87 -0
  80. package/skills/{uncharted → j-uncharted}/SKILL.md +35 -28
  81. package/skills/{uncharted → j-uncharted}/assets/UNDERSTANDING_DOC_TEMPLATE.md +2 -2
  82. package/skills/{uncharted → j-uncharted}/scripts/detect-dependencies.sh +1 -1
  83. package/skills/{uncharted → j-uncharted}/scripts/detect-tests.sh +1 -1
  84. package/skills/{uncharted → j-uncharted}/scripts/directory-triage.sh +3 -3
  85. package/skills/{uncharted → j-uncharted}/scripts/elicitation-state.sh +3 -3
  86. package/skills/{uncharted → j-uncharted}/scripts/enumerate-target.sh +1 -1
  87. package/skills/{uncharted → j-uncharted}/scripts/import-source.sh +1 -1
  88. package/skills/{uncharted → j-uncharted}/scripts/inspect-provenance.sh +1 -1
  89. package/skills/{uncharted → j-uncharted}/scripts/resolve-segment-target.sh +5 -5
  90. package/skills/{uncharted → j-uncharted}/scripts/run-engine.sh +1 -1
  91. package/skills/{uncharted → j-uncharted}/scripts/validate-proposed-items.sh +2 -2
  92. package/skills/{uncharted → j-uncharted}/scripts/write-backfilled-epics.sh +1 -1
  93. package/skills/j-wtf/SKILL.md +27 -0
  94. package/skills/jenga/SKILL.md +1 -1
  95. package/skills/jenga/scripts/render-confirmation.sh +55 -18
  96. package/skills/jenga-permission-level/SKILL.md +1 -1
  97. package/templates/SCRUM_BOARD_SCHEMA.md +33 -2
  98. package/templates/agent-context.md.tpl +32 -9
  99. package/templates/copilot-instructions.md.tpl +66 -11
  100. package/skills/continue/SKILL.md +0 -29
  101. package/skills/error/SKILL.md +0 -29
  102. package/skills/examplify/SKILL.md +0 -42
  103. package/skills/init/assets/scope-thresholds_template.json +0 -7
  104. package/skills/jbp/SKILL.md +0 -25
  105. package/skills/lgtm/SKILL.md +0 -21
  106. package/skills/todo/SKILL.md +0 -48
  107. package/skills/wtf/SKILL.md +0 -20
  108. /package/skills/{close-story → j-close-story}/scripts/compute-scope-divergence.sh +0 -0
  109. /package/skills/{close-story → j-close-story}/scripts/extract-diff-stats.sh +0 -0
  110. /package/skills/{close-story → j-close-story}/scripts/update-task-frontmatter.sh +0 -0
  111. /package/skills/{commit → j-commit}/assets/user_instructions_template.md +0 -0
  112. /package/skills/{distribute → j-distribute}/CONFIG_SCHEMA.md +0 -0
  113. /package/skills/{distribute → j-distribute}/scripts/check-version.sh +0 -0
  114. /package/skills/{distribute → j-distribute}/scripts/commit-version-bump.sh +0 -0
  115. /package/skills/{do → j-do}/assets/intent-vs-diff-prompt.md +0 -0
  116. /package/skills/{do → j-do}/assets/sender_template.json +0 -0
  117. /package/skills/{doc → j-doc}/assets/path-objectives.yaml +0 -0
  118. /package/skills/{doc-sync → j-doc-sync}/assets/default_excludes.txt +0 -0
  119. /package/skills/{doc-sync → j-doc-sync}/assets/doc_targets.md +0 -0
  120. /package/skills/{evaluate → j-evaluate}/assets/evaluation_invokation_template.yml +0 -0
  121. /package/skills/{evaluate → j-evaluate}/assets/evaluation_rapport_template.md +0 -0
  122. /package/skills/{idea → j-idea}/assets/idea_template.md +0 -0
  123. /package/skills/{init → j-init}/assets/.gitignore_template +0 -0
  124. /package/skills/{init → j-init}/assets/PROJECT_SUMMARY_template.md +0 -0
  125. /package/skills/{init → j-init}/assets/directory_structure.txt +0 -0
  126. /package/skills/{init → j-init}/assets/strategy_stub_template.md +0 -0
  127. /package/skills/{init → j-init}/assets/test-config_template.json +0 -0
  128. /package/skills/{init → j-init}/assets/workflow_template.json +0 -0
  129. /package/skills/{init → j-init}/scripts/apply-project-visibility.sh +0 -0
  130. /package/skills/{init → j-init}/scripts/detect-existing-codebase.sh +0 -0
  131. /package/skills/{init → j-init}/scripts/init.sh +0 -0
  132. /package/skills/{pi-plan → j-pi-plan}/assets/epic.json +0 -0
  133. /package/skills/{pi-plan → j-pi-plan}/assets/story_template.md +0 -0
  134. /package/skills/{publish → j-publish}/assets/ExportOptions.plist.template +0 -0
  135. /package/skills/{publish → j-publish}/assets/ownership-matrix.md +0 -0
  136. /package/skills/{publish → j-publish}/assets/publish.example.json +0 -0
  137. /package/skills/{publish → j-publish}/assets/publish.example.npm-ci.json +0 -0
  138. /package/skills/{publish → j-publish}/assets/publish.example.npm.json +0 -0
  139. /package/skills/{publish → j-publish}/assets/secrets-guide.md +0 -0
  140. /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-minimal.json +0 -0
  141. /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-with-empty-secrets.json +0 -0
  142. /package/skills/{publish → j-publish}/schemas/fixtures/npm-ci-with-workflow-path.json +0 -0
  143. /package/skills/{publish → j-publish}/scripts/check_target_config.sh +0 -0
  144. /package/skills/{publish → j-publish}/scripts/droplet_pipeline.sh +0 -0
  145. /package/skills/{publish → j-publish}/scripts/finalize_changelog.sh +0 -0
  146. /package/skills/{publish → j-publish}/scripts/generate_release_notes.sh +0 -0
  147. /package/skills/{publish → j-publish}/scripts/ios_pipeline.sh +0 -0
  148. /package/skills/{publish → j-publish}/scripts/npm_pipeline.sh +0 -0
  149. /package/skills/{publish → j-publish}/scripts/publish_common.sh +0 -0
  150. /package/skills/{publish → j-publish}/scripts/reconcile_tags.sh +0 -0
  151. /package/skills/{publish → j-publish}/scripts/run_gates.sh +0 -0
  152. /package/skills/{publish → j-publish}/scripts/setup_wizard.sh +0 -0
  153. /package/skills/{publish → j-publish}/scripts/show_history.sh +0 -0
  154. /package/skills/{publish → j-publish}/scripts/suggest_semver_bump.sh +0 -0
  155. /package/skills/{publish → j-publish}/scripts/validate_config.sh +0 -0
  156. /package/skills/{publish → j-publish}/scripts/validate_droplet_env.sh +0 -0
  157. /package/skills/{publish → j-publish}/scripts/validate_ios_env.sh +0 -0
  158. /package/skills/{publish → j-publish}/scripts/validate_npm_ci_env.sh +0 -0
  159. /package/skills/{publish → j-publish}/scripts/validate_npm_env.sh +0 -0
  160. /package/skills/{publish → j-publish}/scripts/write_ledger_entry.sh +0 -0
  161. /package/skills/{reconcile → j-reconcile}/assets/report_format.md +0 -0
  162. /package/skills/{reconcile-origin → j-reconcile-origin}/scripts/reconcile-origin.sh +0 -0
  163. /package/skills/{skillify → j-skillify}/assets/init-new/SKILL.md +0 -0
  164. /package/skills/{skillify → j-skillify}/assets/init-new/assets/.gitignore_template +0 -0
  165. /package/skills/{skillify → j-skillify}/assets/init-new/assets/PROJECT_SUMMARY_template.md +0 -0
  166. /package/skills/{skillify → j-skillify}/assets/init-new/assets/directory_structure.txt +0 -0
  167. /package/skills/{skillify → j-skillify}/assets/init-new/assets/test-config_template.json +0 -0
  168. /package/skills/{skillify → j-skillify}/assets/init-new/assets/workflow_template.json +0 -0
  169. /package/skills/{skillify → j-skillify}/assets/init-new/scripts/init.sh +0 -0
  170. /package/skills/{skillify → j-skillify}/assets/init-old/SKILL.md +0 -0
  171. /package/skills/{status → j-status}/assets/output_format.md +0 -0
  172. /package/skills/{todo → j-todo}/assets/todo_template.md +0 -0
  173. /package/skills/{uncharted → j-uncharted}/assets/SEGMENT_PROPOSAL_TEMPLATE.md +0 -0
  174. /package/skills/{uncharted → j-uncharted}/scripts/apply-subsystem-cap.sh +0 -0
  175. /package/skills/{uncharted → j-uncharted}/scripts/discover-subsystems.sh +0 -0
@@ -1,21 +1,36 @@
1
1
  ---
2
- name: do
3
- description: Execute tasks from the scrum board. Reads from project/todo.md, resolves each entry to its full scrum board context, and drives the developer agent through implementation with the correct sender object and communication contract. Loops until all selected tasks are done or the user exits.
2
+ name: j.do
3
+ description: Polyfill alias of the do skill under a collision-safe directory name. Identical behavior to /do — Execute tasks from the scrum board. Reads from project/todo.md, resolves each entry to its full scrum board context, and drives the developer agent through implementation with the correct sender object and communication contract. Loops until all selected tasks are done or the user exits. Use when the bare /do form is shadowed by another tool's own built-in command of the same name.
4
4
  keywords:
5
5
  - do
6
6
  - execute
7
7
  - implement
8
8
  - work on
9
9
  - build
10
+ - j-do
11
+ - polyfill
10
12
  examples:
11
13
  - "implement the login feature"
12
14
  - "work on the API endpoint"
15
+ - "j-do"
13
16
  metadata:
14
17
  prefered_agent: developer
15
18
  ---
16
19
 
17
20
  # Do — Execute Scrum Board Tasks
18
21
 
22
+ This skill is a literal-directory-name duplicate of `skills/do/`. It exists so that `/j-do` (and `j.j-do`) give a guaranteed-unshadowed way to reach the same flow as `/do`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/do` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
23
+
24
+ This file is generated/synced by `scripts/generate-j-alias.sh do` from `skills/do/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
25
+
26
+ ## `--trivial` Flag
27
+
28
+ **Syntax:** `/do <id> --trivial` — a dispatch-time override, distinct from `/todo --trivial` (a creation-time flag documented in `skills/todo/SKILL.md`). Where `/todo --trivial` writes a brand-new task straight to `execution_scope: inline`, `/do <id> --trivial` overrides an **already-existing** task's `execution_scope` — whatever it currently is, including absent (legacy tasks with no execution-scope fields at all) — to `inline` at the moment it's dispatched. See `### 4.1.5. \`--trivial\` Dispatch-Time Override` below for the full mechanics.
29
+
30
+ **No softer fallback tier — hard fallback to the full pipeline instead.** Unlike `light` scope (which sits between `inline` and `task`), `--trivial` always forces `inline` directly, with no intermediate tier to fall back to first. To compensate, a `--trivial`-forced run that fails `scripts/smoke-harness.sh` or shows detected scope creep mid-run automatically re-routes to the full `task` pipeline (worktree + developer + tester) via the same `#### Fallback to Full Task-Scope Pipeline` procedure the `light`-tier fallback uses — see `### 4.2`'s failure-handling branches and the shared Fallback subsection under `### 4.3`.
31
+
32
+ **Human-only, same as `/todo --trivial`.** `--trivial` is invoked by a human typing `/do <id> --trivial` — it is never applied autonomously by `/jenga` or the scrum-master's own breakdown/dispatch passes.
33
+
19
34
  ## Instructions
20
35
 
21
36
  ### 0. Load threshold config
@@ -166,7 +181,7 @@ After acquiring the epic lock and before writing the bundle manifest, scan all o
166
181
 
167
182
  1. **Extract expected files** from the task's frontmatter field `scope_rationale` and from the task's `## Description` section. Use a best-effort prose heuristic: split the text on whitespace and punctuation, then retain any token that either (a) contains a `/` character or (b) matches the pattern `*.*` (a dot surrounded by non-dot characters on both sides, e.g. `SKILL.md`, `foo.json`). Collect all retained tokens into a set called `expected_files`. This is intentionally permissive — false positives (expected files that were never actually changed) are acceptable and produce no report.
168
183
 
169
- 2. **Compute unexpected files**: let `actual_files` = the array stored at `task_changed_files[<task_id>]` in the bundle manifest (from step c.1). Compute `unexpected = actual_files − expected_files` (set difference: files in `actual_files` that have no match in `expected_files`). Matching is case-sensitive and exact against the relative path or the basename of the path — a token like `SKILL.md` matches any actual file whose basename is `SKILL.md` (e.g. `skills/do/SKILL.md`).
184
+ 2. **Compute unexpected files**: let `actual_files` = the array stored at `task_changed_files[<task_id>]` in the bundle manifest (from step c.1). Compute `unexpected = actual_files − expected_files` (set difference: files in `actual_files` that have no match in `expected_files`). Matching is case-sensitive and exact against the relative path or the basename of the path — a token like `SKILL.md` matches any actual file whose basename is `SKILL.md` (e.g. `skills/j-do/SKILL.md`).
170
185
 
171
186
  3. **If `unexpected` is non-empty**:
172
187
  a. Write a Markdown conflict report to `project/queue/conflict-<task_id>.md` with the following structure:
@@ -318,9 +333,40 @@ Before invoking the developer, check whether this task was manually scoped by a
318
333
  ```
319
334
  Then proceed to step 4.2.
320
335
 
336
+ ### 4.1.5. `--trivial` Dispatch-Time Override
337
+
338
+ After override validation (step 4.1) and before branching on `execution_scope` in step 4.2, check whether this invocation was `/do <id> --trivial`.
339
+
340
+ 1. **Detect the flag.** If the task was invoked as `/do <id>` with no `--trivial` flag, skip this entire section and proceed directly to `### 4.2`.
341
+
342
+ 2. **If `--trivial` is present**, read the task's current `execution_scope` from frontmatter. Treat an absent value as `task`, per the epic's backward-compatibility rule (a task that omits `execution_scope` is treated as `execution_scope: task`). Call this the **prior tier** — this covers both tasks nobody flagged as trivial at creation (an already-assigned `story`/`task`/`light` tier) and legacy tasks with no `execution_scope` set at all.
343
+
344
+ 3. **Overwrite `execution_scope` to `inline`** in the task's frontmatter, unconditionally — `--trivial` always forces `inline`, never a softer "lightest safe tier."
345
+
346
+ 4. **Record the override for audit**, reusing the existing `jenga_assigned` / `override_justification` pairing already defined in `templates/SCRUM_BOARD_SCHEMA.md` for exactly this situation ("scope overridden by a human"), rather than inventing a new field:
347
+ - Set `jenga_assigned: false` (if not already `false`).
348
+ - Set (or append to, if already present) `override_justification`:
349
+ ```
350
+ override_justification: "/do --trivial dispatch-time override on <date>: execution_scope forced from '<prior_tier>' to 'inline' by human operator."
351
+ ```
352
+ - Also set (or append to) `scope_rationale`, mirroring the phrasing convention `skills/todo/scripts/add_trivial_task.sh` already uses for the creation-time flag, so both audit fields agree on the prior tier:
353
+ ```
354
+ scope_rationale: "forced inline via /do --trivial (dispatch-time override); prior execution_scope was '<prior_tier>'"
355
+ ```
356
+ - Emit a non-fatal log line (styled like 4.2's `AUTO-CORRECTION` message):
357
+ ```
358
+ TRIVIAL OVERRIDE [<task_id>]: execution_scope forced from "<prior_tier>" to "inline" via --trivial dispatch-time override.
359
+ ```
360
+
361
+ 5. **Set an in-session marker** (this dispatch is a `--trivial`-forced run) — this does not need to be persisted to frontmatter; it only needs to survive for the remainder of this `/do` invocation. This marker is distinct from an organically-assigned `execution_scope: inline` task (one the scrum-master or `/jenga` assigned `inline` to directly, with no `--trivial` involved) because its failure handling differs — see `### 4.2`'s failure-handling steps below. Do not confuse a `--trivial`-forced run with an organic `inline` task when applying those steps.
362
+
363
+ 6. **Proceed to `### 4.2. Inline Execution Path`** with `execution_scope` now `inline`. Everything else about inline execution (implementation, smoke test invocation, commit convention) is identical between an organic `inline` task and a `--trivial`-forced one — only the two failure-handling branches in `### 4.2` differ, per the marker set in step 5 above.
364
+
365
+ **Precedence with the locked-task dispatch guard.** If `crucial_level: locked` (checked by `### 4.2`'s locked-task dispatch guard, which always runs and always wins), `--trivial` is redundant but harmless — the task was already going to be forced `inline`. The locked-task guard's own audit fields take precedence for that correction; do not double-write conflicting `override_justification` text. A `locked` task's fallback behavior remains "halt and report," never the `--trivial` fallback below, regardless of whether `--trivial` was also passed.
366
+
321
367
  ### 4.2. Inline Execution Path (execution_scope: inline)
322
368
 
323
- After resolving the task context (step 4) and passing override validation (step 4.1), read `execution_scope` from the task frontmatter.
369
+ After resolving the task context (step 4), passing override validation (step 4.1), and applying the `--trivial` dispatch-time override if present (step 4.1.5), read `execution_scope` from the task frontmatter.
324
370
 
325
371
  **Locked-task dispatch guard (defense-in-depth).** Before branching on `execution_scope` below, read `crucial_level` from the task frontmatter (per `templates/SCRUM_BOARD_SCHEMA.md`'s Crucial Flag Fields). If `crucial_level: locked`:
326
372
 
@@ -349,12 +395,14 @@ After resolving the task context (step 4) and passing override validation (step
349
395
  WARNING [<task_id>]: scripts/smoke-harness.sh not found. Smoke test skipped (stub pass).
350
396
  ```
351
397
  4. **If the smoke test exits non-zero**:
352
- - Write `status: Failed` to the task's frontmatter.
353
- - Emit:
354
- ```
355
- INLINE TASK FAILED [<task_id>]: smoke test returned non-zero exit code. Task marked Failed. Halting.
356
- ```
357
- - Do not commit. Do not proceed to the next task.
398
+ - **If this is a `--trivial`-forced run** (marker set in step 4.1.5 — and `crucial_level` is not `locked`, which never falls back, per 4.1.5's precedence note): do NOT write `status: Failed`. `--trivial` always forces `inline` with no softer "lightest safe tier" to fall back to first, so a smoke-harness failure here goes straight to the shared `#### Fallback to Full Task-Scope Pipeline` procedure below (origin: `trivial`). Do not proceed with the remaining inline steps below — the Fallback procedure takes over from here.
399
+ - **Otherwise** (an organically-assigned `inline` task, `--trivial` not involved): behavior is unchanged from before —
400
+ - Write `status: Failed` to the task's frontmatter.
401
+ - Emit:
402
+ ```
403
+ INLINE TASK FAILED [<task_id>]: smoke test returned non-zero exit code. Task marked Failed. Halting.
404
+ ```
405
+ - Do not commit. Do not proceed to the next task.
358
406
  5. **If the smoke test passes**:
359
407
  - Commit the changes using the standard commit convention (`task(<task_id>): <short description>`) via `/commit` in inline mode (E32_S04_T03).
360
408
  - Run the **Intent-vs-Diff Check** (see `### 5.1. Intent-vs-Diff Check` below) for this task.
@@ -365,9 +413,58 @@ After resolving the task context (step 4) and passing override validation (step
365
413
  7. `inline` tasks always have `needs_docs: false` — skip plan and summary documentation for the implemented task.
366
414
  8. Continue to `### 6. Verify documentation`, then `### 7. After successful completion`.
367
415
 
368
- If the implementation cannot be completed inline (scope is larger than anticipated), abort and re-route to the normal developer path (step 5) — unless `crucial_level: locked`, in which case do not re-route; re-attempt inline or halt and report, per the locked-task dispatch guard above.
416
+ If the implementation cannot be completed inline (scope is larger than anticipated — detected scope creep mid-run):
417
+ - **If this is a `--trivial`-forced run** (and `crucial_level` is not `locked`): invoke the shared `#### Fallback to Full Task-Scope Pipeline` procedure below (origin: `trivial`) — the same procedure the smoke-harness-failure branch above uses, not a second bespoke re-route.
418
+ - **Otherwise** (an organically-assigned `inline` task): abort and re-route to the normal developer path (step 5), unchanged from before.
419
+ - **Regardless of `--trivial`**, if `crucial_level: locked`, do not re-route via either path above; re-attempt inline or halt and report, per the locked-task dispatch guard above.
420
+
421
+ **If `execution_scope` is `light`** (and `crucial_level` is not `locked` — the locked-task dispatch guard above already ran and takes precedence over any scope check), proceed to `### 4.3. Light Execution Path` below instead of step 5.
422
+
423
+ **If `execution_scope` is not `inline` and not `light`** (or is absent / `task` / `story` / `epic`) **and `crucial_level` is not `locked`**, proceed to step 5 (invoke the developer agent) as normal.
424
+
425
+ ### 4.3. Light Execution Path (execution_scope: light)
426
+
427
+ After resolving the task context (step 4), passing override validation (step 4.1), and applying the `--trivial` dispatch-time override if present (step 4.1.5 — note `--trivial` always forces `inline`, so a `light`-scoped task only reaches this section if `--trivial` was *not* passed), if `execution_scope: light` and `crucial_level` is not `locked` (per the locked-task dispatch guard in 4.2, which runs first and always wins), route the task through this path instead of the full `task`-scope pipeline in step 5.
428
+
429
+ `light` sits between `inline` and `task`: unlike `inline`, it spawns a real developer subagent (so it can handle small branching logic that inline's main-session execution isn't suited for); unlike `task`, it does not create a dedicated worktree and does not invoke the tester as a separate step.
430
+
431
+ 1. **Spawn a developer subagent** (Agent tool, `subagent_type: "developer"`) with the same sender object and context payload as step 5 would use, but with an explicit instruction added to the dispatch prompt: **do not create a worktree** — implement directly against the current checkout (the session's existing working tree), not an isolated `.claude/worktrees/<slug>` copy. This is the one concrete difference from the step-5 `task` path: everything else about how the subagent implements the task (reading the task file, following acceptance criteria, following repo conventions) is unchanged.
432
+
433
+ 2. **After the developer subagent reports implementation complete**, run the smoke test harness using the same invocation convention as `### 4.2. Inline Execution Path`:
434
+ - Run `bash scripts/smoke-harness.sh <changed_file>...`, passing the paths the subagent changed. With no arguments the harness infers them from `git diff --name-only HEAD`. It exits `0` on pass and `1` on failure.
435
+ - If `scripts/smoke-harness.sh` does not exist, log a warning and treat the result as a pass:
436
+ ```
437
+ WARNING [<task_id>]: scripts/smoke-harness.sh not found. Smoke test skipped (stub pass).
438
+ ```
439
+
440
+ 3. **If the smoke test passes**:
441
+ - The developer subagent self-verifies the implementation against the task's acceptance criteria. No tester subagent is invoked for a `light`-scoped task — this is a deliberate, documented exception to "the tester is the sole status-writer" (`agents/tester.md`), mirroring the same exception already established for `inline` scope in step 5 of `### 4.2`. Since no tester runs, the developer/orchestrator is the one who writes the terminal status for a `light`-scoped task.
442
+ - Commit the changes using the standard commit convention (`task(<task_id>): <short description>`) via `/commit`.
443
+ - Run the **Intent-vs-Diff Check** (see `### 5.1. Intent-vs-Diff Check` below) for this task.
444
+ - Write `status: Passed` and `date_completed: <today>` to the task's frontmatter if self-verification passes.
445
+ - Remove the task from `project/todo.md`.
446
+ - Continue to `### 6. Verify documentation`, then `### 7. After successful completion`.
447
+
448
+ 4. **If the smoke test fails (non-zero exit)**: do NOT write `status: Failed` and do NOT halt. Instead, invoke `#### Fallback to Full Task-Scope Pipeline` below (origin: `light`).
449
+
450
+ #### Fallback to Full Task-Scope Pipeline
369
451
 
370
- **If `execution_scope` is not `inline`** (or is absent / `task` / `story` / `epic`) **and `crucial_level` is not `locked`**, proceed to step 5 (invoke the developer agent) as normal.
452
+ This is a self-contained, reusable procedure with two current callers — `### 4.2`'s `--trivial`-forced inline failure branches (origin: `trivial`) and `### 4.3`'s `light`-scope smoke-harness failure (origin: `light`) — given a task that was attempted under a reduced-overhead execution scope and failed its smoke-harness check (or, for `trivial`, showed detected scope creep mid-run), do the following. The only thing that varies by caller is the notice text in step 5; steps 1–4 and 6 are identical regardless of origin.
453
+
454
+ 1. **Do not mark the task `Failed`.** A smoke-harness failure (or detected scope creep) under a reduced-overhead scope means the scope was too small for the task, not that the task itself is unworkable — the correct response is to retry under full isolation, not to reject the work.
455
+ 2. **Create a worktree** for the task, named `<E##_S##_T##-short-slug>` per standard Worktree Management conventions, if one does not already exist for this task. (A task dispatched under `light` scope, or forced `inline` via `--trivial`, never had one — both premises skip worktree creation — so this step always creates a fresh worktree in that case.)
456
+ 3. **Spawn a developer subagent** in that worktree and have it pick up from the current state of the code (the changes already made by the reduced-overhead attempt are still present in the working tree / already committed, if any commit occurred — the subagent continues from there rather than starting over).
457
+ 4. **Invoke the tester agent** per the normal `### 5. Invoke the developer agent` flow's contract — full sender object, commit SHAs, worktree path. The tester is responsible for the terminal status write, exactly as in the standard `task`-scope pipeline.
458
+ 5. **Emit a clear, non-fatal fallback notice** to the user/orchestrator, using the message matching the caller's origin:
459
+ - origin `light`:
460
+ ```
461
+ LIGHT SCOPE FALLBACK [<task_id>]: smoke test failed; re-routing to full task-scope pipeline (worktree + developer + tester).
462
+ ```
463
+ - origin `trivial`:
464
+ ```
465
+ TRIVIAL OVERRIDE FALLBACK [<task_id>]: smoke test failed (or scope creep detected); re-routing to full task-scope pipeline (worktree + developer + tester).
466
+ ```
467
+ 6. Resume normal `task`-scope processing (steps 6–8 below) once the tester returns a verdict.
371
468
 
372
469
  ### 5. Invoke the developer agent
373
470
  Pass the following to the developer agent:
@@ -395,7 +492,7 @@ After the developer agent returns (or after inline execution completes), run the
395
492
 
396
493
  2. Run `git diff --name-only HEAD~1` to retrieve the list of changed file names (relative paths, one per line).
397
494
 
398
- 3. Read the prompt template from `skills/do/assets/intent-vs-diff-prompt.md`. Extract the prompt block (the content between the triple backticks under `## Prompt`).
495
+ 3. Read the prompt template from `skills/j-do/assets/intent-vs-diff-prompt.md`. Extract the prompt block (the content between the triple backticks under `## Prompt`).
399
496
 
400
497
  4. Substitute the placeholders:
401
498
  - `{description}` — full text of the task's `## Description` section
@@ -417,7 +514,7 @@ After the developer agent returns (or after inline execution completes), run the
417
514
 
418
515
  **This check is non-blocking.** It does not change the task's Passed/Failed outcome. It only writes `divergence_flag: true` and emits a warning for human review. Execution continues regardless of the check result.
419
516
 
420
- **Prompt calibration:** The prompt in `skills/do/assets/intent-vs-diff-prompt.md` is tuned to flag only files with zero plausible connection to the stated task. Test files, documentation files, lock files, and clearly implied files are excluded from flagging. See the `## False-Positive Tuning Rationale` section in the prompt template for full details.
517
+ **Prompt calibration:** The prompt in `skills/j-do/assets/intent-vs-diff-prompt.md` is tuned to flag only files with zero plausible connection to the stated task. Test files, documentation files, lock files, and clearly implied files are excluded from flagging. See the `## False-Positive Tuning Rationale` section in the prompt template for full details.
421
518
 
422
519
  ### 6. Verify documentation
423
520
  After the developer completes the task, confirm the following documentation was written:
@@ -0,0 +1,155 @@
1
+ # `/doc` Authoring and Usage Guide
2
+
3
+ `/doc` generates or regenerates a complete Markdown document for a resolved target path. The skill owns the entire target file: it resolves the documentation objective first, gathers evidence, reads any existing target for still-valid maintainer intent, then writes a full replacement document.
4
+
5
+ ## Basic Usage
6
+
7
+ ### Default target
8
+
9
+ ```text
10
+ /doc
11
+ ```
12
+
13
+ When no target is provided, `/doc` resolves the default target from `skills/j-doc/assets/path-objectives.yaml`. Today that default is `README.md`.
14
+
15
+ Expected flow:
16
+ 1. Resolve `README.md`
17
+ 2. Match the `project overview` objective
18
+ 3. Gather project evidence
19
+ 4. Regenerate the full `README.md`
20
+
21
+ ### Custom target
22
+
23
+ Canonical custom-target form:
24
+
25
+ ```text
26
+ /doc docs/API.md
27
+ ```
28
+
29
+ Accepted convenience form:
30
+
31
+ ```text
32
+ /doc update: docs/API.md
33
+ ```
34
+
35
+ Both forms resolve `docs/API.md`, then apply the matching rule from `skills/j-doc/assets/path-objectives.yaml`.
36
+
37
+ ## Target Resolution and Objective Rules
38
+
39
+ `skills/j-doc/assets/path-objectives.yaml` is the source of truth for:
40
+ - the default target
41
+ - known target paths
42
+ - each path's documentation objective
43
+ - required and optional sections for known targets
44
+
45
+ Known targets bypass ambiguity. Unknown targets must stop for clarification.
46
+
47
+ ## Evidence Sources and Precedence
48
+
49
+ `/doc` builds a synthesis context before writing. When sources disagree, use this precedence order:
50
+ 1. explicit user instruction
51
+ 2. scrum-board context
52
+ 3. codebase evidence
53
+ 4. git history
54
+
55
+ The synthesis context contract currently includes:
56
+ - `target_path`
57
+ - `objective`
58
+ - `project_name`
59
+ - `project_description`
60
+ - `features`
61
+ - `getting_started`
62
+ - `board_items`
63
+ - `conflicts_resolved`
64
+ - `sources_used`
65
+ - `existing_intent`
66
+
67
+ Use stronger sources to break ties. Do not let weaker evidence overwrite explicit user direction.
68
+
69
+ ## `last_update` Provenance
70
+
71
+ `last_update` is the documentation provenance field described by Epic E24's provenance work. It is intended to capture the most recent completed board item that materially updated the target document.
72
+
73
+ ### Expected source of truth
74
+
75
+ The provenance lookup relies on scrum-board `docs: [...]` annotations that point at repo-relative documentation targets such as:
76
+ - `README.md`
77
+ - `docs/API.md`
78
+
79
+ Board authors should add `docs` annotations to stories or tasks whenever implementation work changes a specific document or should be reflected in that document later.
80
+
81
+ ### How provenance is expected to resolve
82
+
83
+ 1. Look for completed board items whose `docs` list includes the target path exactly.
84
+ 2. Prefer the most recent qualifying item.
85
+ 3. Use that item as the basis for the document's `last_update` value.
86
+
87
+ ### Fallback behavior
88
+
89
+ If provenance cannot be resolved, `/doc` should follow the fallback defined by E24_S05:
90
+ - omit `last_update`, or
91
+ - mark it as `unknown`
92
+
93
+ Typical failure modes:
94
+ - the relevant board item never declared `docs: [...]`
95
+ - the target path in the board item does not exactly match the generated path
96
+ - the board item exists but is not yet in a completed/passed state
97
+
98
+ ## Ambiguity Gate
99
+
100
+ If the resolved target path is not present in `skills/j-doc/assets/path-objectives.yaml`, `/doc` must not guess.
101
+
102
+ It should stop and ask exactly:
103
+
104
+ ```text
105
+ What should <target_path> document? Please describe the objective.
106
+ ```
107
+
108
+ ### Example
109
+
110
+ ```text
111
+ /doc update: docs/UNKNOWN.md
112
+ ```
113
+
114
+ Expected behavior:
115
+ - do not generate a file yet
116
+ - do not invent a target objective
117
+ - ask the user what `docs/UNKNOWN.md` is meant to document
118
+
119
+ Once the user clarifies the objective, surface the resolved contract and continue.
120
+
121
+ ## Target-Specific Notes
122
+
123
+ ### `README.md`
124
+ Use `/doc` with no arguments when you want to regenerate the project overview. The generated file should center on:
125
+ - project description
126
+ - getting started steps
127
+ - examples only when they are strongly supported by evidence
128
+
129
+ ### `docs/API.md`
130
+ Use `/doc docs/API.md` (or `/doc update: docs/API.md`) when you want an API reference document. The generated file should remain grounded in known interfaces, endpoints, parameters, return values, and errors.
131
+
132
+ ## Tips for Board Authors
133
+
134
+ Add `docs` annotations when board work affects documentation scope or provenance. Good examples:
135
+
136
+ ```yaml
137
+ docs:
138
+ - README.md
139
+ - docs/API.md
140
+ ```
141
+
142
+ Use annotations when:
143
+ - a task introduces or changes user-visible behavior that belongs in README
144
+ - a story adds or changes an endpoint, command, interface, or workflow doc
145
+ - you want `/doc` provenance to trace the work back to the board reliably
146
+
147
+ Avoid annotations when the work has no documentation impact.
148
+
149
+ ## Maintainer Checklist
150
+
151
+ Before relying on `/doc`, confirm that:
152
+ 1. the target path exists in `skills/j-doc/assets/path-objectives.yaml`, or you are prepared to answer the ambiguity prompt
153
+ 2. relevant board items include accurate `docs: [...]` annotations
154
+ 3. higher-priority evidence sources are up to date
155
+ 4. any existing target file content that should survive regeneration is genuinely still valid
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: doc
3
- description: Generate or update a documentation file by resolving a target path to a clear documentation objective before writing.
2
+ name: j.doc
3
+ description: Polyfill alias of the doc skill under a collision-safe directory name. Identical behavior to /doc — Generate or update a documentation file by resolving a target path to a clear documentation objective before writing. Use when the bare /doc form is shadowed by another tool's own built-in command of the same name.
4
4
  metadata:
5
5
  prefered_agent: developer
6
6
  keywords:
@@ -9,15 +9,23 @@ keywords:
9
9
  - write docs
10
10
  - generate docs
11
11
  - update docs
12
+ - j-doc
13
+ - polyfill
12
14
  examples:
13
15
  - "/doc"
14
16
  - "/doc docs/API.md"
17
+ - "/doc update: docs/API.md"
15
18
  - "generate documentation for the CLI"
16
19
  - "update the contributing guide"
20
+ - "j-doc"
17
21
  ---
18
22
 
19
23
  # Doc — Documentation Synthesis and Regeneration
20
24
 
25
+ This skill is a literal-directory-name duplicate of `skills/doc/`. It exists so that `/j-doc` (and `j.j-doc`) give a guaranteed-unshadowed way to reach the same flow as `/doc`, even if a host tool's own built-in command of the same name would otherwise shadow or override the bare `/doc` alias (Claude Code's native skill resolution is a literal-string, directory-name-based match — see `docs/skill-authoring.md`'s "Invocation Convention").
26
+
27
+ This file is generated/synced by `scripts/generate-j-alias.sh doc` from `skills/doc/SKILL.md` — do not hand-edit it; re-run the generator instead to pick up source changes.
28
+
21
29
  ## Input Format
22
30
 
23
31
  ```text
@@ -25,12 +33,15 @@ examples:
25
33
  ```
26
34
 
27
35
  - If `target-path` is omitted, default to `README.md`.
36
+ - If the remainder starts with `update:`, strip that prefix, then trim again before resolving the target path.
28
37
  - If `target-path` is provided, use it exactly as written after `/doc`.
29
38
  - Do not guess additional arguments or rewrite the requested path.
30
39
 
31
40
  ## Reference Asset
32
41
 
33
- Load `skills/doc/assets/path-objectives.yaml` before resolving the documentation objective. Treat it as the source of truth for the `default_target`, known target paths, and their structural requirements.
42
+ Load `skills/j-doc/assets/path-objectives.yaml` before resolving the documentation objective. Treat it as the source of truth for the `default_target`, known target paths, and their structural requirements.
43
+
44
+ For extended usage guidance, provenance notes, and board-author tips, see `skills/j-doc/README.md`.
34
45
 
35
46
  ## Synthesis Context Contract
36
47
 
@@ -47,6 +58,7 @@ board_items: []
47
58
  conflicts_resolved: []
48
59
  sources_used: []
49
60
  existing_intent: null
61
+ last_update: null
50
62
  ```
51
63
 
52
64
  Required fields from E24_S03:
@@ -60,27 +72,30 @@ Required fields from E24_S03:
60
72
  - `conflicts_resolved`
61
73
  - `sources_used`
62
74
  - `existing_intent`
75
+ - `last_update`
63
76
 
64
- If the shared collector from E24_S03 is not yet merged, construct a temporary context with the same field names so later steps remain compatible.
77
+ If the shared collector from E24_S03 is not yet merged, construct a temporary context with the same field names so later steps remain compatible. `last_update` is resolved during the provenance step below.
65
78
 
66
79
  ## Instructions
67
80
 
68
81
  ### 1. Parse the target path
69
82
 
70
- 1. Read `default_target` from `skills/doc/assets/path-objectives.yaml`. If it is missing, fall back to `README.md`.
83
+ 1. Read `default_target` from `skills/j-doc/assets/path-objectives.yaml`. If it is missing, fall back to `README.md`.
71
84
  2. Remove the `/doc` command token from the invocation.
72
85
  3. Trim the remaining text.
73
- 4. If nothing remains, set `target_path` to `default_target`.
74
- 5. Otherwise, set `target_path` to the trimmed remainder.
86
+ 4. If the trimmed remainder starts with the exact prefix `update:`, remove that prefix and trim the remainder again.
87
+ 5. If nothing remains, set `target_path` to `default_target`.
88
+ 6. Otherwise, set `target_path` to the trimmed remainder.
75
89
 
76
90
  Examples:
77
91
  - `/doc` → `target_path = README.md`
78
92
  - `/doc docs/API.md` → `target_path = docs/API.md`
93
+ - `/doc update: docs/API.md` → `target_path = docs/API.md`
79
94
  - `/doc docs/CLI.md` → `target_path = docs/CLI.md`
80
95
 
81
96
  ### 2. Resolve the objective from the rule table
82
97
 
83
- 1. Read `skills/doc/assets/path-objectives.yaml`.
98
+ 1. Read `skills/j-doc/assets/path-objectives.yaml`.
84
99
  2. Find an entry whose `path` exactly matches `target_path`.
85
100
  3. If a match exists, set:
86
101
  - `objective` to the entry's `objective`
@@ -105,7 +120,7 @@ If the matched rule includes section guidance, carry it forward as constraints f
105
120
 
106
121
  ### 4. Ambiguity gate for unknown targets
107
122
 
108
- If `target_path` is not present in `skills/doc/assets/path-objectives.yaml`:
123
+ If `target_path` is not present in `skills/j-doc/assets/path-objectives.yaml`:
109
124
 
110
125
  - Ask the user exactly: `What should <target_path> document? Please describe the objective.`
111
126
  - Do **not** guess the objective.
@@ -135,15 +150,37 @@ If `target_path` is not present in `skills/doc/assets/path-objectives.yaml`:
135
150
 
136
151
  If the target file does not exist, keep `existing_intent = null`.
137
152
 
138
- ### 7. Generate a complete replacement file
153
+ ### 7. Resolve `last_update` provenance before writing
154
+
155
+ 1. Run `python3 skills/j-doc/scripts/resolve_last_update.py <target_path>` from the repository root.
156
+ 2. The resolver must scan `project/board/epics/`, `project/board/stories/`, and `project/board/tasks/`.
157
+ 3. Treat a board item as provenance only when all of the following are true:
158
+ - `status` is exactly `Done` or `Passed`
159
+ - `docs` is a YAML list that contains `target_path` as an exact repo-relative string match
160
+ - `date_completed` is present and parses as `YYYY-MM-DD`
161
+ 4. If multiple board items match, select the most recent `date_completed` and store it in `synthesis_context.last_update`.
162
+ 5. If no matching provenance is found, set `synthesis_context.last_update = "unknown"`. This is the required fallback because it keeps the frontmatter shape stable while making the missing provenance explicit.
163
+ 6. Ignore board items in any other status, items missing `docs`, and items whose `docs` entry uses a non-matching path form.
164
+
165
+ ### 8. Generate a complete replacement file
139
166
 
140
167
  1. Build a **full file string** from the synthesis context and the resolved target objective.
141
- 2. Treat the generated output as the entire authoritative file.
142
- 3. Do **not** patch a single section, append new text to the end, or leave untouched legacy sections in place.
143
- 4. Keep the output valid Markdown.
144
- 5. When writing, replace the old file contents in one operation.
168
+ 2. Start the file with YAML frontmatter for provenance, even when provenance could not be resolved:
169
+
170
+ ```yaml
171
+ ---
172
+ last_update: <YYYY-MM-DD or unknown>
173
+ ---
174
+ ```
175
+
176
+ 3. Use the resolved `synthesis_context.last_update` value in that frontmatter. Emit `unknown` verbatim when no completed board item provides provenance.
177
+ 4. This fallback is mandatory: do not omit the `last_update` key when provenance is missing.
178
+ 5. Treat the generated output as the entire authoritative file.
179
+ 6. Do **not** patch a single section, append new text to the end, or leave untouched legacy sections in place.
180
+ 7. Keep the output valid Markdown.
181
+ 8. When writing, replace the old file contents in one operation.
145
182
 
146
- ### 8. Generate `README.md` for the project-overview objective
183
+ ### 9. Generate `README.md` for the project-overview objective
147
184
 
148
185
  When `target_path = README.md`, generate the full document around the resolved project-overview contract.
149
186
 
@@ -175,7 +212,7 @@ When `target_path = README.md`, generate the full document around the resolved p
175
212
  - Preserve useful setup warnings from `existing_intent` when they are still valid.
176
213
  - Output valid Markdown lists or numbered steps.
177
214
 
178
- ### 9. Conditionally include a README Examples section
215
+ ### 10. Conditionally include a README Examples section
179
216
 
180
217
  Only add `## Examples` to `README.md` when the synthesis context supports a grounded project-type inference.
181
218
 
@@ -212,7 +249,7 @@ Choose the strongest evidenced type in this priority order when multiple types a
212
249
  - Do **not** include placeholder examples, pseudo-commands, or guessed endpoints.
213
250
  - If you cannot produce two grounded examples, omit the section instead of improvising.
214
251
 
215
- ### 10. Generate non-README targets from the rule table
252
+ ### 11. Generate non-README targets from the rule table
216
253
 
217
254
  For every known non-README target, the path-to-objective rule table determines the file structure. Generate a full document that satisfies the matched rule.
218
255
 
@@ -309,6 +346,6 @@ Rules:
309
346
  - Summarize each entry from commit subjects and, when needed, nearby commit context.
310
347
  - Keep newest entries first.
311
348
 
312
- ### 11. Continue using the resolved objective
349
+ ### 12. Continue using the resolved objective
313
350
 
314
351
  After the target path and objective are resolved, use them as the contract for all subsequent `/doc` work. Known paths must bypass the ambiguity gate, and all later decisions about evidence gathering, scope, regeneration, and structure must honor the surfaced `target_path` and `objective` instead of inferring a different goal.
@@ -0,0 +1,72 @@
1
+ # `/doc` authoring notes
2
+
3
+ ## `last_update` provenance
4
+
5
+ `/doc` writes a `last_update` frontmatter field at the top of generated documentation files. That value is derived from completed scrum-board items that explicitly declare they affected the target document.
6
+
7
+ The resolver is `skills/j-doc/scripts/resolve_last_update.py`. It scans:
8
+
9
+ - `project/board/epics/`
10
+ - `project/board/stories/`
11
+ - `project/board/tasks/`
12
+
13
+ A board item counts as provenance only when all of the following are true:
14
+
15
+ 1. `status` is `Done` or `Passed`
16
+ 2. `docs` is a YAML list
17
+ 3. The `docs` list contains the target file path as an exact repo-relative match (for example `README.md` or `docs/API.md`)
18
+ 4. `date_completed` exists and parses as `YYYY-MM-DD`
19
+
20
+ If multiple board items match, `/doc` uses the most recent `date_completed` as `last_update`.
21
+
22
+ ## Required board annotations
23
+
24
+ For provenance to work, the scrum-board item that changed a documentation file must carry a matching `docs: [...]` annotation in its YAML frontmatter.
25
+
26
+ Examples:
27
+
28
+ ```yaml
29
+ docs:
30
+ - README.md
31
+ - docs/API.md
32
+ ```
33
+
34
+ Use repo-relative paths only. The resolver does not normalize absolute paths or `./`-prefixed variants.
35
+
36
+ ## Fallback behavior
37
+
38
+ When `/doc` cannot determine provenance, it still emits valid YAML frontmatter and sets:
39
+
40
+ ```yaml
41
+ last_update: unknown
42
+ ```
43
+
44
+ This fallback is intentional. It keeps the frontmatter shape stable while making the missing provenance explicit to both humans and downstream tooling.
45
+
46
+ ## Failure modes and assumptions
47
+
48
+ ### Board item completed without `docs` annotations
49
+
50
+ If a task, story, or epic reached `Done`/`Passed` but omitted the target file from `docs`, `/doc` cannot attribute that item to the document. The resolver will ignore it and may fall back to `unknown`.
51
+
52
+ ### Target path mismatch
53
+
54
+ Matching is exact and repo-relative. These examples do **not** match `README.md`:
55
+
56
+ - `/Users/sam/.../README.md`
57
+ - `./README.md`
58
+ - `docs/../README.md`
59
+
60
+ Authors should record the canonical repo-relative path that `/doc` was invoked with.
61
+
62
+ ### Item not in a completed status
63
+
64
+ Items in statuses such as `Pending`, `In Progress`, `Blocked`, or `Failed` do not count as provenance even if they include the right `docs` annotation. Only completed work is eligible.
65
+
66
+ ### Missing or invalid `date_completed`
67
+
68
+ A matching board item without a valid `date_completed` cannot contribute a `last_update` value. The resolver skips it and logs a warning to stderr.
69
+
70
+ ### Malformed legacy board files
71
+
72
+ Some older board artifacts may not follow the current YAML-frontmatter schema. The resolver skips unparseable files instead of failing the whole `/doc` run. This is a degradation path, not successful provenance.