@windyroad/itil 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env bash
2
+ # packages/itil/scripts/update-problem-rfcs-section.sh
3
+ #
4
+ # Idempotently refresh the auto-maintained `## RFCs` section on a
5
+ # problem ticket file based on which RFCs in <rfcs-dir> claim the
6
+ # ticket via their YAML frontmatter `problems:` list.
7
+ #
8
+ # Called inline by `/wr-itil:capture-rfc` Step 6 and `/wr-itil:manage-rfc`
9
+ # Step 7 (transitions) + Step 9 (review re-rank) so the cross-tier
10
+ # reverse-trace is current at every commit per ADR-014 single-commit
11
+ # grain. Closes ADR-060 Phase 1 item 10 + Confirmation criterion 3
12
+ # (skill-side primary surface; architect Q1 + Q3 verdicts).
13
+ #
14
+ # Usage:
15
+ # update-problem-rfcs-section.sh <problem-file> [<rfcs-dir>]
16
+ #
17
+ # Default <rfcs-dir> is `docs/rfcs`.
18
+ #
19
+ # Lazy-empty discipline (per JTBD-101 atomic-fix-adopter friction
20
+ # guard + architect Q3 verdict): if zero RFCs trace this problem, the
21
+ # `## RFCs` section is REMOVED entirely. Atomic-fix tickets with no
22
+ # RFC trace stay free of empty-table noise.
23
+ #
24
+ # Idempotent: running over a current section is a no-op (no file diff).
25
+ #
26
+ # Section placement (per architect Q3 verdict):
27
+ # - Before `## Fix Released` if present (closure section stays at tail
28
+ # per ADR-022 trailing-audit-artefact convention).
29
+ # - Else at EOF.
30
+ #
31
+ # Output:
32
+ # - Rewrites the problem ticket in-place when the section needs an
33
+ # update; otherwise leaves the file untouched.
34
+ # - Emits exit 0 always (caller skills don't need defensive handling).
35
+ #
36
+ # @adr ADR-060 (Phase 1 item 10 + Confirmation criterion 3 — auto-
37
+ # maintained reverse trace; architect Q3 — table format, lazy empty,
38
+ # between `## Related` and `## Fix Released`)
39
+ # @adr ADR-014 (called by capture-rfc Step 6 + manage-rfc Step 7+9
40
+ # to ride the same single-purpose commit)
41
+ # @adr ADR-022 (`## Fix Released` is the trailing closure section;
42
+ # `## RFCs` precedes it)
43
+ # @adr ADR-052 (behavioural bats coverage in
44
+ # packages/itil/scripts/test/update-problem-rfcs-section.bats)
45
+ # @problem P170
46
+
47
+ set -uo pipefail
48
+
49
+ PROBLEM_FILE="${1:?missing problem-file arg}"
50
+ RFCS_DIR="${2:-docs/rfcs}"
51
+
52
+ [ -f "$PROBLEM_FILE" ] || exit 0
53
+
54
+ PBASE="$(basename "$PROBLEM_FILE")"
55
+ PNUM="${PBASE%%-*}"
56
+ PID="P${PNUM}"
57
+
58
+ # ── Step 1: scan rfcs-dir for RFCs whose frontmatter claims PID ─────────────
59
+
60
+ ROWS_TMP=$(mktemp)
61
+ trap 'rm -f "$ROWS_TMP"' EXIT
62
+
63
+ shopt -s nullglob
64
+ for f in "$RFCS_DIR"/RFC-[0-9][0-9][0-9]-*.md; do
65
+ base="$(basename "$f")"
66
+ num="${base#RFC-}"
67
+ num="${num%%-*}"
68
+ rfc_id="RFC-${num}"
69
+ case "$base" in
70
+ *.proposed.md) ticket_status="proposed" ;;
71
+ *.accepted.md) ticket_status="accepted" ;;
72
+ *.in-progress.md) ticket_status="in-progress" ;;
73
+ *.verifying.md) ticket_status="verifying" ;;
74
+ *.closed.md) ticket_status="closed" ;;
75
+ *) continue ;;
76
+ esac
77
+
78
+ # Parse frontmatter `problems: [P<NNN>, P<NNN>, ...]` (single-line form).
79
+ raw=$(awk '/^problems:/ { print; exit }' "$f")
80
+ inner=$(echo "$raw" | sed -E 's/^[[:space:]]*problems:[[:space:]]*\[//; s/\][[:space:]]*$//')
81
+
82
+ claims=0
83
+ while IFS= read -r tok; do
84
+ tok=$(echo "$tok" | tr -d ' "'\''')
85
+ [ "$tok" = "$PID" ] && { claims=1; break; }
86
+ done <<< "$(echo "$inner" | tr ',' '\n')"
87
+
88
+ [ "$claims" -eq 0 ] && continue
89
+
90
+ # Extract title from `# RFC-<NNN>: <Title>` heading.
91
+ title=$(awk -v rid="$rfc_id" 'BEGIN{prefix="^# " rid ": "} { if (match($0, prefix)) { print substr($0, RSTART + RLENGTH); exit } }' "$f")
92
+ [ -z "$title" ] && title="(untitled)"
93
+
94
+ printf '%s\t%s\t%s\n' "$rfc_id" "$ticket_status" "$title" >> "$ROWS_TMP"
95
+ done
96
+ shopt -u nullglob
97
+
98
+ SORTED_ROWS=$(sort -k1,1 "$ROWS_TMP" 2>/dev/null || true)
99
+ HAS_ROWS=0
100
+ [ -n "$SORTED_ROWS" ] && HAS_ROWS=1
101
+
102
+ # ── Step 2: rewrite problem file with idempotent section ────────────────────
103
+
104
+ TMPFILE=$(mktemp)
105
+ trap 'rm -f "$ROWS_TMP" "$TMPFILE"' EXIT
106
+
107
+ # Single-pass awk:
108
+ # - drops any existing `## RFCs` section (header through line before
109
+ # next `## ` header or EOF).
110
+ # - splits the rest into PRE (lines before `## Fix Released`) and
111
+ # POST (`## Fix Released` and after).
112
+ PRE_LINES=$(awk '
113
+ BEGIN { skip=0; in_post=0 }
114
+ /^## RFCs[[:space:]]*$/ { skip=1; next }
115
+ /^## / && skip==1 { skip=0 }
116
+ skip==1 { next }
117
+ /^## Fix Released/ { in_post=1 }
118
+ in_post==0 { print }
119
+ ' "$PROBLEM_FILE")
120
+
121
+ POST_LINES=$(awk '
122
+ BEGIN { skip=0; in_post=0 }
123
+ /^## RFCs[[:space:]]*$/ { skip=1; next }
124
+ /^## / && skip==1 { skip=0 }
125
+ skip==1 { next }
126
+ /^## Fix Released/ { in_post=1 }
127
+ in_post==1 { print }
128
+ ' "$PROBLEM_FILE")
129
+
130
+ # Trim trailing blank lines off PRE_LINES.
131
+ PRE_LINES=$(printf '%s\n' "$PRE_LINES" | awk '
132
+ { lines[NR]=$0 }
133
+ END {
134
+ last=NR
135
+ while (last > 0 && lines[last] ~ /^[[:space:]]*$/) last--
136
+ for (i=1; i<=last; i++) print lines[i]
137
+ }
138
+ ')
139
+
140
+ {
141
+ printf '%s\n' "$PRE_LINES"
142
+ if [ "$HAS_ROWS" -eq 1 ]; then
143
+ printf '\n## RFCs\n\n'
144
+ printf '| RFC | Status | Title |\n'
145
+ printf '|-----|--------|-------|\n'
146
+ while IFS=$'\t' read -r rid st ti; do
147
+ [ -z "$rid" ] && continue
148
+ printf '| %s | %s | %s |\n' "$rid" "$st" "$ti"
149
+ done <<< "$SORTED_ROWS"
150
+ fi
151
+ if [ -n "$POST_LINES" ]; then
152
+ printf '\n%s\n' "$POST_LINES"
153
+ fi
154
+ } > "$TMPFILE"
155
+
156
+ # Idempotency: only replace when content changed.
157
+ if ! cmp -s "$PROBLEM_FILE" "$TMPFILE"; then
158
+ mv "$TMPFILE" "$PROBLEM_FILE"
159
+ fi
160
+ exit 0
@@ -0,0 +1,276 @@
1
+ ---
2
+ name: wr-itil:capture-rfc
3
+ description: Lightweight RFC-capture skill for aside-invocation during foreground work — mandatory problem-trace per ADR-060 I1 invariant, skeleton RFC file, single commit per capture, no inline README refresh. Defers full duplicate analysis and README refresh to /wr-itil:manage-rfc. Use this when the user (or agent) wants to capture an RFC quickly with a clear problem trace. For full lifecycle management, use /wr-itil:manage-rfc.
4
+ allowed-tools: Read, Write, Edit, Bash, Grep, Glob
5
+ ---
6
+
7
+ # Capture RFC Skill
8
+
9
+ Capture a Request for Change (RFC) ticket quickly during foreground work. Lightweight aside-invocation surface that complements the heavyweight `/wr-itil:manage-rfc` flow. Mirrors `/wr-itil:capture-problem` shape per ADR-032 lightweight + heavyweight skill split.
10
+
11
+ This skill is one half of the capture-then-manage RFC framework introduced by ADR-060 (Problem-RFC-Story framework with mandatory problem-trace and unified problem ontology, accepted 2026-05-05). The other half is `/wr-itil:manage-rfc` (heavyweight intake + lifecycle management).
12
+
13
+ **Related JTBDs**: JTBD-008 (primary — Decompose a Fix Into Coordinated Changes; this skill IS the capture-time decomposition surface), JTBD-001 (extended scope — change-set-level governance), JTBD-101 (atomic-fix-adopter friction guard — capture-rfc remains opt-in, never auto-fires on atomic captures).
14
+
15
+ ## When to invoke
16
+
17
+ - **Multi-commit fix at the start of work**: agent / user observes that a problem fix decomposes into multiple coordinated changes (a refactor across packages, a phased migration, a framework evolution). Capture an RFC scoping the work *before* the first commit lands so each phase competes for WSJF attention as a first-class entity (per JTBD-008).
18
+ - **Retrospective migration**: lifting an existing multi-commit problem into the RFC framework (e.g. RFC-001 retro on P168 in Slice 4 of `docs/plans/170-rfc-framework-story-map.md`). The bounded-escape carve-out at Step 2 permits Closed/Verifying/Parked problem traces for this case.
19
+ - **Ad-hoc planned change**: user names work that doesn't yet have a problem ticket but clearly serves one. The I1 invariant requires the problem ticket to exist FIRST — this skill refuses without a `--problem` trace, redirecting the user to `/wr-itil:capture-problem` to open the problem first, then back to capture-rfc.
20
+
21
+ **Use `/wr-itil:manage-rfc` instead** when:
22
+ - The work is moving an existing RFC through its lifecycle (proposed → accepted → in-progress → verifying → closed).
23
+ - The user wants to walk a full intake flow with structured re-rank prompts and scope-expansion deviation-approval.
24
+ - Multi-RFC coordination decisions need to be captured (manage-rfc handles meta-RFC and cross-RFC ADR creation; capture-rfc creates one RFC per invocation).
25
+
26
+ ## Argument grammar
27
+
28
+ **Positional**: `<problem-trace> <description>` where `<problem-trace>` is `P<NNN>` or `P<NNN>,P<NNN>,...` (no spaces inside the trace; multiple problems comma-separated).
29
+
30
+ ```
31
+ /wr-itil:capture-rfc P168 Pipeline consume-catalog and bootstrap-from-reports — multi-commit retrofit
32
+ /wr-itil:capture-rfc P038,P064 Voice-and-tone gates on external comms — coordinated rollout across changeset/PR/release-notes
33
+ ```
34
+
35
+ **ADR-060 § Phase 1 item 2 phrasing footnote**: ADR-060 names "mandatory `--problem P<NNN>` flag" verbatim. This skill uses the **positional** form (no `--problem` prefix) to match the lightweight aside-invocation grammar of `capture-problem` (per ADR-032) and because Claude Code skill arguments don't carry a proper CLI flag parser. The hard-block intent (ADR-060 § Confirmation criterion 1: "without a problem trace") is preserved verbatim — only the surface syntax differs. The `--problem` phrasing in ADR-060 reads as exemplar, not contract.
36
+
37
+ ## Rule 6 audit (per ADR-032 + ADR-013 + ADR-060)
38
+
39
+ This skill has **one direction-setting AskUserQuestion** (problem-trace, when arguments are non-empty but contain no parseable trace) and **one optional taste AskUserQuestion** (title/scope summary, silent-default if unavailable). Every other potentially-interactive decision is framework-mediated per ADR-044:
40
+
41
+ | Decision | Resolution | Authority class |
42
+ |----------|-----------|-----------------|
43
+ | Problem trace presence | I1 hard-block — refuse on missing trace; emit deny log + halt-with-stderr-directive | direction-setting (the user/caller MUST supply; framework cannot guess) |
44
+ | Problem trace validation | Mechanical: each `P<NNN>` must exist in `docs/problems/`. Open/Known Error/Verifying = pass; Closed/Parked = advisory-warn but proceed (bounded-escape carve-out — see Step 2 rationale) | silent-mechanical |
45
+ | RFC ID allocation | Mechanical: `max(local, origin) + 1`, three-digit padded | silent-mechanical |
46
+ | Title kebab-slug | Mechanical: first 8-10 non-stopword tokens of description | silent-mechanical |
47
+ | Title prose / scope summary refinement | Optional `AskUserQuestion`; silent-default to derived form when unavailable | taste |
48
+ | File write / frontmatter | Mechanical: shape per `docs/rfcs/README.md` § RFC body structure | silent-mechanical |
49
+ | Single commit | Mechanical: `docs(rfcs): capture RFC-<NNN> <title>` | silent-mechanical |
50
+ | Empty arguments | Halt-with-stderr-directive: print "capture-rfc requires `<problem-trace> <description>` — invoke /wr-itil:manage-rfc instead for the full intake flow" and exit. AFK orchestrators MUST NOT invoke capture-rfc with empty arguments. | n/a |
51
+
52
+ Per ADR-013 Rule 6 fail-safe + ADR-044 + P132 + inverse-P078: every silent-mechanical branch above resolves without user input, so AFK and interactive contexts behave identically modulo the optional taste prompt.
53
+
54
+ ## Steps
55
+
56
+ ### 0. Preflight (Phase 1 cross-directory)
57
+
58
+ **Phase 1 sequencing note**: this skill's preflight uses `wr-itil-reconcile-readme docs/problems` (the existing problems-README reconciliation contract per P118) because the sibling `wr-itil-reconcile-rfcs` script lands in Slice 3 task B5.T6. RFC trace integrity depends on the problems README being clean — every RFC traces to ≥ 1 problem (I1), so an out-of-date problems README directly threatens the trace validation in Step 2. Once Slice 3 ships `wr-itil-reconcile-rfcs docs/rfcs`, swap this preflight to call BOTH (the cross-tier integrity check holds at both surfaces).
59
+
60
+ ```bash
61
+ wr-itil-reconcile-readme docs/problems > /tmp/wr-itil-drift-$$.txt
62
+ reconcile_exit=$?
63
+ if [ "$reconcile_exit" -eq 1 ]; then
64
+ wr-itil-classify-readme-drift /tmp/wr-itil-drift-$$.txt docs/problems
65
+ classify_exit=$?
66
+ rm -f /tmp/wr-itil-drift-$$.txt
67
+ # classify_exit 0 (INLINE_REFRESH): proceed (no inline refresh in this skill).
68
+ # classify_exit 1 (HALT_ROUTE_RECONCILE): halt; invoke /wr-itil:reconcile-readme.
69
+ # classify_exit 2 (parse error): conservative halt-and-route.
70
+ fi
71
+ ```
72
+
73
+ ### 1. Parse arguments
74
+
75
+ The arguments must begin with a problem-trace token (`P<NNN>` or comma-separated `P<NNN>,P<NNN>,...`). The remainder is the description.
76
+
77
+ ```bash
78
+ # Tokenise: first token = problem-trace; rest = description
79
+ problem_trace="$1"; shift
80
+ description="$*"
81
+ ```
82
+
83
+ If `$problem_trace` does not match `^P[0-9]{3}(,P[0-9]{3})*$` (regex), this is an I1 violation — go to Step 2's deny path. If `$description` is empty, halt with the empty-arguments directive from the Rule 6 audit table above.
84
+
85
+ Derive a kebab-case title slug from the first 8-10 non-stopword tokens of `$description` (matching `capture-problem` slug derivation).
86
+
87
+ ### 2. Validate problem trace + I1 hard-block enforcement
88
+
89
+ For each `P<NNN>` in the trace list:
90
+
91
+ ```bash
92
+ # Check existence in any lifecycle status
93
+ trace_files=$(ls docs/problems/<NNN>-*.md 2>/dev/null)
94
+ ```
95
+
96
+ **I1 hard-block (per ADR-060 § Confirmation criterion 1)**:
97
+
98
+ - **Trace token absent OR malformed**: emit deny log entry + halt with stderr directive:
99
+ ```bash
100
+ mkdir -p logs
101
+ printf '{"timestamp":"%s","session_id":"%s","reason":"%s","args":%s}\n' \
102
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$(get_current_session_id 2>/dev/null || echo unknown)" \
103
+ "<missing|malformed|unresolved>-trace" \
104
+ "$(printf '%s' "$ARGUMENTS" | jq -Rs .)" \
105
+ >> logs/rfc-capture-denials.jsonl
106
+ echo "/wr-itil:capture-rfc requires a leading problem-trace argument (P<NNN> or P<NNN>,P<NNN>...). Open the driving problem via /wr-itil:capture-problem first, then re-invoke capture-rfc with the trace." >&2
107
+ exit 1
108
+ ```
109
+ The deny log feeds the trace-violation-rate reassessment criterion in ADR-060 § Reassessment Criteria (>20% denial rate triggers ADR-060 reassessment).
110
+
111
+ - **Each `P<NNN>` must resolve to a file in `docs/problems/`**. If any does not, emit deny log entry with `reason: unresolved-trace` + the unresolved IDs, halt, exit 1.
112
+
113
+ **Bounded-escape carve-out for Closed/Verifying/Parked traces**:
114
+
115
+ For each resolved trace file, classify by suffix:
116
+ - `.open.md`, `.known-error.md` → pass silently.
117
+ - `.verifying.md` → pass with advisory note in the report ("trace P<NNN> is Verification Pending — RFC may close before driving problem closes").
118
+ - `.closed.md`, `.parked.md` → pass with advisory-warn in the report ("trace P<NNN> is <Closed|Parked> — capture proceeds for retrospective/historical RFC; bounded-escape carve-out per ADR-060 § Confirmation criterion 5 + Phase 1 item 9").
119
+
120
+ **Why advisory and not hard-block at capture-time**: the bounded-escape contract in ADR-060 § Confirmation criterion 2 scopes I1 hard-block to `accepted → in-progress` and `→ verifying` lifecycle transitions; advisory-with-escalation only fires at `→ closed` transition. Capture-time tolerance for Closed/Parked traces is **load-bearing for the Phase 1 dogfood pass**: RFC-001 retro on P168 (P168 is `.verifying.md`) is structurally impossible without it. This is NOT a relaxation of I1; it is the bounded-escape window the ADR carved out at the right lifecycle phase. See ADR-060 § Confirmation criterion 5 (no semantic loss) + Phase 1 item 9 (retro migration as dogfood pass).
121
+
122
+ ### 3. Compute next RFC ID
123
+
124
+ Same `max(local, origin) + 1` formula as `capture-problem` Step 3, scanning `docs/rfcs/RFC-*.md` instead:
125
+
126
+ ```bash
127
+ local_max=$(ls docs/rfcs/RFC-*.md 2>/dev/null | sed 's|.*/RFC-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
128
+ origin_max=$(git ls-tree --name-only origin/main docs/rfcs/ 2>/dev/null | sed 's|^docs/rfcs/RFC-||;s|-.*||' | grep -oE '^[0-9]+' | sort -n | tail -1)
129
+ next=$(printf '%03d' $(( $(echo -e "${local_max:-0}\n${origin_max:-0}" | sort -n | tail -1) + 1 )))
130
+ ```
131
+
132
+ Log the renumber decision in the operation report if origin and local diverged.
133
+
134
+ ### 4. Optional taste prompt for title / scope summary
135
+
136
+ If interactive (AskUserQuestion available) AND the description is short enough that the derived title slug may not capture intent, fire one `AskUserQuestion` with `header: "RFC title"` offering: (a) the derived kebab-slug as default, (b) "edit". This is **taste** authority class per ADR-044 — silent-default to (a) when AskUserQuestion is unavailable or the description already reads as a clean title.
137
+
138
+ ### 5. Write the RFC file
139
+
140
+ **File path**: `docs/rfcs/RFC-<NNN>-<kebab-title>.proposed.md`
141
+
142
+ **Template** (mirrors `docs/rfcs/README.md` § RFC body structure):
143
+
144
+ ```markdown
145
+ ---
146
+ status: proposed
147
+ rfc-id: <kebab-slug>
148
+ reported: <YYYY-MM-DD>
149
+ decision-makers: [<git config user.name>]
150
+ problems: [P<NNN>, P<NNN>, ...]
151
+ adrs: []
152
+ jtbd: []
153
+ ---
154
+
155
+ # RFC-<NNN>: <Title>
156
+
157
+ **Status**: proposed
158
+ **Reported**: <YYYY-MM-DD>
159
+ **Problems**: <P<NNN> [, P<NNN>, ...]>
160
+ **ADRs**: (none)
161
+ **JTBD**: (none)
162
+
163
+ ## Summary
164
+
165
+ <description from arguments>
166
+
167
+ ## Driving problem trace
168
+
169
+ <for each P<NNN>: one-line summary linking the RFC scope to the problem's symptom or RCA finding>
170
+
171
+ ## Scope
172
+
173
+ (deferred — populate at /wr-itil:manage-rfc accepted transition)
174
+
175
+ ## Tasks
176
+
177
+ - [ ] (deferred — populate at /wr-itil:manage-rfc accepted transition)
178
+
179
+ ## Commits
180
+
181
+ (maintained automatically — populated by the commit-message RFC trailer hook per ADR-060 Phase 1 item 12; lands in Slice 3 task B5.T9)
182
+
183
+ ## Related
184
+
185
+ (captured via /wr-itil:capture-rfc; expand at next /wr-itil:manage-rfc invocation)
186
+ ```
187
+
188
+ The deferred-section pattern matches `capture-problem`'s placeholder approach — the captured RFC is intentionally minimal; full scope and task decomposition land at the manage-rfc accepted-transition step.
189
+
190
+ ### 6. Single commit — `## RFCs` reverse-trace refresh; no rfcs README refresh
191
+
192
+ **Stage list**: the new RFC file PLUS each driving problem ticket file whose `## RFCs` section needs the reverse-trace row added (per ADR-060 Phase 1 item 10 + Confirmation criterion 3 — auto-maintained reverse trace; architect Q1 verdict skill-side primary). **Do NOT** stage `docs/rfcs/README.md`. The deferred-rfcs-README-refresh contract is the load-bearing capture-time speed differentiator from `/wr-itil:manage-rfc` (mirrors `capture-problem` deferred-`docs/problems/README.md` contract). The next `/wr-itil:manage-rfc review` invocation OR `wr-itil-reconcile-rfcs` refreshes the rfcs README.
193
+
194
+ The reverse-trace refresh on driving problem tickets, however, IS in-commit per ADR-014 single-commit grain — the cross-tier `## RFCs` table on a problem ticket must stay current the moment a new RFC traces it. Otherwise the trailer hook (`itil-rfc-trailer-advisory.sh`) would fire on every capture commit and the reverse-trace would lag by one manage-rfc invocation.
195
+
196
+ For each problem ID in `$problem_trace`, invoke the helper before commit:
197
+
198
+ ```bash
199
+ for pid_token in $(echo "$problem_trace" | tr ',' ' '); do
200
+ pid_num="${pid_token#P}"
201
+ problem_file=$(ls docs/problems/${pid_num}-*.md 2>/dev/null | head -1)
202
+ [ -z "$problem_file" ] && continue
203
+ bash "$(wr-itil-script-path 2>/dev/null || echo packages/itil/scripts)/update-problem-rfcs-section.sh" "$problem_file" docs/rfcs
204
+ git add "$problem_file"
205
+ done
206
+ ```
207
+
208
+ The helper (`packages/itil/scripts/update-problem-rfcs-section.sh`) is idempotent: running over a current section is a no-op. Lazy-empty discipline applies (zero traced RFCs → section absent) — capture-rfc invocations always have ≥ 1 trace at this step, so this surface always emits a populated section. The `git add` is conditional on the helper actually modifying the file — `cmp -s` no-op-on-current is the helper's idempotency contract; `git add` of an unchanged file is also a no-op.
209
+
210
+ Stage the new RFC file:
211
+
212
+ ```bash
213
+ git add docs/rfcs/RFC-<NNN>-<slug>.proposed.md
214
+ ```
215
+
216
+ Satisfy the commit gate per ADR-014:
217
+
218
+ - **Primary**: delegate to subagent type `wr-risk-scorer:pipeline` via the Agent tool.
219
+ - **Fallback**: invoke `/wr-risk-scorer:assess-release` via the Skill tool when the subagent type is unavailable.
220
+
221
+ Commit message:
222
+
223
+ ```
224
+ docs(rfcs): capture RFC-<NNN> <title>
225
+
226
+ Refs: RFC-<NNN>
227
+ ```
228
+
229
+ The `capture` verb mirrors `capture-problem`'s audit signal (lightweight aside path vs. heavyweight `manage-rfc` intake). The `Refs: RFC-<NNN>` trailer is the commit-message RFC trailer convention per ADR-060 finding 8 + Phase 1 item 12 (the trailer-recognition hook lands in Slice 3 task B5.T9).
230
+
231
+ ### 7. Report
232
+
233
+ After the commit, report:
234
+
235
+ - The new RFC file path and ID.
236
+ - The traced problems with their lifecycle states (Open / Known Error / Verifying / Closed / Parked).
237
+ - Any advisory warnings (Verifying, Closed, Parked traces).
238
+ - Trailing pointer: `Run /wr-itil:manage-rfc <RFC-<NNN>> next to populate Scope / Tasks and advance to accepted; refresh docs/rfcs/README.md.`
239
+
240
+ The trailing pointer is **not optional** — it is the user-visible signal that the RFC is intentionally skeleton-only and how to advance it.
241
+
242
+ ## Composition with manage-rfc
243
+
244
+ | Concern | manage-rfc | capture-rfc |
245
+ |---------|------------|-------------|
246
+ | Problem-trace I1 enforcement | Hard-block at lifecycle transitions to irreversible states; advisory at `→ closed` | Hard-block at capture-time; deny logged to `logs/rfc-capture-denials.jsonl` |
247
+ | Multi-RFC / meta-RFC coordination | Step 9 review supports cross-RFC re-rank + meta-RFC ADR creation | Out of scope: capture-rfc creates one RFC per invocation |
248
+ | Skeleton-fill | Full-intake; AskUserQuestion for missing fields; deviation-approval on scope expansion | Deferred-placeholder pattern; one optional taste prompt only |
249
+ | README refresh | P094 / P062 inline (regenerate + stage in same commit) | Deferred to `/wr-itil:manage-rfc review` or `wr-itil-reconcile-rfcs` (Slice 3) |
250
+ | Status transitions | Step 7 owns proposed → accepted → in-progress → verifying → closed | Out of scope (creation only) |
251
+ | Commit grain | One commit per intake / per transition | One commit per capture |
252
+ | Use case | Full lifecycle management | Aside-invocation; capture-and-continue |
253
+
254
+ The two skills share the `/tmp/wr-itil-rfc-capture-grep-${SESSION_ID}` create-gate marker (sibling to `/tmp/manage-problem-grep-${SESSION_ID}`; sibling-marker option per architect verdict on capture-rfc sub-decision (a) — preserves audit-trail per-surface granularity).
255
+
256
+ ## Related
257
+
258
+ - **ADR-060** — Problem-RFC-Story framework with mandatory problem-trace and unified problem ontology. Driving accepted ADR.
259
+ - **P170** — `docs/problems/170-...open.md` — driver problem ticket.
260
+ - **`docs/plans/170-rfc-framework-story-map.md`** — Slice 2 task B5.T3 lands this skill.
261
+ - **JTBD-008** — Decompose a Fix Into Coordinated Changes. Primary persona-anchor.
262
+ - **JTBD-001** (extended scope) — change-set-level governance composition.
263
+ - **JTBD-101** (atomic-fix-adopter friction guard) — capture-rfc remains opt-in aside-invocation.
264
+ - **`docs/rfcs/README.md`** — RFC tier lifecycle index + frontmatter shape spec (Slice 2 tasks B5.T1 + B5.T2 — committed `adc53c8`).
265
+ - **ADR-014** — governance skills commit their own work. Single-commit grain per capture.
266
+ - **ADR-022** — problem lifecycle conventions; RFC lifecycle mirrors.
267
+ - **ADR-032** — governance-skill aside-invocation pattern. Lightweight + heavyweight split.
268
+ - **ADR-038** — progressive disclosure. SKILL.md (this file) + future REFERENCE.md split (deferred per ADR-054 — REFERENCE.md lands when SKILL.md size pressure surfaces empirically).
269
+ - **ADR-044** — decision delegation contract. Authority classes named in the Rule 6 audit table above.
270
+ - **ADR-049** — plugin-bundled scripts via `bin/` on `$PATH`. `wr-itil-reconcile-rfcs` shim follows this grammar (Slice 3 B5.T7).
271
+ - **ADR-051** — load-bearing-from-the-start. I1 hard-block ships behaviourally on day one, not deferred.
272
+ - **ADR-052** — behavioural-tests default. Bats coverage in Slice 2 task B5.T5 (no structural grep on SKILL.md content per P081).
273
+ - **P057** — staging trap rule (re-stage after Edit) — applies to capture-rfc only when an Edit follows the Write (rare; lifecycle-transition territory belongs to manage-rfc).
274
+ - **P078** capture-on-correction — capture-rfc may be the correct response to a strong-signal user correction that names multi-commit work; orchestrators should offer capture-rfc as one option in the capture menu.
275
+ - **P119** — create-gate marker. Hook generalisation per architect verdict on sub-decision (a) — `manage-problem-enforce-create.sh` widens to also accept `docs/rfcs/RFC-*.proposed.md` Writes, with case-branched deny messages naming the right skill (capture-rfc vs capture-problem).
276
+ - **P132** + inverse-P078 — mechanical-stage carve-outs prevent over-asking; named in the Rule 6 audit table.