@windyroad/itil 0.56.0 → 0.56.1

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.
@@ -497,5 +497,5 @@
497
497
  }
498
498
  },
499
499
  "name": "wr-itil",
500
- "version": "0.56.0"
500
+ "version": "0.56.1"
501
501
  }
@@ -51,22 +51,37 @@ if [ -z "$ASSISTANT_TEXT" ]; then
51
51
  exit 0
52
52
  fi
53
53
 
54
- # Scan for prose-ask patterns. If none match, exit silently.
54
+ # Scan for prose-ask patterns. If one matches, emit the prose-ask nudge.
55
55
  MATCH=$(echo "$ASSISTANT_TEXT" | detect_prose_ask 2>/dev/null) || true
56
- if [ -z "$MATCH" ]; then
56
+ if [ -n "$MATCH" ]; then
57
+ # Emit stopReason. Structured JSON so Claude Code injects the nudge
58
+ # into the next assistant context. The user does not see this — the
59
+ # next turn does.
60
+ jq -n --arg match "$MATCH" '{
61
+ stopReason: (
62
+ "PROSE-ASK DETECTED in your last turn (pattern: \"" + $match + "\"). " +
63
+ "If the decision is obvious from direction / policy / session context, ACT — do not ask. " +
64
+ "If genuinely ambiguous, re-emit via the AskUserQuestion tool. " +
65
+ "Never prose-ask. See ADR-013 Rule 1 + feedback_act_on_obvious_decisions.md."
66
+ )
67
+ }'
57
68
  exit 0
58
69
  fi
59
70
 
60
- # Emit stopReason. Structured JSON so Claude Code injects the nudge
61
- # into the next assistant context. The user does not see this — the
62
- # next turn does.
63
- jq -n --arg match "$MATCH" '{
64
- stopReason: (
65
- "PROSE-ASK DETECTED in your last turn (pattern: \"" + $match + "\"). " +
66
- "If the decision is obvious from direction / policy / session context, ACT — do not ask. " +
67
- "If genuinely ambiguous, re-emit via the AskUserQuestion tool. " +
68
- "Never prose-ask. See ADR-013 Rule 1 + feedback_act_on_obvious_decisions.md."
69
- )
70
- }'
71
+ # P403: scan for mechanical-step-framed-as-user-optional. When a skill
72
+ # contract mandates a mechanical step, re-surfacing it as a user decision
73
+ # (or a budget-caution skip) reintroduces the friction the mechanical-stage
74
+ # carve-out (P132 / ADR-044) was engineered to remove.
75
+ MECH_MATCH=$(echo "$ASSISTANT_TEXT" | detect_mechanical_optional 2>/dev/null) || true
76
+ if [ -n "$MECH_MATCH" ]; then
77
+ jq -n --arg match "$MECH_MATCH" '{
78
+ stopReason: (
79
+ "MECHANICAL-STEP-FRAMED-AS-OPTIONAL detected in your last turn (closer: \"" + $match + "\"). " +
80
+ "A skill contract that mandates a mechanical step has already resolved that decision — do not re-surface it as a user choice or skip it on budget-caution grounds. " +
81
+ "Run the step, then report it done. See P132 / ADR-044 mechanical-stage carve-out."
82
+ )
83
+ }'
84
+ exit 0
85
+ fi
71
86
 
72
87
  exit 0
@@ -79,6 +79,84 @@ CORRECTION_SIGNAL_PATTERNS=(
79
79
  '\bno\b.*\bwrong\b'
80
80
  )
81
81
 
82
+ # P403: mechanical-step-framed-as-user-optional detection. When a skill
83
+ # contract mandates a mechanical step (review-problems Step 7 auto-release,
84
+ # a full re-rank, etc.), the agent must not re-surface the step as a user
85
+ # decision — or as a budget-caution skip — in end-of-turn prose. That
86
+ # reintroduces the exact friction the mechanical-stage carve-out (P132 /
87
+ # ADR-044 category 4 silent-framework) was engineered to remove.
88
+ #
89
+ # The detector fires only when ALL THREE co-occur in the turn text: a
90
+ # step-skip verb, a step / mechanical-pass reference, AND an
91
+ # offloaded-justification closer. The three-way AND is the anti-over-fire
92
+ # guard (inverse-P078 / P132): a legitimately user-owned decision, or a
93
+ # skipped step reported with a substantive reason, does not fire. Same
94
+ # accepted false-positive posture as CORRECTION_SIGNAL_PATTERNS above — a
95
+ # rare over-fire costs only a non-blocking next-turn nudge.
96
+ #
97
+ # Case-insensitive (grep -Eqi). grep matches per line; the two P403
98
+ # evidence phrasings are single-line, so per-line matching is sufficient.
99
+
100
+ # 1. Step-skip verbs — the step was not run.
101
+ MECHANICAL_STEP_SKIP_PATTERNS=(
102
+ '\bskip(ped|ping|s)?\b'
103
+ '\bdefer(red|ring|s)?\b'
104
+ '\bomit(ted|ting|s)?\b'
105
+ '\bleft out\b'
106
+ )
107
+
108
+ # 2. Step / mechanical-pass reference — the skipped thing is a skill step.
109
+ MECHANICAL_STEP_REF_PATTERNS=(
110
+ '\bstep[[:space:]]+[0-9]+'
111
+ '\bre-rank\b'
112
+ '\bauto-release\b'
113
+ '\binbound-discovery\b'
114
+ '\brelevance-close\b'
115
+ '\bverification queue\b'
116
+ )
117
+
118
+ # 3. Offloaded-justification closer — the mandate handed back to the user
119
+ # ("your call") or self-authorised away on budget grounds ("context budget").
120
+ MECHANICAL_OPTIONAL_PATTERNS=(
121
+ 'your call'
122
+ 'up to you'
123
+ 'worth doing'
124
+ "user'?s call"
125
+ 'if you (want|prefer|would like)'
126
+ 'feel free to'
127
+ 'context budget'
128
+ 'to stay within'
129
+ 'budget[- ]?caution'
130
+ )
131
+
132
+ # detect_mechanical_optional: scans text on stdin. Exits 0 (and echoes the
133
+ # matched optional-closer phrase) only when a step-skip verb, a step
134
+ # reference, AND an offloaded-justification closer ALL match somewhere in
135
+ # the text. Exits 1 otherwise. Mirrors detect_prose_ask's shape.
136
+ detect_mechanical_optional() {
137
+ local text
138
+ text=$(cat)
139
+ local pattern
140
+ local skip_hit="" ref_hit="" opt_hit=""
141
+ for pattern in "${MECHANICAL_STEP_SKIP_PATTERNS[@]}"; do
142
+ if echo "$text" | grep -Eqi -- "$pattern"; then skip_hit=1; break; fi
143
+ done
144
+ [ -n "$skip_hit" ] || return 1
145
+ for pattern in "${MECHANICAL_STEP_REF_PATTERNS[@]}"; do
146
+ if echo "$text" | grep -Eqi -- "$pattern"; then ref_hit=1; break; fi
147
+ done
148
+ [ -n "$ref_hit" ] || return 1
149
+ for pattern in "${MECHANICAL_OPTIONAL_PATTERNS[@]}"; do
150
+ if echo "$text" | grep -Eqi -- "$pattern"; then
151
+ echo "$pattern"
152
+ opt_hit=1
153
+ break
154
+ fi
155
+ done
156
+ [ -n "$opt_hit" ] || return 1
157
+ return 0
158
+ }
159
+
82
160
  # detect_prose_ask: scans text on stdin for canonical prose-ask
83
161
  # phrasings. Exits 0 if any pattern matches, 1 otherwise. Writes the
84
162
  # first matched phrase to stdout (for observability in the Stop hook
@@ -174,3 +174,51 @@ JSON
174
174
  [ "$status" -eq 0 ]
175
175
  [[ "$output" == *"stopReason"* ]]
176
176
  }
