@windyroad/architect 0.7.4 → 0.8.0-preview.387

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.
@@ -123,5 +123,5 @@
123
123
  }
124
124
  },
125
125
  "name": "wr-architect",
126
- "version": "0.7.4"
126
+ "version": "0.8.0"
127
127
  }
package/README.md CHANGED
@@ -43,6 +43,22 @@ This walks you through creating an ADR in [MADR 4.0](https://adr.github.io/madr/
43
43
 
44
44
  The `capture-adr` skill is the foreground-lightweight aside-invocation variant of `create-adr` (per ADR-032 background-capture pattern). Use it when an architecture decision surfaces mid-conversation and you want the ADR scaffold drafted without losing the operational thread.
45
45
 
46
+ **Review recorded decisions that lack human oversight:**
47
+
48
+ ```
49
+ /wr-architect:review-decisions
50
+ ```
51
+
52
+ The `review-decisions` skill drains the set of ADRs that were recorded without a human confirming the chosen option (per ADR-066). It surfaces each decision's chosen option and alternatives via AskUserQuestion so you confirm, amend, or reject the auto-made call, then writes a `human-oversight: confirmed` marker. Detection is a token-cheap grep over ADR frontmatter; a session-start nudge reports the unoversighted count. New ADRs created through `create-adr` are born oversighted, so the unconfirmed set only shrinks.
53
+
54
+ **Run an on-demand architecture compliance review:**
55
+
56
+ ```
57
+ /wr-architect:review-design
58
+ ```
59
+
60
+ The `review-design` skill checks staged changes and recent commits against the existing ADRs in `docs/decisions/` — a pre-flight you can run before editing architecture-bearing files or cutting a release, without waiting for the per-edit gate.
61
+
46
62
  ## How It Works
47
63
 
48
64
  | Hook | Trigger | What it does |
@@ -53,6 +69,7 @@ The `capture-adr` skill is the foreground-lightweight aside-invocation variant o
53
69
  | `architect-mark-reviewed.sh` | Agent completes | Marks the review as done (TTL: 3600s) |
54
70
  | `architect-refresh-hash.sh` | After edit | Refreshes the content hash so the next edit triggers a fresh review |
55
71
  | `architect-slide-marker.sh` | Agent or Bash | Slides the review marker forward across non-edit operations so an active review session is not invalidated by intervening Bash or sub-agent calls |
72
+ | `architect-oversight-nudge.sh` | Session start | Reports how many recorded decisions lack human oversight and points to `/wr-architect:review-decisions`; silent when none, and self-suppressed inside AFK iterations |
56
73
 
57
74
  ## Agent
58
75
 
@@ -62,26 +79,6 @@ The `wr-architect:agent` reviews proposed changes against existing decisions in
62
79
  - Whether a new ADR should be created
63
80
  - Whether existing decisions are stale and need reassessment
64
81
 
65
- ## Jobs to be Done
66
-
67
- This plugin serves the [Jobs to be Done](../../docs/jtbd/) below. Per [ADR-051](../../docs/decisions/051-jtbd-anchored-readme-with-drift-advisory.proposed.md), the persona-grouped JTBD anchor is the canonical source of truth for the README's value framing.
68
-
69
- ### Tech lead / consultant
70
-
71
- - **[JTBD-202 Run Pre-Flight Governance Checks Before Release or Handover](../../docs/jtbd/tech-lead/JTBD-202-pre-flight-governance-check.proposed.md)** — architect review is available via `/wr-architect:review-design` for on-demand pre-flight, and via `wr-architect:agent` for automatic review on every edit.
72
-
73
- ### Solo developer
74
-
75
- - **[JTBD-001 Enforce Governance Without Slowing Down](../../docs/jtbd/solo-developer/JTBD-001-enforce-governance.proposed.md)** — architecture decisions are reviewed automatically; the agent reads the project's existing ADRs without needing to be told what to look for.
76
-
77
- ### Plugin developer
78
-
79
- - **[JTBD-101 Extend the Suite with New Plugins](../../docs/jtbd/plugin-developer/JTBD-101-extend-suite.proposed.md)** — `/wr-architect:create-adr` is the canonical surface for documenting structural decisions in MADR 4.0 format so contributors learn the "why" behind existing patterns.
80
-
81
- ### Plugin user
82
-
83
- - **[JTBD-302 Trust That the README Describes the Plugin I Just Installed](../../docs/jtbd/plugin-user/JTBD-302-trust-readme-describes-installed-behaviour.proposed.md)** — this README is anchored on current JTBD job IDs; drift between prose and shipped behaviour is detectable at retro time per ADR-051.
84
-
85
82
  ## Updating and Uninstalling
86
83
 
87
84
  ```bash
package/agents/agent.md CHANGED
@@ -62,7 +62,9 @@ Flag when a proposed change represents an undocumented decision:
62
62
  - **New script**: Does this introduce a new workflow step?
63
63
  - **Structural change**: Does this reorganize code in a way that affects how the team works?
64
64
 
65
- ### Runtime-Path Performance Review (per ADR-023)
65
+ ### Runtime-Path Performance Review (per ADR-026, specialised by ADR-023)
66
+
67
+ This review is grounded in ADR-026 (Agent output grounding) — the parent no-ungrounded-claims principle — as specialised by ADR-023 (wr-architect performance review scope) for runtime-path changes. The qualitative-claim ban below is the ADR-026 grounding requirement applied to performance estimates.
66
68
 
67
69
  When a proposed change touches any of the following runtime-path surfaces, you MUST perform a per-request performance review in addition to the ADR-conformance review:
68
70
 
@@ -128,9 +130,34 @@ If there are issues:
128
130
  >
129
131
  > 2. ...
130
132
 
133
+ If a new decision must be recorded but it has 2+ viable options and no pinned direction (per ADR-064 (Architect Needs-Direction verdict)):
134
+
135
+ > **Architecture Review: NEEDS DIRECTION**
136
+ >
137
+ > A decision must be recorded but the option is not pinned — the user, not the agent, owns this choice.
138
+ >
139
+ > - **Decision question**: <the question to settle, in one line>
140
+ > - **Option A** — <name + one-line, grounded in what you read>
141
+ > - **Option B** — <name + one-line, grounded in what you read>
142
+ > - (further options as applicable; include "do nothing / status quo" where relevant)
143
+ > - **Advisory lean (optional)**: <your recommendation + why — but do NOT auto-pick, and do NOT prose-ask>
144
+ >
145
+ > The main agent (or calling skill) translates this into an `AskUserQuestion` before the decision is recorded — never a prose ask. Under an AFK orchestrator that cannot ask mid-loop, the verdict queues to the iteration's `outstanding_questions` for batched return-presentation (ADR-044 (Decision-delegation contract)), never blocking or guessing.
146
+
147
+ ### When to emit Needs Direction (per ADR-064)
148
+
149
+ Emit **NEEDS DIRECTION** only when ALL of the following hold:
150
+
151
+ 1. The change requires recording a new decision (you would otherwise flag `[Undocumented Decision]`).
152
+ 2. There are **2+ viable options**.
153
+ 3. **No direction is pinned.** Direction counts as pinned — and you must NOT ask, instead reporting PASS / ISSUES FOUND and naming the pinned source — when the option is fixed by any of: a same-turn pin, a same-session pin, an accepted ADR, `RISK-POLICY.md` appetite, or a CLAUDE.md mandatory rule.
154
+
155
+ Do NOT emit Needs Direction for the "obvious choice" / only-one-viable-option case (see "When NOT to flag" above) — over-firing on obvious choices is the over-ask trap CLAUDE.md P132 warns against. Needs Direction is the architect-surface instance of ADR-044 category 1 (direction-setting); `AskUserQuestion` remains a primary-agent affordance — you name the question + options, the main agent owns the ask.
156
+
131
157
  Issue types:
132
158
  - **[Decision Conflict]**: Change conflicts with an accepted/proposed decision
133
159
  - **[Undocumented Decision]**: Change represents an architectural choice not covered by any existing decision
160
+ - **[Needs Direction]**: A new decision must be recorded but has 2+ viable options with no pinned direction — name the question + options for the main agent to translate into an `AskUserQuestion` (ADR-064)
134
161
  - **[Decision Format]**: A decision file doesn't follow MADR 4.0 format
135
162
  - **[Missing Supersession]**: A new decision should supersede an old one but doesn't
136
163
  - **[Confirmation Violation]**: New code violates a confirmation criterion of an existing decision
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bats
2
+ # Doc-lint guard: architect agent.md must carry the NEEDS DIRECTION verdict
3
+ # type (ADR-064) so the architect names the question + viable options for an
4
+ # unpinned 2+-option decision instead of auto-picking or prose-asking, and the
5
+ # main agent translates it into an AskUserQuestion.
6
+ #
7
+ # tdd-review: structural-permitted (justification: P176 — agent behaviour is
8
+ # prompt-driven with no skill-invocation harness to exercise the verdict
9
+ # behaviourally; ADR-052 Surface 2 structural-justified case, NOT an ADR-005
10
+ # Permitted Exception — ADR-052 narrows ADR-005 to exclude prose-doc greps).
11
+ # When P176 lands, upgrade to a behavioural test per ADR-064 Confirmation item 2.
12
+ #
13
+ # Cross-reference:
14
+ # P283 (architect should AskUserQuestion when recording a new decision)
15
+ # ADR-064 (Architect Needs-Direction verdict; main agent owns the AskUserQuestion)
16
+ # ADR-052 Surface 2 (structural-justified verdict) + P176 (harness gap)
17
+ # @jtbd JTBD-001 (enforce governance without slowing down)
18
+
19
+ setup() {
20
+ AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
21
+ AGENT_FILE="${AGENT_DIR}/agent.md"
22
+ }
23
+
24
+ @test "agent.md carries a NEEDS DIRECTION report verdict (ADR-064)" {
25
+ run grep -n "Architecture Review: NEEDS DIRECTION" "$AGENT_FILE"
26
+ [ "$status" -eq 0 ]
27
+ }
28
+
29
+ @test "agent.md lists [Needs Direction] as an issue/verdict type" {
30
+ run grep -n "\[Needs Direction\]" "$AGENT_FILE"
31
+ [ "$status" -eq 0 ]
32
+ }
33
+
34
+ @test "agent.md has a 'When to emit Needs Direction' section citing ADR-064" {
35
+ run grep -n "When to emit Needs Direction" "$AGENT_FILE"
36
+ [ "$status" -eq 0 ]
37
+ run grep -n "ADR-064" "$AGENT_FILE"
38
+ [ "$status" -eq 0 ]
39
+ }
40
+
41
+ @test "agent.md requires the main agent to translate the verdict into AskUserQuestion (not prose)" {
42
+ run grep -n "AskUserQuestion" "$AGENT_FILE"
43
+ [ "$status" -eq 0 ]
44
+ }
45
+
46
+ @test "agent.md guards the negative bound: do NOT emit Needs Direction on obvious/single-option choices" {
47
+ # inverse-P078 over-ask guard — the verdict must not fire when only one viable option exists
48
+ run grep -niE "Do NOT emit Needs Direction.*(obvious|one-viable|only-one)" "$AGENT_FILE"
49
+ [ "$status" -eq 0 ]
50
+ }
51
+
52
+ @test "agent.md performance-review section cites ADR-026 as parent (ADR-026 Confirmation item 1)" {
53
+ run grep -nE "Runtime-Path Performance Review \(per ADR-026" "$AGENT_FILE"
54
+ [ "$status" -eq 0 ]
55
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+ # ADR-049 $PATH shim — dispatches to the canonical detect-unoversighted script.
3
+ exec "$(dirname "$0")/../scripts/detect-unoversighted.sh" "$@"
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ # wr-architect — SessionStart hook (ADR-066)
3
+ #
4
+ # Surfaces a one-line nudge when recorded decisions (ADRs) lack the
5
+ # human-oversight marker, so the user can drain them via
6
+ # /wr-architect:review-decisions. Modelled on the ADR-040 session-start
7
+ # briefing surface and packages/itil/hooks/itil-pending-questions-surface.sh.
8
+ #
9
+ # Detection is token-cheap: it delegates to detect-unoversighted.sh (a grep
10
+ # over ADR frontmatter — no body reads, no per-ADR LLM call). Silent when the
11
+ # unoversighted count is zero (steady state once the set is drained).
12
+ #
13
+ # AFK self-suppress (JTBD-006 friction guard): AFK orchestrators set
14
+ # WR_SUPPRESS_OVERSIGHT_NUDGE=1 before spawning each `claude -p` iteration so
15
+ # this interactive batch-confirm nudge never fires into an absent-user
16
+ # subprocess (the same discipline itil-pending-questions-surface.sh applies
17
+ # with WR_SUPPRESS_PENDING_QUESTIONS). Only the literal "1" suppresses.
18
+
19
+ set -euo pipefail
20
+
21
+ if [ "${WR_SUPPRESS_OVERSIGHT_NUDGE:-}" = "1" ]; then
22
+ exit 0
23
+ fi
24
+
25
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
26
+ DECISIONS_DIR="$PROJECT_DIR/docs/decisions"
27
+
28
+ # Silent when this project has no decision records.
29
+ [ -d "$DECISIONS_DIR" ] || exit 0
30
+
31
+ DETECT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}/scripts/detect-unoversighted.sh"
32
+ [ -x "$DETECT" ] || DETECT="$(dirname "$0")/../scripts/detect-unoversighted.sh"
33
+
34
+ # Count unoversighted ADRs. `grep -c .` counts non-empty lines; tolerate the
35
+ # detector printing nothing (count 0).
36
+ COUNT="$(bash "$DETECT" "$DECISIONS_DIR" 2>/dev/null | grep -c . || true)"
37
+ COUNT="${COUNT:-0}"
38
+
39
+ # Silent-on-no-content per ADR-040 Mechanism step 1.
40
+ [ "$COUNT" -gt 0 ] 2>/dev/null || exit 0
41
+
42
+ if [ "$COUNT" -eq 1 ]; then
43
+ echo "[wr-architect] 1 recorded decision lacks human oversight — run /wr-architect:review-decisions to confirm it."
44
+ else
45
+ echo "[wr-architect] $COUNT recorded decisions lack human oversight — run /wr-architect:review-decisions to confirm them."
46
+ fi
package/hooks/hooks.json CHANGED
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "hooks": {
3
+ "SessionStart": [
4
+ { "matcher": "startup", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-oversight-nudge.sh" }] }
5
+ ],
3
6
  "UserPromptSubmit": [
4
7
  { "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-detect.sh" }] }
5
8
  ],
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bats
2
+
3
+ # ADR-066: architect-oversight-nudge.sh (SessionStart) emits a one-line nudge
4
+ # when ADRs lack the human-oversight marker, is silent when none do, and
5
+ # self-suppresses under the AFK guard (WR_SUPPRESS_OVERSIGHT_NUDGE=1) so the
6
+ # interactive batch-confirm never fires into an absent-user iteration (JTBD-006).
7
+ # Behavioural — exercises the hook against fixture trees and asserts on stdout.
8
+
9
+ setup() {
10
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
11
+ HOOK="$REPO_ROOT/packages/architect/hooks/architect-oversight-nudge.sh"
12
+ PLUGIN_ROOT="$REPO_ROOT/packages/architect"
13
+ DIR="$(mktemp -d)"
14
+ mkdir -p "$DIR/docs/decisions"
15
+ }
16
+
17
+ teardown() {
18
+ rm -rf "$DIR"
19
+ }
20
+
21
+ mk_unmarked() {
22
+ { echo "---"; echo "status: \"proposed\""; echo "date: 2026-05-25"; echo "---"; echo "# $1"; } \
23
+ > "$DIR/docs/decisions/$1"
24
+ }
25
+ mk_marked() {
26
+ { echo "---"; echo "status: \"proposed\""; echo "date: 2026-05-25"; echo "human-oversight: confirmed"; echo "---"; echo "# $1"; } \
27
+ > "$DIR/docs/decisions/$1"
28
+ }
29
+
30
+ @test "emits a count line when there are unoversighted ADRs" {
31
+ mk_unmarked "010-a.proposed.md"
32
+ mk_unmarked "011-b.proposed.md"
33
+ run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
34
+ [ "$status" -eq 0 ]
35
+ [[ "$output" == *"2 recorded decisions lack human oversight"* ]]
36
+ [[ "$output" == *"/wr-architect:review-decisions"* ]]
37
+ }
38
+
39
+ @test "uses singular wording for exactly one unoversighted ADR" {
40
+ mk_unmarked "010-a.proposed.md"
41
+ run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
42
+ [[ "$output" == *"1 recorded decision lacks human oversight"* ]]
43
+ }
44
+
45
+ @test "silent when every ADR is confirmed" {
46
+ mk_marked "010-a.proposed.md"
47
+ run env CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
48
+ [ "$status" -eq 0 ]
49
+ [ -z "$output" ]
50
+ }
51
+
52
+ @test "AFK guard suppresses the nudge entirely" {
53
+ mk_unmarked "010-a.proposed.md"
54
+ run env WR_SUPPRESS_OVERSIGHT_NUDGE=1 CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
55
+ [ "$status" -eq 0 ]
56
+ [ -z "$output" ]
57
+ }
58
+
59
+ @test "guard value other than 1 does not suppress" {
60
+ mk_unmarked "010-a.proposed.md"
61
+ mk_unmarked "011-b.proposed.md"
62
+ run env WR_SUPPRESS_OVERSIGHT_NUDGE=0 CLAUDE_PROJECT_DIR="$DIR" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
63
+ [[ "$output" == *"lack human oversight"* ]]
64
+ }
65
+
66
+ @test "silent when project has no docs/decisions dir" {
67
+ run env CLAUDE_PROJECT_DIR="$DIR/empty" CLAUDE_PLUGIN_ROOT="$PLUGIN_ROOT" bash "$HOOK"
68
+ [ "$status" -eq 0 ]
69
+ [ -z "$output" ]
70
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/architect",
3
- "version": "0.7.4",
3
+ "version": "0.8.0-preview.387",
4
4
  "description": "Architecture decision enforcement for AI coding agents",
5
5
  "bin": {
6
6
  "windyroad-architect": "./bin/install.mjs"
@@ -23,6 +23,7 @@
23
23
  "agents/",
24
24
  "hooks/",
25
25
  "skills/",
26
+ "scripts/",
26
27
  ".claude-plugin/",
27
28
  "lib/"
28
29
  ]
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ # wr-architect — detect ADRs lacking the human-oversight marker (ADR-066)
3
+ #
4
+ # Token-cheap detection: greps each ADR's YAML frontmatter for the presence of
5
+ # `human-oversight: confirmed`. No body reads, no per-ADR LLM call. An ADR is
6
+ # "unoversighted" when its frontmatter does not carry that marker line (or has
7
+ # no frontmatter at all).
8
+ #
9
+ # Usage:
10
+ # detect-unoversighted.sh [DECISIONS_DIR]
11
+ # DECISIONS_DIR defaults to docs/decisions
12
+ #
13
+ # Output: one unoversighted ADR file path per line, sorted. Empty output = the
14
+ # whole set is confirmed. Callers derive the count with `grep -c .` / `wc -l`.
15
+ # Always exits 0 (it is a detector, not a gate).
16
+ #
17
+ # Consumed by: architect-oversight-nudge.sh (SessionStart count) and
18
+ # /wr-architect:review-decisions (the drain list). Marker contract: ADR-066.
19
+
20
+ set -euo pipefail
21
+
22
+ DECISIONS_DIR="${1:-docs/decisions}"
23
+
24
+ [ -d "$DECISIONS_DIR" ] || exit 0
25
+
26
+ # Match both the flat layout (docs/decisions/*.md) and any per-state subdir
27
+ # layout an adopter might introduce later (docs/decisions/*/*.md). README is
28
+ # never a decision record.
29
+ shopt -s nullglob
30
+ for f in "$DECISIONS_DIR"/*.md "$DECISIONS_DIR"/*/*.md; do
31
+ base="$(basename "$f")"
32
+ [ "$base" = "README.md" ] && continue
33
+ # Superseded decisions are retired — a newer ADR replaced them. Confirming a
34
+ # dead decision has no value, so they are not part of the "needs oversight"
35
+ # set (keeps the nudge count and the drain queue focused on live decisions).
36
+ case "$base" in *.superseded.md) continue ;; esac
37
+
38
+ # Extract the frontmatter block: lines between the leading `---` and the
39
+ # next `---`. If line 1 is not `---`, the file has no frontmatter and the
40
+ # awk prints nothing → treated as unoversighted.
41
+ fm="$(awk '
42
+ NR==1 && $0 != "---" { exit }
43
+ NR==1 { next }
44
+ /^---[[:space:]]*$/ { exit }
45
+ { print }
46
+ ' "$f")"
47
+
48
+ if ! printf '%s\n' "$fm" | grep -qiE '^human-oversight:[[:space:]]*confirmed[[:space:]]*$'; then
49
+ echo "$f"
50
+ fi
51
+ done | sort
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env bats
2
+
3
+ # ADR-066: detect-unoversighted.sh prints ADRs whose frontmatter lacks the
4
+ # `human-oversight: confirmed` marker. Behavioural — exercises the script
5
+ # against fixture trees and asserts on its stdout, not its source text.
6
+
7
+ setup() {
8
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
9
+ SCRIPT="$REPO_ROOT/packages/architect/scripts/detect-unoversighted.sh"
10
+ DIR="$(mktemp -d)"
11
+ mkdir -p "$DIR/docs/decisions"
12
+ }
13
+
14
+ teardown() {
15
+ rm -rf "$DIR"
16
+ }
17
+
18
+ mk() { # mk <filename> <frontmatter-extra-lines...>
19
+ local name="$1"; shift
20
+ {
21
+ echo "---"
22
+ echo "status: \"proposed\""
23
+ echo "date: 2026-05-25"
24
+ for line in "$@"; do echo "$line"; done
25
+ echo "---"
26
+ echo "# $name"
27
+ } > "$DIR/docs/decisions/$name"
28
+ }
29
+
30
+ @test "an ADR without the marker is reported" {
31
+ mk "010-no-marker.proposed.md"
32
+ run bash "$SCRIPT" "$DIR/docs/decisions"
33
+ [ "$status" -eq 0 ]
34
+ [[ "$output" == *"010-no-marker.proposed.md"* ]]
35
+ }
36
+
37
+ @test "an ADR carrying human-oversight: confirmed is NOT reported" {
38
+ mk "011-confirmed.proposed.md" "human-oversight: confirmed" "oversight-date: 2026-05-25"
39
+ run bash "$SCRIPT" "$DIR/docs/decisions"
40
+ [ "$status" -eq 0 ]
41
+ [[ "$output" != *"011-confirmed.proposed.md"* ]]
42
+ }
43
+
44
+ @test "marker match is case-insensitive and tolerant of trailing space" {
45
+ mk "012-spacey.proposed.md" "human-oversight: confirmed "
46
+ run bash "$SCRIPT" "$DIR/docs/decisions"
47
+ [[ "$output" != *"012-spacey.proposed.md"* ]]
48
+ }
49
+
50
+ @test "README.md is never reported" {
51
+ echo "# index" > "$DIR/docs/decisions/README.md"
52
+ run bash "$SCRIPT" "$DIR/docs/decisions"
53
+ [[ "$output" != *"README.md"* ]]
54
+ }
55
+
56
+ @test "superseded ADRs are excluded even without the marker" {
57
+ mk "013-old.superseded.md"
58
+ run bash "$SCRIPT" "$DIR/docs/decisions"
59
+ [[ "$output" != *"013-old.superseded.md"* ]]
60
+ }
61
+
62
+ @test "a file with no frontmatter counts as unoversighted" {
63
+ echo "# bare ADR, no frontmatter" > "$DIR/docs/decisions/014-bare.proposed.md"
64
+ run bash "$SCRIPT" "$DIR/docs/decisions"
65
+ [[ "$output" == *"014-bare.proposed.md"* ]]
66
+ }
67
+
68
+ @test "a body line that looks like the marker does not count (frontmatter only)" {
69
+ {
70
+ echo "---"
71
+ echo "status: \"proposed\""
72
+ echo "date: 2026-05-25"
73
+ echo "---"
74
+ echo "# 015"
75
+ echo "human-oversight: confirmed" # in body, not frontmatter
76
+ } > "$DIR/docs/decisions/015-body-trick.proposed.md"
77
+ run bash "$SCRIPT" "$DIR/docs/decisions"
78
+ [[ "$output" == *"015-body-trick.proposed.md"* ]]
79
+ }
80
+
81
+ @test "accepted ADRs are in scope (oversight is orthogonal to status)" {
82
+ mk "016-shipped.accepted.md"
83
+ run bash "$SCRIPT" "$DIR/docs/decisions"
84
+ [[ "$output" == *"016-shipped.accepted.md"* ]]
85
+ }
86
+
87
+ @test "missing decisions dir exits 0 with no output" {
88
+ run bash "$SCRIPT" "$DIR/docs/nonexistent"
89
+ [ "$status" -eq 0 ]
90
+ [ -z "$output" ]
91
+ }
92
+
93
+ @test "fully-confirmed set produces empty output" {
94
+ mk "017-a.proposed.md" "human-oversight: confirmed"
95
+ mk "018-b.accepted.md" "human-oversight: confirmed"
96
+ run bash "$SCRIPT" "$DIR/docs/decisions"
97
+ [ "$status" -eq 0 ]
98
+ [ -z "$output" ]
99
+ }
@@ -168,6 +168,8 @@ After the commit, report:
168
168
 
169
169
  The trailing pointer is **not optional** — it is the user-visible signal that the skeleton needs canonical expansion before acceptance review.
170
170
 
171
+ **Confirm-every-ADR gate (ADR-064):** a capture-adr skeleton is recorded `proposed` with a pre-pinned decision but WITHOUT human review of the options. It must NOT be promoted to `accepted` until it has been through a `/wr-architect:create-adr` (or equivalent) `AskUserQuestion` review-and-confirm pass. Capture records the decision quickly; the confirm — not the capture — is what gives it human oversight. This is prong 1 of P283 (lift auto-/quick-recorded decisions to human-confirmed before they stand).
172
+
171
173
  ## Composition with create-adr
172
174
 
173
175
  | Concern | create-adr | capture-adr |
@@ -8,6 +8,10 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
8
8
 
9
9
  Create a new ADR in `docs/decisions/` following MADR 4.0 format. The wr-architect:agent reviews these files to enforce architectural compliance.
10
10
 
11
+ ## Needs-Direction handoff + confirm-every-ADR (ADR-064)
12
+
13
+ When a `wr-architect:agent` review returns a **NEEDS DIRECTION** verdict (a new decision with 2+ viable options and no pinned direction, per ADR-064), the option choice is the user's, not the agent's — this skill is the translation surface. The architect's named question + options become the Step 2 cat-1 `AskUserQuestion` calls (Considered Options / Decision Outcome), and the Step 5 confirm is the load-bearing **review-and-confirm-every-ADR** gate: an ADR must not stand as a human-oversighted decision (reach `accepted`) without that confirm pass. A `/wr-architect:capture-adr` skeleton — zero-ask precisely because its decision was pre-pinned in `$ARGUMENTS` — must be run through this skill's confirm before promotion to `accepted`. When direction IS already pinned (same-turn / same-session / accepted ADR / RISK-POLICY.md / CLAUDE.md mandatory rule), act on it — do not re-ask (P132 inverse-P078 guard).
14
+
11
15
  ## Steps
12
16
 
13
17
  ### 1. Discover existing decisions
@@ -194,6 +198,15 @@ Present the written ADR and use AskUserQuestion to ask:
194
198
 
195
199
  Apply any feedback by editing the file.
196
200
 
201
+ **Born-confirmed write (ADR-066).** Once the user confirms the ADR via this AskUserQuestion pass, write the human-oversight marker into the frontmatter — insert immediately after the `date:` line:
202
+
203
+ ```yaml
204
+ human-oversight: confirmed
205
+ oversight-date: YYYY-MM-DD # today
206
+ ```
207
+
208
+ This is the load-bearing born-confirmed gate: an ADR recorded through create-adr enters the world already human-oversighted (it does not appear in `/wr-architect:review-decisions`' unoversighted set). Do NOT write the marker if the user has not confirmed (rejected / still-iterating ADRs stay unmarked). The marker is orthogonal to `status:` — a `proposed` ADR can be `human-oversight: confirmed`.
209
+
197
210
  ### 6. Handle supersession (if applicable)
198
211
 
199
212
  If the user mentions this decision replaces an existing one:
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: wr-architect:review-decisions
3
+ description: Drain the set of recorded decisions (ADRs) that lack human oversight. Surfaces each unconfirmed ADR's chosen option and alternatives via AskUserQuestion so a human confirms, amends, or rejects the auto-made call, then writes the human-oversight marker. Use when the session-start nudge reports decisions lack oversight, or any time you want to review recorded decisions.
4
+ allowed-tools: Read, Glob, Grep, Bash, Edit, AskUserQuestion
5
+ ---
6
+
7
+ # Review Decisions — human-oversight drain
8
+
9
+ Lift auto-made architecture decisions to human decisions. Many ADRs were recorded autocratically — the architect proposed an option and it stood without a human picking it. This skill drains the **unoversighted set** (ADRs lacking `human-oversight: confirmed` in frontmatter, per ADR-066): it surfaces each decision's chosen option + the alternatives via `AskUserQuestion`, and writes the oversight marker only when a human confirms.
10
+
11
+ This is the P283 prong-2 drain surface. It is the eat-our-own-dogfood loop: confirming a decision is itself a human decision, so it goes through `AskUserQuestion`.
12
+
13
+ ## When to use
14
+
15
+ - The session-start nudge reported `N decisions lack human oversight`.
16
+ - Pre-handover / pre-release: confirm the recorded decision set reflects human intent.
17
+ - After a batch of AFK-recorded ADRs: review what landed without interactive confirmation.
18
+ - Any focused sitting — the drain is designed for **batches over multiple sittings**, not one blocking pass.
19
+
20
+ ## How it works
21
+
22
+ Each run drains as many ADRs as the user has appetite for, in topic-clustered batches. The marker persists (ADR-009 never-re-ask principle), so a partially-drained set resumes cleanly on the next run.
23
+
24
+ ### Step 1: Enumerate the unoversighted set
25
+
26
+ Run the detector (token-cheap — grep over frontmatter, no body reads):
27
+
28
+ ```bash
29
+ wr-architect-detect-unoversighted docs/decisions
30
+ ```
31
+
32
+ The `wr-architect-detect-unoversighted` command is a `$PATH`-resolved shim (ADR-049 naming grammar) dispatching `packages/architect/scripts/detect-unoversighted.sh`. It prints one unoversighted ADR path per line (superseded ADRs are excluded — a retired decision needs no confirmation). Empty output → the set is fully drained; report "all recorded decisions carry human oversight" and stop.
33
+
34
+ ### Step 2: Cluster + order
35
+
36
+ Read **only the frontmatter + title + Decision Outcome** of each unoversighted ADR (not full bodies — keep it cheap). Group by topic cluster (e.g. release-cadence, governance-gates, AFK-orchestration, decision-recording) and order **load-bearing first**: ADRs that other ADRs cite as parents, that are `accepted` (already shipped — highest drift cost if the auto-pick was wrong), or that govern a hook/gate the user interacts with daily. Defer narrow / low-coupling ADRs.
37
+
38
+ ### Step 3: Present each decision via AskUserQuestion (batched)
39
+
40
+ For each ADR in the ordered queue, surface the decision as an `AskUserQuestion` (cap **4 ADRs per call** per ADR-013 Rule 1; issue further calls sequentially). For each ADR:
41
+
42
+ - **Question**: the decision the ADR records (its Decision Outcome, in one line).
43
+ - **Context**: the chosen option + the alternatives the ADR considered (grounded in the ADR's Considered Options section per ADR-026), and any cited parent ADRs.
44
+ - **Options** (per ADR):
45
+ - **Confirm** — the recorded decision is correct; write the marker.
46
+ - **Amend** — the decision is mostly right but needs a change; capture the change, apply it to the ADR body, then write the marker.
47
+ - **Reject / supersede** — the auto-made pick is wrong; do NOT write the marker. Note the rework needed (a follow-up `/wr-architect:create-adr` supersede, or a problem ticket).
48
+ - **Defer** — skip this sitting; leave unoversighted for a later run.
49
+
50
+ This is a genuine human-decision surface (the whole point of P283) — `AskUserQuestion` is correct here and is NOT over-asking. Do not auto-confirm; do not prose-ask.
51
+
52
+ ### Step 4: Apply the outcome
53
+
54
+ - **Confirm / Amend**: write `human-oversight: confirmed` + `oversight-date: <today, YYYY-MM-DD>` into the ADR's frontmatter (insert after the `date:` line if absent; never duplicate). For Amend, apply the directed body change first. Both edits go through the standard architect / JTBD edit gate per ADR-014.
55
+ - **Reject / supersede**: leave the marker absent. Record the rework (follow-up create-adr supersede or `/wr-itil:capture-problem`).
56
+ - **Defer**: no write.
57
+
58
+ ### Step 5: Commit + report
59
+
60
+ Commit the confirmed/amended ADRs per ADR-014 (one commit for the sitting's drained batch is acceptable — the unit of work is "this drain sitting"). Report: how many confirmed / amended / rejected / deferred, and the remaining unoversighted count (re-run the detector). The session-start nudge count drops by the number confirmed.
61
+
62
+ ## Notes
63
+
64
+ - **Never re-ask** — a confirmed ADR carries the marker permanently and is excluded from future runs (ADR-009 never-re-ask principle). The marker is write-once **except** when an ADR is materially amended after confirmation (the Decision Outcome is rewritten) — a supersede/amend clears it for re-confirmation per ADR-066 Reassessment.
65
+ - **AFK** — this skill is interactive by construction (the confirm IS the human decision). It is not dispatched inside AFK iteration subprocesses; the session-start nudge self-suppresses there (`WR_SUPPRESS_OVERSIGHT_NUDGE=1`) so the drain is never half-run by an absent user.
66
+ - **Born-confirmed going forward** — `/wr-architect:create-adr` writes the marker at its Step 5 confirm, so new ADRs enter the set already oversighted and the unoversighted count only shrinks.
67
+
68
+ ## Related
69
+
70
+ - **ADR-066** — the oversight marker + this drain skill + the detector + the nudge.
71
+ - **ADR-064** — the architect Needs-Direction verdict; the main agent owns `AskUserQuestion` (this skill is that ownership applied to the existing set).
72
+ - **ADR-009** — never-re-ask persistent-marker principle (the marker, not its TTL/drift lifecycle).
73
+ - **ADR-013 / ADR-044** — structured user interaction + decision-delegation taxonomy.
74
+ - **P283** — driving problem ticket (prong 2).