@windyroad/itil 1.2.0 → 2.0.0-preview.1111

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 (266) hide show
  1. package/.agents/plugins/marketplace.json +12 -0
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +42 -0
  4. package/README.md +34 -25
  5. package/agents/hang-off-check.md +34 -34
  6. package/bin/install.mjs +71 -5
  7. package/bin/wr-itil-catchup-scan +4 -4
  8. package/bin/wr-itil-check-deferred-placeholder-staleness +4 -4
  9. package/bin/wr-itil-check-fail-soft-skip-discipline +4 -4
  10. package/bin/wr-itil-check-fix-rfc-trace +4 -4
  11. package/bin/wr-itil-check-locale-discipline +4 -4
  12. package/bin/wr-itil-check-outbound-responses-staleness +4 -4
  13. package/bin/wr-itil-check-problems-readme-budget +4 -4
  14. package/bin/wr-itil-check-rfc-has-stories +4 -4
  15. package/bin/wr-itil-check-rfc-stories-ratified +4 -4
  16. package/bin/wr-itil-check-ticket-jtbd-ratification +4 -4
  17. package/bin/wr-itil-check-upstream-cache-staleness +4 -4
  18. package/bin/wr-itil-check-upstream-responses +4 -4
  19. package/bin/wr-itil-classify-readme-drift +4 -4
  20. package/bin/wr-itil-derive-release-vehicle +4 -4
  21. package/bin/wr-itil-detect-unratified-stories-maps +4 -4
  22. package/bin/wr-itil-effort-tally +4 -4
  23. package/bin/wr-itil-enumerate-postrelease-kv-candidates +4 -4
  24. package/bin/wr-itil-evaluate-relevance +4 -4
  25. package/bin/wr-itil-mark-create-gate +4 -4
  26. package/bin/wr-itil-mark-story-oversight-confirmed +4 -4
  27. package/bin/wr-itil-migrate-problems-layout +4 -4
  28. package/bin/wr-itil-migrate-story-status-mirror +4 -4
  29. package/bin/wr-itil-next-rfc-id +4 -4
  30. package/bin/wr-itil-plugin-exercise-index +4 -4
  31. package/bin/wr-itil-plugin-maturity-populate +4 -4
  32. package/bin/wr-itil-plugin-maturity-render +4 -4
  33. package/bin/wr-itil-plugin-validate-ci-gate +4 -4
  34. package/bin/wr-itil-reconcile-readme +4 -4
  35. package/bin/wr-itil-reconcile-rfcs +4 -4
  36. package/bin/wr-itil-reconcile-stories +4 -4
  37. package/bin/wr-itil-reconcile-story-maps +4 -4
  38. package/bin/wr-itil-render-story-map +4 -4
  39. package/bin/wr-itil-resolve-governance-plugin-dirs +4 -4
  40. package/bin/wr-itil-skill-invocations +4 -4
  41. package/bin/wr-itil-story-map-edit +4 -4
  42. package/bin/wr-itil-story-map-query +4 -4
  43. package/bin/wr-itil-update-jtbd-references-section +4 -4
  44. package/bin/wr-itil-update-problem-references-section +4 -4
  45. package/bin/wr-itil-update-problem-rfcs-section +4 -4
  46. package/bin/wr-itil-update-rfc-commits-section +4 -4
  47. package/bin/wr-itil-update-rfc-references-section +4 -4
  48. package/bin/wr-itil-verify-iter-summary +4 -4
  49. package/hooks/itil-assistant-output-gate.sh +3 -3
  50. package/hooks/itil-assistant-output-review.sh +5 -5
  51. package/hooks/itil-bash-polling-antipattern-detect.sh +11 -11
  52. package/hooks/itil-changeset-discipline.sh +24 -24
  53. package/hooks/itil-claude-space-protection.sh +21 -14
  54. package/hooks/itil-codex-dispatch.sh +164 -0
  55. package/hooks/itil-commit-trailer-transition-advisory.sh +11 -11
  56. package/hooks/itil-correction-detect.sh +8 -8
  57. package/hooks/itil-deferral-cadence-gate.sh +23 -23
  58. package/hooks/itil-fictional-defer-detect.sh +16 -16
  59. package/hooks/itil-fix-title-lifecycle-advisory.sh +11 -11
  60. package/hooks/itil-mid-loop-ask-detect.sh +14 -14
  61. package/hooks/itil-no-implement-draft-gate.sh +18 -18
  62. package/hooks/itil-pending-questions-surface.sh +11 -11
  63. package/hooks/itil-readme-refresh-discipline.sh +27 -27
  64. package/hooks/itil-rfc-oversight-nudge.sh +7 -7
  65. package/hooks/itil-rfc-trailer-advisory.sh +28 -28
  66. package/hooks/itil-runtime-sid-marker.sh +11 -11
  67. package/hooks/itil-story-mirror-migration-nudge.sh +7 -7
  68. package/hooks/lib/block-list.sh +17 -17
  69. package/hooks/lib/changeset-detect.sh +27 -27
  70. package/hooks/lib/claude-space-gate.sh +23 -15
  71. package/hooks/lib/command-detect.sh +12 -12
  72. package/hooks/lib/create-gate.sh +9 -39
  73. package/hooks/lib/detectors.sh +12 -12
  74. package/hooks/lib/readme-refresh-detect.sh +51 -51
  75. package/hooks/lib/runtime-sid.sh +12 -12
  76. package/hooks/lib/session-id.sh +28 -28
  77. package/hooks/lib/session-marker.sh +1 -1
  78. package/hooks/lib/staging-detect.sh +13 -13
  79. package/hooks/manage-problem-enforce-create.sh +16 -27
  80. package/hooks/p057-staging-trap-detect.sh +18 -18
  81. package/hooks/pre-publish-intake-gate.sh +5 -5
  82. package/hooks/staleness-check.sh +6 -6
  83. package/hooks-codex/hooks.json +57 -0
  84. package/lib/check-deferred-placeholder-staleness.sh +10 -10
  85. package/lib/check-outbound-responses-staleness.sh +2 -2
  86. package/lib/check-upstream-cache-staleness.sh +2 -2
  87. package/lib/derive-first-dispatch.sh +19 -19
  88. package/lib/enumerate-postrelease-kv-candidates.sh +18 -18
  89. package/lib/migrate-problems-layout.sh +12 -12
  90. package/lib/story-oversight.sh +27 -27
  91. package/package.json +16 -3
  92. package/scripts/catchup-scan.sh +25 -25
  93. package/scripts/check-fail-soft-skip-discipline.sh +10 -10
  94. package/scripts/check-fix-rfc-trace.sh +8 -8
  95. package/scripts/check-locale-discipline.sh +13 -13
  96. package/scripts/check-problems-readme-budget.sh +12 -12
  97. package/scripts/check-rfc-has-stories.sh +7 -7
  98. package/scripts/check-rfc-rejected-alternatives.sh +11 -11
  99. package/scripts/check-rfc-stories-ratified.sh +9 -9
  100. package/scripts/check-ticket-jtbd-ratification.sh +10 -10
  101. package/scripts/check-upstream-responses.sh +22 -22
  102. package/scripts/classify-readme-drift.sh +13 -13
  103. package/scripts/codex-agent.mjs +104 -0
  104. package/scripts/derive-release-vehicle.sh +23 -23
  105. package/scripts/detect-unoversighted-rfcs.sh +3 -3
  106. package/scripts/detect-unratified-stories-maps.sh +5 -5
  107. package/scripts/effort-tally.sh +10 -10
  108. package/scripts/evaluate-relevance.sh +16 -16
  109. package/scripts/mark-create-gate.sh +4 -4
  110. package/scripts/mark-story-oversight-confirmed.sh +14 -14
  111. package/scripts/migrate-story-status-mirror.sh +6 -6
  112. package/scripts/next-rfc-id.sh +5 -5
  113. package/scripts/plugin-exercise-index.sh +26 -26
  114. package/scripts/plugin-maturity-populate.sh +38 -38
  115. package/scripts/plugin-maturity-render.sh +26 -26
  116. package/scripts/plugin-validate-ci-gate.sh +14 -14
  117. package/scripts/reconcile-readme.sh +23 -23
  118. package/scripts/reconcile-rfcs.sh +13 -13
  119. package/scripts/reconcile-stories.sh +12 -12
  120. package/scripts/reconcile-story-maps.sh +6 -6
  121. package/scripts/render-story-map.mjs +24 -24
  122. package/scripts/render-story-map.sh +3 -3
  123. package/scripts/resolve-governance-plugin-dirs.sh +10 -10
  124. package/scripts/run-check-deferred-placeholder-staleness.sh +3 -3
  125. package/scripts/run-check-outbound-responses-staleness.sh +3 -3
  126. package/scripts/run-check-upstream-cache-staleness.sh +3 -3
  127. package/scripts/run-enumerate-postrelease-kv-candidates.sh +3 -3
  128. package/scripts/run-migrate-problems-layout.sh +3 -3
  129. package/scripts/skill-invocations.sh +29 -29
  130. package/scripts/story-map-edit.mjs +6 -6
  131. package/scripts/story-map-edit.sh +3 -3
  132. package/scripts/story-map-query.mjs +8 -8
  133. package/scripts/story-map-query.sh +3 -3
  134. package/scripts/update-jtbd-references-section.sh +8 -8
  135. package/scripts/update-problem-references-section.sh +12 -12
  136. package/scripts/update-problem-rfcs-section.sh +9 -9
  137. package/scripts/update-rfc-commits-section.sh +7 -7
  138. package/scripts/update-rfc-references-section.sh +3 -3
  139. package/scripts/update-story-references-section.sh +5 -5
  140. package/scripts/verify-iter-summary.sh +3 -3
  141. package/skills/capture-problem/REFERENCE.md +33 -33
  142. package/skills/capture-problem/SKILL.md +108 -108
  143. package/skills/capture-problem/agents/openai.yaml +3 -0
  144. package/skills/capture-rfc/SKILL.md +21 -323
  145. package/skills/capture-rfc/agents/openai.yaml +3 -0
  146. package/skills/capture-story/SKILL.md +65 -65
  147. package/skills/capture-story/agents/openai.yaml +3 -0
  148. package/skills/capture-story-map/SKILL.md +31 -31
  149. package/skills/capture-story-map/agents/openai.yaml +3 -0
  150. package/skills/check-upstream-responses/SKILL.md +38 -38
  151. package/skills/check-upstream-responses/agents/openai.yaml +3 -0
  152. package/skills/close-incident/SKILL.md +25 -25
  153. package/skills/close-incident/agents/openai.yaml +3 -0
  154. package/skills/link-incident/SKILL.md +22 -22
  155. package/skills/link-incident/agents/openai.yaml +3 -0
  156. package/skills/list-incidents/SKILL.md +9 -9
  157. package/skills/list-incidents/agents/openai.yaml +3 -0
  158. package/skills/list-problems/SKILL.md +17 -17
  159. package/skills/list-problems/agents/openai.yaml +3 -0
  160. package/skills/list-stories/SKILL.md +23 -23
  161. package/skills/list-stories/agents/openai.yaml +3 -0
  162. package/skills/list-story-maps/SKILL.md +9 -9
  163. package/skills/list-story-maps/agents/openai.yaml +3 -0
  164. package/skills/manage-incident/SKILL.md +59 -59
  165. package/skills/manage-incident/agents/openai.yaml +3 -0
  166. package/skills/manage-problem/SKILL.md +222 -222
  167. package/skills/manage-problem/agents/openai.yaml +3 -0
  168. package/skills/manage-rfc/SKILL.md +62 -62
  169. package/skills/manage-rfc/agents/openai.yaml +3 -0
  170. package/skills/manage-story/SKILL.md +49 -49
  171. package/skills/manage-story/agents/openai.yaml +3 -0
  172. package/skills/manage-story-map/SKILL.md +30 -30
  173. package/skills/manage-story-map/agents/openai.yaml +3 -0
  174. package/skills/mitigate-incident/SKILL.md +40 -40
  175. package/skills/mitigate-incident/agents/openai.yaml +3 -0
  176. package/skills/reconcile-readme/SKILL.md +28 -28
  177. package/skills/reconcile-readme/agents/openai.yaml +3 -0
  178. package/skills/reconcile-stories/SKILL.md +17 -17
  179. package/skills/reconcile-stories/agents/openai.yaml +3 -0
  180. package/skills/reconcile-story-maps/SKILL.md +11 -11
  181. package/skills/reconcile-story-maps/agents/openai.yaml +3 -0
  182. package/skills/report-upstream/SKILL.md +73 -73
  183. package/skills/report-upstream/agents/openai.yaml +3 -0
  184. package/skills/restore-incident/SKILL.md +28 -28
  185. package/skills/restore-incident/agents/openai.yaml +3 -0
  186. package/skills/review-problems/SKILL.md +129 -129
  187. package/skills/review-problems/agents/openai.yaml +3 -0
  188. package/skills/scaffold-intake/SKILL.md +26 -26
  189. package/skills/scaffold-intake/agents/openai.yaml +3 -0
  190. package/skills/transition-problem/SKILL.md +85 -85
  191. package/skills/transition-problem/agents/openai.yaml +3 -0
  192. package/skills/transition-problems/SKILL.md +69 -69
  193. package/skills/transition-problems/agents/openai.yaml +3 -0
  194. package/skills/update-upstream/SKILL.md +97 -97
  195. package/skills/update-upstream/agents/openai.yaml +3 -0
  196. package/skills/work-problem/SKILL.md +42 -42
  197. package/skills/work-problem/agents/openai.yaml +3 -0
  198. package/skills/work-problems/SKILL.md +327 -327
  199. package/skills/work-problems/agents/openai.yaml +3 -0
  200. package/skills-codex/capture-problem/REFERENCE.md +139 -0
  201. package/skills-codex/capture-problem/SKILL.md +438 -0
  202. package/skills-codex/capture-problem/agents/openai.yaml +3 -0
  203. package/skills-codex/capture-rfc/SKILL.md +45 -0
  204. package/skills-codex/capture-rfc/agents/openai.yaml +3 -0
  205. package/skills-codex/capture-story/SKILL.md +407 -0
  206. package/skills-codex/capture-story/agents/openai.yaml +3 -0
  207. package/skills-codex/capture-story-map/SKILL.md +286 -0
  208. package/skills-codex/capture-story-map/agents/openai.yaml +3 -0
  209. package/skills-codex/check-upstream-responses/SKILL.md +160 -0
  210. package/skills-codex/check-upstream-responses/agents/openai.yaml +3 -0
  211. package/skills-codex/close-incident/SKILL.md +192 -0
  212. package/skills-codex/close-incident/agents/openai.yaml +3 -0
  213. package/skills-codex/link-incident/SKILL.md +173 -0
  214. package/skills-codex/link-incident/agents/openai.yaml +3 -0
  215. package/skills-codex/list-incidents/SKILL.md +92 -0
  216. package/skills-codex/list-incidents/agents/openai.yaml +3 -0
  217. package/skills-codex/list-problems/SKILL.md +126 -0
  218. package/skills-codex/list-problems/agents/openai.yaml +3 -0
  219. package/skills-codex/list-stories/SKILL.md +170 -0
  220. package/skills-codex/list-stories/agents/openai.yaml +3 -0
  221. package/skills-codex/list-story-maps/SKILL.md +104 -0
  222. package/skills-codex/list-story-maps/agents/openai.yaml +3 -0
  223. package/skills-codex/manage-incident/SKILL.md +378 -0
  224. package/skills-codex/manage-incident/agents/openai.yaml +3 -0
  225. package/skills-codex/manage-problem/SKILL.md +1180 -0
  226. package/skills-codex/manage-problem/agents/openai.yaml +3 -0
  227. package/skills-codex/manage-rfc/SKILL.md +314 -0
  228. package/skills-codex/manage-rfc/agents/openai.yaml +3 -0
  229. package/skills-codex/manage-story/SKILL.md +284 -0
  230. package/skills-codex/manage-story/agents/openai.yaml +3 -0
  231. package/skills-codex/manage-story-map/SKILL.md +198 -0
  232. package/skills-codex/manage-story-map/agents/openai.yaml +3 -0
  233. package/skills-codex/mitigate-incident/SKILL.md +239 -0
  234. package/skills-codex/mitigate-incident/agents/openai.yaml +3 -0
  235. package/skills-codex/reconcile-readme/SKILL.md +175 -0
  236. package/skills-codex/reconcile-readme/agents/openai.yaml +3 -0
  237. package/skills-codex/reconcile-stories/SKILL.md +124 -0
  238. package/skills-codex/reconcile-stories/agents/openai.yaml +3 -0
  239. package/skills-codex/reconcile-story-maps/SKILL.md +81 -0
  240. package/skills-codex/reconcile-story-maps/agents/openai.yaml +3 -0
  241. package/skills-codex/report-upstream/SKILL.md +716 -0
  242. package/skills-codex/report-upstream/agents/openai.yaml +3 -0
  243. package/skills-codex/restore-incident/SKILL.md +216 -0
  244. package/skills-codex/restore-incident/agents/openai.yaml +3 -0
  245. package/skills-codex/review-problems/SKILL.md +524 -0
  246. package/skills-codex/review-problems/agents/openai.yaml +3 -0
  247. package/skills-codex/scaffold-intake/SKILL.md +209 -0
  248. package/skills-codex/scaffold-intake/agents/openai.yaml +3 -0
  249. package/skills-codex/scaffold-intake/templates/CONTRIBUTING.md.tmpl +31 -0
  250. package/skills-codex/scaffold-intake/templates/SECURITY.md.tmpl +39 -0
  251. package/skills-codex/scaffold-intake/templates/SUPPORT.md.tmpl +32 -0
  252. package/skills-codex/scaffold-intake/templates/config.yml.tmpl +8 -0
  253. package/skills-codex/scaffold-intake/templates/problem-report.yml.tmpl +114 -0
  254. package/skills-codex/transition-problem/SKILL.md +371 -0
  255. package/skills-codex/transition-problem/agents/openai.yaml +3 -0
  256. package/skills-codex/transition-problems/SKILL.md +310 -0
  257. package/skills-codex/transition-problems/agents/openai.yaml +3 -0
  258. package/skills-codex/update-upstream/SKILL.md +583 -0
  259. package/skills-codex/update-upstream/agents/openai.yaml +3 -0
  260. package/skills-codex/work-problem/SKILL.md +160 -0
  261. package/skills-codex/work-problem/agents/openai.yaml +3 -0
  262. package/skills-codex/work-problems/SKILL.md +58 -0
  263. package/skills-codex/work-problems/agents/openai.yaml +3 -0
  264. package/templates/story-map.css +1 -1
  265. package/bin/wr-itil-mark-rfc-capture-gate +0 -51
  266. package/scripts/mark-rfc-capture-gate.sh +0 -32