177
+
178
+ # P403: mechanical-step-framed-as-user-optional. When a skill contract
179
+ # mandates a mechanical step, the agent must not re-surface it as a user
180
+ # decision (or a budget-caution skip) in end-of-turn prose. The detector
181
+ # fires only when a step-skip signal, a step/mechanical-pass reference,
182
+ # AND an offloaded-justification closer all co-occur (the AND-discriminator).
183
+
184
+ @test "review: P403 evidence 1 — 'Step 7 auto-release skipped — your call' triggers stopReason" {
185
+ write_transcript "review the backlog" "Done. Step 7 auto-release skipped — your call whether to drain via /wr-risk-scorer:assess-release."
186
+ run run_hook
187
+ [ "$status" -eq 0 ]
188
+ [[ "$output" == *"stopReason"* ]]
189
+ [[ "$output" == *"mechanical"* ]]
190
+ }
191
+
192
+ @test "review: P403 evidence 2 — 'Skipped the full re-rank (Step 2) ... to stay within context budget' triggers stopReason" {
193
+ write_transcript "review problems" "Skipped the full 40-ticket re-rank (Step 2), inbound-discovery pipeline (Step 4.5), and relevance-close pass (Step 4.6) to stay within context budget."
194
+ run run_hook
195
+ [ "$status" -eq 0 ]
196
+ [[ "$output" == *"stopReason"* ]]
197
+ }
198
+
199
+ @test "review: AND-discriminator — optional closer WITHOUT a step-skip does not trigger stopReason" {
200
+ # "up to you" is a legitimately user-owned decision with no skipped
201
+ # mechanical step in context — must NOT fire (the inverse-P078 guard).
202
+ write_transcript "which theme" "Both palettes meet contrast AA. It is up to you which one reads better for your brand."
203
+ run run_hook
204
+ [ "$status" -eq 0 ]
205
+ [[ "$output" != *"stopReason"* ]]
206
+ }
207
+
208
+ @test "review: AND-discriminator — skipped step with a real reason (no offload) does not trigger stopReason" {
209
+ # A skipped step reported with a substantive reason (not offloaded to the
210
+ # user, not budget-caution) is a legitimate report, not the P403 defect.
211
+ write_transcript "run it" "Step 2 skipped because its precondition is already satisfied by Step 1. Proceeding to Step 3."
212
+ run run_hook
213
+ [ "$status" -eq 0 ]
214
+ [[ "$output" != *"stopReason"* ]]
215
+ }
216
+
217
+ @test "review: P403 nudge stays within the ADR-045 hook injection budget" {
218
+ write_transcript "review the backlog" "Done. Step 7 auto-release skipped — your call whether to drain."
219
+ run run_hook
220
+ [ "$status" -eq 0 ]
221
+ [[ "$output" == *"stopReason"* ]]
222
+ # ADR-045 advisory band: keep the injected nudge well under 1000 bytes.
223
+ [ "${#output}" -lt 1000 ]
224
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/itil",
3
- "version": "0.56.0",
3
+ "version": "0.56.1",
4
4
  "description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
5
5
  "bin": {
6
6
  "windyroad-itil": "./bin/install.mjs"
@@ -14,7 +14,7 @@ This skill is the foreground-lightweight-capture variant of `/wr-itil:manage-pro
14
14
 
15
15
  When referencing problem, JTBD, ADR, or RFC IDs in prose output (stderr advisories, capture-report messages), always include the human-readable title or substance on first mention. Use the format `JTBD-001 (Enforce Governance Without Slowing Down)`, not bare `JTBD-001`.
16
16
 
17
- **Brief-before-ID discipline at the Step 1.5b derive-then-ratify `AskUserQuestion` surface (P350).** When the derive-then-ratify dispatch proposes persona/JTBD candidates to the user, the question text MUST inline what each proposed JTBD/persona asserts the job statement, the user-need, the persona's key constraint BEFORE naming it by `JTBD-NNN` / `persona-slug`. The user reads the prompt without project filesystem access (mobile clients, accessibility tooling, notification surfaces) and cannot follow links into `docs/jtbd/`. Acceptable option label: *"Developer persona — enforce governance automatically so manual-review safety comes without overhead."* Unacceptable: *"developer + JTBD-001"*. IDs may appear ONLY after a self-contained explanation. Mirrors the canonical `/wr-architect:create-adr` Step 5 § 5a Rule 3 ("No IDs as explainers"). See also session memory `feedback_brief_before_id.md`.
17
+ **Brief-before-ID discipline at the Step 1.5b low-confidence interview surface (P350).** Per the P401 correction the low-confidence path does NOT surface candidate `JTBD-NNN` / `persona-slug` IDs at all — it **interviews** the human about *who* hits the problem and *what job* they are trying to get done, in plain language, so the brief-before-ID discipline is satisfied by construction (no ID is a carrier of meaning). If any option or prose in the interview references an existing job/persona for context, it MUST inline the job statement + the persona's key constraint BEFORE any ID. The user reads the prompt without project filesystem access (mobile clients, accessibility tooling, notification surfaces) and cannot follow links into `docs/jtbd/`. Mirrors the canonical `/wr-architect:create-adr` Step 5 § 5a Rule 3 ("No IDs as explainers"). See also session memory `feedback_brief_before_id.md`.
18
18
 
19
19
  ## When to invoke
20
20
 
@@ -29,7 +29,7 @@ When referencing problem, JTBD, ADR, or RFC IDs in prose output (stderr advisori
29
29
 
30
30
  ## Rule 6 audit (per ADR-032 + ADR-013)
31
31
 
32
- This skill has **at most one direction-setting AskUserQuestion (the I12 derive-then-ratify proposal, fired only when persona/JTBD derivation fails or is ambiguous) and zero control-flow branches keyed on the answer's substance**. Each potentially-interactive decision is framework-mediated per ADR-044:
32
+ This skill has **one direction-setting AskUserQuestion surface — the low-confidence persona/JTBD elicitation interview (fired only when derivation is weak; it may span more than one question to elicit who + why), plus the ADR-068/P288 human-ratify surface when the elicited who/why warrants a NEW persona/JTBD**. Each potentially-interactive decision is framework-mediated per ADR-044:
33
33
 
34
34
  | Decision | Resolution |
35
35
  |----------|-----------|
@@ -39,14 +39,14 @@ This skill has **at most one direction-setting AskUserQuestion (the I12 derive-t
39
39
  | Effort | **Derived at capture** silently per Step 4a (ADR-067 t-shirt buckets + ADR-026 grounding/sentinel). No deferred placeholder. |
40
40
  | Multi-concern split | Out of scope: capture-problem creates one ticket per invocation. Multi-concern observations route to `/wr-itil:manage-problem` (its Step 4b owns the split). |
41
41
  | Empty `$ARGUMENTS` | Halt-with-stderr-directive: print "capture-problem requires a description in $ARGUMENTS — invoke /wr-itil:manage-problem instead for the full intake flow" and exit. AFK orchestrators MUST NOT invoke capture-problem with empty arguments — caller-side contract. |
42
- | JTBD-trace + persona derivation (I12 derive-then-ratify — ADR-060 Amendment 2026-06-02) | **Derive-then-ratify per ADR-044 category 1 (direction-setting) on the AskUserQuestion fallback path; silent-framework category 4 on the derive-success path.** Step 1.5b runs lexical detection (`\bJTBD-[0-9]+\b`) + flag pre-resolution (`--jtbd=` / `--persona=`) + cited-JTBD persona derivation. **Derive-success** → silent-proceed with derived values + stderr advisory. **Derive-failure or ambiguity** AskUserQuestion proposes up-to-3 candidate persona+JTBD pairs + a Reject option (4-option cap per ADR-044 Rule 1). User response semantics: **REJECT** halt-with-stderr-directive + exit non-zero (REJECT of proposed persona/JTBD = REJECT of the problem; no ticket created). **Option-pick** (acceptance of a proposed candidate as-is) → silent-proceed with picked values. **Free-text correction** silent-proceed with corrected values (correction-as-acceptance). |
43
- | AFK halt-without-flags (NEW per Amendment 2026-06-02) | **Halt-with-stderr-directive per ADR-044 silent-framework category 4 — caller-side contract.** When invoked with `--no-prompt` (AFK mode marker) AND derivation fails (no JTBD-NNN citations + no `--persona=` flag + no `--jtbd=` flag, OR cited-JTBD persona-disagreement) → capture HALTS with stderr message `capture-problem: cannot derive persona/JTBD interactively under AFK and no --persona/--jtbd flags supplied; capture refusedre-invoke with explicit anchoring`. Exit non-zero. AFK orchestrators (`/wr-itil:work-problems` capture-on-correction sub-flow, agent-mid-iter `capture-problem` invocations via the Agent tool) MUST pre-resolve persona+JTBD via flags before invoking. JTBD-006 compatibility: halt-with-stderr is the audit-trail-preserving form of "queued"; the directive surfaces on user return; the AFK loop continues to the next problem. |
42
+ | JTBD-trace + persona derivation (I12 derive → interview-on-low-confidence → classify → ratify-creation-only — ADR-060 Amendment 2026-06-02 as corrected by P401 2026-06-29/2026-07-02) | **Derive-first per ADR-044 category 4 (silent-framework); interview + creation-ratify per category 1 (direction-setting).** Step 1.5b runs lexical detection (`\bJTBD-[0-9]+\b`) + flag pre-resolution (`--jtbd=` / `--persona=`) + cited-JTBD persona derivation. **Derive-success** → silent-proceed with derived values + stderr advisory. **Low-confidence** **INTERVIEW** the human to elicit the real who/why (substantive non-leading questions, NOT propose an ID) the agent classifies: elicited job/persona matches an EXISTING artefact map + proceed autonomously; NO existing fit human ratifies the **creation** of a new persona/JTBD (ADR-068/P288) → map + proceed. **A real problem is NEVER discarded over anchoring uncertainty.** Scope-rejection (elicited who/why out of scope) is **external-report-only** at `/wr-itil:manage-problem` ingestion never here. |
43
+ | AFK low-confidence (`--no-prompt`) preserve the finding | **Create-with-unconfirmed-anchoring + queue the elicitation per P401 never-discard + JTBD-006 save-and-continue.** When invoked with `--no-prompt` (AFK mode marker) AND derivation fails (no JTBD-NNN citations + no `--persona=` flag + no `--jtbd=` flag, OR cited-JTBD persona-disagreement) → do NOT fire `AskUserQuestion`, do NOT shoehorn a best-fit, do NOT auto-create a new artefact. Capture the ticket with the greppable `(unconfirmedelicitation queued)` anchoring sentinel + stderr advisory, and queue the elicitation interview for the next interactive session (the AFK orchestrator surfaces it via `outstanding_questions`). ADR-074 is preserved by the existing downstream oversight gates (ADR-068/P288, ADR-090, ADR-060 I13), not by refusing the capture. AFK orchestrators still SHOULD pre-resolve persona+JTBD via flags to skip the sentinel path entirely. |
44
44
 
45
- **P287 / ADR-060 Amendment 2026-06-02 — type-classification retired + I12 hard-block replaced with derive-then-ratify**: the maintainer-side type-classification dispatch (technical vs user-business) was REMOVED per twice-confirmed user direction (2026-05-25 P287 base + 2026-06-02 ADR-060 amendment substance — *"I12 hard-block was wrong. Replacement: the persona and jtbd should be derived by the LLM. And if a persona/jtbd cannot be found then it should be proposed for User ratification. If the user rejects the persona or job to be done then that is should be treated as a rejection of the problem; corrections to the persona or job to be done are treated as acceptance and acceptance is treated as acceptance. Applies to ALL problems."*). The redundant type axis was already covered by RFC/Story persona-anchoring per ADR-060 Phase 4. The original I12 hard-block (type-keyed JTBD-required halt) was REPLACED wholesale in ADR-060 Amendment 2026-06-02 with the derive-then-ratify contract codified in Step 1.5b below. The contract applies to ALL problems (no type-keyed gating; the type axis itself is GONE).
45
+ **P287 / ADR-060 Amendment 2026-06-02 — type-classification retired + I12 hard-block replaced with derive-then-ratify**: the maintainer-side type-classification dispatch (technical vs user-business) was REMOVED per twice-confirmed user direction (2026-05-25 P287 base + 2026-06-02 ADR-060 amendment substance — *"I12 hard-block was wrong. Replacement: the persona and jtbd should be derived by the LLM. And if a persona/jtbd cannot be found then it should be proposed for User ratification. If the user rejects the persona or job to be done then that is should be treated as a rejection of the problem; corrections to the persona or job to be done are treated as acceptance and acceptance is treated as acceptance. Applies to ALL problems."*). The redundant type axis was already covered by RFC/Story persona-anchoring per ADR-060 Phase 4. The original I12 hard-block (type-keyed JTBD-required halt) was REPLACED wholesale in ADR-060 Amendment 2026-06-02 with the derive-then-ratify contract codified in Step 1.5b below. The contract applies to ALL problems (no type-keyed gating; the type axis itself is GONE). **P401 supersession (2026-06-29/2026-07-02):** the 2026-06-02 amendment's *"reject of the proposed persona/JTBD = rejection of the problem; no ticket created"* clause (quoted above) is REVERSED — low-confidence now interviews to elicit the real who/why (never proposes an ID), the agent classifies existing-vs-new, the human ratifies only the CREATION of a new persona/JTBD, and a real problem is NEVER discarded over anchoring uncertainty; scope-rejection is external-report-only. See the P401 supersession note in Step 1.5b.
46
46
 
47
- Per ADR-013 Rule 6 fail-safe: every decision above resolves without interactive user input in non-interactive contexts. The derive-then-ratify AskUserQuestion fires only on derivation-failure (interactive surface) AND only when `--no-prompt` is absent (AFK callers pre-resolve via flags or halt-with-stderr-directive — never silently swallow the ratification gate).
47
+ Per ADR-013 Rule 6 fail-safe: every decision above resolves without interactive user input in non-interactive contexts. The low-confidence **interview** fires only on derivation-failure (interactive surface) AND only when `--no-prompt` is absent; under `--no-prompt` the AFK path captures with the unconfirmed-anchoring sentinel + queues the elicitation (P401) — never silently shoehorning a best-fit or discarding the finding.
48
48
 
49
- **ADR-013 Rule 6 carve-out audit (P352, 2026-06-06 amendment)**: the universal AFK default is **queue-and-continue** (queue the decision, continue the loop). The HALT-with-stderr-directive carve-outs in the Resolution table above (Empty `$ARGUMENTS`, AFK halt-without-flags) are documented deviations from the universal default, authorised by **ADR-074** (Confirm decision substance before building dependent work). Rationale: capture-problem creates a durable ticket artefact; auto-creating with derived-but-unratified persona/JTBD substance would build dependent work (the ticket file, the README row, the WSJF rank) on an unconfirmed decisionthe precise harm ADR-074 prohibits. No-ticket-created is the user-pinned protection; the HALT is the persona-correct shape (JTBD-006's "queued for my return, not guessed at" is satisfied by the stderr directive surfacing on user return + the AFK loop continuing to the next problem).
49
+ **ADR-013 Rule 6 carve-out audit (P352, 2026-06-06 amendment; corrected by P401 2026-06-29/2026-07-02)**: the universal AFK default is **queue-and-continue** (queue the decision, continue the loop). The AFK low-confidence path now **conforms** to that default rather than carving out from it: it captures the ticket with the `(unconfirmed — elicitation queued)` anchoring sentinel and queues the elicitation interview the finding is preserved (P401 never-discard + JTBD-006 "save findings and move to the next problem"), NOT refused. ADR-074 (Confirm decision substance before building dependent work) is still honoured, but by a different tactic than the retired no-ticket halt: the ticket's anchoring is **explicitly unconfirmed** (a greppable sentinel, never a shoehorned best-fit masquerading as confirmed — that would be the P395 harm), and dependent RFC/story/fix work stays gated on anchoring confirmation via the existing downstream oversight markers **ADR-068/P288** (a new persona/JTBD needs human ratification before it exists), **ADR-090** (story maps/stories carry a drift-invalidated oversight marker), and the **ADR-060 I13** propose-fix RFC-trace guard. Until the deferred `/wr-itil:work-problems` caller-side wiring lands (route the queued elicitation into the orchestrator's `outstanding_questions` batch tracked on P401), that downstream protection rests on those existing markers, not on refusing the capture. (The Empty `$ARGUMENTS` halt remains a genuine caller-contract halt there is no description to capture.)
50
50
 
51
51
  ## Steps
52
52
 
@@ -75,7 +75,7 @@ fi
75
75
  |------|-------------------|
76
76
  | `--jtbd=JTBD-NNN[,JTBD-NNN...]` | Pre-resolves the JTBD-trace value. Step 1.5b skips JTBD-trace derivation. Comma-separated list of JTBD IDs (no spaces). |
77
77
  | `--persona=<value>` | Pre-resolves the persona value. Step 1.5b skips persona derivation. Value MUST be one of the directory names under `docs/jtbd/*/` (the adopter's real persona corpus — e.g. `maintainer`, `smb-owner` in adopter repos), falling back to the home-repo set `{developer, tech-lead, plugin-developer, plugin-user}` only when no `docs/jtbd/` directories exist. P383 — never hardcode the home-repo enum (P151/P317 adopter-portability). |
78
- | `--no-prompt` | **AFK mode marker** (REVIVED 2026-06-02 per ADR-060 Amendment 2026-06-02). Suppresses the I12 derive-then-ratify AskUserQuestion fallback. When set AND derivation fails (no JTBD-NNN citations + no `--persona=` flag + no `--jtbd=` flag, OR cited-JTBD persona-disagreement) → capture halts-with-stderr-directive and exits non-zero. AFK orchestrators (`/wr-itil:work-problems` capture-on-correction sub-flow, agent-mid-iter `capture-problem` invocations) MUST pass this flag PLUS pre-resolved `--persona` + `--jtbd` flags to avoid the halt. |
78
+ | `--no-prompt` | **AFK mode marker** (REVIVED 2026-06-02 per ADR-060 Amendment 2026-06-02; behaviour corrected by P401 2026-06-29/2026-07-02). Suppresses the low-confidence interview. When set AND derivation fails (no JTBD-NNN citations + no `--persona=` flag + no `--jtbd=` flag, OR cited-JTBD persona-disagreement) → capture the ticket with the `(unconfirmed — elicitation queued)` anchoring sentinel + stderr advisory and queue the elicitation (P401 never-discard) — it no longer halts-refuses. AFK orchestrators (`/wr-itil:work-problems` capture-on-correction sub-flow, agent-mid-iter `capture-problem` invocations) SHOULD still pass this flag PLUS pre-resolved `--persona` + `--jtbd` flags to skip the sentinel path entirely. |
79
79
 
80
80
  Strip recognised leading flags from `$ARGUMENTS`; the remainder (after flags) is the free-text description. Unknown leading flags halt-with-stderr-directive: print "capture-problem: unknown flag '<flag>' — recognised flags: --jtbd=JTBD-NNN, --persona=<value>, --no-prompt" and exit.
81
81
 
@@ -85,30 +85,44 @@ Empty description (post-flag-strip) halts per the Rule 6 audit above.
85
85
 
86
86
  Derive a kebab-case title slug from the first 8-10 non-stopword tokens of the description (matching the existing `manage-problem` slug derivation pattern).
87
87
 
88
- ### 1.5b JTBD-trace + persona dispatch — I12 derive-then-ratify (ADR-060 Amendment 2026-06-02)
88
+ ### 1.5b JTBD-trace + persona dispatch — I12 derive → interview-on-low-confidence → classify (ADR-060 Amendment 2026-06-02, corrected by P401)
89
89
 
90
- Per ADR-060 § Phase 3 + Phase 4 in-scope amendment (2026-05-13), as amended by P287 (2026-06-02 base — type-classification retired) AND by ADR-060 Amendment 2026-06-02 (I12 hard-block REPLACED with derive-then-ratify; applies to ALL problems; no type-keyed gating). Fires UNCONDITIONALLY. Both `jtbd_trace_value` and `persona_value` are REQUIRED on every captured ticket via the derive-then-ratify contract; on derivation failure or ambiguity, the dispatch proposes candidates for user ratification via `AskUserQuestion` (direction-setting per ADR-044 category 1).
90
+ Per ADR-060 § Phase 3 + Phase 4 in-scope amendment (2026-05-13), as amended by P287 (2026-06-02 base — type-classification retired), by ADR-060 Amendment 2026-06-02 (I12 hard-block REPLACED with derive-then-ratify; applies to ALL problems; no type-keyed gating), AND by the **P401 correction (user direction 2026-06-29, sharpened 2026-07-02)** the low-confidence path is now **interview-to-elicit-who/why**, NOT propose-candidate-IDs-for-ratification; and a real problem is **never discarded** over anchoring uncertainty. Fires UNCONDITIONALLY. Both `jtbd_trace_value` and `persona_value` are REQUIRED on every captured ticket.
91
91
 
92
- **Resolve `jtbd_trace_value`** (an ORDERED list of JTBD IDs) via the following derive-then-ratify dispatch:
92
+ **The corrected contract (one principle, both fields):**
93
+
94
+ 1. The agent **derives** persona + JTBD from the description.
95
+ 2. **Confident** → map to the existing persona/JTBD and **proceed autonomously** (no human — ADR-044 category-4 silent-framework).
96
+ 3. **Not confident** → do **NOT** shoehorn into the nearest existing ID, and do **NOT** ask *"is it JTBD-XXXX?"*. **Interview** the human (`AskUserQuestion`, ADR-013 Rule 1 structured form; may be more than one question) with substantive, non-leading questions about *who* hits this and *what they are trying to get done* — requirements elicitation of the real persona/job, **not** ratification of a guessed ID (this is *more* brief-before-ID-compliant than the old prompt — P350 — since no ID is surfaced at all).
97
+ 4. From the elicited who/why the **agent classifies**: matches an **existing** persona/JTBD → map and proceed (autonomous — the ADR-068 boundary applies only to *creation*, not mapping); **no existing fit** → a **new** persona/JTBD is warranted → route the **creation** to the ADR-068/P288 human-ratify surface (`/wr-jtbd:update-guide` then `/wr-jtbd:confirm-jobs-and-personas`); on ratification, map to the new ID and proceed.
98
+
99
+ The human is involved only for **substance** — the interview when derivation is weak, and ratifying the **creation** of a genuinely new persona/JTBD — never to bless an ID. **A real problem is NEVER discarded over anchoring uncertainty**; anchoring uncertainty is resolved by elicitation, not by rejecting the problem. Scope-rejection (deciding the elicited who/why is out of scope to support) is an **external-report-only** decision handled at `/wr-itil:manage-problem` ingestion — maintainer-side captures here always anchor to an existing or a new job. This is the same `covered → agent proceeds / uncovered → human ratifies a new artefact` boundary ADR-073 draws for the fix-approach axis, applied to the who/why axis.
100
+
101
+ > **P401 supersession note (user direction 2026-06-29 / 2026-07-02).** This reverses the 2026-06-02 ADR-060 amendment substance that framed *"REJECT of the proposed persona/JTBD = rejection of the problem; no ticket created."* That framing shoehorned problems into the nearest ID and discarded legitimate problems over anchoring uncertainty. The reversal is deliberate and user-directed, NOT drift. The corresponding **ADR-060 body amendment** and the **ADR-073 additive symmetric-escalation note** are **queued on P401** for the interactive ratification drain (per P357 — user direction is not itself ADR-body-substance ratification); until they land, this SKILL leads and the ADR bodies follow — the same governed trade-off as the P287 type-axis retirement (see the `## Related` note below). The AFK caller-side wiring in `/wr-itil:work-problems` (route the queued elicitation into its `outstanding_questions` batch) is likewise queued on P401.
102
+
103
+ **Resolve `jtbd_trace_value`** (an ORDERED list of JTBD IDs) via the following derive → interview-on-low-confidence → classify dispatch:
93
104
 
94
105
  1. **If `--jtbd=JTBD-NNN[,JTBD-NNN...]` was set in Step 1**: parse comma-separated list; assign to `jtbd_trace_value`; do NOT run the lexical detector; do NOT fire `AskUserQuestion` (silent-framework per ADR-044 category 4). Caller pre-resolved.
95
106
  2. **Else** run the **lexical JTBD-trace detector** against the description: `grep -oE '\bJTBD-[0-9]+\b' | sort -u`. If ≥1 match found, set `jtbd_trace_value` to the matched IDs (de-duplicated, sorted ascending) and emit stderr advisory: `capture-problem: derived jtbd-trace=<id-list> from description JTBD-NNN citations; re-invoke with --jtbd= to override`. Do NOT fire `AskUserQuestion` (silent-framework).
96
- 3. **Else (no flag, no lexical detection — derive-failure path)**: enter the **derive-then-ratify dispatch**. Propose up-to-3 candidate JTBD IDs to the user via `AskUserQuestion`. The candidates come from LLM analysis of the description's domain signals (e.g. "AFK loop" + "iter dispatch" propose JTBD-006; "ADR / governance" propose JTBD-001; "plugin discoverability" propose JTBD-101). The 4th option is **Reject** (4-option cap per ADR-044 Rule 1). User response semantics:
97
- - **REJECT** halt-with-stderr-directive (`capture-problem: user rejected proposed JTBD trace; per I12 derive-then-ratify (ADR-060 Amendment 2026-06-02), rejection of proposed persona/JTBD = rejection of the problem; no ticket created`); exit non-zero.
98
- - **Option-pick** (acceptance of a proposed JTBD as-is)assign `jtbd_trace_value` to the picked ID; proceed silently.
99
- - **Free-text correction** (user supplies a different JTBD-NNN ID via the AskUserQuestion free-text path) validate the supplied ID matches `\bJTBD-([A-Za-z]+-)?[0-9]+\b` (tolerating the maintainer `JTBD-M-NNN` alpha-infix scheme, P383) AND a matching `docs/jtbd/<persona>/JTBD-<id>-*.md` file exists; assign `jtbd_trace_value` to the corrected ID; proceed silently (correction-as-acceptance).
100
- 4. **AFK halt (the `--no-prompt` branch)**: if `--no-prompt` was set in Step 1 AND control reaches step 3 (no flag + no lexical detection) → SKIP the `AskUserQuestion`; halt-with-stderr-directive (`capture-problem: cannot derive JTBD interactively under AFK and no --jtbd= flag supplied; capture refusedre-invoke with explicit anchoring`); exit non-zero.
107
+ 3. **Else (no flag, no lexical detection — low-confidence path)**: do **NOT** shoehorn a best-fit JTBD and do **NOT** propose candidate `JTBD-NNN` IDs for ratification. **Interview** the human via `AskUserQuestion` (may span who + why in one dispatch shared with the persona resolution below) with substantive, non-leading questions about *what job* the affected user is trying to get done. From the elicited answer the **agent classifies**:
108
+ - **Elicited job matches an existing JTBD** set `jtbd_trace_value` to that ID and proceed (autonomous mapping no further ratification; the ADR-068 human-oversight boundary applies only to *creation*).
109
+ - **No existing JTBD fits** a new JTBD is warranted route the **creation** to the ADR-068/P288 human-ratify surface (`/wr-jtbd:update-guide` then `/wr-jtbd:confirm-jobs-and-personas`); on ratification, set `jtbd_trace_value` to the new ID and proceed.
110
+ - **The problem is never discarded** over anchoring uncertainty. (Scope-rejection deciding the elicited who/why is out of scope to support is an external-report-only decision at `/wr-itil:manage-problem` ingestion, never here.)
111
+ 4. **AFK (the `--no-prompt` branch) — preserve the finding, queue the elicitation**: if `--no-prompt` was set in Step 1 AND control reaches step 3 (no flag + no lexical detection) → SKIP the `AskUserQuestion`, do **NOT** shoehorn a best-fit ID, and do **NOT** auto-create a new JTBD. Set `jtbd_trace_value` to the greppable unconfirmed-anchoring sentinel `(unconfirmed — elicitation queued)`, capture the ticket, and **queue the persona/JTBD elicitation interview** for the next interactive session (the AFK orchestrator surfaces it via its `outstanding_questions` batch). Emit stderr advisory `capture-problem: JTBD low-confidence under AFK; ticket captured with unconfirmed anchoring; elicitation queueddo not build dependent RFC/story/fix work until anchoring is confirmed`. The ticket IS created (P401 never-discard + JTBD-006 save-and-continue); ADR-074's "don't build on unconfirmed substance" is preserved by the existing downstream oversight gates (ADR-068/P288 new-persona/JTBD ratification; ADR-090 story-oversight; ADR-060 I13 propose-fix RFC-trace guard), NOT by refusing the capture.
101
112
 
102
- **Resolve `persona_value`** (a scalar persona value — validated against the **adopter's persona corpus**: the directory names under `docs/jtbd/*/`, falling back to the home-repo set `{developer, tech-lead, plugin-developer, plugin-user}` only when no `docs/jtbd/` directories exist; P383, never hardcode the home-repo enum — P151/P317 adopter-portability) via the following derive-then-ratify dispatch:
113
+ **Resolve `persona_value`** (a scalar persona value — validated against the **adopter's persona corpus**: the directory names under `docs/jtbd/*/`, falling back to the home-repo set `{developer, tech-lead, plugin-developer, plugin-user}` only when no `docs/jtbd/` directories exist; P383, never hardcode the home-repo enum — P151/P317 adopter-portability) via the following derive → interview-on-low-confidence → classify dispatch:
103
114
 
104
115
  1. **If `--persona=<value>` was set in Step 1**: validate `<value>` against the persona corpus (the `docs/jtbd/*/` directory names, or the home-repo fallback set when no jtbd dirs exist — e.g. `ls -d docs/jtbd/*/ | xargs -n1 basename`); halt-with-directive if invalid; otherwise assign and proceed silently. Caller pre-resolved.
105
116
  2. **Else if `jtbd_trace_value` is non-empty AND cited JTBDs agree on a single persona**: derive `persona_value` from the cited JTBDs' `persona:` (and optionally `secondary-persona:`) frontmatter; emit stderr advisory: `capture-problem: derived persona=<value> from cited JTBD <id> frontmatter`; proceed silently.
106
- 3. **Else (no flag + (no cited JTBDs OR cited-JTBD persona-disagreement) — derive-failure / ambiguity path)**: enter the **derive-then-ratify dispatch**. Propose up-to-3 candidate persona values to the user via `AskUserQuestion`. Candidate generation: on cited-JTBD persona-disagreement, the candidates are the union-of-derived-personas from the cited JTBDs. On no-cited-JTBDs, the candidates come from LLM analysis of the description's persona signals (e.g. "ADR / governance" → propose `developer`; "plugin install / autocomplete" → propose `plugin-user`; "plugin maintainer / scaffold" propose `plugin-developer`). The 4th option is **Reject** (4-option cap per ADR-044 Rule 1). User response semantics same as JTBD-trace step 3: REJECT → halt-with-stderr-directive + exit non-zero (rejection of proposed persona = rejection of the problem); option-pick → assign + proceed silently (acceptance); free-text correction → validate against the persona corpus (the `docs/jtbd/*/` directory names, enum fallback when no jtbd dirs) + assign + proceed silently (correction-as-acceptance).
107
- 4. **AFK halt (the `--no-prompt` branch)**: if `--no-prompt` was set in Step 1 AND control reaches step 3 SKIP the `AskUserQuestion`; halt-with-stderr-directive (`capture-problem: cannot derive persona interactively under AFK and no --persona= flag supplied; capture refused re-invoke with explicit anchoring`); exit non-zero.
117
+ 3. **Else (no flag + (no cited JTBDs OR cited-JTBD persona-disagreement) — low-confidence / ambiguity path)**: do **NOT** shoehorn a best-fit persona and do **NOT** propose candidate persona IDs for ratification. **Interview** the human via `AskUserQuestion` (share the dispatch with the JTBD-trace interview above one elicitation covers *who* + *what job*) with substantive, non-leading questions about *who* actually hits this problem. From the elicited answer the **agent classifies**:
118
+ - **Elicited persona matches an existing persona** (a `docs/jtbd/*/` directory)assign `persona_value` to it and proceed (autonomous mappingADR-068 boundary is creation-only).
119
+ - **No existing persona fits** → a new persona is warranted → route the **creation** to the ADR-068/P288 human-ratify surface (`/wr-jtbd:update-guide` then `/wr-jtbd:confirm-jobs-and-personas`); on ratification assign `persona_value` to the new persona and proceed.
120
+ - **The problem is never discarded** over persona uncertainty. Scope-rejection remains external-report-only (`/wr-itil:manage-problem` ingestion).
121
+ 4. **AFK (the `--no-prompt` branch) — preserve the finding, queue the elicitation**: if `--no-prompt` was set in Step 1 AND control reaches step 3 → SKIP the `AskUserQuestion`, do **NOT** shoehorn a best-fit persona, and do **NOT** auto-create a new persona. Set `persona_value` to the greppable unconfirmed-anchoring sentinel `(unconfirmed — elicitation queued)`, capture the ticket, and queue the elicitation interview for the next interactive session. Emit stderr advisory `capture-problem: persona low-confidence under AFK; ticket captured with unconfirmed anchoring; elicitation queued — do not build dependent RFC/story/fix work until anchoring is confirmed`. The ticket IS created (P401 never-discard); ADR-074 preserved via the existing downstream oversight gates, not by refusing the capture.
108
122
 
109
123
  **JTBD-301 scope preservation**: this dispatch fires on the maintainer-side `/wr-itil:capture-problem` only. Plugin-user-side `.github/ISSUE_TEMPLATE/problem-report.yml` MUST NOT prompt for JTBD trace or persona — preserves the JTBD-301 firewall per ADR-060 P4.3 maintainer-side / plugin-user-side asymmetry clarifier. Triage during `/wr-itil:manage-problem` ingestion assigns both fields from the reporter's symptom signals (per the JTBD-301 maintainer-side-complement extension, amended 2026-06-02 to remove the type-axis residue).
110
124
 
111
- **ADR-044 authority taxonomy**: silent-framework (category 4) on the derive-success paths (flag pre-resolution, lexical detection, cited-JTBD agreement); **direction-setting (category 1)** on the derive-failure AskUserQuestion fallback paths (the user is being asked to ratify the captured ticket's substance persona + JTBD trace are direction-setting for the ticket's future trace per ADR-060 amendment's I12 reframe — NOT a taste preference between equally-valid options).
125
+ **ADR-044 authority taxonomy**: silent-framework (category 4) on the derive-success paths (flag pre-resolution, lexical detection, cited-JTBD agreement) AND on the agent's existing-vs-new classification of the elicited who/why (mechanical framework resolution — the agent maps the elicited job to an existing artefact without a consent gate); **direction-setting (category 1)** on the low-confidence **interview** (requirements elicitation of the real persona/job) and on the human ratification of the **creation** of a new persona/JTBD (per ADR-068/P288) — NOT a taste preference between equally-valid options, and NOT ratification of a guessed ID (P401).
112
126
 
113
127
  ### 2. Minimal-grep duplicate check (3-keyword title-only) + hang-off-check subagent dispatch (P346 Phase 3 amendment, 2026-05-31)
114
128
 
@@ -372,10 +386,10 @@ The trailing pointer is **not optional** — it is the user-visible signal for u
372
386
  |---------|----------------|-----------------|
373
387
  | Duplicate-check | Wide-net grep + AskUserQuestion branch on matches | 3-keyword title-only grep, list-only (no branch) |
374
388
  | Multi-concern split | Step 4b AskUserQuestion | Out of scope (one ticket per invocation) |
375
- | Skeleton-fill | Full-intake; AskUserQuestion for missing fields | Deferred-placeholder pattern; I12 derive-then-ratify AskUserQuestion fires on derivation-failure (REJECT/CORRECTION/ACCEPT semantics) |
389
+ | Skeleton-fill | Full-intake; AskUserQuestion for missing fields | Deferred-placeholder pattern; low-confidence persona/JTBD → interview-to-elicit-who/why (never propose an ID; never discard the problem) |
376
390
  | Type-tag prompt | RETIRED (P287, 2026-06-02) | RETIRED (P287, 2026-06-02) — the technical/user-business axis was removed as redundant with RFC/Story persona-anchoring per ADR-060 Phase 4 |
377
- | JTBD-trace + persona | Step 4-equivalent ingestion path | Step 1.5b I12 derive-then-ratify dispatch (ADR-060 Amendment 2026-06-02) — flag pre-resolution (`--jtbd=` / `--persona=`) silent-proceeds; lexical detection of JTBD-NNN citations silent-proceeds; cited-JTBD persona derivation silent-proceeds; derivation-failureAskUserQuestion proposal with REJECT (= problem rejected; no ticket) / option-pick (acceptance) / free-text correction (correction-as-acceptance); AFK callers pre-resolve via flags or halt-with-stderr-directive when `--no-prompt` |
378
- | AskUserQuestion authority | Multiple branches (deviation-approval / direction-setting / taste / mechanical) | One direction-setting branch on the I12 derive-failure fallback (ADR-044 category 1); silent-framework (category 4) on derive-success paths; zero control-flow branches keyed on the answer's substance (REJECT/option-pick/correction are uniform handlers) |
391
+ | JTBD-trace + persona | Step 4-equivalent ingestion path | Step 1.5b derive → interview → classify dispatch (ADR-060 Amendment 2026-06-02 as corrected by P401) — flag pre-resolution (`--jtbd=` / `--persona=`) silent-proceeds; lexical detection of JTBD-NNN citations silent-proceeds; cited-JTBD persona derivation silent-proceeds; low-confidenceINTERVIEW to elicit who/why (not propose an ID) agent classifies existing:map+proceed / no-fit:human-ratifies-CREATION (ADR-068/P288); problem NEVER discarded over anchoring; AFK `--no-prompt` → capture with unconfirmed-anchoring sentinel + queue elicitation |
392
+ | AskUserQuestion authority | Multiple branches (deviation-approval / direction-setting / taste / mechanical) | Direction-setting (ADR-044 category 1) on the low-confidence interview + on the new-artefact creation-ratify; silent-framework (category 4) on derive-success paths AND on the agent's existing-vs-new classification of the elicited who/why |
379
393
  | README refresh | P094 inline (regenerate + stage in same commit) | P094 inline (regenerate + stage in same commit) — P199 Option 2 amendment 2026-06-05; previously deferred to next `/wr-itil:review-problems` |
380
394
  | Status transitions | Step 7 owns Open → Known Error → Verifying → Closed | Out of scope (creation only) |
381
395
  | Commit grain | One commit per intake (or per split-concern set) | One commit per capture |
@@ -404,7 +418,8 @@ The two skills share the `/tmp/manage-problem-grep-${SESSION_ID}` create-gate ma
404
418
  - **P185** — `/wr-itil:capture-problem` historical: asked a classification question (type) it could answer itself; the Step 1.5 derive-first refactor (lexical-signal classifier + stderr advisory) shipped the fix in 2026-05-15. P287 then retired the entire surface in 2026-06-02 as the classification axis itself was redundant with RFC/Story persona-anchoring.
405
419
  - **ADR-049** — bin/ on PATH; capture-problem reuses the existing `wr-itil-reconcile-readme` shim.
406
420
  - **ADR-052** — behavioural-tests-default for skill testing; SKILL.md I2 surface coverage gap is named, not silent (P176 + ADR-052 § Surface 2).
407
- - **ADR-060** (`docs/decisions/060-...accepted.md`) — body currently encodes the type-tag schema (Decision Outcome item 1, I2 type-uniformity, I12 hard-block, Phase-4 persona+jtbd machinery keyed on `type:user-business`). P287 retires the SKILL implementation of these clauses unilaterally per twice-confirmed user direction; the ADR body amendment substance (I12 replacement shape, Phase-4 rework) is queued for user re-confirmation per ADR-074. Until the amendment lands, ADR-060 body and SKILL implementation are intentionally inconsistent — this is the P287 trade-off the user accepted.
421
+ - **ADR-060** (`docs/decisions/060-...accepted.md`) — body currently encodes the type-tag schema (Decision Outcome item 1, I2 type-uniformity, I12 hard-block, Phase-4 persona+jtbd machinery keyed on `type:user-business`) AND the 2026-06-02 amendment's REJECT=discard clause. P287 retires the SKILL implementation of the type clauses unilaterally per twice-confirmed user direction; **P401 (2026-06-29/2026-07-02) reverses the REJECT=discard clause to interview-on-low-confidence + never-discard + ratify-creation-only** (see the Step 1.5b supersession note). Both ADR body amendment substances (the P287 type rework; the P401 I12 reshape) plus the **ADR-073 additive symmetric covered→agent / uncovered→human-ratifies-new-persona/JTBD escalation note** are queued for user re-confirmation per ADR-074/P357. Until they land, ADR-060/ADR-073 bodies and SKILL implementation are intentionally inconsistent — the same governed SKILL-leads-ADR-follows trade-off the user accepted for P287.
422
+ - **P401** (`docs/problems/open/401-capture-persona-jtbd-shoehorns-or-discards-instead-of-interviewing.md`) — the driver: the old propose-candidate-IDs + REJECT=discard flow shoehorned problems into the nearest persona/JTBD and discarded legitimate problems over anchoring uncertainty. This SKILL amendment lands the corrected interview-based shape; the ADR-060/ADR-073 body amendments + the `/wr-itil:work-problems` AFK caller-side wiring (route the queued elicitation into `outstanding_questions`) remain tracked on P401's Investigation Tasks.
408
423
  - **JTBD-301** (`docs/jtbd/plugin-user/JTBD-301-...md`) — plugin-user no-pre-classification persona constraint; the Step 1.5b maintainer-side scope guard preserves the firewall on the JTBD-trace + persona axis. The type-axis firewall is moot (axis retired).
409
424
  - `packages/itil/skills/manage-problem/SKILL.md` — heavyweight intake counterpart.
410
425
  - `packages/itil/skills/review-problems/SKILL.md` — re-rates the deferred placeholders + refreshes README.md.
@@ -11,17 +11,23 @@
11
11
  # silent-resolve jtbd_trace_value to the matched IDs.
12
12
  # - --jtbd=JTBD-NNN[,...] flag pre-resolves jtbd_trace_value silently.
13
13
  # - --persona=<value> flag pre-resolves persona_value silently.
14
- # - Derive-failure (no flag + no lexical detection + no cited-JTBD
15
- # agreement) → AskUserQuestion proposal with REJECT/option-pick/
16
- # free-text correction semantics (REJECT = problem rejected; no
17
- # ticket; option-pick = acceptance; correction = correction-as-
18
- # acceptance).
19
- # - --no-prompt + derive-failure halt-with-stderr-directive (AFK
20
- # callers MUST pre-resolve via flags).
14
+ # - Low-confidence (no flag + no lexical detection + no cited-JTBD
15
+ # agreement) → P401 CORRECTED shape (user direction 2026-06-29,
16
+ # sharpened 2026-07-02): INTERVIEW the human to elicit the real
17
+ # who/why (NOT propose an ID) agent classifies existing-vs-new →
18
+ # existing:map+proceed autonomously / no-fit:human-ratifies-CREATION
19
+ # of a new persona/JTBD (ADR-068/P288). A real problem is NEVER
20
+ # discarded over anchoring uncertainty. Scope-rejection (elicited
21
+ # who/why out of scope) is EXTERNAL-report-only, at manage-problem
22
+ # ingestion — never here.
23
+ # - --no-prompt + low-confidence → preserve the finding: CREATE the
24
+ # ticket with the `(unconfirmed — elicitation queued)` anchoring
25
+ # sentinel + queue the elicitation (P401 never-discard + JTBD-006
26
+ # save-and-continue). It no longer halt-refuses.
21
27
  # - Skeleton template carries **JTBD**: and **Persona**: body fields.
22
28
  #
23
- # i12_should_halt_afk predicate (NEW per ADR-060 Amendment 2026-06-02)
24
- # encodes the AFK halt-without-flags branch. The historical
29
+ # afk_low_confidence_action predicate (P401 2026-06-29) encodes the AFK
30
+ # create-with-unconfirmed-sentinel branch. The historical
25
31
  # i12_should_block predicate is preserved as a regression guard
26
32
  # (never returns 0) against re-introduction of the type-keyed hard-block.
27
33
  #
@@ -56,51 +62,67 @@ i12_should_block() {
56
62
  return 1
57
63
  }
58
64
 
59
- # ADR-060 Amendment 2026-06-02 — NEW positive predicate for I12 derive-
60
- # then-ratify AFK halt-without-flags branch. Returns 0 (halt) when:
61
- # - --no-prompt is set AND
62
- # - derivation failed (no flag pre-resolution + no lexical detection
63
- # + no cited-JTBD agreement).
64
- # Returns 1 (proceed) otherwise. Inputs:
65
+ # P401 (2026-06-29 / 2026-07-02)AFK low-confidence action. The
66
+ # corrected shape PRESERVES THE FINDING: under --no-prompt + low-
67
+ # confidence, capture the ticket with the unconfirmed-anchoring sentinel
68
+ # and queue the elicitation. It NO LONGER halt-refuses (that discarded
69
+ # legitimate problems over anchoring uncertainty). Returns the action.
70
+ # Inputs:
65
71
  # $1: no_prompt_flag ("1" if --no-prompt set, "" otherwise)
66
72
  # $2: derivation_resolved ("1" if persona+JTBD resolved by any of
67
73
  # flag/lexical/cited-JTBD path; "" otherwise)
68
- i12_should_halt_afk() {
74
+ AFK_SENTINEL="(unconfirmed — elicitation queued)"
75
+ afk_low_confidence_action() {
69
76
  local no_prompt="$1"
70
77
  local derivation_resolved="$2"
71
78
  if [ "$no_prompt" = "1" ] && [ -z "$derivation_resolved" ]; then
72
- return 0 # halt
79
+ echo "CREATE_UNCONFIRMED_QUEUE_ELICITATION"
80
+ else
81
+ echo "PROCEED" # derivation succeeded, or interactive interview fires
73
82
  fi
74
- return 1 # proceed (interactive ratification fires, or derivation succeeded)
75
- }
76
-
77
- # ADR-060 Amendment 2026-06-02 reference impl for AskUserQuestion
78
- # response semantics in the I12 derive-then-ratify dispatch. Returns:
79
- # "REJECT" when user picked the Reject option
80
- # "ACCEPT:<v>" when user picked a proposed option <v> as-is
81
- # "CORRECT:<v>" when user supplied free-text correction <v>
82
- # Behaviourally the SKILL must treat REJECT as halt-with-stderr-directive
83
- # (no ticket); ACCEPT and CORRECT both yield ticket-with-value.
84
- classify_ratification_response() {
85
- local response="$1"
86
- case "$response" in
87
- REJECT) echo "REJECT" ;;
88
- OPTION:*) echo "ACCEPT:${response#OPTION:}" ;;
89
- FREETEXT:*) echo "CORRECT:${response#FREETEXT:}" ;;
90
- *) echo "UNKNOWN:$response" ;;
83
+ }
84
+
85
+ # P401 — reference impl for the corrected low-confidence resolution of a
86
+ # MAINTAINER-INTERNAL capture. The agent interviews to elicit who/why,
87
+ # then classifies the elicited fit. Returns the resolution action:
88
+ # "MAP_EXISTING" elicited job/persona matches an existing artefact
89
+ # map autonomously (ADR-068 boundary is creation-only)
90
+ # "RATIFY_CREATE_NEW" no existing fit human ratifies the CREATION of a
91
+ # new persona/JTBD (ADR-068/P288), then map
92
+ # The problem is NEVER discarded over anchoring uncertainty.
93
+ resolve_low_confidence_internal() {
94
+ local elicited_fit="$1"
95
+ case "$elicited_fit" in
96
+ existing) echo "MAP_EXISTING" ;;
97
+ none) echo "RATIFY_CREATE_NEW" ;;
98
+ *) echo "INTERVIEW" ;; # elicit who/why first
91
99
  esac
92
100
  }
93
101
 
94
- # Returns 0 when the response yields a ticket; 1 when it halts capture.
95
- ratification_creates_ticket() {
96
- local classified="$1"
97
- case "$classified" in
98
- REJECT) return 1 ;; # no ticket; capture halts
99
- ACCEPT:*|CORRECT:*) return 0 ;; # ticket created
102
+ # P401 every maintainer-internal low-confidence resolution yields a
103
+ # ticket (never discard). CREATE_UNCONFIRMED is the AFK sentinel path.
104
+ internal_resolution_creates_ticket() {
105
+ case "$1" in
106
+ MAP_EXISTING|RATIFY_CREATE_NEW|CREATE_UNCONFIRMED_QUEUE_ELICITATION) return 0 ;;
100
107
  *) return 1 ;;
101
108
  esac
102
109
  }
103
110
 
111
+ # P401 — scope-rejection is EXTERNAL-report-only (at manage-problem
112
+ # ingestion, NOT capture-problem). Through the elicitation interview the
113
+ # maintainer may decide the elicited who/why is out of scope to support
114
+ # and decline. This is the ONLY path that yields no ticket, and only for
115
+ # external reports. A maintainer-internal capture ALWAYS anchors.
116
+ # Inputs: $1 origin ("internal"|"external"); $2 in_scope ("yes"|"no").
117
+ external_scope_disposition() {
118
+ local origin="$1" in_scope="$2"
119
+ if [ "$origin" = "external" ] && [ "$in_scope" = "no" ]; then
120
+ echo "DECLINE_SCOPE" # deliberate product-scope decline; no ticket
121
+ else
122
+ echo "ANCHOR" # internal always anchors; external in-scope anchors
123
+ fi
124
+ }
125
+
104
126
  # Reference implementation of --jtbd= flag parser. Accepts CSV; returns
105
127
  # space-separated IDs (canonicalised) OR empty if the flag wasn't set.
106
128
  parse_jtbd_flag() {
@@ -217,77 +239,96 @@ parse_no_prompt_flag() {
217
239
  }
218
240
 
219
241
  # ---------------------------------------------------------------------------
220
- # ADR-060 Amendment 2026-06-02 — I12 derive-then-ratify positive controls.
221
- # These exercise the new contract: AskUserQuestion fires on derivation-
222
- # failure with REJECT/option-pick/free-text-correction semantics; AFK
223
- # callers pre-resolve via flags or halt-with-stderr-directive on
224
- # --no-prompt + derive-failure.
242
+ # P401 (2026-06-29 / 2026-07-02)corrected low-confidence contract.
243
+ # Low-confidence INTERVIEWS to elicit who/why (never proposes an ID); the
244
+ # agent classifies existing-vs-new; existing→map+proceed, no-fit→human-
245
+ # ratifies-CREATION; a real problem is NEVER discarded over anchoring;
246
+ # scope-rejection is external-report-only; AFK captures with the
247
+ # unconfirmed-anchoring sentinel + queues the elicitation.
225
248
  # ---------------------------------------------------------------------------
226
249
 
227
- @test "I12 derive-then-ratify: i12_should_halt_afk halts on --no-prompt + derive-failure" {
228
- # AFK caller passed --no-prompt; derivation failed (no flag pre-resolution,
229
- # no lexical detection, no cited-JTBD agreement). MUST halt.
230
- i12_should_halt_afk "1" ""
250
+ @test "P401 low-confidence interviews (elicits who/why) rather than proposing an ID" {
251
+ # Before classification, the resolution action is INTERVIEW the agent
252
+ # elicits the real who/why, NOT a candidate JTBD-NNN to ratify.
253
+ result=$(resolve_low_confidence_internal "unknown")
254
+ [ "$result" = "INTERVIEW" ]
231
255
  }
232
256
 
233
- @test "I12 derive-then-ratify: i12_should_halt_afk proceeds when --no-prompt set but derivation succeeded" {
234
- # AFK caller passed --no-prompt AND pre-resolved via flags. Derivation
235
- # succeeded; proceed silently with derived values.
236
- ! i12_should_halt_afk "1" "1"
257
+ @test "P401 elicited who/why matching an existing artefact maps autonomously" {
258
+ # Classification: elicited job matches an existing JTBD/persona map and
259
+ # proceed with no further human ratification (ADR-068 boundary is
260
+ # creation-only). Yields a ticket.
261
+ result=$(resolve_low_confidence_internal "existing")
262
+ [ "$result" = "MAP_EXISTING" ]
263
+ internal_resolution_creates_ticket "$result"
237
264
  }
238
265
 
239
- @test "I12 derive-then-ratify: i12_should_halt_afk proceeds when no --no-prompt (interactive mode)" {
240
- # Interactive caller; derivation failed; AskUserQuestion fires (proceed
241
- # past the AFK halt gate, into the ratification dispatch).
242
- ! i12_should_halt_afk "" ""
266
+ @test "P401 elicited who/why with no existing fit routes to human-ratified new-artefact creation" {
267
+ # No existing fit a new persona/JTBD is warranted → human ratifies the
268
+ # CREATION (ADR-068/P288), then map. Still yields a ticket (never discard).
269
+ result=$(resolve_low_confidence_internal "none")
270
+ [ "$result" = "RATIFY_CREATE_NEW" ]
271
+ internal_resolution_creates_ticket "$result"
243
272
  }
244
273
 
245
- @test "I12 derive-then-ratify: i12_should_halt_afk proceeds when interactive AND derivation succeeded" {
246
- ! i12_should_halt_afk "" "1"
274
+ @test "P401 a maintainer-internal problem is NEVER discarded over anchoring uncertainty" {
275
+ # Every internal low-confidence resolution — map-existing, ratify-new, or
276
+ # the AFK create-with-unconfirmed-sentinel — yields a ticket.
277
+ internal_resolution_creates_ticket "MAP_EXISTING"
278
+ internal_resolution_creates_ticket "RATIFY_CREATE_NEW"
279
+ internal_resolution_creates_ticket "CREATE_UNCONFIRMED_QUEUE_ELICITATION"
247
280
  }
248
281
 
249
- @test "I12 derive-then-ratify: REJECT response halts capture (no ticket created)" {
250
- classified=$(classify_ratification_response "REJECT")
251
- [ "$classified" = "REJECT" ]
252
- ! ratification_creates_ticket "$classified"
282
+ @test "P401 AFK low-confidence creates ticket with unconfirmed sentinel + queues elicitation (not halt-refuse)" {
283
+ # --no-prompt + derivation-failure → preserve the finding.
284
+ result=$(afk_low_confidence_action "1" "")
285
+ [ "$result" = "CREATE_UNCONFIRMED_QUEUE_ELICITATION" ]
286
+ # The AFK sentinel is a real (non-empty) anchoring value written to the
287
+ # ticket — the finding is preserved, not discarded.
288
+ [ -n "$AFK_SENTINEL" ]
289
+ internal_resolution_creates_ticket "$result"
253
290
  }
254
291
 
255
- @test "I12 derive-then-ratify: option-pick (ACCEPTANCE) yields ticket with proposed values" {
256
- classified=$(classify_ratification_response "OPTION:developer")
257
- [ "$classified" = "ACCEPT:developer" ]
258
- ratification_creates_ticket "$classified"
292
+ @test "P401 AFK proceeds normally when derivation succeeded (flags pre-resolved)" {
293
+ # AFK orchestrator pattern: pass --no-prompt PLUS --persona + --jtbd to
294
+ # skip the sentinel path entirely.
295
+ no_prompt=$(parse_no_prompt_flag "--persona=developer" "--jtbd=JTBD-006" "--no-prompt" "fix work-problems iter halt")
296
+ [ "$no_prompt" = "1" ]
297
+ persona=$(validate_persona "developer")
298
+ [ "$persona" = "developer" ]
299
+ jtbd=$(parse_jtbd_flag "--jtbd=JTBD-006")
300
+ [ "$jtbd" = "JTBD-006" ]
301
+ result=$(afk_low_confidence_action "$no_prompt" "1")
302
+ [ "$result" = "PROCEED" ]
259
303
  }
260
304
 
261
- @test "I12 derive-then-ratify: free-text correction (CORRECTION-AS-ACCEPTANCE) yields ticket with corrected values" {
262
- classified=$(classify_ratification_response "FREETEXT:plugin-user")
263
- [ "$classified" = "CORRECT:plugin-user" ]
264
- ratification_creates_ticket "$classified"
305
+ @test "P401 interactive low-confidence proceeds into the interview (no --no-prompt)" {
306
+ result=$(afk_low_confidence_action "" "")
307
+ [ "$result" = "PROCEED" ]
265
308
  }
266
309
 
267
- @test "I12 derive-then-ratify: parse_no_prompt_flag detects --no-prompt anywhere in args" {
310
+ @test "P401 scope-rejection is external-report-only; maintainer-internal always anchors" {
311
+ # External report whose elicited who/why we do NOT want to support →
312
+ # deliberate scope decline (no ticket) — the ONLY no-ticket path.
313
+ [ "$(external_scope_disposition external no)" = "DECLINE_SCOPE" ]
314
+ # External report in scope → anchors.
315
+ [ "$(external_scope_disposition external yes)" = "ANCHOR" ]
316
+ # Maintainer-internal ALWAYS anchors, regardless of scope signal —
317
+ # internal captures are never scope-rejected.
318
+ [ "$(external_scope_disposition internal no)" = "ANCHOR" ]
319
+ [ "$(external_scope_disposition internal yes)" = "ANCHOR" ]
320
+ }
321
+
322
+ @test "P401 parse_no_prompt_flag detects --no-prompt anywhere in args" {
268
323
  result=$(parse_no_prompt_flag "--persona=developer" "--no-prompt" "description text")
269
324
  [ "$result" = "1" ]
270
325
  }
271
326
 
272
- @test "I12 derive-then-ratify: parse_no_prompt_flag empty when --no-prompt absent" {
327
+ @test "P401 parse_no_prompt_flag empty when --no-prompt absent" {
273
328
  result=$(parse_no_prompt_flag "--persona=developer" "description text")
274
329
  [ -z "$result" ]
275
330
  }
276
331
 
277
- @test "I12 derive-then-ratify: flag pre-resolution short-circuits derive-failure (AFK-safe path)" {
278
- # AFK orchestrator pattern: pass --no-prompt PLUS --persona + --jtbd to
279
- # avoid the AFK halt. Verifies the load-bearing caller-side contract.
280
- no_prompt=$(parse_no_prompt_flag "--persona=developer" "--jtbd=JTBD-006" "--no-prompt" "fix work-problems iter halt")
281
- [ "$no_prompt" = "1" ]
282
- persona=$(validate_persona "developer")
283
- [ "$persona" = "developer" ]
284
- jtbd=$(parse_jtbd_flag "--jtbd=JTBD-006")
285
- [ "$jtbd" = "JTBD-006" ]
286
- # Derivation resolved (both flags present); halt predicate proceeds.
287
- derivation_resolved="1"
288
- ! i12_should_halt_afk "$no_prompt" "$derivation_resolved"
289
- }
290
-
291
332
  @test "SKILL.md: Step 1.5b section header exists for JTBD-trace + persona dispatch" {
292
333
  grep -qE '^### 1\.5b JTBD-trace \+ persona dispatch' "$SKILL_FILE"
293
334
  }
@@ -328,18 +369,30 @@ parse_no_prompt_flag() {
328
369
  grep -qE '\| `--no-prompt`' "$SKILL_FILE"
329
370
  }
330
371
 
331
- @test "SKILL.md: Step 1.5b names REJECT-as-problem-rejection semantics" {
332
- grep -qE 'REJECT.*=.*[Rr]ejection of the problem|rejection of proposed persona/JTBD = (rejection|REJECT) of the problem' "$SKILL_FILE"
372
+ @test "SKILL.md: Step 1.5b names P401 never-discard-over-anchoring rule" {
373
+ grep -qiE 'never discarded over anchoring uncertainty' "$SKILL_FILE"
374
+ }
375
+
376
+ @test "SKILL.md: Step 1.5b names interview-to-elicit-who/why (not propose an ID)" {
377
+ grep -qiE '[Ii]nterview.*(who|why|elicit)|elicit the real who/why' "$SKILL_FILE"
378
+ }
379
+
380
+ @test "SKILL.md: Step 1.5b names scope-rejection as external-report-only" {
381
+ grep -qiE 'external-report-only' "$SKILL_FILE"
382
+ }
383
+
384
+ @test "SKILL.md: Step 1.5b names AFK unconfirmed-anchoring sentinel + queued elicitation" {
385
+ grep -qiE 'unconfirmed — elicitation queued|unconfirmed-anchoring sentinel' "$SKILL_FILE"
333
386
  }
334
387
 
335
- @test "SKILL.md: Step 1.5b names AFK halt-with-stderr-directive on --no-prompt + derive-failure" {
336
- grep -qE 'halt-with-stderr-directive.*AFK|AFK.*halt-with-stderr-directive|cannot derive .* under AFK' "$SKILL_FILE"
388
+ @test "SKILL.md: Step 1.5b routes new persona/JTBD creation to ADR-068/P288 human ratify" {
389
+ grep -qE 'ratif.*(creation|CREATION).*(ADR-068|P288)|(ADR-068|P288).*creation' "$SKILL_FILE"
337
390
  }
338
391
 
339
- @test "SKILL.md: allowed-tools includes AskUserQuestion (for I12 ratification dispatch)" {
392
+ @test "SKILL.md: allowed-tools includes AskUserQuestion (for the low-confidence interview)" {
340
393
  grep -qE '^allowed-tools:.*AskUserQuestion' "$SKILL_FILE"
341
394
  }
342
395
 
343
- @test "SKILL.md: ADR-044 authority taxonomy names direction-setting (category 1) for ratification fallback" {
396
+ @test "SKILL.md: ADR-044 authority taxonomy names direction-setting (category 1) for interview + creation-ratify" {
344
397
  grep -qE 'direction-setting.*category 1|category 1.*direction-setting' "$SKILL_FILE"
345
398
  }
@@ -18,7 +18,7 @@ This skill is the P071 phased-landing split of `/wr-itil:manage-incident <I> res
18
18
 
19
19
  - `<I###>` — the incident ID (e.g. `I007` or bare `007`). Resolves to `docs/incidents/<I###>-*.mitigating.md` (primary path) or `docs/incidents/<I###>-*.restored.md` (idempotent re-invocation).
20
20
 
21
- If `$ARGUMENTS` is empty or malformed, ask via `AskUserQuestion` for the incident ID.
21
+ If `$ARGUMENTS` is empty or malformed, fail-fast with a usage message and exit (per ADR-044 Framework-Mediated Surface; matches the `mitigate-incident` Surface 1 / `transition-problem` / `work-problem` precedent). Argument malformation is a typo-class signal, not a decision — the slash command is the input contract; re-typing is faster than a multi-turn `AskUserQuestion` dialogue, and the user-memory direction `feedback_act_on_obvious_decisions.md` pins this. This scopes to the `<I###>` ID only — the verification signal (Pre-flight / Step 3) and the problem-handoff decision (Step 5) remain genuine interactive user-authority surfaces. The exact usage block is in Step 1.
22
22
 
23
23
  ## Pre-flight (ADR-011)
24
24
 
@@ -31,12 +31,21 @@ If either pre-flight fails, block the transition and ask via `AskUserQuestion` w
31
31
 
32
32
  ## Steps
33
33
 
34
- ### 1. Parse arguments
34
+ ### 1. Parse arguments (fail-fast on typos — ADR-044 Surface 1)
35
35
 
36
36
  Extract `<I###>` from `$ARGUMENTS`. Normalise:
37
37
 
38
38
  - Accept `I007`, `i007`, `007`, `7` → canonicalise to `I007` (uppercase I + zero-padded 3 digits).
39
- - If missing, ask via `AskUserQuestion`.
39
+ - If missing, malformed, or unrecognisable, emit the usage block below and exit. **Do not** fire `AskUserQuestion` for argument backfill — argument shape is a typo-class signal, not a decision. The framework-mediated answer per ADR-044 is fail-fast + exit; the user re-types in 1 second. Matches the `mitigate-incident` Step 1 + `transition-problem` Step 1 + `work-problem` singular precedent for consistency across the suite (JTBD-101 — clear patterns).
40
+
41
+ **Usage block** (emitted on any malformed-argument case; copy verbatim so adopters get a consistent shape):
42
+
43
+ ```
44
+ Usage: /wr-itil:restore-incident <I###>
45
+ <I###> — incident ID (e.g. I007 or bare 007); must resolve to docs/incidents/<I###>-*.{mitigating,restored}.md
46
+
47
+ Run /wr-itil:list-incidents to see active incidents if you don't know the ID.
48
+ ```
40
49
 
41
50
  ### 2. Locate the incident file
42
51
 
@@ -181,6 +190,7 @@ If the user wants any of the above, the skill reports the appropriate sibling an
181
190
  - **ADR-011** (`docs/decisions/011-manage-incident-skill.proposed.md`) — incident lifecycle file-suffix conventions (`.investigating.md` / `.mitigating.md` / `.restored.md` / `.closed.md`) + Decision Outcome point 4 (direct Skill-tool invocation of `/wr-itil:manage-problem` for problem handoff).
182
191
  - **ADR-013** Rule 1 — structured user interaction (verification-signal and handoff prompts use AskUserQuestion; deprecation notice uses systemMessage).
183
192
  - **ADR-013** Rule 6 — policy-within-appetite non-interactive actions (release drain).
193
+ - **ADR-044** (`docs/decisions/044-decision-delegation-contract.proposed.md`) — Framework-Mediated Surface: `<I###>` argument-shape backfill is a typo-class signal resolved by fail-fast + exit (Arguments + Step 1), NOT a user decision. The genuine user-authority asks remain interactive per the 6-class taxonomy: verification-signal + mitigation-attempts pre-flight (cat-2 deviation-approval), problem-handoff + no-problem justification (cat-1 direction-setting). P136 Phase-remediation surface (mirrors the shipped `mitigate-incident` Surface 1).
184
194
  - **ADR-014** — governance skills commit their own work.
185
195
  - **ADR-015** — release scorer delegation pattern.
186
196
  - **ADR-020** — auto-release when changesets are queued.
@@ -140,3 +140,31 @@ setup() {
140
140
  run grep -inE "If arguments start with \"(list|mitigate|restore|close|link)\"|If arguments contain \"(list|mitigate|restore|close|link)\"" "$SKILL_FILE"
141
141
  [ "$status" -ne 0 ]
142
142
  }
143
+
144
+ # --- P136 ADR-044 alignment: argument-backfill fail-fast ---
145
+ # tdd-review: structural-permitted — P081 bridge per the P136 Fix Strategy.
146
+ # Pins the lazy-AskUserQuestion removal so a future reword cannot silently
147
+ # reintroduce the typo-class <I###> argument-backfill ask (the exact P136
148
+ # regression class). Behavioural retrofit owned by P081 Phase 2.
149
+
150
+ @test "SKILL.md fails fast on missing/malformed <I###> — no AskUserQuestion for ID backfill (P136 / ADR-044 Surface 1)" {
151
+ # ADR-044 framework-mediated: argument shape is a typo-class signal resolved
152
+ # by fail-fast + usage block, NOT a user decision. Mirrors mitigate-incident
153
+ # Surface 1. Regression guard: the old "ask via AskUserQuestion for the
154
+ # incident ID" backfill prose must NOT return.
155
+ run grep -inE "ask via .AskUserQuestion. for the incident ID" "$SKILL_FILE"
156
+ [ "$status" -ne 0 ]
157
+ run grep -inE "fail-fast|emit the usage block below and exit" "$SKILL_FILE"
158
+ [ "$status" -eq 0 ]
159
+ run grep -inE "fire .AskUserQuestion. for argument backfill" "$SKILL_FILE"
160
+ [ "$status" -eq 0 ]
161
+ }
162
+
163
+ @test "SKILL.md keeps the genuine user-authority asks after the fail-fast scope-down (P136 / ADR-044)" {
164
+ # The fail-fast scopes to the <I###> ID ONLY. The cat-2 evidence pre-flight
165
+ # and cat-1 problem-handoff asks remain interactive — do not over-remove.
166
+ run grep -inE "ADR-044" "$SKILL_FILE"
167
+ [ "$status" -eq 0 ]
168
+ run grep -nE "^allowed-tools:.*AskUserQuestion" "$SKILL_FILE"
169
+ [ "$status" -eq 0 ]
170
+ }
@@ -86,7 +86,7 @@ After re-scoring, present three sections matching the README.md format (same ren
86
86
  - `no — not observed` — fix released but no session-observable evidence yet. Default for newly-released tickets. Aging is preserved separately via the `Released` column — the Released column is the aging signal, `Likely verified?` is the evidence signal.
87
87
  - `no — observed regression` — fix released and the bug recurred this session. Cite the recurrence inline (≤ 120 chars).
88
88
 
89
- Any change to the canonical cell shape MUST update this rendering block, Step 5's README template, AND every co-located render site listed in the VQ-SORT-DIRECTION drift-tripwire above — drift re-opens P186. Surface `yes — observed: …` rows first in Step 4's verification prompt (user can batch-close them); `no — observed regression` rows must NOT be batch-closed (they may signal a botched fix and warrant a flip-back to `.known-error.md`).
89
+ Any change to the canonical cell shape MUST update this rendering block, Step 5's README template, AND every co-located render site listed in the VQ-SORT-DIRECTION drift-tripwire above — drift re-opens P186. Step 4 routes each cell value to a distinct bucket: `yes — observed: …` rows close **on evidence** (mechanical, no `AskUserQuestion` — framework-mediated per ADR-044); `no — not observed` rows route to the verification ask (genuine user-authority); `no — observed regression` rows must NOT be batch-closed (they may signal a botched fix and warrant a flip-back to `.known-error.md`).
90
90
 
91
91
  ```
92
92
  | ID | Title | Released | Fix summary | Likely verified? |
@@ -111,15 +111,17 @@ Omit an empty section rather than rendering an empty header.
111
111
 
112
112
  ### 4. Verification prompt (Verification Pending → Closed)
113
113
 
114
- Target the dual-tolerant glob `docs/problems/*.verifying.md docs/problems/verifying/*.md` (RFC-002 migration window) — do NOT scan `.known-error.md` bodies for a `## Fix Released` section (per ADR-022, Verification Pending is a first-class status, not a substring marker). For each verifying ticket file, use `AskUserQuestion` to ask whether the fix has been verified in production.
114
+ Target the dual-tolerant glob `docs/problems/*.verifying.md docs/problems/verifying/*.md` (RFC-002 migration window) — do NOT scan `.known-error.md` bodies for a `## Fix Released` section (per ADR-022, Verification Pending is a first-class status, not a substring marker). Bucket each verifying ticket by its Step-3 `Likely verified?` cell (the P186 evidence-first cell shape: `yes — observed: <evidence>` / `no — not observed` / `no — observed regression`) and route each bucket differently. **Do NOT fire one `AskUserQuestion` per ticket** the evidence-backed subset closes on evidence; only the unobserved subset asks.
115
115
 
116
- The question MUST include a fix summary extracted from the `## Fix Released` sectioninclude the first sentence (or first bullet list) of that section in the question body or as the option description, so the user can answer without reading the full problem file. Do NOT ask with only the problem ID + title + version.
116
+ **Bucket 1 `yes — observed: <evidence>` → close-on-evidence (framework-mediated, silent agent action per ADR-044 + P135).** These rows carry ADR-026-grounded cited evidence (a prior Step 4 user confirmation, an in-session test invocation + observable outcome, or a `run-retro` Step 4a close-on-evidence citation — see the Step 3 cell definition). The framework has resolved this decision: a `.verifying.md` ticket with specific cited evidence IS verified per ADR-022's evidence semantics, so close it mechanically WITHOUT `AskUserQuestion` mirroring the shipped `run-retro` Step 4a step 5 close-on-evidence. A per-candidate ask here is lazy deferral (sub-contracting a framework-resolved decision back to the user) per the Step 2d Ask Hygiene Pass. For each such ticket: close the problem (`git mv` from `.verifying.md` to `.closed.md`, update Status to "Closed", re-stage per the P057 staging trap) and update the `Likely verified?` cell to `yes observed: closed-on-evidence <YYYY-MM-DD> — <citation>`. Report each closure in the review output with a documented reversible recovery path: `Recovery: rerun /wr-itil:transition-problem <NNN> known-error to reopen` — closes are cheap and reversible; user disagreement surfaces via authentic-correction (ADR-044 category 6), not a pre-close consent gate.
117
117
 
118
- - Surface the Step 3 `yesobserved: …` tickets first so the user can batch-close them (per P186 evidence-first cell shape).
119
- - If the user confirms: close the problem (`git mv` from `.verifying.md` to `.closed.md`, update Status to "Closed", re-stage per the P057 staging trap). Update the `Likely verified?` cell on the same render path to `yes — observed: user confirmed <YYYY-MM-DD>`.
120
- - If the user says no or is unsure: leave the ticket as Verification Pending. If the user reports recurrence, update the cell to `no — observed regression — <one-line citation>` and flag for `.verifying.md` `.known-error.md` flip-back via `/wr-itil:transition-problem`.
118
+ **Bucket 2 — `no — not observed` → ask (genuine user-authority).** No session-observable evidence yet, so the user may hold out-of-band production knowledge the agent cannot observe — this is the genuine user-input surface. Use `AskUserQuestion` to ask whether the fix has been verified in production. The question MUST include a fix summary extracted from the `## Fix Released` section inline the first sentence (or first bullet list) of that section in the question body or option description per the brief-before-ID discipline, so the user can answer without reading the full problem file. Do NOT ask with only the problem ID + title + version.
119
+ - If the user confirms: close the problem (`git mv` from `.verifying.md` to `.closed.md`, update Status to "Closed", re-stage per the P057 staging trap). Update the `Likely verified?` cell to `yes — observed: user confirmed <YYYY-MM-DD>`.
120
+ - If the user says no or is unsure: leave the ticket as Verification Pending. If the user reports recurrence, update the cell to `no — observed regression — <one-line citation>` and route it to Bucket 3.
121
121
 
122
- **AFK / non-interactive branch (ADR-013 Rule 6):** when `AskUserQuestion` is unavailable, record the Verification Queue in the review output and skip the prompt. Do NOT auto-close verifying tickets only the user can make that call. The user sees the queue on next interactive invocation.
122
+ **Bucket 3 `no — observed regression` → flip-back, never batch-close (unchanged per P186).** The fix recurred; this is a botched fix, not a closure candidate. Do NOT close it. Flag for `.verifying.md` `.known-error.md` flip-back via `/wr-itil:transition-problem <NNN> known-error` with the recurrence citation.
123
+
124
+ **AFK / non-interactive branch (ADR-013 Rule 6; ADR-044 framework-mediated-verification-close):** the Bucket 1 close-on-evidence fires in AFK too — evidence-backed closure is framework-mediated, not gated on `AskUserQuestion` availability (exactly parallel to `run-retro` Step 4a, which closes silently even in AFK-by-construction subprocesses); report each close + recovery path in the review output. Only Bucket 2 (`no — not observed`) defers when `AskUserQuestion` is unavailable — record those rows in the Verification Queue and skip the prompt; do NOT auto-close them (no evidence → genuine user call). Bucket 3 flip-backs proceed. The user sees the queued Bucket-2 rows on next interactive invocation. This supersedes the prior blanket "do NOT auto-close verifying tickets — only the user can make that call", which pre-dated the P186 evidence-first cell.
123
125
 
124
126
  <!-- ADR-062-step-naming-reconciliation: this skill's current numbering has 7 steps; ADR-062 was authored against a stale view that called the inbound-discovery sub-step "Step 8.5" and the README renderer "Step 9e". Both names appear verbatim in headers below so ADR-062 § Confirmation criterion 1 ("Step 8.5") and § Confirmation criterion final bullet ("Step 9e") remain string-anchorable. Do NOT strip the "Step 8.5" / "Step 9e" substrings on rename. -->
125
127
 
@@ -205,3 +205,31 @@ setup() {
205
205
  run grep -inE "Effort.*→.*transitive via|transitive via.*P[0-9]" "$SKILL_FILE"
206
206
  [ "$status" -eq 0 ]
207
207
  }
208
+
209
+ # --- P136 ADR-044 alignment: Step 4 close-on-evidence bucket routing ---
210
+ # tdd-review: structural-permitted — P081 bridge per the P136 Fix Strategy.
211
+ # Pins the Step 4 lazy-ask removal (close the evidence-backed subset
212
+ # mechanically; ask only the unobserved subset) so a future reword cannot
213
+ # silently revert to a per-ticket AskUserQuestion (the exact P136 regression
214
+ # class). Behavioural retrofit owned by P081 Phase 2.
215
+
216
+ @test "SKILL.md Step 4 closes the yes-observed subset on evidence without AskUserQuestion (P136 / ADR-044 + run-retro Step 4a)" {
217
+ run grep -inE "close-on-evidence" "$SKILL_FILE"
218
+ [ "$status" -eq 0 ]
219
+ run grep -inE "Do NOT fire one .AskUserQuestion. per ticket" "$SKILL_FILE"
220
+ [ "$status" -eq 0 ]
221
+ run grep -inE "ADR-044" "$SKILL_FILE"
222
+ [ "$status" -eq 0 ]
223
+ }
224
+
225
+ @test "SKILL.md Step 4 keeps the three-way split — ask no-not-observed, flip-back regressions (P136)" {
226
+ # Bucket 2 (no — not observed) still asks; Bucket 3 (no — observed
227
+ # regression) still flips back and is never batch-closed. Do not collapse
228
+ # the three-way routing to a two-way one (JTBD-201 audit-trail invariant).
229
+ run grep -inE "no — not observed" "$SKILL_FILE"
230
+ [ "$status" -eq 0 ]
231
+ run grep -inE "no — observed regression" "$SKILL_FILE"
232
+ [ "$status" -eq 0 ]
233
+ run grep -inE "flip-back" "$SKILL_FILE"
234
+ [ "$status" -eq 0 ]
235
+ }
@@ -1142,6 +1142,17 @@ The skill should produce a final summary when the loop ends:
1142
1142
  |---------|---------------------|--------|
1143
1143
  | P016 (Multi-concern splitting) | user-answerable (verification) | Awaiting user verification |
1144
1144
 
1145
+ ### Reported Upstream
1146
+
1147
+ <!-- @jtbd JTBD-006 (Progress the Backlog While I'm Away — the summary reports ACTUAL upstream filings so the AFK audit trail is honest, never a re-run-to-file checklist) -->
1148
+
1149
+ (Renders when ≥1 upstream-blocked ticket was auto-filed or queued this loop by the Step 4 `upstream-blocked` row's per-iter auto-invoke of `/wr-itil:report-upstream`. Reports ACTUAL filings and queued drafts — never a to-do list of "re-run to file". Omitted entirely when no ticket was upstream-reported this loop.)
1150
+
1151
+ | Ticket | Upstream action | Result |
1152
+ |--------|-----------------|--------|
1153
+ | P067 (adopter hook path bug) | Filed to windyroad/agent-plugins#142 | Sent (below appetite) |
1154
+ | P071 (security-classified regression) | Queued to `## Queued Upstream Report` | Above appetite — surfaced as outstanding question |
1155
+
1145
1156
  ### Outstanding Design Questions
1146
1157
 
1147
1158
  (Emitted only when stop-condition #2 fires AND at least one skipped ticket has a `user-answerable (design/direction/pacing/scope)` skip-reason. Populated by Step 2.5 in non-interactive / AFK mode per ADR-013 Rule 6.)
@@ -1182,6 +1193,8 @@ ALL_DONE
1182
1193
 
1183
1194
  When every skipped ticket is in the `upstream-blocked` category (stop-condition #3) or there are no skipped tickets (stop-condition #1), omit the Outstanding Design Questions section entirely rather than rendering an empty heading. The Session Cost section always renders when at least one iteration ran.
1184
1195
 
1196
+ **Upstream reports are auto-filed per-iter, never deferred to a wrap-time batch choice (P413).** The `### Reported Upstream` section reports ACTUAL filings and queued drafts produced by the Step 4 `upstream-blocked` row's per-iter auto-invoke of `/wr-itil:report-upstream` (below-appetite → sent during the loop; above-appetite → risk-reduced then sent-or-queued per P352). There is **no "batch-report upstream" mode** and no wrap-time reporting decision: the summary MUST NOT emit a "N upstream-blocked tickets are unreported — re-run `/wr-itil:work-problems` and choose batch-report upstream" nudge. That nudge is an agent-invented permission gate the framework did not authorise — the same class as P390 / P341 / P175 (agent-invented loop-control the framework already resolved per ADR-044), and it directly contradicts the ADR-024 2026-06-04 (P270) auto-fire contract the Step 4 row (lines 503 / 511) and decision table (line 1077) mandate. A below-appetite report just sends during the loop; an above-appetite report queues to `## Queued Upstream Report` and surfaces at Step 2.4 gate (a) as an `outstanding_questions` entry — never as a "re-run to report" instruction the user must action. If the loop ends with upstream-blocked tickets that were NOT reported, that is a bug (the auto-fire did not fire), not a batch the user should be asked to trigger.
1197
+
1185
1198
  ## Related
1186
1199
 
1187
1200
  - **P341** (`docs/problems/open/341-work-problems-skill-must-surface-outstanding-questions-then-run-retro-before-emitting-all-done.md`) — driver for Step 2.4 Pre-`ALL_DONE` gate sequence (UNCONDITIONAL fire of outstanding-questions surface + session-level retro before `ALL_DONE` emit). 2026-05-31 user direction (verbatim in ticket Description): *"The work-problems skill MUST surface the outstanding questions at the end before emitting ALL_DONE. It MUST then run a retro. Only then should it emit ALL_DONE."* Closes the structural gap that allowed `ALL_DONE` to emit while direction-class observations remained queued AND without a session-level retro running. Behavioural second-source: `test/work-problems-p341-pre-all-done-gate.bats`. Composes with P086 (extends iter-level retro-on-exit to orchestrator-level), P126 (preserves `halt-paths-must-route-design-questions-through-Step-2.5b` principle), ADR-014 (retro commits its own work), ADR-044 (framework-resolution boundary for when to surface — now framework-resolved as unconditional pre-`ALL_DONE`).
@@ -114,13 +114,19 @@ setup() {
114
114
  # Per-SKILL carve-out audit annotations
115
115
  # ----------------------------------------------------------------------
116
116
 
117
- @test "capture-problem SKILL.md carries the P352 carve-out audit (HALT per ADR-074)" {
117
+ @test "capture-problem SKILL.md carries the P352 carve-out audit (P401-corrected: conforms to queue-and-continue; ADR-074 preserved via downstream gating)" {
118
118
  SKILL="${REPO_ROOT}/packages/itil/skills/capture-problem/SKILL.md"
119
119
  [ -f "$SKILL" ]
120
120
  run grep -nE "ADR-013 Rule 6 carve-out audit \(P352" "$SKILL"
121
121
  [ "$status" -eq 0 ]
122
- # And the carve-out must name its authorising ADR
123
- run grep -nE "authorised by \*\*ADR-074" "$SKILL"
122
+ # Post-P401 (2026-06-29/2026-07-02) the AFK low-confidence path no longer
123
+ # HALTs it CONFORMS to the queue-and-continue default: capture the
124
+ # ticket with the unconfirmed-anchoring sentinel + queue the elicitation.
125
+ run grep -niE "conform.*queue-and-continue|unconfirmed — elicitation queued" "$SKILL"
126
+ [ "$status" -eq 0 ]
127
+ # ADR-074 is still named as the honoured constraint (preserved by
128
+ # downstream oversight gating, not by a no-ticket halt).
129
+ run grep -nE "ADR-074" "$SKILL"
124
130
  [ "$status" -eq 0 ]
125
131
  }
126
132