@windyroad/itil 0.47.10 → 0.47.11-preview.591
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/capture-problem/REFERENCE.md +16 -14
- package/skills/capture-problem/SKILL.md +35 -20
- package/skills/manage-problem/SKILL.md +3 -1
- package/skills/report-upstream/SKILL.md +3 -2
- package/skills/review-problems/SKILL.md +4 -1
- package/skills/scaffold-intake/SKILL.md +2 -0
- package/skills/work-problems/SKILL.md +4 -2
- package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +160 -0
- package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +95 -0
package/package.json
CHANGED
|
@@ -27,25 +27,27 @@ This is the structural rationale for:
|
|
|
27
27
|
- **Title-only filename match** — body-content matches would be too noisy at the conservative threshold. Files whose filenames have zero overlap but whose bodies mention a keyword are almost always different tickets that happen to discuss similar topics. False-positive cost would dominate.
|
|
28
28
|
- **No halt-on-match** — even when matches are found, capture proceeds. The duplicate gets resolved at next `/wr-itil:review-problems` (where the full-rank scan can detect and merge actual duplicates with the user in the loop).
|
|
29
29
|
|
|
30
|
-
###
|
|
30
|
+
### README refresh: inline (P199 Option 2 amendment, 2026-06-05)
|
|
31
31
|
|
|
32
|
-
Capture-problem
|
|
32
|
+
Capture-problem stages `docs/problems/README.md` inline at Step 6, mirroring `/wr-itil:manage-problem` Step 5 P094 (refresh-on-create) + P134 (last-reviewed rotation). The previously-load-bearing "Deferred-README-refresh contract" was reversed by user direction recorded in P199 on 2026-05-31, then implemented on 2026-06-05.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
| WSJF ranking visibility | Immediate | Pending review |
|
|
39
|
-
| Audit trail (commit) | One commit covers ticket + README | One commit covers ticket only |
|
|
40
|
-
| README staleness window | None | Bounded by next review invocation |
|
|
34
|
+
**Rationale for the reversal** (user direction):
|
|
35
|
+
- The P165 README-refresh-discipline hook (shipped after the initial capture-problem design) blocks every capture commit that does not stage README. The P262 workaround (a `RISK_BYPASS: capture-deferred-readme` trailer) cleared the gate but kept the README transiently stale by design — a contract that always felt half-superseded by P165 reality.
|
|
36
|
+
- Option 2 acknowledges reality: stage the README. The cost is one mechanical render-and-stage primitive (already proven in `/wr-itil:manage-problem`); the capture-time speed distinction from manage-problem comes from the wide-net duplicate grep + AskUserQuestion branches that capture-problem skips, not the README skip.
|
|
37
|
+
- The `RISK_BYPASS: capture-deferred-readme` trailer is dropped from emission. The allow-list entry in `packages/itil/hooks/lib/readme-refresh-detect.sh::_README_REFRESH_BYPASS_TRAILERS` is retained as inert dead code for adopter compatibility (minimal-change discipline).
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
**Trade-off table (post-amendment)**:
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
| Surface | manage-problem | capture-problem (post-P199) |
|
|
42
|
+
|---------|----------------|------------------------------|
|
|
43
|
+
| README authoritativeness | Always current at commit boundary | Always current at commit boundary |
|
|
44
|
+
| Capture-time turn cost | +1-2 turns (regenerate + stage) | +1-2 turns (same primitive) |
|
|
45
|
+
| WSJF ranking visibility | Immediate (deferred-placeholder row) | Immediate (deferred-placeholder row) |
|
|
46
|
+
| Audit trail (commit) | One commit covers ticket + README | One commit covers ticket + README |
|
|
47
|
+
| README staleness window | None | None |
|
|
48
|
+
| Distinguishing cost shape | Wide-net duplicate grep + multi-AskUserQuestion branches | Title-only 3-keyword grep + zero AskUserQuestion |
|
|
47
49
|
|
|
48
|
-
The
|
|
50
|
+
The on-disk ticket inventory remains the source of truth; `/wr-itil:list-problems` cache-stale fallback re-derives directly from ticket files when needed.
|
|
49
51
|
|
|
50
52
|
### No AskUserQuestion at all
|
|
51
53
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wr-itil:capture-problem
|
|
3
|
-
description: Lightweight problem-capture skill for aside-invocation during foreground work — minimal duplicate-check, skeleton ticket file, single commit per capture
|
|
3
|
+
description: Lightweight problem-capture skill for aside-invocation during foreground work — minimal duplicate-check, skeleton ticket file, single commit per capture (covers new ticket + inline README refresh per P094 per P199 Option 2 amendment 2026-06-05). Defers full duplicate analysis to /wr-itil:review-problems. Use this when the user (or agent mid-iter) wants to capture an observation quickly without disrupting current task flow. For full-intake new-problem creation, use /wr-itil:manage-problem.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -46,6 +46,8 @@ This skill has **at most one direction-setting AskUserQuestion (the I12 derive-t
|
|
|
46
46
|
|
|
47
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).
|
|
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 decision — the 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).
|
|
50
|
+
|
|
49
51
|
## Steps
|
|
50
52
|
|
|
51
53
|
### 0. README reconciliation preflight (P118)
|
|
@@ -287,12 +289,27 @@ The deferred-placeholder pattern is load-bearing — `/wr-itil:review-problems`
|
|
|
287
289
|
|
|
288
290
|
Single `Write` to `docs/problems/open/<NNN>-<kebab-title>.md` (per ADR-031 per-state-subdir layout). The P119 PreToolUse hook permits the Write because Step 2 set the marker.
|
|
289
291
|
|
|
290
|
-
### 6. Commit per ADR-014 — single commit,
|
|
292
|
+
### 6. Commit per ADR-014 — single commit, inline README refresh (P094)
|
|
293
|
+
|
|
294
|
+
**P199 / Option 2 amendment (2026-06-05).** This step previously skipped the README refresh and emitted a `RISK_BYPASS: capture-deferred-readme` trailer to clear the P165 README-refresh gate. The user-directed Option 2 resolution (recorded 2026-05-31 on P199) kills the deferred-README-refresh contract: capture-problem now stages `docs/problems/README.md` inline, mirroring `/wr-itil:manage-problem` Step 5 P094 (refresh-on-create) + P134 (last-reviewed rotation). The trailer is dropped from the commit; the allow-list entry in `packages/itil/hooks/lib/readme-refresh-detect.sh::_README_REFRESH_BYPASS_TRAILERS` is retained as inert dead code (minimal-change discipline — future adopters that registered against the token continue to work). Authority: P199 Option 2 user direction + ADR-032 amendment + ADR-014 bypass-token-table amendment (same single coherent commit).
|
|
295
|
+
|
|
296
|
+
#### README.md refresh on new ticket (P094)
|
|
297
|
+
|
|
298
|
+
After writing the new `.open.md` file at Step 5, regenerate `docs/problems/README.md` to insert the new ticket's row into the WSJF Rankings, and stage the refreshed README in the same commit as the new ticket. The mechanism is **inline at this execution site per P331** — not deferred via cross-reference — so a single-pass agent reading Step 6 does not silently skip the archive step (the canonical P331 silent-skip regression).
|
|
291
299
|
|
|
292
|
-
**
|
|
300
|
+
**Mechanism**: use the same rendering rules as `/wr-itil:manage-problem` Step 5 P094 / Step 7 P062 (glob `docs/problems/*.open.md` / `*.known-error.md` / `*.verifying.md` / `*.parked.md` AND the per-state-subdir layout `docs/problems/open/*.md` / `docs/problems/known-error/*.md` / `docs/problems/verifying/*.md` / `docs/problems/parked/*.md`; rank open/known-error by WSJF; list verifyings in the Verification Queue ordered by Released date ASC per P150; list parkeds in the Parked section). The refresh is a **render, not a re-rank** — existing WSJF values on the other ticket files are trusted per P062's established discipline. Only the new ticket's own (deferred-placeholder) WSJF is consumed from its freshly-written file. **WSJF Rankings tier + tie-break sort** (P138 + ADR-076) and **Verification Queue sort direction** (P150) and **Likely-verified cell shape** (P186) all follow the canonical render rules — see `/wr-itil:manage-problem` Step 5 P094 block for the full prose; drift here re-opens those tickets.
|
|
301
|
+
|
|
302
|
+
**P134 last-reviewed rotation** — inline at this execution site (not deferred to a § subsection) per P331 silent-skip discipline. MUST execute IN ORDER:
|
|
303
|
+
|
|
304
|
+
1. **Read** line 3 of `docs/problems/README.md`: `awk 'NR==3' docs/problems/README.md`.
|
|
305
|
+
2. **Append-if-non-empty (BEFORE step 3, not after)** — if line 3 is non-empty AND not a same-session same-verb near-duplicate of the new fragment, append the existing line 3 verbatim to `docs/problems/README-history.md` under a `## YYYY-MM-DD` heading (creating the heading on first append for that date; subsequent same-day appends nest under the existing heading). Run this BEFORE the Edit-tool rewrite in step 3 — Edit's replace pattern destroys the displaced content otherwise.
|
|
306
|
+
3. **Rewrite** line 3 of `docs/problems/README.md` with the new fragment of form `> Last reviewed: YYYY-MM-DD **P<NNN> captured** — <one-line title> (lightweight aside via /wr-itil:capture-problem)`. Soft cap ≤ 1024 bytes per fragment; hard ceiling 5120 bytes per ADR-040 Tier 3 envelope.
|
|
307
|
+
4. **Stage all three** — `git add docs/problems/open/<NNN>-<kebab-title>.md docs/problems/README.md docs/problems/README-history.md` so the same single commit per ADR-014 captures the new ticket + refreshed README + (when line-3 displaced) history. Omit `README-history.md` from the stage list when no line-3 displacement occurred (no untracked diff). Canonical rationale anchor: `/wr-itil:manage-problem` § Last-reviewed line discipline (P134) subsection.
|
|
293
308
|
|
|
294
309
|
```bash
|
|
295
|
-
git add docs/problems/open/<NNN>-<kebab-title>.md
|
|
310
|
+
git add docs/problems/open/<NNN>-<kebab-title>.md docs/problems/README.md
|
|
311
|
+
# If line-3 was rotated above, also:
|
|
312
|
+
git add docs/problems/README-history.md
|
|
296
313
|
```
|
|
297
314
|
|
|
298
315
|
Satisfy the commit gate per ADR-014 — same two-path pattern as manage-problem Step 11:
|
|
@@ -300,20 +317,17 @@ Satisfy the commit gate per ADR-014 — same two-path pattern as manage-problem
|
|
|
300
317
|
- **Primary**: delegate to subagent type `wr-risk-scorer:pipeline` via the Agent tool.
|
|
301
318
|
- **Fallback**: invoke `/wr-risk-scorer:assess-release` via the Skill tool when the subagent type is unavailable in the current tool surface.
|
|
302
319
|
|
|
303
|
-
Land the commit via the **`wr-risk-scorer-restage-commit`** helper — atomic re-stage + commit in a single bash call (P326 wrapper). The Agent-tool delegation above can silently clear the index; the helper re-adds the supplied
|
|
320
|
+
Land the commit via the **`wr-risk-scorer-restage-commit`** helper — atomic re-stage + commit in a single bash call (P326 wrapper). The Agent-tool delegation above can silently clear the index; the helper re-adds the supplied paths, asserts non-empty staging, then runs `git commit` with the supplied `-m` args:
|
|
304
321
|
|
|
305
322
|
```bash
|
|
306
323
|
wr-risk-scorer-restage-commit \
|
|
307
324
|
-m "docs(problems): capture P<NNN> <title>" \
|
|
308
|
-
|
|
309
|
-
|
|
325
|
+
-- docs/problems/open/<NNN>-<kebab-title>.md docs/problems/README.md
|
|
326
|
+
# If README-history.md was modified, append it to the path list:
|
|
327
|
+
# -- docs/problems/open/<NNN>-<kebab-title>.md docs/problems/README.md docs/problems/README-history.md
|
|
310
328
|
```
|
|
311
329
|
|
|
312
|
-
The `capture` verb in the message is the audit signal that this ticket landed via the lightweight aside path (vs. `open` for manage-problem's full intake).
|
|
313
|
-
|
|
314
|
-
**Why the trailer (P262)**: the P165 README-refresh-discipline hook (`packages/itil/hooks/itil-readme-refresh-discipline.sh`) treats any newly-staged ticket file as ranking-bearing and DENIES a `git commit` that does not also stage `docs/problems/README.md`. That enforcement is correct for `/wr-itil:manage-problem`'s full-intake path (P094 refresh-on-create) but conflicts with this skill's deliberate deferred-README-refresh contract. The `RISK_BYPASS: capture-deferred-readme` trailer is a registered allow-list token (P265 mechanism; registry of record is the ADR-014 commit-message bypass-token table) that clears the **README-refresh gate ONLY** — the commit is still risk-scored normally (`risk-score-commit-gate.sh` does not recognise this token).
|
|
315
|
-
|
|
316
|
-
Do NOT drop the trailer and stage the README instead — that would silently abandon the deferred-README-refresh contract (the capture-time-speed distinction this skill exists to provide per ADR-032). The README is reconciled at the next `/wr-itil:review-problems` per Step 7's trailing pointer.
|
|
330
|
+
The `capture` verb in the message is the audit signal that this ticket landed via the lightweight aside path (vs. `open` for manage-problem's full intake). The P165 README-refresh-discipline hook now allows the commit naturally because the README is staged — no `RISK_BYPASS` trailer needed.
|
|
317
331
|
|
|
318
332
|
### 7. Report
|
|
319
333
|
|
|
@@ -331,15 +345,15 @@ After the commit, report:
|
|
|
331
345
|
|
|
332
346
|
| `preflight_reason` | Trailing-pointer shape |
|
|
333
347
|
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------|
|
|
334
|
-
| `no-deferred-placeholders` / `below-threshold ...` / `fresh-readme ...` | Default (low-priority) pointer: *"Run `/wr-itil:review-problems` next to
|
|
335
|
-
| `no-readme count=<N>` | **Highlighted (actionable) pointer**: *"⚠ `<N>` deferred-placeholder ticket(s) have accumulated AND `docs/problems/README.md` is missing/malformed — run `/wr-itil:review-problems` NOW to rebuild the README and re-rate placeholders."* |
|
|
336
|
-
| `stale-readme count=<N> age=<X>s threshold=<Y>s` | **Highlighted (actionable) pointer**: *"⚠ `<N>` deferred-placeholder ticket(s) have accumulated AND the WSJF Rankings cadence is `<X>` days stale (> 7-day threshold) — run `/wr-itil:review-problems` NOW to re-rate placeholders
|
|
348
|
+
| `no-deferred-placeholders` / `below-threshold ...` / `fresh-readme ...` | Default (low-priority) pointer: *"Run `/wr-itil:review-problems` next to re-rate the deferred Priority/Effort placeholders on P\<NNN\>."* (README is now refreshed inline at Step 6 per P199 Option 2 — the pointer no longer names a README-refresh action in the default shape.) |
|
|
349
|
+
| `no-readme count=<N>` | **Highlighted (actionable) pointer**: *"⚠ `<N>` deferred-placeholder ticket(s) have accumulated AND `docs/problems/README.md` is missing/malformed — run `/wr-itil:review-problems` NOW to rebuild the README and re-rate placeholders."* (Fires only when README is genuinely missing/malformed despite this skill's inline refresh — a drift class the helper still surfaces.) |
|
|
350
|
+
| `stale-readme count=<N> age=<X>s threshold=<Y>s` | **Highlighted (actionable) pointer**: *"⚠ `<N>` deferred-placeholder ticket(s) have accumulated AND the WSJF Rankings cadence is `<X>` days stale (> 7-day threshold) — run `/wr-itil:review-problems` NOW to re-rate placeholders."* (Inline refresh at Step 6 freshens the README mtime on every capture, so this shape now fires only when captures are absent for > 7 days — a real cadence-stale signal, not capture-driven drift.) |
|
|
337
351
|
|
|
338
|
-
**Why conditional, not auto-dispatch** (ADR-032 + JTBD-001): capture-problem is intentionally lightweight per ADR-032 P155 amendment. Auto-dispatching review-problems from capture would re-introduce the ~10-turn ceremony the lightweight aside is engineered to avoid. The conditional pointer
|
|
352
|
+
**Why conditional, not auto-dispatch** (ADR-032 + JTBD-001): capture-problem is intentionally lightweight per ADR-032 P155 amendment. Auto-dispatching review-problems from capture would re-introduce the ~10-turn ceremony the lightweight aside is engineered to avoid. The conditional pointer surfaces the signal "deferred-placeholder backlog has grown AND the cadence axis hit threshold" when both axes fire. The user picks when to absorb the re-rate cost.
|
|
339
353
|
|
|
340
354
|
**Fail-soft**: any error in the helper invocation MUST NOT block the report — fall back to the default pointer shape.
|
|
341
355
|
|
|
342
|
-
The trailing pointer is **not optional** — it is the user-visible signal
|
|
356
|
+
The trailing pointer is **not optional** — it is the user-visible signal for deferred-placeholder re-rating cadence. The conditional highlight (P271) escalates the signal when the deferred-placeholder backlog AND the cadence axis both hit threshold. Drift here re-opens P271.
|
|
343
357
|
|
|
344
358
|
<!-- @jtbd JTBD-001 (Enforce Governance Without Slowing Down — conditional highlight escalates the signal without forcing a flow break) -->
|
|
345
359
|
|
|
@@ -353,7 +367,7 @@ The trailing pointer is **not optional** — it is the user-visible signal that
|
|
|
353
367
|
| 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 |
|
|
354
368
|
| 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-failure → AskUserQuestion 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` |
|
|
355
369
|
| 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) |
|
|
356
|
-
| README refresh | P094 inline (regenerate + stage in same commit) |
|
|
370
|
+
| 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` |
|
|
357
371
|
| Status transitions | Step 7 owns Open → Known Error → Verifying → Closed | Out of scope (creation only) |
|
|
358
372
|
| Commit grain | One commit per intake (or per split-concern set) | One commit per capture |
|
|
359
373
|
| Use case | Full-intake new problem; user wants to walk the flow | Aside-invocation; capture-and-continue |
|
|
@@ -366,8 +380,9 @@ The two skills share the `/tmp/manage-problem-grep-${SESSION_ID}` create-gate ma
|
|
|
366
380
|
- **P014** (`docs/problems/open/014-aside-invocation-for-governance-skills.md`) — parent / master tracker.
|
|
367
381
|
- **P078** — capture-on-correction OFFER pattern; depends on capture-problem shipping.
|
|
368
382
|
- **P119** — manage-problem create-gate hook; capture-problem composes with the same marker.
|
|
369
|
-
- **
|
|
370
|
-
- **
|
|
383
|
+
- **P199** (`docs/problems/verifying/199-...md`) — Option 2 amendment 2026-06-05: kill the deferred-README-refresh contract; Step 6 now stages README inline per P094. User direction recorded 2026-05-31 in the ticket. This SKILL change rides with the ADR-032 + ADR-014 amendments in the same coherent commit.
|
|
384
|
+
- **P262** (closed) — the P165 README-refresh-discipline hook conflicted with this skill's previous deferred-README-refresh contract. The prior workaround was the `RISK_BYPASS: capture-deferred-readme` allow-list token. Superseded by P199 Option 2 (2026-06-05) — capture-problem now stages README inline and the trailer is no longer emitted. The allow-list entry in `packages/itil/hooks/lib/readme-refresh-detect.sh::_README_REFRESH_BYPASS_TRAILERS` is retained as inert dead code (minimal-change discipline; adopter compatibility).
|
|
385
|
+
- **P265** — the RISK_BYPASS-trailer allow-list mechanism in `readme-refresh-detect.sh`. Still in force for the `adr-031-migration` token; the `capture-deferred-readme` entry is now inert (no live emitter) but registered for adopter compatibility.
|
|
371
386
|
- **P170** (`docs/problems/known-error/170-problem-tickets-strain-as-fixes-decompose-into-multiple-coordinated-changes-need-rfc-framework.md`) — RFC framework driver; Slice 4 B7.T3 / item 8c historically authored the type-classification prompt at Step 1.5 (RETIRED by P287, 2026-06-02).
|
|
372
387
|
- **P176** — agent-side I2 (no type-branching) coverage gap on the SKILL.md surface. P287 retires the type axis altogether; the regression guard is preserved under `packages/itil/scripts/test/no-type-regression-guard.bats` (asserting the `**Type**:` field is GONE from skeleton templates).
|
|
373
388
|
- **P287** (`docs/problems/.../287-remove-technical-user-business-type-classification-from-problems-redundant-with-rfc-persona-anchoring.md`) — the user direction (twice-confirmed 2026-05-25 + 2026-06-02) that retired Step 1.5 Type classification; ADR-060 amendment substance (I12 replacement, Phase-4 rework) queued for user re-confirmation per ADR-074.
|
|
@@ -179,7 +179,7 @@ What "work" means depends on the problem's status:
|
|
|
179
179
|
Exit 0 = unconfirmed (born without `human-oversight: confirmed`, not superseded) → the guard fires for that ADR. Exit 1 = confirmed or superseded → OK to build. Exit 2 = not found → treat as not-a-blocker (surface in the report).
|
|
180
180
|
3. **If any referenced decision is unconfirmed**: do NOT implement yet. Surface its **substance** (the chosen option the ADR records — not a grain/meta question) for human confirmation:
|
|
181
181
|
- **Interactive**: `AskUserQuestion` presenting the ADR's Decision Outcome + Considered Options so the user confirms / amends / rejects the substantive choice. On confirm, the recording skill writes the `human-oversight: confirmed` marker (ADR-066) before the build proceeds.
|
|
182
|
-
- **AFK** (`/wr-itil:work-problems` orchestrator): NEVER ask mid-loop — queue the substance to the iteration's `outstanding_questions` (ADR-044 AFK carve-out) and skip the build; do not guess.
|
|
182
|
+
- **AFK** (`/wr-itil:work-problems` orchestrator): NEVER ask mid-loop — queue the substance to the iteration's `outstanding_questions` (ADR-044 AFK carve-out) and skip the build; do not guess. This is the **queue-and-continue** universal default per ADR-013 Rule 6 (P352, 2026-06-06 amendment): the iter queues the substance + advances; the orchestrator main turn surfaces the queued question at loop end via the Step 2.5 batched AskUserQuestion.
|
|
183
183
|
4. This ask is **ADR-044 category-1 direction-setting** and is EXCLUDED from the lazy-AskUserQuestion regression metric (it is legitimate, not lazy). The trigger is narrow — detection is mechanical (the predicate); only genuine unconfirmed decisions about to be built on fire it. Do NOT over-fire on confirmed/superseded/obvious decisions (inverse-P078 / P132 guard). A born-`proposed` marker is fine for *recording*; it is not a licence to *build* (ADR-066 carve-out).
|
|
184
184
|
|
|
185
185
|
The Phase 2 working-the-problem traversal makes "implement the fix" concretely traceable via stories (per ADR-060 lines 300-320). Replaces the prior vague "implement the fix following the project's development workflow" with a deterministic problem → RFC → story dispatch:
|
|
@@ -496,6 +496,8 @@ Before writing the problem file, perform a concern-boundary analysis on the gath
|
|
|
496
496
|
|
|
497
497
|
**Non-interactive fallback**: When `AskUserQuestion` is unavailable (e.g., non-interactive/AFK mode), automatically split into separate problems and note the auto-split in output. Do not block creation.
|
|
498
498
|
|
|
499
|
+
**ADR-013 Rule 6 carve-out audit (P352, 2026-06-06 amendment)**: the universal AFK default is **queue-and-continue**; this site is a documented **AUTO-DEFAULT** carve-out. Authorising principle: policy-authorised safe default per ADR-044 category 4 (silent framework). Splitting is fully reversible (manual combine via Related cross-references + WSJF re-rank), the framework's lifecycle model rewards explicit per-concern WSJF ranking, and "split when in doubt" is the persona-correct safe heuristic for JTBD-006 — the loop progresses, over-splits are cheap to combine, and halt would cost more loop throughput than the over-split risk. Symmetric with the parallel `/wr-architect:create-adr` Step 1 multi-decision auto-split (same authority, same rationale).
|
|
500
|
+
|
|
499
501
|
**Split implementation**: When splitting, assign consecutive IDs (e.g., if next ID is 035, create P035 and P036). Create each problem file independently. Cross-reference each ticket in the other's "Related" section.
|
|
500
502
|
|
|
501
503
|
**Scope**: This step applies only to **new problem creation** (steps 2–5). It does NOT apply to updates, status transitions, or reviews of existing tickets.
|
|
@@ -401,10 +401,11 @@ Open the issue:
|
|
|
401
401
|
gh issue create \
|
|
402
402
|
--repo "${UPSTREAM_OWNER_REPO}" \
|
|
403
403
|
--title "${TITLE_PREFIXED_BY_TEMPLATE}" \
|
|
404
|
-
--body "${FILLED_BODY}"
|
|
405
|
-
--label "${MATCHED_TEMPLATE_LABEL_IF_ANY}"
|
|
404
|
+
--body "${FILLED_BODY}"
|
|
406
405
|
```
|
|
407
406
|
|
|
407
|
+
Do **not** pass `--label` on this call (P207). Labels are supplied by the matched template's YAML `labels:` frontmatter and applied by GitHub when the issue form is submitted; passing `--label <name>` for a label that has not been pre-created on the upstream repo causes `gh issue create` to hard-fail with `could not add label: '<name>' not found`. The flag is redundant when the matched template carries `labels:` and a hard-fail surface when it does not. If the upstream has no matched template at all (structured-default body path, Step 3 preference order item 7), omit labels entirely — leave triage to the upstream maintainer's existing routing.
|
|
408
|
+
|
|
408
409
|
Capture the returned issue URL. The voice-tone gate per ADR-028 may delegate-and-retry; treat this as expected (see "Voice-tone gate interaction" above). Proceed to Step 7 once the issue is created.
|
|
409
410
|
|
|
410
411
|
### 5c. Comment path (P070)
|
|
@@ -134,7 +134,7 @@ Per ADR-062 (peer of ADR-024). Polls configured upstream channels, runs each unm
|
|
|
134
134
|
Read `docs/problems/.upstream-channels.json`. Branch on state:
|
|
135
135
|
|
|
136
136
|
- **File exists and parses cleanly** → continue to 4.5b with the parsed `channels[]` list.
|
|
137
|
-
- **File exists but is malformed JSON** → log an advisory note (`channel config malformed JSON; inbound-discovery skipped this pass — fix the file then re-invoke`) and skip Step 4.5.
|
|
137
|
+
- **File exists but is malformed JSON** → log an advisory note (`channel config malformed JSON; inbound-discovery skipped this pass — fix the file then re-invoke`) and skip Step 4.5. **ADR-013 Rule 6 carve-out (P352, 2026-06-06 amendment)**: this is a documented SKIP carve-out (deviation from the universal queue-and-continue default). Authorising principle: user-shipped artefact protection — the user already SHIPPED a config and the malformation is an editing artefact best resolved by the user reading the parse error; auto-rewriting their file (queue-then-overwrite-on-return) would destroy their work. The advisory note IS the queued surface for user attention on next interactive session; the loop continues. Same shape as a parse-error halt at a user-owned file boundary.
|
|
138
138
|
- **File does NOT exist** → run the **auto-bootstrap routine** below per P351 / JTBD-101 / JTBD-007. **Adopters who never want to configure inbound-discovery** can keep `.upstream-channels.json` absent by answering `decline` at the interactive prompt OR allowing the AFK-mode outstanding-question to lapse; the absence stays zero-ceremony-tax (ADR-062 § Downstream-adopter non-obligation), but the silent skip is replaced by an explicit one-time-per-session prompt so the adopter has a visible signal that the inbound-discovery capability exists. <!-- @jtbd JTBD-101 (Extend the Suite — deliver-installed-features signal) --> <!-- @jtbd JTBD-007 (Keep Plugins Current — process reports what configured) --> <!-- @problem P351 (auto-bootstrap on missing precondition config) -->
|
|
139
139
|
|
|
140
140
|
**Auto-bootstrap routine (P351)**: replaces the prior "missing file → silent skip" behaviour. The routine branches on AskUserQuestion availability per ADR-013 Rule 6 + ADR-044 category 1 (direction-setting):
|
|
@@ -149,6 +149,9 @@ Read `docs/problems/.upstream-channels.json`. Branch on state:
|
|
|
149
149
|
- On `Decline permanently (write empty channels stub)`: write `{"channels": [], "ttl_seconds": 86400, "declined_at": "<ISO>"}` so future invocations parse cleanly + skip silently. Per ADR-062 § Downstream-adopter non-obligation — the empty-channels stub IS the documented "I never want this" surface.
|
|
150
150
|
|
|
151
151
|
- **AFK mode** (AskUserQuestion unavailable, e.g. invoked from `/wr-itil:work-problems`):
|
|
152
|
+
|
|
153
|
+
**ADR-013 Rule 6 universal default (P352, 2026-06-06 amendment)** — queue-and-continue. This branch is the canonical exemplar: P351 lifted this site from the prior "missing file → silent skip" anti-pattern to queue-and-continue. The pattern below is the model the rest of the suite follows.
|
|
154
|
+
|
|
152
155
|
1. Log advisory (`inbound-discovery: channel config absent; queued config-direction outstanding_question, skipping THIS pass to allow other passes to proceed`).
|
|
153
156
|
2. Queue a `direction` entry per `/wr-itil:work-problems` SKILL.md Step 5 `outstanding_questions` schema (ADR-044 category 1):
|
|
154
157
|
|
|
@@ -164,6 +164,8 @@ When all three checks pass, the host emits a one-shot `AskUserQuestion` prompt w
|
|
|
164
164
|
|
|
165
165
|
**AFK fail-safe**: when the host is invoked from an AFK orchestrator, do NOT fire the prompt. Append a one-line "pending intake scaffold" note to the iteration report and continue. The user catches up on next interactive session.
|
|
166
166
|
|
|
167
|
+
**ADR-013 Rule 6 universal default (P352, 2026-06-06 amendment)**: this IS queue-and-continue — the iteration-report note is the queued surface; the loop advances. Persona-correct for JTBD-006 ("queued for my return, not guessed at"). Not a carve-out — this is the canonical default shape.
|
|
168
|
+
|
|
167
169
|
### Trigger 2: Pre-publish PreToolUse gate (hard stop)
|
|
168
170
|
|
|
169
171
|
`packages/itil/hooks/pre-publish-intake-gate.sh` matches `npm publish` and `gh pr merge ... changeset-release/*` and denies if any of the five intake files are missing AND the decline marker is absent AND `INTAKE_BYPASS` is not set.
|
|
@@ -511,7 +511,7 @@ rm -f "$ITER_JSON"
|
|
|
511
511
|
|
|
512
512
|
1. **Context**: this is one iteration of the AFK work-problems loop. The user is AFK. The orchestrator selected `P<NNN> (<title>)` as the highest-WSJF actionable ticket.
|
|
513
513
|
2. **Task**: apply the `/wr-itil:manage-problem` workflow for `work highest WSJF problem that can be progressed non-interactively as the user is AFK`. Follow manage-problem SKILL.md verbatim, including architect / jtbd / style-guide / voice-tone gate reviews and the commit gate (manage-problem Step 11). Because this subprocess has the Agent tool in its own surface, the normal review-via-subagent paths work — no inline-verdict fallback needed.
|
|
514
|
-
3. **Constraints**: commit the completed work per ADR-014. Do NOT push, do NOT run `push:watch`, do NOT run `release:watch` — the orchestrator's Step 6.5 owns release cadence. Do NOT invoke `capture-*` background skills mid-iter (AFK carve-out — ADR-032), **EXCEPT for retro-surfaced observations of recurring class-of-behaviour** — those route to `/wr-itil:capture-problem` per the **P342 mechanical-stage carve-out** (see retro-on-exit constraint #4 below; same trust-boundary as `/wr-retrospective:run-retro` Step 4a verification close-on-evidence — P342). Do NOT use `ScheduleWakeup` under any circumstance (P083 — iteration workers must not self-reschedule). **NEVER call `AskUserQuestion` mid-loop in AFK** (P135 / ADR-044): direction / deviation-approval / one-time-override / silent-framework observations queue at `ITERATION_SUMMARY.outstanding_questions` for loop-end batched presentation. **This includes the manage-problem substance-confirm-before-build guard (ADR-074 (Confirm a decision's substance before building dependent work)):** when the propose-fix step detects that the fix builds on a born-`proposed` decision whose substance is unconfirmed (via `wr-architect-is-decision-unconfirmed`), the iter does NOT implement on it and does NOT ask mid-loop — it queues a `category: "direction"` entry naming the unconfirmed ADR + its Decision Outcome for loop-end confirmation, and routes the ticket to `action: skipped`, `skip_reason_category: user-answerable`. Building on the unconfirmed substance instead (or guessing the choice) is the P315 failure this guard exists to prevent. The queued substance-confirm is a legitimate cat-1 direction ask — it is NOT counted as lazy in the Step 2d Ask Hygiene Pass (ADR-074 lazy-count exclusion). Per-iter `AskUserQuestion` calls are sub-contracting framework-resolved decisions back to the user (lazy deferral per Step 2d Ask Hygiene Pass classification). Non-interactive defaults apply per ADR-013 Rule 6 + ADR-044's framework-resolution boundary. **Treat the user as transient** (P130): even when observably present at orchestrator dispatch time, the user may answer one question and disappear for hours; presence is not a reliable signal and is not the goal. The iter's job is to progress the ticket and accumulate questions for batched surfacing — not to ask "is it OK to proceed?" at a mechanical-stage boundary. **Do NOT poll `bats` output with a bats-console-summary regex against TAP-format output** (P146 — bash until-loop-deadlock antipattern). The bats-console-summary line `<N> tests, <M> failures` is emitted ONLY by bats's *default* (non-TAP) formatter; `bats --tap` does not emit a console summary, so a polling loop of shape `until [ -f $OUT ] && grep -qE '^[0-9]+ tests?,' $OUT; do sleep 5; done` spins forever after bats completes (silent deadlock — no error, no exit; recovery requires manual SIGTERM with metadata loss per the P146/P147 stuck-before-emit subclass). When you need to wait on a backgrounded bats run, prefer `wait $bg_pid` (Unix idiom — completion signaled by process exit, no regex required) or, for the Bash tool, `run_in_background=true` + `BashOutput` polling on the tool's exit-state field rather than regex-poll on stdout. If you genuinely must regex-poll TAP output, anchor on the TAP plan line `^[0-9]+\.\.[0-9]+` (e.g. `1..1455`) — TAP's plan line is emitted on completion and is format-stable across bats versions; the bats-console-summary line is not. The console-summary vs TAP-format divergence is the load-bearing detail: `bats` and `bats --tap` produce structurally different stdout, and the antipattern assumes the former when iter dispatch typically uses the latter. **Do NOT poll subprocess completion with `pgrep -f '<pattern>'` inside an `until` / `while` loop** (P232 — self-referential pgrep deadlock; sibling variant of P146). `pgrep -f` matches against the FULL command line of every running process, so the polling loop's own `zsh -c` argument (which contains the literal `pgrep -f '<pattern>'` text) matches itself; with multiple concurrent polling loops, each loop matches the others and spins forever. Worked example of the antipattern: `until ! pgrep -f 'bats --recursive' > /dev/null 2>&1; do sleep 5; done` — the 2026-05-16 P232 deadlock witness; 4 concurrent polling loops each matched the others' command lines while no actual bats process ran; 45 min wall-clock + $20-30 wasted before manual SIGTERM. The same self-reference shape applies to `while pgrep -f ...; do sleep; done` and to `until ! pkill -0 -f '<pattern>'` / `while pkill -0 -f '<pattern>'` (signal-0 polling). The structural fix is the same as P146: prefer `wait $bg_pid` (Unix idiom — shell-native completion signal, no regex / no pgrep) or Bash-tool `run_in_background=true` + `BashOutput` polling (harness-tracked completion state). The hook `packages/itil/hooks/itil-bash-polling-antipattern-detect.sh` denies these shapes at PreToolUse:Bash, but the prompt rule belongs here too — structural enforcement + prompt discipline together close the class.
|
|
514
|
+
3. **Constraints**: commit the completed work per ADR-014. Do NOT push, do NOT run `push:watch`, do NOT run `release:watch` — the orchestrator's Step 6.5 owns release cadence. Do NOT invoke `capture-*` background skills mid-iter (AFK carve-out — ADR-032), **EXCEPT for retro-surfaced observations of recurring class-of-behaviour** — those route to `/wr-itil:capture-problem` per the **P342 mechanical-stage carve-out** (see retro-on-exit constraint #4 below; same trust-boundary as `/wr-retrospective:run-retro` Step 4a verification close-on-evidence — P342). Do NOT use `ScheduleWakeup` under any circumstance (P083 — iteration workers must not self-reschedule). **NEVER call `AskUserQuestion` mid-loop in AFK** (P135 / ADR-044): direction / deviation-approval / one-time-override / silent-framework observations queue at `ITERATION_SUMMARY.outstanding_questions` for loop-end batched presentation. **This includes the manage-problem substance-confirm-before-build guard (ADR-074 (Confirm a decision's substance before building dependent work)):** when the propose-fix step detects that the fix builds on a born-`proposed` decision whose substance is unconfirmed (via `wr-architect-is-decision-unconfirmed`), the iter does NOT implement on it and does NOT ask mid-loop — it queues a `category: "direction"` entry naming the unconfirmed ADR + its Decision Outcome for loop-end confirmation, and routes the ticket to `action: skipped`, `skip_reason_category: user-answerable`. Building on the unconfirmed substance instead (or guessing the choice) is the P315 failure this guard exists to prevent. The queued substance-confirm is a legitimate cat-1 direction ask — it is NOT counted as lazy in the Step 2d Ask Hygiene Pass (ADR-074 lazy-count exclusion). Per-iter `AskUserQuestion` calls are sub-contracting framework-resolved decisions back to the user (lazy deferral per Step 2d Ask Hygiene Pass classification). Non-interactive defaults apply per ADR-013 Rule 6 + ADR-044's framework-resolution boundary. **Treat the user as transient** (P130): even when observably present at orchestrator dispatch time, the user may answer one question and disappear for hours; presence is not a reliable signal and is not the goal. The iter's job is to progress the ticket and accumulate questions for batched surfacing — not to ask "is it OK to proceed?" at a mechanical-stage boundary. **Do NOT poll `bats` output with a bats-console-summary regex against TAP-format output** (P146 — bash until-loop-deadlock antipattern). The bats-console-summary line `<N> tests, <M> failures` is emitted ONLY by bats's *default* (non-TAP) formatter; `bats --tap` does not emit a console summary, so a polling loop of shape `until [ -f $OUT ] && grep -qE '^[0-9]+ tests?,' $OUT; do sleep 5; done` spins forever after bats completes (silent deadlock — no error, no exit; recovery requires manual SIGTERM with metadata loss per the P146/P147 stuck-before-emit subclass). When you need to wait on a backgrounded bats run, prefer `wait $bg_pid` (Unix idiom — completion signaled by process exit, no regex required) or, for the Bash tool, `run_in_background=true` + `BashOutput` polling on the tool's exit-state field rather than regex-poll on stdout. If you genuinely must regex-poll TAP output, anchor on the TAP plan line `^[0-9]+\.\.[0-9]+` (e.g. `1..1455`) — TAP's plan line is emitted on completion and is format-stable across bats versions; the bats-console-summary line is not. The console-summary vs TAP-format divergence is the load-bearing detail: `bats` and `bats --tap` produce structurally different stdout, and the antipattern assumes the former when iter dispatch typically uses the latter. **Do NOT poll subprocess completion with `pgrep -f '<pattern>'` inside an `until` / `while` loop** (P232 — self-referential pgrep deadlock; sibling variant of P146). `pgrep -f` matches against the FULL command line of every running process, so the polling loop's own `zsh -c` argument (which contains the literal `pgrep -f '<pattern>'` text) matches itself; with multiple concurrent polling loops, each loop matches the others and spins forever. Worked example of the antipattern: `until ! pgrep -f 'bats --recursive' > /dev/null 2>&1; do sleep 5; done` — the 2026-05-16 P232 deadlock witness; 4 concurrent polling loops each matched the others' command lines while no actual bats process ran; 45 min wall-clock + $20-30 wasted before manual SIGTERM. The same self-reference shape applies to `while pgrep -f ...; do sleep; done` and to `until ! pkill -0 -f '<pattern>'` / `while pkill -0 -f '<pattern>'` (signal-0 polling). The structural fix is the same as P146: prefer `wait $bg_pid` (Unix idiom — shell-native completion signal, no regex / no pgrep) or Bash-tool `run_in_background=true` + `BashOutput` polling (harness-tracked completion state). The hook `packages/itil/hooks/itil-bash-polling-antipattern-detect.sh` denies these shapes at PreToolUse:Bash, but the prompt rule belongs here too — structural enforcement + prompt discipline together close the class. **If the fix changes shippable code or package behaviour** (any path under `packages/<plugin>/{src,bin,hooks,skills,scripts,lib,agents}` excluding test paths — `test/`, `hooks/test/`, `scripts/test/` — and excluding `README.md` + `docs/*.md`), **the iter MUST author a `.changeset/*.md` entry in the same single ADR-014-grain commit as the fix** (the changeset names the bumping plugin via the YAML frontmatter `"@windyroad/<plugin>": <patch|minor|major>` per the changesets-action contract). **Doc-only changes** (under `docs/`, `*.md`) **and test-only changes** (under any `test/` path) **that ship no behaviour MAY omit the changeset**. The orchestrator's Step 6.5 release-cadence drain runs `release:watch` only when `.changeset/` is non-empty after push — without an iter-authored changeset, code-shape fixes accumulate without ever shipping to npm (violating JTBD-006's audit-trail expectation + JTBD-007's "Keep Plugins Current" closure dependency). Hook `packages/itil/hooks/itil-changeset-discipline.sh` (P141) provides hook-level enforcement at `git commit` time as defence-in-depth — but plugin hook execution depends on the marketplace cache carrying the current hook version, so the prompt-time constraint here MUST land independently (composes-with the hook; does NOT rely on the hook being installed). Inbound-reported from downstream consumer bbstats as their P195 — see [Related](#related) for `**Origin**: inbound-reported (bbstats#195)` per ADR-076. **`@jtbd JTBD-006`** (load-bearing) **`@jtbd JTBD-007`** (closure-dependent).
|
|
515
515
|
4. **Retro-on-exit (P086) + retro-surfaced observation classification (P342)**: before emitting `ITERATION_SUMMARY`, invoke `/wr-retrospective:run-retro`. Retro runs INSIDE this subprocess so its Step 2b pipeline-instability scan has access to the iteration's rich tool-call history (hook misbehaviour, repeat-workaround patterns, subagent-delegation friction, release-path instability). Retro may create tickets or update `docs/BRIEFING.md` — run-retro commits its own work per ADR-014; any tickets it creates ride into either the iteration's own commit (if retro runs before the main commit) or a retro-owned follow-up commit, and the orchestrator picks them up on the next Step 1 scan. Proceed to `ITERATION_SUMMARY` emission regardless of retro findings — retro is non-blocking at the iter-subprocess layer (do not block on retro): if retro fails or surfaces findings, the iteration still returns a summary so the AFK loop does not silently halt on a flaky retro run. (Session-level retro at the orchestrator-main-turn layer per Step 2.4 gate (b) IS load-bearing — distinct surface; see Step 2.4 prose for the orchestrator-layer halt semantics.)
|
|
516
516
|
|
|
517
517
|
**P342 classification taxonomy — retro-surfaced observations.** When the iter-retro's Step 4b Stage 1 surfaces a ticketable observation, the routing depends on classification:
|
|
@@ -1023,4 +1023,6 @@ When every skipped ticket is in the `upstream-blocked` category (stop-condition
|
|
|
1023
1023
|
- **ADR-022** (`docs/decisions/022-problem-verification-pending.proposed.md`) — iteration outcomes map into the return-summary's `outcome` field (`verifying` for a released fix, `known-error` for a root-cause-confirmed ticket awaiting release, etc.).
|
|
1024
1024
|
- **ADR-032** (`docs/decisions/032-governance-skill-invocation-patterns.proposed.md`) — pattern taxonomy parent; Step 5 implements the AFK iteration-isolation wrapper — subprocess-boundary variant per the P084 amendment (2026-04-21), refining the P077 Agent-tool amendment. The P077 amendment remains in the ADR as the historical Agent-tool variant; the subprocess variant is the lead for new adopters.
|
|
1025
1025
|
- **ADR-037** (`docs/decisions/037-skill-testing-strategy.proposed.md`) — doc-lint bats contract-assertion pattern used by `test/work-problems-step-5-delegation.bats`.
|
|
1026
|
-
- **
|
|
1026
|
+
- **P206** (`docs/problems/known-error/206-work-problems-iter-workers-dont-add-changesets-fix-commits-accumulate-without-release.md`) — driver for Step 5 iter-prompt-body's explicit "if the fix changes shippable code, author a `.changeset/*.md` in the same commit" constraint (composes defence-in-depth with hook P141's `git commit`-time enforcement). Inbound-reported by downstream consumer **bbstats** as their P195 (`**Origin**: inbound-reported (bbstats#195)` per ADR-076 sort tier). Behavioural second-source: `test/work-problems-step-5-iter-changeset-required.bats` (structural-permitted per ADR-052; tdd-review comment in fixture).
|
|
1027
|
+
- **P141** (`docs/problems/verifying/141-iter-prompt-time-reminder-misses-40-percent-of-publishable-iters-hook-level-enforcement.md`) — sibling hook (`packages/itil/hooks/itil-changeset-discipline.sh`) that enforces the changeset-discipline rule at `git commit` time. The Step 5 iter-prompt-body constraint composes-with this hook; the prompt-time rule is load-bearing because plugin-hook execution depends on the marketplace cache carrying the current hook version (a fresh-cache adopter without P141 still gets the constraint via the prompt).
|
|
1028
|
+
- **JTBD-001**, **JTBD-006**, **JTBD-007**, **JTBD-101**, **JTBD-201** — personas whose reliability expectations the iteration-isolation wrapper restores. JTBD-006 (Progress the Backlog While I'm Away) + JTBD-007 (Keep Plugins Current Across Projects) are the load-bearing pair for the P206 changeset-discipline constraint — JTBD-006 requires the audit trail to stay accurate at release boundary; JTBD-007's closure depends on fixes actually shipping to npm.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# ADR-013 Rule 6 P352 amendment (2026-06-06): queue-and-continue is the
|
|
3
|
+
# universal AFK default when a skill needs user input but AskUserQuestion is
|
|
4
|
+
# unavailable. HALT/SKIP/AUTO-DEFAULT are deviations requiring inline-cited
|
|
5
|
+
# carve-out justification.
|
|
6
|
+
#
|
|
7
|
+
# Structural assertion — Permitted Exception to the source-grep ban (ADR-005 /
|
|
8
|
+
# P011). These assertions are load-bearing-string checks on the ADR + SKILL
|
|
9
|
+
# specification prose. Per P081, structural tests are placeholders for
|
|
10
|
+
# behavioural tests against P012's skill-testing harness; until the harness
|
|
11
|
+
# can exercise AFK fallback shapes, prose assertions on the carve-out audit
|
|
12
|
+
# are the confirmation mechanism named in the amended Rule 6 Confirmation
|
|
13
|
+
# section.
|
|
14
|
+
#
|
|
15
|
+
# tdd-review: structural-permitted (justification: ADR Rule 6 + SKILL.md prose
|
|
16
|
+
# contract assertions for an interaction-pattern contract that has no
|
|
17
|
+
# behavioural skill-runtime harness yet — P012 + P081 Phase 2 bridge window.
|
|
18
|
+
# Isomorphic precedent in this repo: work-problems-above-appetite-remediation.bats,
|
|
19
|
+
# create-adr-substance-confirm-pattern.bats, create-adr-adr-044-contract.bats.)
|
|
20
|
+
#
|
|
21
|
+
# @problem P352 (AFK queue-and-continue is the universal default)
|
|
22
|
+
# @adr ADR-013 (structured user interaction; Rule 6 amended 2026-06-06)
|
|
23
|
+
# @adr ADR-044 (decision-delegation contract; AUTO-DEFAULT lives inside framework-resolution)
|
|
24
|
+
# @adr ADR-052 (behavioural-by-default with structural bridge window)
|
|
25
|
+
# @adr ADR-074 (confirm decision substance before building; authorises HALT carve-outs)
|
|
26
|
+
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary persona)
|
|
27
|
+
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — queue keeps governance on during AFK)
|
|
28
|
+
|
|
29
|
+
setup() {
|
|
30
|
+
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
31
|
+
ADR_013="${REPO_ROOT}/docs/decisions/013-structured-user-interaction-for-governance-decisions.proposed.md"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# ----------------------------------------------------------------------
|
|
35
|
+
# ADR-013 Rule 6 amendment prose
|
|
36
|
+
# ----------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
@test "ADR-013 file exists" {
|
|
39
|
+
[ -f "$ADR_013" ]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@test "ADR-013 Rule 6 names queue-and-continue as the universal default (P352 amendment)" {
|
|
43
|
+
# The load-bearing prose: queue-and-continue is THE universal default.
|
|
44
|
+
run grep -nE "queue-and-continue is the universal default" "$ADR_013"
|
|
45
|
+
[ "$status" -eq 0 ]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@test "ADR-013 Rule 6 dates the amendment (2026-06-06)" {
|
|
49
|
+
# Date-anchoring lets future readers correlate the prose with P352 timeline.
|
|
50
|
+
run grep -nE "2026-06-06 amendment" "$ADR_013"
|
|
51
|
+
[ "$status" -eq 0 ]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@test "ADR-013 Rule 6 names halt-with-directive AND silent-skip as deviations" {
|
|
55
|
+
# The amendment's contract: HALT and SKIP are DEVIATIONS requiring carve-out
|
|
56
|
+
# justification — they are not the default.
|
|
57
|
+
run grep -nE "DEVIATIONS that require an explicit" "$ADR_013"
|
|
58
|
+
[ "$status" -eq 0 ]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@test "ADR-013 Rule 6 documents the capture-problem HALT carve-out (ADR-074 authority)" {
|
|
62
|
+
# The amendment must explicitly name the documented HALT carve-outs so
|
|
63
|
+
# readers know the SKILL surfaces that LEGITIMATELY halt and why.
|
|
64
|
+
run grep -nE "capture-problem.*derive-then-ratify HALT" "$ADR_013"
|
|
65
|
+
[ "$status" -eq 0 ]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@test "ADR-013 Rule 6 documents the create-adr Step 5 HALT carve-out" {
|
|
69
|
+
run grep -nE "create-adr.*Step 5 substance-confirm HALT" "$ADR_013"
|
|
70
|
+
[ "$status" -eq 0 ]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@test "ADR-013 Rule 6 documents the manage-problem create-gate HALT carve-out" {
|
|
74
|
+
run grep -nE "manage-problem.*create-gate HALT" "$ADR_013"
|
|
75
|
+
[ "$status" -eq 0 ]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@test "ADR-013 Rule 6 names AUTO-DEFAULT as framework-resolved-only (ADR-044 boundary)" {
|
|
79
|
+
# AUTO-DEFAULT is permitted ONLY when the decision is framework-resolved.
|
|
80
|
+
# Outside the framework-resolution boundary, AUTO-DEFAULT is a defect.
|
|
81
|
+
run grep -nE "AUTO-DEFAULT.*permitted ONLY when the decision is framework-resolved" "$ADR_013"
|
|
82
|
+
[ "$status" -eq 0 ]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@test "ADR-013 Rule 6 cites ADR-044 (decision-delegation framework-resolution boundary)" {
|
|
86
|
+
run grep -nE "ADR-044" "$ADR_013"
|
|
87
|
+
[ "$status" -eq 0 ]
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@test "ADR-013 Rule 6 cites ADR-074 (substance-confirm authority for HALT carve-outs)" {
|
|
91
|
+
run grep -nE "ADR-074" "$ADR_013"
|
|
92
|
+
[ "$status" -eq 0 ]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@test "ADR-013 Rule 6 cites JTBD-006 (Progress the Backlog While I'm Away)" {
|
|
96
|
+
run grep -nE "JTBD-006" "$ADR_013"
|
|
97
|
+
[ "$status" -eq 0 ]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@test "ADR-013 Rule 6 cites P352 as the originating ticket" {
|
|
101
|
+
run grep -nE "\bP352\b" "$ADR_013"
|
|
102
|
+
[ "$status" -eq 0 ]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@test "ADR-013 Rule 6 records the shared-helper extraction as a follow-on (deferred)" {
|
|
106
|
+
# The ratified design explicitly deferred the shared-helper extraction to
|
|
107
|
+
# follow-on. The prose must record the deferral so future readers (and
|
|
108
|
+
# future iter agents) know the interim contract.
|
|
109
|
+
run grep -nE "Shared-helper extraction deferred" "$ADR_013"
|
|
110
|
+
[ "$status" -eq 0 ]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# ----------------------------------------------------------------------
|
|
114
|
+
# Per-SKILL carve-out audit annotations
|
|
115
|
+
# ----------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
@test "capture-problem SKILL.md carries the P352 carve-out audit (HALT per ADR-074)" {
|
|
118
|
+
SKILL="${REPO_ROOT}/packages/itil/skills/capture-problem/SKILL.md"
|
|
119
|
+
[ -f "$SKILL" ]
|
|
120
|
+
run grep -nE "ADR-013 Rule 6 carve-out audit \(P352" "$SKILL"
|
|
121
|
+
[ "$status" -eq 0 ]
|
|
122
|
+
# And the carve-out must name its authorising ADR
|
|
123
|
+
run grep -nE "authorised by \*\*ADR-074" "$SKILL"
|
|
124
|
+
[ "$status" -eq 0 ]
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@test "create-adr SKILL.md carries the P352 carve-out audit (Step 1 AUTO-DEFAULT + Step 5 HALT)" {
|
|
128
|
+
SKILL="${REPO_ROOT}/packages/architect/skills/create-adr/SKILL.md"
|
|
129
|
+
[ -f "$SKILL" ]
|
|
130
|
+
run grep -nE "ADR-013 Rule 6 carve-out audit \(P352" "$SKILL"
|
|
131
|
+
[ "$status" -eq 0 ]
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@test "manage-problem SKILL.md carries the P352 carve-out audit (Step 4b AUTO-DEFAULT)" {
|
|
135
|
+
SKILL="${REPO_ROOT}/packages/itil/skills/manage-problem/SKILL.md"
|
|
136
|
+
[ -f "$SKILL" ]
|
|
137
|
+
run grep -nE "ADR-013 Rule 6 carve-out audit \(P352" "$SKILL"
|
|
138
|
+
[ "$status" -eq 0 ]
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@test "review-problems SKILL.md cites the P352 amendment at the Step 4.5 AFK branch" {
|
|
142
|
+
SKILL="${REPO_ROOT}/packages/itil/skills/review-problems/SKILL.md"
|
|
143
|
+
[ -f "$SKILL" ]
|
|
144
|
+
run grep -nE "ADR-013 Rule 6 universal default \(P352" "$SKILL"
|
|
145
|
+
[ "$status" -eq 0 ]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@test "scaffold-intake SKILL.md cites the P352 amendment as canonical queue-and-continue" {
|
|
149
|
+
SKILL="${REPO_ROOT}/packages/itil/skills/scaffold-intake/SKILL.md"
|
|
150
|
+
[ -f "$SKILL" ]
|
|
151
|
+
run grep -nE "ADR-013 Rule 6 universal default \(P352" "$SKILL"
|
|
152
|
+
[ "$status" -eq 0 ]
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@test "run-retro SKILL.md cites the P352 amendment at the Step 1.5 AFK branch" {
|
|
156
|
+
SKILL="${REPO_ROOT}/packages/retrospective/skills/run-retro/SKILL.md"
|
|
157
|
+
[ -f "$SKILL" ]
|
|
158
|
+
run grep -nE "ADR-013 Rule 6 universal default \(P352" "$SKILL"
|
|
159
|
+
[ "$status" -eq 0 ]
|
|
160
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
# P206 — work-problems Step 5 iteration-prompt-body must EXPLICITLY require
|
|
3
|
+
# AFK iter subprocesses to author a `.changeset/*.md` alongside any fix
|
|
4
|
+
# commit that ships shippable code. Hook P141 (itil-changeset-discipline.sh)
|
|
5
|
+
# enforces this at git-commit time but depends on the plugin marketplace
|
|
6
|
+
# cache being current. The prompt-time constraint composes defence-in-depth
|
|
7
|
+
# with the hook so iter subprocesses self-author the changeset rather than
|
|
8
|
+
# discovering the gap at commit time (or worse — slipping through when the
|
|
9
|
+
# hook is missing from the install).
|
|
10
|
+
#
|
|
11
|
+
# Reported as inbound from downstream consumer bbstats (their P195) on
|
|
12
|
+
# 2026-05-15; covered by ADR-076 Origin field tier.
|
|
13
|
+
#
|
|
14
|
+
# tdd-review: structural-permitted (justification: SKILL.md is the named
|
|
15
|
+
# contract document under ADR-052; behavioural alternative would require a
|
|
16
|
+
# synthetic `claude -p` iter dispatch harness that completes a fix commit
|
|
17
|
+
# and asserts `.changeset/*.md` co-presence — that harness sits outside the
|
|
18
|
+
# skill layer and depends on the Anthropic CLI binary. Same Permitted
|
|
19
|
+
# Exception precedent as `work-problems-step-5-delegation.bats:99-105` and
|
|
20
|
+
# the P083 / P086 / P089 ScheduleWakeup / retro / stdin-redirect fixtures
|
|
21
|
+
# in the same directory).
|
|
22
|
+
#
|
|
23
|
+
# @problem P206
|
|
24
|
+
# @problem P141
|
|
25
|
+
# @jtbd JTBD-006
|
|
26
|
+
# @jtbd JTBD-007
|
|
27
|
+
# @jtbd JTBD-001
|
|
28
|
+
#
|
|
29
|
+
# Cross-reference:
|
|
30
|
+
# P206 — this ticket (work-problems iter workers don't add changesets)
|
|
31
|
+
# P141 — sibling changeset-discipline hook (hook-level enforcement;
|
|
32
|
+
# prompt-time constraint composes defence-in-depth)
|
|
33
|
+
# bbstats#195 — inbound report from downstream consumer
|
|
34
|
+
# ADR-014 (governance skills commit their own work)
|
|
35
|
+
# ADR-018 (inter-iteration release cadence — changesets are the load-
|
|
36
|
+
# bearing input to ADR-020's auto-release path)
|
|
37
|
+
# ADR-052 (behavioural tests default; structural-permitted with comment)
|
|
38
|
+
# ADR-076 (inbound-reported problems rank ahead via sort tier — Origin
|
|
39
|
+
# field stamping)
|
|
40
|
+
# JTBD-006 (Progress the Backlog While I'm Away) — load-bearing
|
|
41
|
+
# JTBD-007 (Keep Plugins Current Across Projects) — closure depends on
|
|
42
|
+
# release actually shipping
|
|
43
|
+
|
|
44
|
+
setup() {
|
|
45
|
+
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
46
|
+
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@test "SKILL.md Step 5 iteration-prompt-body names changeset as required when fix changes shippable code (P206)" {
|
|
50
|
+
# The iteration-prompt-body must EXPLICITLY require iter subprocesses to
|
|
51
|
+
# author a `.changeset/*.md` alongside any fix commit that ships shippable
|
|
52
|
+
# code. Without the explicit constraint, iter subprocesses can complete
|
|
53
|
+
# fix commits that the orchestrator's Step 6.5 release-cadence drain
|
|
54
|
+
# then has nothing to release — fixes accumulate without an npm publish.
|
|
55
|
+
# The constraint must name `changeset` AND a "shippable code" qualifier
|
|
56
|
+
# so doc-only and test-only commits are correctly exempted.
|
|
57
|
+
run grep -niE "changeset.{0,200}(shippable|publishable|packages/<plugin>)" "$SKILL_FILE"
|
|
58
|
+
[ "$status" -eq 0 ]
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@test "SKILL.md Step 5 iteration-prompt-body exempts doc-only and test-only changes from the changeset requirement (P206)" {
|
|
62
|
+
# Doc-only changes (e.g. JTBD edits, ADR edits, retro additions) and
|
|
63
|
+
# test-only changes (under `test/`) ship no behaviour — requiring a
|
|
64
|
+
# changeset for them would author noise CHANGELOG bullets per release.
|
|
65
|
+
# The constraint must name the exemption explicitly so iter subprocesses
|
|
66
|
+
# do not over-apply the rule.
|
|
67
|
+
run grep -niE "(doc.?only|docs.?only|test.?only).{0,80}(omit|may omit|no changeset|not required)|changeset.{0,80}(omit|exempt)" "$SKILL_FILE"
|
|
68
|
+
[ "$status" -eq 0 ]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@test "SKILL.md Step 5 iteration-prompt-body cites P141 as the defence-in-depth hook (P206)" {
|
|
72
|
+
# The prompt-time constraint composes with hook P141 (changeset-discipline).
|
|
73
|
+
# Naming P141 inline in the prompt-body makes the defence-in-depth
|
|
74
|
+
# composition self-documenting — a future contributor reading the prompt
|
|
75
|
+
# understands the hook is the second layer, not the only layer.
|
|
76
|
+
run grep -nE "P141" "$SKILL_FILE"
|
|
77
|
+
[ "$status" -eq 0 ]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@test "SKILL.md Related section cites P206 (this fix)" {
|
|
81
|
+
# ADR-037 + ADR-052 self-documenting contract: the contract document
|
|
82
|
+
# carries a Related section listing the problem tickets it satisfies.
|
|
83
|
+
# P206 closure depends on this citation landing.
|
|
84
|
+
run grep -nE "P206" "$SKILL_FILE"
|
|
85
|
+
[ "$status" -eq 0 ]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@test "SKILL.md Step 5 iteration-prompt-body cites bbstats#195 as the inbound source (P206 + ADR-076 Origin)" {
|
|
89
|
+
# ADR-076 reported-first tier requires the Origin field to be visible at
|
|
90
|
+
# the contract surface so future contributors understand the constraint
|
|
91
|
+
# was driven by external evidence, not internal speculation. The bbstats
|
|
92
|
+
# back-link is the audit anchor.
|
|
93
|
+
run grep -niE "bbstats.{0,20}195|bbstats/.{0,30}195|bbstats#195" "$SKILL_FILE"
|
|
94
|
+
[ "$status" -eq 0 ]
|
|
95
|
+
}
|