@@ -0,0 +1,583 @@
1
+ ---
2
+ name: wr-itil:update-upstream
3
+ description: Post a lifecycle-update comment to an upstream issue when a local problem ticket transitions. Drafts a transition-specific update (root-cause confirmed / fix released / closed), composes the prose through the external-comms risk gate + voice-tone gate, auto-posts within appetite, queues above-appetite. Reciprocal sibling to /wr-itil:report-upstream — initial-filing vs lifecycle-update split per the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem).
4
+ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, request_user_input, Skill, Agent
5
+ ---
6
+
7
+ <!-- Generated from the runtime-neutral skill source. Do not edit. -->
8
+
9
+ > Codex runtime note: use `request_user_input` only where this contract
10
+ > explicitly requires a human decision. Resolve `<itil-plugin-root>` from
11
+ > this installed `SKILL.md`: it is two directories above the skill
12
+ > directory. Run bundled commands from `<itil-plugin-root>/bin/`; do not
13
+ > search the adopter repository or rely on those commands being on `PATH`.
14
+ > Spawn `wr-itil:hang-off-check` with the native Codex subagent tool, wait
15
+ > for it, and close that same agent.
16
+
17
+
18
+ <!--
19
+ @jtbd the "Report a Problem Without Pre-Classifying It" user outcome (Report a Problem Without Pre-Classifying It — reporter feedback loop)
20
+ @jtbd the ": Enforce Governance Without Slowing Down" user outcome (Enforce Governance Without Slowing Down — no manual policing of upstream issues)
21
+ @jtbd the "Restore Service Fast with an Audit Trail" user outcome (Restore Service Fast with an Audit Trail — symmetric local/upstream audit trail)
22
+ @jtbd the "Extend the Suite with New Plugins" user outcome (Extend the Suite with Clear Patterns — downstream adopters inherit bidirectional contract)
23
+ @problem the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem
24
+ @adr the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule (amended the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem — bidirectional lifecycle updates; Phase 2 — --catchup migration mode + idempotency)
25
+ @adr the "Plugin-bundled scripts invoked from SKILL.md resolve via `bin/` on `$PATH`" architecture rule (catchup worklist scanner invoked via <itil-plugin-root>/bin/wr-itil-catchup-scan bin shim)
26
+ @adr the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule (voice-tone gate on `gh issue comment` / `gh issue close`)
27
+ @adr the "Structured User Interaction for Governance-Skill Decisions" architecture rule (Rule 1 request_user_input; Rule 6 AFK fail-safe)
28
+ @adr the "Governance Skills Commit Their Own Completed Work" architecture rule (single-commit grain — transition + back-write + upstream comment)
29
+ @adr the "Rename `wr-problem` Plugin to `wr-itil`" architecture rule amended (sibling-skill naming; split execution ownership)
30
+ @adr the "— Decision-Delegation Contract: when agents act on the framework vs ask the user" architecture rule (decision-delegation contract — framework-resolution boundary)
31
+ @adr the ": promptfoo as the behavioural test harness for agent-prose verdicts" architecture rule (Amendment 2026-06-02 — paired promptfoo eval discharges the ": Functional defects in shipped plugin behaviour" standing risk prose floor)
32
+ @adr the ": promptfoo as the behavioural test harness for agent-prose verdicts" architecture rule (evidence-floor — paired Tier-A/B eval ships in same commit as SKILL)
33
+ -->
34
+
35
+ # Update Upstream — Lifecycle-Update Skill
36
+
37
+ Post a lifecycle-update comment to an upstream issue or pull request when the local problem ticket transitions. Reads the local ticket's `## Reported Upstream` section, drafts a transition-specific update from the templates below, composes the draft through the external-comms risk gate (`wr-risk-scorer:external-comms`) and voice-tone gate (`wr-voice-tone:external-comms`), auto-posts via `gh issue comment` or `gh pr comment` when both gates pass within appetite, closes only issue targets on Verifying → Closed, and queues an `outstanding_questions` entry when either gate scores above appetite.
38
+
39
+ This skill is the **reciprocal sibling** to [`/wr-itil:report-upstream`](../report-upstream/SKILL.md) — that skill files the initial upstream report; this skill keeps the upstream record in sync as the local ticket walks its lifecycle. The split is per [the "Rename `wr-problem` Plugin to `wr-itil`" architecture rule](../../../docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md) amended Skill Granularity rule (one skill per distinct user intent) — initial-filing and lifecycle-update are distinct user intents with distinct autocomplete surfaces.
40
+
41
+ This skill implements the bidirectional extension to the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule's outbound contract — see the **the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem)** entry in the ADR's `## Amendments` section. The amendment authorises this sibling skill, defines the transition-template shape, and pins the same external-comms + voice-tone gate composition that the post-the "Agent waits for human to initiate upstream report instead of filing on detect — feedback delay class" problem amendment uses for the initial-filing path.
42
+
43
+ ## Invocation
44
+
45
+ ```
46
+ /wr-itil:update-upstream <NNN> # single-ticket lifecycle update
47
+ /wr-itil:update-upstream --catchup # batch-retroactive migration (Phase 2)
48
+ ```
49
+
50
+ - `<NNN>`: the three-digit local ticket ID (e.g. `080`). The ticket file is discovered via the same dual-tolerant lookup as [`/wr-itil:report-upstream`](../report-upstream/SKILL.md) (flat layout + per-state subdir per the ": docs/problems/ flat layout migration — per-state subdirs + adopter auto-migration" release design migration window).
51
+ - `--catchup`: one-shot batch-retroactive migration mode (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2 — see [§ Catchup migration mode](#catchup-migration-mode-phase-2)). Walks the existing `.verifying.md` + `.closed.md` corpus and posts the lifecycle update each ticket should have received but did not (because it was reported upstream / transitioned before the per-ticket auto-update path shipped). Idempotent — already-updated tickets are skipped.
52
+
53
+ The single-ticket form is typically invoked from `/wr-itil:transition-problem` Step 7's advisory subsection when the transitioning ticket carries a `## Reported Upstream` section (per the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule Confirmation criterion 3a — the back-write that `/wr-itil:report-upstream` Step 7 writes). User-initiated single-ticket invocation is also supported. The `--catchup` form is user-initiated only (a deliberate one-shot migration, never auto-fired from a transition).
54
+
55
+ ## Scope
56
+
57
+ **In scope:**
58
+ - Read the local ticket's `## Reported Upstream` section and extract each upstream URL + matched template + disclosure path recorded there (**outbound** direction).
59
+ - Read the local ticket's `**Origin**: inbound-reported (#NN)` field and dispatch a reporter-facing fix-released / closed verdict comment on the originating own-repo issue (**inbound** direction, the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem). See [§ Inbound-origin verdict dispatch (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem)](#inbound-origin-verdict-dispatch-p363).
60
+ - Determine the local ticket's current Status from the filename suffix.
61
+ - Draft a transition-specific lifecycle-update comment per the templates below (Open→KE / KE→Verifying / Verifying→Closed).
62
+ - Compose the drafted prose through `wr-risk-scorer:external-comms` + `wr-voice-tone:external-comms` gates.
63
+ - Within appetite → post via `gh issue comment <n>`, or `gh pr comment <n>` when the disclosure path records a pull request (the "Prefer an upstream pull request over an issue when the upstream accepts pull requests" architecture rule); on Verifying→Closed also run `gh issue close <n>` — **but never `gh pr close`** (see below).
64
+ - Above appetite → request_user_input (interactive) / queue `outstanding_questions` (AFK, per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem queue-and-continue).
65
+ - Back-write a `## Upstream Lifecycle Updates` log entry to the local ticket recording the transition, the matched URL, the posted comment URL, and the disclosure path.
66
+ - **Historical catch-up migration (`--catchup`, the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2)** — one-shot retroactive scan of the existing `.verifying.md` + `.closed.md` corpus; posts the lifecycle update each linked-upstream ticket should already carry. Idempotent — re-running is safe. See [§ Catchup migration mode](#catchup-migration-mode-phase-2).
67
+
68
+ **Out of scope:**
69
+ - Initial upstream filing — that's `/wr-itil:report-upstream`.
70
+ - Cross-tracker propagation (linking the upstream update back into a different upstream's parallel issue) — out of scope; one local ticket → N upstream URLs is supported, but each URL update is independent.
71
+
72
+ ## Step-0 deferral (the "Governance skill auto-delegation — Step 0 delegates skill workflow to a subagent" architecture rule)
73
+
74
+ This skill does NOT implement the "Governance skill auto-delegation — Step 0 delegates skill workflow to a subagent" architecture rule's Step-0 auto-delegation pattern. Same rationale as [`/wr-itil:report-upstream`](../report-upstream/SKILL.md) Step-0 deferral: the local ticket and the `## Reported Upstream` extraction must stay in main-agent context for the gate composition and the back-write, so wrapping the flow in a subagent would not reduce main-agent context cost. Trigger to revisit per the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule's Reassessment Criteria — if a third skill that reads `## Reported Upstream` lands, factor the read into a Step-0-delegated subagent.
75
+
76
+ ## Voice-tone gate interaction (the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule)
77
+
78
+ The skill's `gh issue comment` and `gh issue close` calls are **on the gated surface list per [the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule](../../../docs/decisions/028-voice-tone-gate-external-comms.proposed.md)** (Voice-tone gate on external communications). Expected behaviour during these tool calls:
79
+
80
+ 1. The voice-tone gate fires `PreToolUse:Bash` with a deny-plus-delegate response.
81
+ 2. The hook delegates to `wr-voice-tone:agent` to review the drafted body for brand-voice + tone alignment against `docs/VOICE-AND-TONE.md`.
82
+ 3. Once the agent's marker lands, the same `gh issue comment` or `gh issue close` call retries and proceeds.
83
+
84
+ The skill should treat this transient deny-plus-delegate as the expected path, not as an error.
85
+
86
+ If `wr-voice-tone:agent` is not installed in the project, the gate is dormant and the skill proceeds without delegation.
87
+
88
+ ## Steps
89
+
90
+ ### 1. Read the local problem ticket
91
+
92
+ Dual-tolerant lookup spans flat layout AND per-state subdir layout (the ": docs/problems/ flat layout migration — per-state subdirs + adopter auto-migration" release design migration window):
93
+
94
+ ```bash
95
+ LOCAL_TICKET=$(ls docs/problems/${LOCAL_ID}-*.{open,known-error,verifying,closed,parked}.md docs/problems/*/${LOCAL_ID}-*.md 2>/dev/null | head -1)
96
+ [ -n "$LOCAL_TICKET" ] || { echo "Error: local ticket P${LOCAL_ID} not found in docs/problems/"; exit 1; }
97
+ ```
98
+
99
+ Extract:
100
+ - Title (from H1).
101
+ - Current Status (from filename suffix — `.open.md` / `.known-error.md` / `.verifying.md` / `.closed.md` / `.parked.md`).
102
+ - The `## Reported Upstream` section (zero or more **outbound** upstream entries, each with URL + disclosure path) — the **outbound** direction (a ticket *we* reported up to someone else).
103
+ - The `**Origin**: inbound-reported (#NN)` field (the [the "Inbound-reported problems rank ahead of internally-discovered problems via a sort tier" architecture rule](../../../docs/decisions/076-inbound-reported-problems-rank-ahead-via-sort-tier.proposed.md) rank-authoritative on-ticket field) — the **inbound** direction (a ticket someone else reported *against us* on our own repo, `#NN` being the originating issue). Drives the inbound dispatch leg below (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem).
104
+ - For `.verifying.md` tickets: the `## Fix Released` section (release marker, version, commit SHA, PR number).
105
+ - For `.known-error.md` tickets: the `## Fix Strategy` section (planned fix path; cited in KE updates so the reporter knows the direction).
106
+
107
+ **No-op exit (dual-direction).** If the ticket has NEITHER a `## Reported Upstream` section NOR an `**Origin**: inbound-reported (#NN)` field, exit cleanly with a one-line message: `No ## Reported Upstream section and no inbound Origin in P${LOCAL_ID}; nothing to update.` This is the **no-op exit** — most local tickets are neither reported upstream nor inbound-originated, and the skill's invocation from `transition-problem` Step 7 is unconditional; a missing surface is the common case, not an error. When EITHER surface is present, proceed: the outbound entries route through Steps 2–6; the inbound Origin field routes through the [§ Inbound-origin verdict dispatch (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem)](#inbound-origin-verdict-dispatch-p363) leg below. When BOTH are present, the two legs fire **independently** (each gate-composed, posted, and logged separately).
108
+
109
+ ### 2. Parse each upstream entry
110
+
111
+ For each `- **URL**: <url>` line under `## Reported Upstream`, extract:
112
+ - The upstream URL.
113
+ - The matched template name (`- **Template used**: <name>`).
114
+ - The disclosure path (`- **Disclosure path**: <path>`).
115
+ - The reported date (`- **Reported**: <YYYY-MM-DD>`).
116
+
117
+ Skip entries whose disclosure path is `drafted-and-saved (mailbox / out-of-band)` — those reports were never filed via `gh`, so there is no issue to comment on. Log a one-line skip note: `Skipping upstream entry <url> — disclosure path is out-of-band; user follow-up required.` The skip is **not** queued as an `outstanding_questions` entry (the user already owns the out-of-band channel per the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule no-infra-for-email constraint).
118
+
119
+ Multiple `## Reported Upstream` entries are supported (the local ticket may have been filed to multiple upstream trackers). Process each entry independently — the gate composition + post + back-write all run per-entry; one above-appetite entry queues only that entry, the rest proceed.
120
+
121
+ ### 3. Determine the transition that fired this invocation
122
+
123
+ The skill is typically invoked AFTER the local ticket's filename suffix has changed (the `transition-problem` Step 7 advisory subsection fires AFTER the `git mv` + Status edit + re-stage). Compare the current suffix against the most recent `## Upstream Lifecycle Updates` log entry (if any) to identify which transition just fired:
124
+
125
+ | Last logged Status | Current suffix | Transition fired |
126
+ |---|---|---|
127
+ | (none) | `.known-error.md` | Open → Known Error |
128
+ | (none) | `.verifying.md` | Open → Known Error (skipped) → Verification Pending |
129
+ | Open | `.known-error.md` | Open → Known Error |
130
+ | Known Error | `.verifying.md` | Known Error → Verification Pending |
131
+ | Verification Pending | `.closed.md` | Verification Pending → Closed |
132
+ | any | matching last logged | no transition since last update — exit no-op |
133
+
134
+ If the current suffix matches the last logged Status, exit clean: `No transition since last upstream update; nothing to post.` This guards against re-firing on a manage-problem update that doesn't change Status (Priority/Effort/WSJF edits, root-cause refinement edits).
135
+
136
+ If the current suffix is `.parked.md`, exit clean: `Local ticket is Parked; no upstream lifecycle update applies.` Parking is a transient hold (per the "Problem lifecycle — add a Verification Pending status between Known Error and Closed" architecture rule) and does not warrant an upstream comment.
137
+
138
+ ### 4. Draft the lifecycle-update comment
139
+
140
+ Per-transition templates. Each template's `<placeholders>` are filled from the local ticket's sections (per Step 1's extraction).
141
+
142
+ #### Open → Known Error template
143
+
144
+ ```markdown
145
+ Update from <downstream-repo-url>/<local-ticket-relative-path>:
146
+
147
+ **Status**: Root cause identified (local ticket transitioned to Known Error).
148
+
149
+ **Investigation findings**:
150
+
151
+ <one-paragraph synthesis from the local ticket's Root Cause Analysis section — substantive, not just "we found it">
152
+
153
+ **Planned fix path**:
154
+
155
+ <from the local ticket's Fix Strategy section, or "Fix path under design" if absent>
156
+
157
+ **Workaround**:
158
+
159
+ <from the local ticket's Workaround section, or "None identified yet" if absent>
160
+
161
+ We'll post here again when the fix releases. Local tracking: P<NNN>.
162
+ ```
163
+
164
+ #### Known Error → Verification Pending template
165
+
166
+ ```markdown
167
+ Update from <downstream-repo-url>/<local-ticket-relative-path>:
168
+
169
+ **Status**: Fix released (local ticket transitioned to Verification Pending).
170
+
171
+ **Release**:
172
+
173
+ - **Package**: `<package>@<version>` (or "see release notes" if not derivable)
174
+ - **Merge PR**: #<N> (or commit SHA if direct-to-main)
175
+ - **Released**: <YYYY-MM-DD>
176
+
177
+ **Fix summary**:
178
+
179
+ <one-sentence summary from the local ticket's ## Fix Released section>
180
+
181
+ Please upgrade and verify when convenient. We'll close this issue after your confirmation OR after a 14-day quiet period (per the "Problem 048: manage-problem does not surface Fix Released problems as verification candidates when the fix path has been exercised" problem default). Local tracking: P<NNN>.
182
+ ```
183
+
184
+ #### Verification Pending → Closed template
185
+
186
+ ```markdown
187
+ Update from <downstream-repo-url>/<local-ticket-relative-path>:
188
+
189
+ **Status**: Closed locally after user-side verification.
190
+
191
+ Closing this issue to match. Thanks for the report — your filing is what got this on the queue. Local tracking: P<NNN>.
192
+ ```
193
+
194
+ After posting the Verifying → Closed comment, the skill also runs `gh issue close <n>` (per Step 5b below) so the upstream tracker matches local state.
195
+
196
+ #### Template-filling rules
197
+
198
+ - **No invention**: if a section the template cites is absent from the local ticket, write the explicit "absent" phrasing ("Fix path under design", "None identified yet") rather than synthesising content. The risk gate and voice-tone gate cannot guard against invented technical claims; the no-invention rule does.
199
+ - **Source-citation**: every template starts with `Update from <downstream-repo-url>/<local-ticket-relative-path>:` so the upstream maintainer can navigate back to the source ticket without ambiguity. The cross-reference URL uses the same shape as `/wr-itil:report-upstream` Step 5's `## Cross-reference` section.
200
+ - **No "we" assumptions about the upstream maintainer**: the lifecycle templates are written from the downstream-reporter perspective. Use "we" only when referring to the downstream team; do not use it to suggest joint authorship of the upstream fix unless the local ticket's Fix Strategy explicitly records an upstream-collaborative path.
201
+
202
+ ### 5. Compose through external-comms + voice-tone gates
203
+
204
+ #### 5a. External-comms risk gate
205
+
206
+ Score the drafted comment body via the `wr-risk-scorer:external-comms` agent (shipped per [the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule](../../../docs/decisions/028-voice-tone-gate-external-comms.proposed.md) — the same agent the post-the "Agent waits for human to initiate upstream report instead of filing on detect — feedback delay class" problem amendment uses for the initial-filing path's pre-fire gate). Invocation: delegate via the native Codex subagent tool with `subagent_type: "wr-risk-scorer:external-comms"` passing the drafted body + the upstream URL + the transition type as context.
207
+
208
+ The agent returns a structured verdict:
209
+
210
+ ```
211
+ EXTERNAL_COMMS_RISK_VERDICT
212
+ band: Low (<=4/25) | Medium (5..16) | High (17+)
213
+ score: <0..25>
214
+ pass: true | false
215
+ reason: <one-line rationale>
216
+ ```
217
+
218
+ - **`pass: true` AND band ≤ Low (4/25)**: within appetite per RISK-POLICY.md commit-layer. Proceed to 5b (voice-tone).
219
+ - **`pass: false` OR band > Low**: above appetite. Branch to 5c (above-appetite handling).
220
+
221
+ #### 5b. Voice-tone gate
222
+
223
+ `gh issue comment` and `gh issue close` are on the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule gated surface list. The PreToolUse:Bash hook fires deny-plus-delegate to `wr-voice-tone:agent`. The agent reads the drafted body against `docs/VOICE-AND-TONE.md` and writes the bypass marker on PASS; the original `gh` call retries automatically.
224
+
225
+ A FAIL verdict on the voice-tone gate is treated identically to an above-appetite risk verdict — branch to 5c.
226
+
227
+ #### 5c. Above-appetite handling
228
+
229
+ The decision policy here is **framework-resolved** per [the "— Decision-Delegation Contract: when agents act on the framework vs ask the user" architecture rule](../../../docs/decisions/044-decision-delegation-contract.proposed.md) (decision-delegation contract) and the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6 (AFK fail-safe). No per-transition `request_user_input` for the GATE FIRING — the gate scoring is itself the framework. The above-appetite handling differs by orchestrator context:
230
+
231
+ - **Interactive context** (per the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 1): use `request_user_input` to surface the drafted comment + the gate verdict + the matched URL, with options:
232
+ - `Post the comment anyway (Recommended after review)` — user has read the draft and judged the post warranted; the skill bypasses the gate for this single post.
233
+ - `Risk-reduce and re-score` — invoke a tighter draft (shorter / fewer claims / stricter source-citation) and re-run the gate.
234
+ - `Queue for later review` — save the draft to `## Queued Upstream Update` on the local ticket; user acts on return.
235
+ - `Skip this update` — exit no-op for this upstream entry; the next transition's invocation re-considers.
236
+
237
+ - **AFK / non-interactive context** (per the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6 + the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem queue-and-continue): the skill applies **silent risk-reduce + re-score** first — re-draft the comment with tighter source-citation + shorter prose, then re-invoke the external-comms gate. If the re-scored verdict is within appetite, proceed via 5b. Otherwise, save the drafted comment to the local ticket's `## Queued Upstream Update` section (shape below) and queue an `outstanding_questions` entry (category: `deviation-approval`) naming the local ticket ID + the matched URL + the residual band + the risk-reduce attempts taken. **The orchestrator continues per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem** — do NOT halt the loop on an above-appetite upstream update.
238
+
239
+ The silent risk-reduce step is **mechanical** per the "— Decision-Delegation Contract: when agents act on the framework vs ask the user" architecture rule framework-resolution boundary — the skill owns the re-draft; per-iter `request_user_input` for risk-reduce vocabulary is the lazy-deferral anti-pattern the "Agents over-ask in interactive sessions — conflating mechanical-stages with user-interactive-stages of multi-stage skill contracts (inverse-)" problem closes.
240
+
241
+ #### Queued Upstream Update save format
242
+
243
+ ```markdown
244
+ ## Queued Upstream Update
245
+
246
+ - **Drafted**: <YYYY-MM-DD>
247
+ - **Transition**: Open → Known Error | Known Error → Verification Pending | Verification Pending → Closed
248
+ - **Target URL**: <upstream-issue-url>
249
+ - **Halt reason**: above-appetite external-comms gate (band: <verdict band>; score: <verdict score>; reason: <verdict reason>) | above-appetite voice-tone gate (reason: <verdict reason>)
250
+ - **Risk-reduce attempts**: <count, e.g. "1 — tighter source-citation; re-scored band Medium">
251
+ - **Drafted comment body**:
252
+
253
+ <the body that would have been posted as a `gh issue comment`, ready for manual review>
254
+ ```
255
+
256
+ Per [the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule](../../../docs/decisions/024-cross-project-problem-reporting-contract.proposed.md) amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem), the section name `## Queued Upstream Update` is the lifecycle-update analogue of `## Queued Upstream Report` (the initial-filing analogue per the 2026-06-04 second-amendment leaf (c) rename). Same shape; distinct section so a single local ticket can carry both a queued report (initial filing held) and a queued update (lifecycle update held) without collision.
257
+
258
+ ### 5b. (final). Post via gh issue comment
259
+
260
+ Within-appetite path. Post the drafted comment:
261
+
262
+ ```bash
263
+ gh issue comment "${UPSTREAM_ISSUE_NUMBER}" \
264
+ --repo "${UPSTREAM_OWNER_REPO}" \
265
+ --body "${DRAFTED_COMMENT_BODY}"
266
+ ```
267
+
268
+ Capture the returned comment URL (gh prints `https://github.com/<owner>/<repo>/issues/<n>#issuecomment-<id>`).
269
+
270
+ On the **Verifying → Closed** transition, after posting the comment, also close the upstream issue:
271
+
272
+ ```bash
273
+ gh issue close "${UPSTREAM_ISSUE_NUMBER}" \
274
+ --repo "${UPSTREAM_OWNER_REPO}" \
275
+ --comment "" \
276
+ --reason completed
277
+ ```
278
+
279
+ `--comment ""` suppresses gh's own auto-comment (we already posted the closing comment above); `--reason completed` matches the `.closed.md` semantics.
280
+
281
+ If the issue is already closed upstream (someone else closed it manually), `gh issue close` returns a benign error — capture the existing state and continue to Step 6 with `closed-already-upstream` recorded in the back-write disclosure path.
282
+
283
+ #### Pull-request targets never get closed (the "Prefer an upstream pull request over an issue when the upstream accepts pull requests" architecture rule)
284
+
285
+ When the `## Reported Upstream` disclosure path records a **pull request**, post the comment with `gh pr comment` and **stop there**. Do not run `gh pr close`, on this transition or any other.
286
+
287
+ A merged pull request closes itself, so closing is redundant. An unmerged one is still work we authored and offered; closing it is a hostile act against our own contribution and withdraws it from the maintainer's queue without saying so. The local ticket reaching `.closed.md` means *we* consider the problem resolved locally — it does not mean the upstream has finished deciding.
288
+
289
+ Record `posted-pr-comment` in the back-write disclosure path. On a pull-request target `posted-comment-and-closed` is unreachable by construction.
290
+
291
+ ### 6. Back-write to local ticket
292
+
293
+ Append a log entry to the local ticket's `## Upstream Lifecycle Updates` section (create the section if absent — never inserted mid-document; appended after all existing sections per the same discipline as `## Reported Upstream` in `/wr-itil:report-upstream` Step 7):
294
+
295
+ ```markdown
296
+ ## Upstream Lifecycle Updates
297
+
298
+ - **<YYYY-MM-DD>** — Open → Known Error
299
+ - **Target URL**: <upstream-issue-url>
300
+ - **Comment URL**: <posted-comment-url> (or "queued — see ## Queued Upstream Update" when above-appetite)
301
+ - **Disclosure path**: posted-comment | posted-pr-comment (pull-request target, the "Prefer an upstream pull request over an issue when the upstream accepts pull requests" architecture rule — never closed) | posted-comment-and-closed (Verifying → Closed, issue targets only) | queued-above-appetite | closed-already-upstream | skipped-out-of-band
302
+ - **Gate verdict**: external-comms <band/score> + voice-tone <pass|fail>
303
+
304
+ - **<YYYY-MM-DD>** — Known Error → Verification Pending
305
+ - ... (next entry appends; never replaces earlier entries)
306
+ ```
307
+
308
+ The log is append-only — each transition adds an entry; earlier entries are never overwritten. The log is the audit trail per the "Restore Service Fast with an Audit Trail" user outcome's symmetric-audit-trail outcome and per the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule Confirmation criterion 3a's `## Reported Upstream` back-write pattern (extended for the bidirectional case).
309
+
310
+ ### Inbound-origin verdict dispatch (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem)
311
+
312
+ <!-- @jtbd the "Report a Problem Without Pre-Classifying It" user outcome (Report a Problem Without Pre-Classifying It — inbound reporter feedback loop: the fix-released verdict leg for tickets someone else filed against us) -->
313
+
314
+ This leg runs **in addition to** Steps 2–6 (the outbound `## Reported Upstream` path), keyed off the `**Origin**: inbound-reported (#NN)` field Step 1 extracted. It closes the "Report a Problem Without Pre-Classifying It" user outcome fix-released-verdict promise for the **inbound** direction — a plugin-user filed a `problem-report` issue *against us* (recorded at intake by the "Inbound upstream-report discovery + assessment pipeline (peer of )" architecture rule's safe-and-valid branch, which stamps the on-ticket `**Origin**` field per [the "Inbound-reported problems rank ahead of internally-discovered problems via a sort tier" architecture rule](../../../docs/decisions/076-inbound-reported-problems-rank-ahead-via-sort-tier.proposed.md)) and never heard the fix shipped because the outbound machinery only reads `## Reported Upstream`. Authority: [the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule](../../../docs/decisions/024-cross-project-problem-reporting-contract.proposed.md) amendment (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem, inbound-verdict dispatch leg).
315
+
316
+ **Why the Origin field, not `## Reported Upstream` (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem design):** the inbound issue lives on OUR OWN repo (it was filed against us). Writing it into `## Reported Upstream` would contaminate `/wr-itil:check-upstream-responses` (the "No process for issue reporters to check for responses — symmetric gap to inbound discovery" problem), which polls that section as OUTBOUND issues we filed *elsewhere*. Consuming the `**Origin**` field — distinct by construction — keeps the inbound and outbound data shapes separate and the "No process for issue reporters to check for responses — symmetric gap to inbound discovery" problem uncontaminated.
317
+
318
+ #### I1. Parse the inbound origin
319
+
320
+ From the `**Origin**: inbound-reported (#NN)` field, extract the originating issue number `NN`. Resolve the repo it lives on as **our own repo** — the `gh` default for the current working tree (`gh repo view --json nameWithOwner -q .nameWithOwner`), NOT an external upstream owner/repo. If the `**Origin**` field is `internal` or absent, this leg does not run (the no-op is already handled at Step 1 when both surfaces are absent).
321
+
322
+ #### I2. Determine the transition (same suffix logic as Step 3)
323
+
324
+ Reuse Step 3's transition table (filename-suffix vs last-logged Status) — it is direction-agnostic. The inbound leg fires verdict comments for the **fix-released** and **closed** transitions (the verdicts a reporter most wants); Open → Known Error fires an optional progress comment only when the reporter explicitly asked for status. If the suffix matches the last logged inbound entry, exit no-op (`No inbound transition since last update; nothing to post.`).
325
+
326
+ #### I3. Generate the inbound verdict comment (reporter-facing, LLM-generated — no templates)
327
+
328
+ These comments are **generated from the local ticket's context, not filled from canned templates** (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem rework, Directive 1). Templates produce cold, patterned prose that reporters recognise as form-letters; instead the agent reads the source-of-truth sections below and GENERATES each comment per the per-transition prompt, then rides the gate chain in [I5](#i5-compose-through-gates--post-same-composition-as-step-5) (cog-a11y → risk → voice-tone).
329
+
330
+ **Source-of-truth sections** (read from the local ticket before generating): `## Description` (the reporter's original symptom report), `## Workaround`, `## Root Cause Analysis`, `## Fix Released` (the release marker, version, commit SHA — the released `@windyroad/<pkg>@<version>` upgrade target comes from here).
331
+
332
+ **No-invention rule (load-bearing, carried from Step 4):** if a cited section is absent or empty, say so honestly ("we don't have a workaround to share yet") — NEVER synthesise technical claims. The gates cannot catch invented facts; the no-invention rule does. This mirrors the "Inbound upstream-report discovery + assessment pipeline (peer of )" architecture rule's safe-and-valid acknowledgement shape (Decision Outcome step 6).
333
+
334
+ **Anti-leakage discipline (the "Inbound-discovery ack comments are bureaucratic, not verdict-shaped ( violation)" problem/the "agent surfaces decisions to user using opaque IDs (P-numbers, ADR-numbers, JTBD-numbers) without explaining what they mean — empathy gap" problem — REVISED per repo visibility, Directive 3):** these bodies are reporter-facing on our own repo. Determine repo visibility once: `gh repo view --json visibility -q .visibility` → `PUBLIC` / `PRIVATE` / `INTERNAL`.
335
+
336
+ - **PUBLIC** — you MAY refer to a problem / ADR / RFC / JTBD / Story, but ALWAYS by its **title AND as a link**, never a bare ID:
337
+ - Bad (bare ID, opaque): `Tracked locally as the "Latent octal-eval bug in next-ID formula across all 4 ticket-creator skills — `$(( $local_max + 1 ))` fails with "value too great for base" when local_max reaches 099" problem.`
338
+ - Bad (title only, no link): `Tracked as the octal-eval bug.`
339
+ - Good (title + linked ID): `Tracked as [Latent octal-eval bug in next-ID formula](https://github.com/windyroad/agent-plugins/blob/main/docs/problems/known-error/164-octal-eval-bug-in-next-id-formula-across-ticket-creator-skills-fires-when-ids-cross-099.md) (the "Latent octal-eval bug in next-ID formula across all 4 ticket-creator skills — `$(( $local_max + 1 ))` fails with "value too great for base" when local_max reaches 099" problem).`
340
+ - Resolve the link: ADR / RFC / JTBD / Story canonical paths live on `main`; for a problem ticket the filename carries the state suffix + slug — resolve the actual filename via `ls docs/<class>/<NNN>-*` (or `gh search code`) before linking. Grounded in [the "Plugin-published artefacts use namespace-prefixed permalinks for internal IDs" architecture rule](../../../docs/decisions/055-plugin-published-namespace-prefixed-internal-ids.proposed.md)'s permalink-progressive-enhancement shape and the "Inbound-discovery ack comments are bureaucratic, not verdict-shaped ( violation)" problem's jargon-vs-link distinction.
341
+ - **PRIVATE / INTERNAL / indeterminate** — strict ban (the prior the "Inbound-discovery ack comments are bureaucratic, not verdict-shaped ( violation)" problem rule): omit problem / ADR / RFC / JTBD / Story references entirely. External readers can't reach the URLs, so a link is worse than no reference.
342
+
343
+ **Always banned (regardless of visibility):** classification tokens (`safe-and-valid`, `inbound-reported`, `clear-malicious`, `above-threshold-pushback`), internal step IDs (`Step 4.5e`, `step 6`), agent-internal vocabulary (`framework-resolution boundary`, `mechanical-stage carve-out`), runtime-detail prose (`marker-vs-file deadlock`, `subprocess-boundary contract`), and absolute `docs/problems/...` path strings (always prefer the rendered link). The released `@windyroad/<pkg>@<version>` upgrade target is always permitted.
344
+
345
+ **Open → Known Error generation prompt** (only when the reporter explicitly asked for interim status — otherwise skip O→KE and wait for the fix-released verdict):
346
+
347
+ ```text
348
+ GOAL: convey the root cause in plain, reporter-readable terms, AND share the
349
+ WORKAROUND so the reporter is unblocked while the fix is in flight (Directive 2).
350
+
351
+ READ: ## Description (their symptom report), ## Root Cause Analysis, ## Workaround.
352
+
353
+ ROOT CAUSE: explain what's actually going wrong in terms the reporter can act
354
+ on — no internal mechanism jargon.
355
+
356
+ WORKAROUND — share it with correct PROVENANCE (Directive 4):
357
+ 1. ## Workaround empty / "(deferred to investigation)": be honest — "we don't
358
+ have a workaround to share yet" — do NOT fabricate one.
359
+ 2. Otherwise determine WHO first provided it. Read the originating issue's
360
+ body + comments:
361
+ gh issue view <NN> --repo <OWN_OWNER_REPO> --json comments,body \
362
+ --jq '.body, .comments[].body'
363
+ and semantically match (your judgement, not strict-string) the local
364
+ ## Workaround against the issue body and each commenter's prose:
365
+ - MAINTAINER-AUTHORED (no match in issue body or any comment): share the
366
+ workaround in our own voice.
367
+ - REPORTER-PROVIDED (matches the issue body / the reporter's own comment):
368
+ credit the reporter — e.g. "Thanks again — your workaround in the
369
+ original report turned out to be exactly right. To confirm the details:"
370
+ then the exact ## Workaround prose (we've validated it).
371
+ - COMMENTER-PROVIDED (matches a comment by someone other than the
372
+ reporter): credit them by @handle — e.g. "@<handle> — your workaround
373
+ upthread turned out to be the right path. Confirmed the details:" then
374
+ the exact ## Workaround prose.
375
+ - BOTH-SOURCE (reporter proposed X, a commenter refined to X'): credit
376
+ both per their contribution.
377
+ Honour @handles via standard GitHub-flavoured markdown so the credited
378
+ person is notified.
379
+ 3. Always CONFIRM THE EXACT workaround details (the validated ## Workaround
380
+ prose) — never paraphrase a confirmed workaround into vagueness.
381
+
382
+ LENGTH: concise — usually 3–6 sentences. Bullet list ONLY for a genuine
383
+ multi-step workaround. Apply the anti-leakage discipline above. Voice/tone per
384
+ docs/VOICE-AND-TONE.md (the voice-tone gate runs anyway).
385
+ ```
386
+
387
+ **Known Error → Verification Pending (fix released) generation prompt:**
388
+
389
+ ```text
390
+ GOAL: tell the reporter the fix shipped, name the upgrade target, invite verify.
391
+
392
+ READ: ## Fix Released (release marker, version, commit SHA), ## Workaround.
393
+
394
+ INCLUDE:
395
+ - What changed, in one reporter-readable sentence (from ## Fix Released) — no
396
+ invented detail.
397
+ - The upgrade target: `@windyroad/<pkg>@<version>` (or later).
398
+ - If ## Workaround had a workaround: note it's no longer needed after upgrade.
399
+ - An invitation to upgrade and confirm, and "reply here if it persists".
400
+
401
+ LENGTH: concise — usually 3–5 sentences. Apply the anti-leakage discipline
402
+ above. Voice/tone per docs/VOICE-AND-TONE.md.
403
+ ```
404
+
405
+ **Verification Pending → Closed generation prompt:**
406
+
407
+ ```text
408
+ GOAL: close the loop warmly, thank the reporter, give the reopen path.
409
+
410
+ READ: ## Fix Released (the released version).
411
+
412
+ INCLUDE:
413
+ - The fix is confirmed on our side and shipped in `@windyroad/<pkg>@<version>`.
414
+ - A genuine thank-you — their report is what got it fixed.
415
+ - The reopen path: reply or reopen if it resurfaces.
416
+
417
+ LENGTH: concise — usually 2–4 sentences. Apply the anti-leakage discipline
418
+ above. Voice/tone per docs/VOICE-AND-TONE.md.
419
+ ```
420
+
421
+ #### I4. Idempotency guard (before posting)
422
+
423
+ Inbound dispatch may re-fire (re-run on a later transition, or a stale-grep re-dispatch). Before posting, scan the originating issue's existing comments:
424
+
425
+ ```bash
426
+ gh issue view "${NN}" --repo "${OWN_OWNER_REPO}" --json comments \
427
+ -q '.comments[].body' | grep -F "@windyroad/${PKG}@${VERSION}"
428
+ ```
429
+
430
+ The verdict marker is the released `@windyroad/<pkg>@<version>` string (plus the commit SHA carried in `## Fix Released` when present) — unique enough that a prior matching comment means the verdict already posted. If a matching comment is found, **skip the post**, back-write an `already-posted-inbound` reconciliation entry to the lifecycle log (I6), and continue. This makes the inbound leg idempotent on re-runs.
431
+
432
+ #### I5. Compose through gates + post (same composition as Step 5)
433
+
434
+ Route the GENERATED comment through the reporter-facing gate chain — **cognitive-accessibility → external-comms (risk) → voice-tone** (Directive 1's "run cog-a11y, risk, voice and tone"). The risk + voice-tone legs are the SAME `wr-risk-scorer:external-comms` + `wr-voice-tone:external-comms` dual gate (AND composition) as Step 5 — no weaker path for inbound.
435
+
436
+ **Cog-a11y gate (when-available, the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem-gated — do NOT block):** the cognitive-accessibility evaluator rides FIRST so reporter-facing prose is checked for plain-language / reading-level before the risk + voice-tone legs. `@windyroad/cognitive-a11y` does not exist yet ([the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem](../../../docs/problems/open/338-p082-phase-2-cognitive-a11y-evaluator-on-external-comms-surfaces-new-windyroad-cognitive-a11y-plugin.md) Open) — until it lands the chain degrades to the existing external-comms + voice-tone dual gate, exactly as the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule's per-evaluator marker scheme handles an uninstalled evaluator (an absent evaluator's gate is simply not registered → the remaining legs' PASS unblocks the retry). The cog-a11y-as-third-external-comms-evaluator declaration is recorded in [the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule](../../../docs/decisions/028-voice-tone-gate-external-comms.proposed.md)'s `## Amendments` (the locus the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule's own Reassessment Criteria designate for a third evaluator); this leg is the consumer-side wiring note only. **Do NOT block this iteration's inbound dispatch on the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem** — ship the wiring, ride the dual gate today.
437
+
438
+ Above-appetite handling is identical to Step 5c (silent risk-reduce + re-score; if still above, save to `## Queued Upstream Update` + queue an `outstanding_questions` entry; the orchestrator continues per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem — do NOT halt). Within appetite, post on our own repo:
439
+
440
+ ```bash
441
+ gh issue comment "${NN}" --repo "${OWN_OWNER_REPO}" --body "${INBOUND_BODY}"
442
+ ```
443
+
444
+ On the **Verification Pending → Closed** transition, after the comment, also close the originating issue so our own tracker matches the local `.closed.md` state (this addresses the "work-problems orchestrator carries prior-ticket Fix Strategy text into iter dispatch without re-grounding in design intent" problem #97 *silent-and-unclosed* witness):
445
+
446
+ ```bash
447
+ gh issue close "${NN}" --repo "${OWN_OWNER_REPO}" --comment "" --reason completed
448
+ ```
449
+
450
+ If the issue is already closed (someone closed it manually), `gh issue close` returns a benign error — record `closed-already` in the disclosure path and continue.
451
+
452
+ #### I6. Back-write to the lifecycle log
453
+
454
+ Append to the same `## Upstream Lifecycle Updates` log (Step 6 shape), tagged for the inbound direction so the audit trail stays unified:
455
+
456
+ ```markdown
457
+ - **<YYYY-MM-DD>** — Known Error → Verification Pending (inbound)
458
+ - **Target**: inbound #<NN> (own repo <OWN_OWNER_REPO>)
459
+ - **Comment URL**: <posted-comment-url> (or "skipped — already-posted-inbound" when the idempotency guard matched, or "queued — see ## Queued Upstream Update" when above-appetite)
460
+ - **Disclosure path**: posted-inbound-comment | posted-inbound-comment-and-closed (Verifying → Closed) | already-posted-inbound | queued-above-appetite | closed-already
461
+ - **Gate verdict**: external-comms <band/score> + voice-tone <pass|fail>
462
+ ```
463
+
464
+ The log stays append-only and direction-tagged; `/wr-itil:check-upstream-responses` (the "No process for issue reporters to check for responses — symmetric gap to inbound discovery" problem) does NOT read this section, so logging inbound entries here cannot contaminate the outbound poller.
465
+
466
+ #### I7. Both-direction tickets
467
+
468
+ A ticket may carry BOTH a `## Reported Upstream` section AND an inbound `**Origin**` field (we reported it upstream *and* someone reported it against us). The two legs are **independent**: the outbound entries run Steps 2–6 against their external URLs; the inbound leg runs I1–I6 against the own-repo issue. Each gate-composes, posts, and logs separately — one above-appetite leg queues only itself; the other proceeds.
469
+
470
+ ### 7. Commit per the "Governance Skills Commit Their Own Completed Work" architecture rule
471
+
472
+ When invoked from `transition-problem` Step 7's advisory subsection, the upstream comment + back-write + the ticket rename + the README refresh all join the **same single commit** per the "Governance Skills Commit Their Own Completed Work" architecture rule's single-commit grain — never split across commits. The transition-problem skill owns the commit; this skill's edits ride that commit as additional staged changes.
473
+
474
+ When invoked user-initiatedly (no transition in this session, e.g. retroactive catch-up), the skill commits its own work:
475
+
476
+ 1. `git add docs/problems/<state>/<NNN>-<title>.md` (the back-write + any `## Queued Upstream Update` appendage).
477
+ 2. Score commit/push/release risk via `wr-risk-scorer:pipeline` subagent (or fall back to `/wr-risk-scorer:assess-release` skill per the "On-Demand Assessment Skills for Governance Plugins" architecture rule).
478
+ 3. `git commit -m "docs(problems): P<NNN> upstream lifecycle update — <transition>"`.
479
+
480
+ If the cumulative pipeline risk lands above appetite and `request_user_input` is unavailable, apply the [the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6](../../../docs/decisions/013-structured-user-interaction-for-governance-decisions.proposed.md) non-interactive fail-safe: skip the commit and report the uncommitted state. Do NOT auto-commit above appetite without the user's call.
481
+
482
+ ## Catchup migration mode (Phase 2)
483
+
484
+ `/wr-itil:update-upstream --catchup` runs a one-shot batch-retroactive migration. It exists because the per-ticket auto-update path (Phase 1) only fires on transitions that happen *after* it shipped — every ticket reported upstream and transitioned *before* Phase 1 silently missed its lifecycle update, leaving upstream issues looking abandoned. Catchup back-fills that history. Authority: [the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule](../../../docs/decisions/024-cross-project-problem-reporting-contract.proposed.md) amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2).
485
+
486
+ This mode is **user-initiated only** — it is never auto-fired from a transition. It is a deliberate corpus-wide migration the maintainer runs once (or re-runs safely, thanks to idempotency).
487
+
488
+ ### C1. Build the worklist (read-only scan)
489
+
490
+ Invoke the worklist scanner via its [the "Plugin-bundled scripts invoked from SKILL.md resolve via `bin/` on `$PATH`" architecture rule](../../../docs/decisions/049-plugin-script-resolution-via-bin-on-path.proposed.md) `$PATH` shim — **never** via a repo-relative `packages/...` path (that path does not resolve in adopter trees):
491
+
492
+ ```bash
493
+ <itil-plugin-root>/bin/wr-itil-catchup-scan
494
+ ```
495
+
496
+ The scanner (`<itil-plugin-root>/scripts/catchup-scan.sh`, dispatched by the `<itil-plugin-root>/bin/wr-itil-catchup-scan` bin shim) is **read-only and local** — it makes no `gh` calls and writes nothing. It walks the `.verifying.md` + `.closed.md` corpus (dual-tolerant flat + per-state subdir per the ": docs/problems/ flat layout migration — per-state subdirs + adopter auto-migration" release design), filters to tickets carrying a `## Reported Upstream` section, applies marker-based idempotency, and prints a worklist:
497
+
498
+ ```
499
+ CATCHUP P<NNN> <url> state=<verifying|closed> transition=<KE->Verifying|Verifying->Closed>
500
+ SKIP P<NNN> <url> reason=already-logged
501
+ SKIP P<NNN> <url> reason=out-of-band
502
+ ```
503
+
504
+ plus a `SUMMARY scanned=… catchup=… skip-logged=… skip-out-of-band=…` line on stderr. Tickets with no `## Reported Upstream` section produce no line (the common case). Open / Known-Error / Parked tickets are out of the catchup corpus — only post-fix states (Verifying, Closed) carry the lifecycle updates a reporter most wants retroactively.
505
+
506
+ ### C2. Idempotency contract
507
+
508
+ Catchup is **idempotent** (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2 acceptance criterion 3). The scanner skips a ticket whose `## Upstream Lifecycle Updates` log already records an entry for the current target state:
509
+
510
+ - `.verifying.md` → already-logged iff the log contains a `→ Verification Pending` entry.
511
+ - `.closed.md` → already-logged iff the log contains a `→ Closed` entry.
512
+
513
+ The append-only log (written by Step 6 on every post) is the source of truth — the same marker the per-ticket path writes. Re-running `--catchup` therefore never double-posts. As defence-in-depth, before posting each `CATCHUP` entry the SKILL MAY also scan the upstream issue for a prior `Update from …` comment authored by the posting account (`gh issue view <n> --json comments`); if one already matches the target transition, treat it as already-logged, back-write the log entry to reconcile, and skip the post. The body-marker check is primary (cheap, no `gh` round-trip); the comment scan is the belt-and-braces fallback for tickets whose log predates Phase 1's back-write.
514
+
515
+ ### C3. Process each CATCHUP entry
516
+
517
+ For each `CATCHUP` line, parse its `disclosure=` token and run the **existing per-ticket flow** (Steps 4–6) against that ticket ID. `disclosure=pull-request` selects `gh pr comment` and forbids any close command; `disclosure=issue` selects `gh issue comment` and permits `gh issue close` for Verifying → Closed:
518
+
519
+ 1. Draft the transition template (Step 4) for the entry's transition (`KE->Verifying` → Known Error → Verification Pending template; `Verifying->Closed` → Verification Pending → Closed template). Only an issue disclosure also runs `gh issue close`; a pull-request disclosure never runs `gh pr close`.
520
+ 2. Compose through the external-comms + voice-tone gates (Step 5) — **identical** dual-gate composition as the per-ticket path. Above-appetite handling (Step 5c) is unchanged: silent risk-reduce + re-score, then queue to `## Queued Upstream Update` + `outstanding_questions` (category `deviation-approval`) per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem if still above. Catchup does NOT bypass the gates.
521
+ 3. Post within appetite (Step 5b final) and back-write the `## Upstream Lifecycle Updates` log (Step 6).
522
+
523
+ Process entries one at a time so a single above-appetite entry queues only itself; the rest proceed. There is no batch-cap on the number of catchup posts — the gate composition is the rate-limit, and the corpus is bounded (one pass over local tickets).
524
+
525
+ ### C4. Commit per the "Governance Skills Commit Their Own Completed Work" architecture rule
526
+
527
+ The catchup migration is user-initiated, so it owns its commit per the Step 7 user-initiated path: stage every touched ticket's back-write (and any `## Queued Upstream Update` appendage), score commit/push/release risk via `wr-risk-scorer:pipeline`, and commit once covering the whole pass — `docs(problems): upstream lifecycle catchup migration — <N> tickets (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2)`. Above-appetite-and-no-request_user_input → the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6 fail-safe (report the uncommitted state, do not auto-commit).
528
+
529
+ ### C5. Verification
530
+
531
+ The live-upstream end-to-end confirmation (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem acceptance criterion 7 — a catchup comment actually lands on a real upstream issue) is the overall the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem verification step. Running `--catchup` against the real corpus (e.g. the "`/wr-itil:report-upstream` is installed and enabled but does not appear in Codex slash-command autocomplete" problem's `https://github.com/anthropics/claude-code/issues/52831`) and confirming the comment posts is what closes the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem to Verifying once a fresh release ships the mode.
532
+
533
+ ## AFK behaviour summary
534
+
535
+ Four distinct AFK branches. Per the [the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule](../../../docs/decisions/024-cross-project-problem-reporting-contract.proposed.md) amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem) — same composition shape as the post-the "Agent waits for human to initiate upstream report instead of filing on detect — feedback delay class" problem initial-filing path — ALL pre-post branches route through the `wr-risk-scorer:external-comms` + `wr-voice-tone:external-comms` gates. Below-appetite proceeds; above-appetite silent risk-reduces + re-scores; if still above, queues per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem queue-and-continue without halting the loop.
536
+
537
+ | Branch | AFK behaviour | Authority |
538
+ |---|---|---|
539
+ | Below-appetite post (Step 5b final) | Post via `gh issue comment`; on Verifying→Closed also `gh issue close`. Back-write to `## Upstream Lifecycle Updates`. Voice-tone gate per the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule may delegate-and-retry on the post; treat as expected. | the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem); the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule |
540
+ | Above-appetite — silent risk-reduce + re-score within appetite | Re-draft with tighter source-citation + shorter prose; re-invoke `wr-risk-scorer:external-comms`. If within → post per the below-appetite branch. | the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem); the "— Decision-Delegation Contract: when agents act on the framework vs ask the user" architecture rule framework-resolution boundary; the "Auto-apply scorer remediations to reach within appetite — open action-class vocabulary" architecture rule within-axis precedent (open-vocabulary risk-reducing measures) |
541
+ | Above-appetite — silent risk-reduce did not bring within appetite | Save drafted comment to `## Queued Upstream Update` + queue `outstanding_questions` entry (category: `deviation-approval`). Orchestrator continues per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem. | the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem); the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6; the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem |
542
+ | Above-appetite commit (Step 7) | Skip the commit, report uncommitted state. | the "Structured User Interaction for Governance-Skill Decisions" architecture rule Rule 6 |
543
+ | **Inbound-origin verdict (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem)** | When the ticket carries `**Origin**: inbound-reported (#NN)`, run the [§ Inbound-origin verdict dispatch](#inbound-origin-verdict-dispatch-p363) leg (I1–I7): idempotency-guard, then **GENERATE** the verdict comment from ticket context (no templates; O→KE shares the workaround with provenance-credit), route through the cog-a11y → external-comms → voice-tone gate chain (cog-a11y when-available per the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem; dual gate today), post `gh issue comment` on our own repo (and `gh issue close` on Verifying → Closed), back-write a direction-tagged lifecycle log entry. Above-appetite queues per the rows above (does NOT halt). Reporter-facing prose; anti-leakage visibility-gated (PUBLIC → titled+linked refs; PRIVATE/indeterminate → strict ban; classification tokens / step IDs / internal vocab always banned — the "Inbound-discovery ack comments are bureaucratic, not verdict-shaped ( violation)" problem/the "agent surfaces decisions to user using opaque IDs (P-numbers, ADR-numbers, JTBD-numbers) without explaining what they mean — empathy gap" problem). | the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule amendment (the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem); the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule (cog-a11y third evaluator, the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem); the "Plugin-published artefacts use namespace-prefixed permalinks for internal IDs" architecture rule (linked-title); the "Inbound-reported problems rank ahead of internally-discovered problems via a sort tier" architecture rule (Origin field); the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem |
544
+
545
+ The pre-amendment "halt-the-orchestrator on above-appetite" semantics are **superseded** by queue-and-continue per the "AFK iter default when a skill needs to ask a question and request_user_input is unavailable — should queue the question and move to the next iteration (not halt, not silently skip)" problem — same shape as the post-the "Agent waits for human to initiate upstream report instead of filing on detect — feedback delay class" problem initial-filing path.
546
+
547
+ ## Triggered from transition-problem Step 7
548
+
549
+ [`/wr-itil:transition-problem`](../transition-problem/SKILL.md) Step 7 hosts an advisory subsection that fires this skill when the transitioning ticket carries a `## Reported Upstream` section. The advisory wires the trigger; this skill owns the execution. The same "copy, not move" pattern (per [the "Rename `wr-problem` Plugin to `wr-itil`" architecture rule](../../../docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md) amended Split-skill execution ownership rule, the "Problem 093: `/wr-itil:transition-problem` ↔ `/wr-itil:manage-problem` circular delegation for `<NNN> <status>` args" problem) replicates the advisory in `/wr-itil:manage-problem`'s in-skill Step 7 block so in-skill callers (Step 9b auto-transition, Step 9d closure, the Parked path) also fire the lifecycle update.
550
+
551
+ Both call sites delegate via the installed skill invocation:
552
+
553
+ ```
554
+ /wr-itil:update-upstream <NNN>
555
+ ```
556
+
557
+ The skill's no-op exit (Step 1) means firing the trigger unconditionally on every transition is cheap — most tickets have no `## Reported Upstream` section and exit immediately.
558
+
559
+ ## References
560
+
561
+ - [the "Cross-project problem-reporting contract — `report-upstream` skill in `@windyroad/itil`" architecture rule](../../../docs/decisions/024-cross-project-problem-reporting-contract.proposed.md) — primary contract this skill extends. The "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem amendment in `## Amendments` authorises the bidirectional lifecycle-update sibling skill, the transition-template shape, and the external-comms + voice-tone gate composition; the **the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem Phase 2 amendment** authorises the `--catchup` migration mode, the read-only worklist scanner, and the marker-based idempotency contract.
562
+ - [the "Plugin-bundled scripts invoked from SKILL.md resolve via `bin/` on `$PATH`" architecture rule](../../../docs/decisions/049-plugin-script-resolution-via-bin-on-path.proposed.md) — the catchup worklist scanner is invoked as `<itil-plugin-root>/bin/wr-itil-catchup-scan` ($PATH shim), never via a repo-relative `packages/...` path.
563
+ - [`<itil-plugin-root>/scripts/catchup-scan.sh`](../../scripts/catchup-scan.sh) — read-only local worklist scanner for `--catchup`; behavioural bats at `<itil-plugin-root>/scripts/test/catchup-scan.bats`.
564
+ - [the "External-comms gate — voice-tone + risk/leak evaluators on shared PreToolUse surface" architecture rule](../../../docs/decisions/028-voice-tone-gate-external-comms.proposed.md) — voice-tone gate on `gh issue comment` and `gh issue close`.
565
+ - [the "Structured User Interaction for Governance-Skill Decisions" architecture rule](../../../docs/decisions/013-structured-user-interaction-for-governance-decisions.proposed.md) — interaction policy; Rule 1 governs the interactive above-appetite path; Rule 6 governs the AFK fail-safe.
566
+ - [the "Governance Skills Commit Their Own Completed Work" architecture rule](../../../docs/decisions/014-governance-skills-commit-their-own-work.proposed.md) — single-commit grain for transition + back-write + upstream post.
567
+ - [the "Rename `wr-problem` Plugin to `wr-itil`" architecture rule](../../../docs/decisions/010-rename-wr-problem-to-wr-itil.proposed.md) amended — sibling-skill naming + split execution ownership (the "Problem 093: `/wr-itil:transition-problem` ↔ `/wr-itil:manage-problem` circular delegation for `<NNN> <status>` args" problem "copy, not move").
568
+ - [the "— Decision-Delegation Contract: when agents act on the framework vs ask the user" architecture rule](../../../docs/decisions/044-decision-delegation-contract.proposed.md) — framework-resolution boundary; the gate verdict IS the framework, no per-transition request_user_input for the gate firing itself.
569
+ - [the "Auto-apply scorer remediations to reach within appetite — open action-class vocabulary" architecture rule](../../../docs/decisions/042-auto-apply-scorer-remediations-open-vocabulary.proposed.md) — within-axis precedent for open-vocabulary risk-reducing measures.
570
+ - [the ": promptfoo as the behavioural test harness for agent-prose verdicts" architecture rule](../../../docs/decisions/075-promptfoo-agent-prose-verdict-eval-harness.proposed.md) Amendment 2026-06-02 — paired promptfoo Tier-A/B eval discharges the ": Functional defects in shipped plugin behaviour" standing risk prose-floor for SKILL surfaces.
571
+ - [the ": promptfoo as the behavioural test harness for agent-prose verdicts" architecture rule](../../../docs/decisions/075-agent-prose-behavioural-test-harness.proposed.md) — evidence-floor; the paired eval ships in the same commit as this SKILL prose for atomic the ": Functional defects in shipped plugin behaviour" standing risk discharge.
572
+ - **the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem** — driving problem ticket (No bidirectional update of upstream-reported problems).
573
+ - **the "Inbound-reported tickets never receive fix-released verdict on originating issue" problem** — driving problem ticket for the [§ Inbound-origin verdict dispatch](#inbound-origin-verdict-dispatch-p363) leg (inbound-reported tickets never received a fix-released verdict on the originating issue). Fix option (b) — consume the `**Origin**` field — user-ratified 2026-06-22. **Rework 2026-06-23** (four user directives): the inbound verdict is LLM-generated per-context (not templated); O→KE shares the workaround with reporter/commenter provenance-credit; anti-leakage is visibility-gated (PUBLIC → titled+linked refs); the gate chain gains a cog-a11y leg first (the "Phase 2 — cognitive-accessibility evaluator on the 4 external-comms surfaces (gh / npm / changeset / git commit), shipped as a NEW `@windyroad/cognitive-a11y` plugin" problem-gated).
574
+ - [the "Plugin-published artefacts use namespace-prefixed permalinks for internal IDs" architecture rule](../../../docs/decisions/055-plugin-published-namespace-prefixed-internal-ids.proposed.md) — grounds the PUBLIC-repo titled+linked reference discipline (permalink-progressive-enhancement; cures the bare-ID collision failure mode).
575
+ - [the "Inbound-reported problems rank ahead of internally-discovered problems via a sort tier" architecture rule](../../../docs/decisions/076-inbound-reported-problems-rank-ahead-via-sort-tier.proposed.md) — owns the `**Origin**: inbound-reported (#NN)` on-ticket field this leg consumes.
576
+ - [the "Inbound upstream-report discovery + assessment pipeline (peer of )" architecture rule](../../../docs/decisions/062-inbound-upstream-report-discovery-assessment-pipeline.proposed.md) — inbound intake-time pipeline; its safe-and-valid branch is the Origin-field writer this leg reads at fix-released time.
577
+ - **the "Problem 079: No inbound sync of upstream-reported problems — reports filed via the intake templates never surface in the local backlog" problem** — sibling problem (inbound-discovery leg); together the "Problem 079: No inbound sync of upstream-reported problems — reports filed via the intake templates never surface in the local backlog" problem + the "Problem 080: No bidirectional update of upstream-reported problems — local lifecycle transitions never propagate back to the reporter" problem close the reporter-loop end-to-end.
578
+ - **the "Problem 078: Assistant does not offer to capture a problem ticket when the user delivers strong-signal correction" problem** — capture-on-correction; the manage-problem trap this skill closes (manual upstream-update step gets forgotten under load).
579
+ - [`<itil-plugin-root>/skills/report-upstream/SKILL.md`](../report-upstream/SKILL.md) — reciprocal sibling (initial-filing path); shares the `## Reported Upstream` contract this skill consumes.
580
+ - [`<itil-plugin-root>/skills/transition-problem/SKILL.md`](../transition-problem/SKILL.md) — Step 7 advisory subsection fires this skill.
581
+ - [`<itil-plugin-root>/skills/manage-problem/SKILL.md`](../manage-problem/SKILL.md) — in-skill Step 7 copy fires this skill (per the "Rename `wr-problem` Plugin to `wr-itil`" architecture rule amended "copy, not move").
582
+
583
+ $ARGUMENTS