@windyroad/architect 0.15.3-preview.593 → 0.15.4-preview.598
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.
|
@@ -124,7 +124,7 @@ cat <<EOF
|
|
|
124
124
|
"hookSpecificOutput": {
|
|
125
125
|
"hookEventName": "PreToolUse",
|
|
126
126
|
"permissionDecision": "deny",
|
|
127
|
-
"permissionDecisionReason": "BLOCKED: Cannot edit '${BASENAME}' without architecture review. You MUST first delegate to wr-architect:agent using the Agent tool (subagent_type: 'wr-architect:agent'). The architect will review against existing decisions in docs/decisions/ and flag if a new decision should be documented. After the review completes, this file will be unblocked automatically."
|
|
127
|
+
"permissionDecisionReason": "BLOCKED: Cannot edit '${BASENAME}' without architecture review. You MUST first delegate to wr-architect:agent using the Agent tool (subagent_type: 'wr-architect:agent'). The architect will review against existing decisions in docs/decisions/ and flag if a new decision should be documented. After the review completes, this file will be unblocked automatically. ${ARCHITECT_GATE_REASON}"
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
EOF
|
|
@@ -35,7 +35,7 @@ cat <<EOF
|
|
|
35
35
|
"hookSpecificOutput": {
|
|
36
36
|
"hookEventName": "PreToolUse",
|
|
37
37
|
"permissionDecision": "deny",
|
|
38
|
-
"permissionDecisionReason": "BLOCKED: Architect must review the plan file before exiting plan mode. You MUST first delegate to wr-architect:agent using the Agent tool (subagent_type: 'wr-architect:agent') to review the plan against existing decisions in docs/decisions/. After the review completes, this will be unblocked automatically."
|
|
38
|
+
"permissionDecisionReason": "BLOCKED: Architect must review the plan file before exiting plan mode. You MUST first delegate to wr-architect:agent using the Agent tool (subagent_type: 'wr-architect:agent') to review the plan against existing decisions in docs/decisions/. After the review completes, this will be unblocked automatically. ${ARCHITECT_GATE_REASON}"
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
EOF
|
|
@@ -8,6 +8,12 @@ _ARCHITECT_GATE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
8
8
|
source "$_ARCHITECT_GATE_DIR/gate-helpers.sh"
|
|
9
9
|
|
|
10
10
|
# Check architect gate marker. Returns 0 if marker is valid (allow), 1 if invalid (deny).
|
|
11
|
+
# Sets ARCHITECT_GATE_REASON on failure with an explicit recovery directive
|
|
12
|
+
# naming the wr-architect:agent subagent_type (P215 / RFC-021 — mirrors the
|
|
13
|
+
# sibling REVIEW_GATE_REASON pattern in review-gate.sh). Downstream
|
|
14
|
+
# enforcement hooks (architect-enforce-edit.sh, architect-plan-enforce.sh)
|
|
15
|
+
# append this reason to their BLOCKED deny message so the agent sees a clear
|
|
16
|
+
# recovery affordance without having to read source.
|
|
11
17
|
# Usage: check_architect_gate "$SESSION_ID"
|
|
12
18
|
check_architect_gate() {
|
|
13
19
|
local SESSION_ID="$1"
|
|
@@ -38,6 +44,7 @@ check_architect_gate() {
|
|
|
38
44
|
fi
|
|
39
45
|
if [ "$STORED" != "$CURRENT" ]; then
|
|
40
46
|
rm -f "$MARKER" "$HASH_FILE"
|
|
47
|
+
ARCHITECT_GATE_REASON="Decision drift detected — docs/decisions/ changed substantively since the last architect review. Re-delegate to wr-architect:agent via the Agent tool (subagent_type: 'wr-architect:agent') to refresh the marker."
|
|
41
48
|
return 1 # Drift detected, deny
|
|
42
49
|
else
|
|
43
50
|
touch "$MARKER" # Slide TTL window forward
|
|
@@ -49,10 +56,12 @@ check_architect_gate() {
|
|
|
49
56
|
fi
|
|
50
57
|
else
|
|
51
58
|
rm -f "$MARKER"
|
|
59
|
+
ARCHITECT_GATE_REASON="Architect review expired (${AGE}s old, TTL ${TTL_SECONDS}s). Re-delegate to wr-architect:agent via the Agent tool (subagent_type: 'wr-architect:agent') to refresh the marker."
|
|
52
60
|
return 1 # TTL expired, deny
|
|
53
61
|
fi
|
|
54
62
|
fi
|
|
55
63
|
|
|
64
|
+
ARCHITECT_GATE_REASON="No architect review marker found for this session. Delegate to wr-architect:agent via the Agent tool (subagent_type: 'wr-architect:agent') so the architect can review and create the marker."
|
|
56
65
|
return 1 # No marker, deny
|
|
57
66
|
}
|
|
58
67
|
|
|
@@ -30,3 +30,59 @@ teardown() {
|
|
|
30
30
|
ARCHITECT_TTL=0 run check_architect_gate "$TEST_SESSION"
|
|
31
31
|
[ "$status" -ne 0 ]
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
# P215 / RFC-021 — ARCHITECT_GATE_REASON behaviour. The gate must expose a
|
|
35
|
+
# differentiated reason per failure mode (no marker / TTL expired / drift
|
|
36
|
+
# detected) so the downstream deny message carries a clear recovery directive.
|
|
37
|
+
# Mirrors sibling REVIEW_GATE_REASON pattern in jtbd/voice-tone/style-guide
|
|
38
|
+
# review-gate.sh.
|
|
39
|
+
|
|
40
|
+
@test "ARCHITECT_GATE_REASON names re-delegate directive when no marker" {
|
|
41
|
+
ARCHITECT_GATE_REASON=""
|
|
42
|
+
check_architect_gate "$TEST_SESSION" || true
|
|
43
|
+
[[ "$ARCHITECT_GATE_REASON" == *"wr-architect:agent"* ]]
|
|
44
|
+
[[ "$ARCHITECT_GATE_REASON" == *"Agent tool"* ]]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@test "ARCHITECT_GATE_REASON names re-delegate directive when TTL expired" {
|
|
48
|
+
touch "/tmp/architect-reviewed-${TEST_SESSION}"
|
|
49
|
+
ARCHITECT_GATE_REASON=""
|
|
50
|
+
ARCHITECT_TTL=0 check_architect_gate "$TEST_SESSION" || true
|
|
51
|
+
[[ "$ARCHITECT_GATE_REASON" == *"expired"* ]]
|
|
52
|
+
[[ "$ARCHITECT_GATE_REASON" == *"wr-architect:agent"* ]]
|
|
53
|
+
[[ "$ARCHITECT_GATE_REASON" == *"refresh the marker"* ]]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@test "ARCHITECT_GATE_REASON names drift directive when stored hash differs" {
|
|
57
|
+
# Set up project root with a docs/decisions directory and a stored hash that
|
|
58
|
+
# differs from the current substance hash to force the drift branch.
|
|
59
|
+
TEST_PROJECT_DIR=$(mktemp -d)
|
|
60
|
+
mkdir -p "$TEST_PROJECT_DIR/docs/decisions"
|
|
61
|
+
echo "# ADR-001 current content" > "$TEST_PROJECT_DIR/docs/decisions/001-x.md"
|
|
62
|
+
touch "/tmp/architect-reviewed-${TEST_SESSION}"
|
|
63
|
+
echo "stale-hash-that-will-not-match" > "/tmp/architect-reviewed-${TEST_SESSION}.hash"
|
|
64
|
+
ARCHITECT_GATE_REASON=""
|
|
65
|
+
CLAUDE_PROJECT_DIR="$TEST_PROJECT_DIR" check_architect_gate "$TEST_SESSION" || true
|
|
66
|
+
rm -rf "$TEST_PROJECT_DIR"
|
|
67
|
+
[[ "$ARCHITECT_GATE_REASON" == *"drift"* ]] || [[ "$ARCHITECT_GATE_REASON" == *"changed"* ]]
|
|
68
|
+
[[ "$ARCHITECT_GATE_REASON" == *"wr-architect:agent"* ]]
|
|
69
|
+
[[ "$ARCHITECT_GATE_REASON" == *"refresh the marker"* ]]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@test "architect-enforce-edit deny output includes ARCHITECT_GATE_REASON directive" {
|
|
73
|
+
HOOK="$SCRIPT_DIR/architect-enforce-edit.sh"
|
|
74
|
+
ORIG_DIR="$PWD"
|
|
75
|
+
TEST_DIR=$(mktemp -d)
|
|
76
|
+
cd "$TEST_DIR"
|
|
77
|
+
mkdir -p docs/decisions
|
|
78
|
+
echo "# adr stub" > docs/decisions/001-x.md
|
|
79
|
+
json="{\"tool_input\":{\"file_path\":\"$PWD/src/x.ts\"},\"session_id\":\"deny-test-$$\"}"
|
|
80
|
+
run bash -c "echo '$json' | bash '$HOOK'"
|
|
81
|
+
cd "$ORIG_DIR"
|
|
82
|
+
rm -rf "$TEST_DIR"
|
|
83
|
+
[[ "$output" == *"BLOCKED"* ]]
|
|
84
|
+
[[ "$output" == *"wr-architect:agent"* ]]
|
|
85
|
+
# No marker exists for this fresh session — deny reason must explicitly
|
|
86
|
+
# name the re-delegate directive (not vague "review required").
|
|
87
|
+
[[ "$output" == *"No architect review marker"* ]] || [[ "$output" == *"marker"* ]]
|
|
88
|
+
}
|