@windyroad/itil 0.61.1 → 0.61.2
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 +7 -2
- package/agents/test/fixtures/proceed-new-genuinely-new.md +0 -43
- package/agents/test/fixtures/proceed-new-subtle-sibling.md +0 -47
- package/agents/test/fixtures/regression-p347-vs-p346.md +0 -54
- package/agents/test/hang-off-check.bats +0 -225
- package/hooks/test/block-list.bats +0 -153
- package/hooks/test/command-detect.bats +0 -181
- package/hooks/test/itil-assistant-output-gate.bats +0 -114
- package/hooks/test/itil-assistant-output-review.bats +0 -224
- package/hooks/test/itil-bash-polling-antipattern-detect.bats +0 -154
- package/hooks/test/itil-changeset-discipline.bats +0 -603
- package/hooks/test/itil-claude-space-protection.bats +0 -294
- package/hooks/test/itil-commit-trailer-transition-advisory.bats +0 -80
- package/hooks/test/itil-correction-detect.bats +0 -189
- package/hooks/test/itil-deferral-cadence-gate.bats +0 -187
- package/hooks/test/itil-fictional-defer-detect.bats +0 -292
- package/hooks/test/itil-fix-title-lifecycle-advisory.bats +0 -129
- package/hooks/test/itil-mid-loop-ask-detect.bats +0 -220
- package/hooks/test/itil-no-implement-draft-gate.bats +0 -210
- package/hooks/test/itil-pending-questions-surface.bats +0 -307
- package/hooks/test/itil-readme-refresh-discipline.bats +0 -642
- package/hooks/test/itil-rfc-oversight-nudge.bats +0 -83
- package/hooks/test/itil-rfc-trailer-advisory.bats +0 -375
- package/hooks/test/itil-story-mirror-migration-nudge.bats +0 -122
- package/hooks/test/manage-problem-enforce-create.bats +0 -424
- package/hooks/test/p057-staging-trap-detect.bats +0 -231
- package/hooks/test/pre-publish-intake-gate.bats +0 -144
- package/hooks/test/runtime-sid-marker.bats +0 -90
- package/hooks/test/session-id.bats +0 -370
- package/scripts/migrate-problems-add-type.sh +0 -116
- package/scripts/test/catchup-scan.bats +0 -274
- package/scripts/test/check-afk-accept-eligible.bats +0 -310
- package/scripts/test/check-fail-soft-skip-discipline.bats +0 -172
- package/scripts/test/check-fix-rfc-trace.bats +0 -164
- package/scripts/test/check-locale-discipline.bats +0 -291
- package/scripts/test/check-problems-readme-budget.bats +0 -192
- package/scripts/test/check-rfc-has-stories.bats +0 -69
- package/scripts/test/check-rfc-rejected-alternatives.bats +0 -108
- package/scripts/test/check-rfc-stories-ratified.bats +0 -82
- package/scripts/test/check-upstream-responses.bats +0 -503
- package/scripts/test/classify-readme-drift.bats +0 -392
- package/scripts/test/derive-first-dispatch.bats +0 -274
- package/scripts/test/derive-release-vehicle.bats +0 -454
- package/scripts/test/detect-unratified-stories-maps.bats +0 -60
- package/scripts/test/dual-tolerant-glob-rfc-002-t2.bats +0 -309
- package/scripts/test/effort-tally.bats +0 -170
- package/scripts/test/evaluate-relevance.bats +0 -773
- package/scripts/test/kind-a-commands.bats +0 -46
- package/scripts/test/mark-create-gate.bats +0 -59
- package/scripts/test/mark-story-oversight-confirmed.bats +0 -53
- package/scripts/test/migrate-problems-add-type.bats +0 -280
- package/scripts/test/migrate-story-status-mirror.bats +0 -167
- package/scripts/test/no-type-regression-guard.bats +0 -74
- package/scripts/test/oversight-mirror-corpus-lint.bats +0 -150
- package/scripts/test/plugin-exercise-index.bats +0 -386
- package/scripts/test/plugin-maturity-doc-lint.bats +0 -470
- package/scripts/test/plugin-maturity-populate.bats +0 -631
- package/scripts/test/plugin-maturity-render.bats +0 -469
- package/scripts/test/plugin-validate-ci-gate.bats +0 -208
- package/scripts/test/reconcile-readme.bats +0 -1007
- package/scripts/test/reconcile-rfcs.bats +0 -496
- package/scripts/test/reconcile-stories.bats +0 -173
- package/scripts/test/reconcile-story-maps.bats +0 -74
- package/scripts/test/release-watch-poll-loop.bats +0 -180
- package/scripts/test/resolve-governance-plugin-dirs.bats +0 -78
- package/scripts/test/rfc-stories-extension.bats +0 -175
- package/scripts/test/skill-invocations.bats +0 -535
- package/scripts/test/skill-md-dual-tolerant-coverage-rfc-002-t3.bats +0 -374
- package/scripts/test/story-oversight-lib.bats +0 -190
- package/scripts/test/update-jtbd-references-related-problems.bats +0 -178
- package/scripts/test/update-problem-references-section.bats +0 -242
- package/scripts/test/update-problem-rfcs-section.bats +0 -242
- package/scripts/test/update-references-section-sibling-helpers.bats +0 -80
- package/scripts/test/update-rfc-commits-section.bats +0 -77
- package/scripts/test/verify-iter-summary.bats +0 -196
- package/scripts/test/working-the-problem-traversal.bats +0 -116
- package/skills/capture-problem/test/capture-problem-step-1-5b-jtbd-trace.bats +0 -398
- package/skills/capture-problem/test/capture-problem.bats +0 -389
- package/skills/capture-story/test/capture-story-behavioural.bats +0 -317
- package/skills/capture-story-map/test/capture-story-map-behavioural.bats +0 -98
- package/skills/close-incident/test/close-incident-contract.bats +0 -146
- package/skills/link-incident/test/link-incident-contract.bats +0 -125
- package/skills/list-incidents/test/list-incidents-contract.bats +0 -115
- package/skills/list-problems/test/list-problems-contract.bats +0 -100
- package/skills/list-stories/test/list-stories-contract.bats +0 -127
- package/skills/list-story-maps/test/list-story-maps-contract.bats +0 -46
- package/skills/manage-incident/test/manage-incident-adr-044-contract.bats +0 -206
- package/skills/manage-incident/test/manage-incident-close-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-link-forwarder.bats +0 -67
- package/skills/manage-incident/test/manage-incident-list-forwarder.bats +0 -68
- package/skills/manage-incident/test/manage-incident-mitigate-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident-restore-forwarder.bats +0 -66
- package/skills/manage-incident/test/manage-incident.bats +0 -171
- package/skills/manage-problem/test/manage-problem-adr-044-step4-derive-first.bats +0 -151
- package/skills/manage-problem/test/manage-problem-auto-migrate-step.bats +0 -53
- package/skills/manage-problem/test/manage-problem-concern-boundary.bats +0 -64
- package/skills/manage-problem/test/manage-problem-effort-buckets.bats +0 -56
- package/skills/manage-problem/test/manage-problem-external-root-cause-detection.bats +0 -119
- package/skills/manage-problem/test/manage-problem-first-run-intake-prompt.bats +0 -43
- package/skills/manage-problem/test/manage-problem-git-mv-restage-reminder.bats +0 -48
- package/skills/manage-problem/test/manage-problem-id-collision-guard.bats +0 -39
- package/skills/manage-problem/test/manage-problem-list-forwarder.bats +0 -66
- package/skills/manage-problem/test/manage-problem-next-id-origin-lookup.bats +0 -50
- package/skills/manage-problem/test/manage-problem-no-prose-options.bats +0 -74
- package/skills/manage-problem/test/manage-problem-output-formatting.bats +0 -30
- package/skills/manage-problem/test/manage-problem-parked-and-cache.bats +0 -73
- package/skills/manage-problem/test/manage-problem-readme-refresh-on-transition.bats +0 -62
- package/skills/manage-problem/test/manage-problem-readme-tie-break-order.bats +0 -318
- package/skills/manage-problem/test/manage-problem-readme-vq-sort-order.bats +0 -206
- package/skills/manage-problem/test/manage-problem-release-vehicle-seed.bats +0 -83
- package/skills/manage-problem/test/manage-problem-review-forwarder.bats +0 -71
- package/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats +0 -97
- package/skills/manage-problem/test/manage-problem-transition-forwarder.bats +0 -96
- package/skills/manage-problem/test/manage-problem-transitive-dependencies.bats +0 -365
- package/skills/manage-problem/test/manage-problem-verification-detection.bats +0 -64
- package/skills/manage-problem/test/manage-problem-verification-pending.bats +0 -114
- package/skills/manage-problem/test/manage-problem-work-forwarder.bats +0 -88
- package/skills/manage-story/test/manage-story-contract.bats +0 -174
- package/skills/manage-story-map/test/manage-story-map-contract.bats +0 -63
- package/skills/mitigate-incident/test/mitigate-incident-contract.bats +0 -258
- package/skills/reconcile-readme/test/reconcile-readme-contract.bats +0 -201
- package/skills/report-upstream/test/report-upstream-contract.bats +0 -394
- package/skills/restore-incident/test/restore-incident-contract.bats +0 -170
- package/skills/review-problems/test/inbound-channels-cache-shape.bats +0 -127
- package/skills/review-problems/test/inbound-discovery-contract.bats +0 -383
- package/skills/review-problems/test/jtbd-301-verdict-shape-contract.bats +0 -225
- package/skills/review-problems/test/review-problems-contract.bats +0 -235
- package/skills/review-problems/test/review-problems-likely-verified-cell-shape.bats +0 -229
- package/skills/scaffold-intake/test/scaffold-intake-contract.bats +0 -126
- package/skills/scaffold-intake/test/scaffold-intake-fixture.bats +0 -164
- package/skills/scaffold-intake/test/scaffold-intake-secrets-absent.bats +0 -87
- package/skills/transition-problem/test/transition-problem-contract.bats +0 -285
- package/skills/transition-problems/test/transition-problems-contract.bats +0 -331
- package/skills/update-upstream/test/update-upstream-contract.bats +0 -375
- package/skills/work-problem/test/work-problem-contract.bats +0 -294
- package/skills/work-problems/test/work-problems-above-appetite-remediation.bats +0 -139
- package/skills/work-problems/test/work-problems-adr-013-rule-6-p352-amendment.bats +0 -166
- package/skills/work-problems/test/work-problems-auto-migrate-step.bats +0 -57
- package/skills/work-problems/test/work-problems-cost-logging.bats +0 -109
- package/skills/work-problems/test/work-problems-deviation-candidate-shape.bats +0 -121
- package/skills/work-problems/test/work-problems-first-run-intake-prompt.bats +0 -36
- package/skills/work-problems/test/work-problems-inter-iteration-verify.bats +0 -59
- package/skills/work-problems/test/work-problems-mid-loop-userpromptsubmit-handler.bats +0 -69
- package/skills/work-problems/test/work-problems-no-mid-loop-asking.bats +0 -192
- package/skills/work-problems/test/work-problems-p341-pre-all-done-gate.bats +0 -122
- package/skills/work-problems/test/work-problems-p342-r007-derive-then-pass-flags.bats +0 -170
- package/skills/work-problems/test/work-problems-p342-retro-auto-ticket-carveout.bats +0 -120
- package/skills/work-problems/test/work-problems-preflight-failure-handling.bats +0 -248
- package/skills/work-problems/test/work-problems-preflight-session-continuity.bats +0 -139
- package/skills/work-problems/test/work-problems-preflight.bats +0 -69
- package/skills/work-problems/test/work-problems-release-cadence.bats +0 -63
- package/skills/work-problems/test/work-problems-step-0-iter-error-staleness.bats +0 -93
- package/skills/work-problems/test/work-problems-step-0b-cache-staleness-behavioural.bats +0 -138
- package/skills/work-problems/test/work-problems-step-0c-deferred-placeholder-staleness-behavioural.bats +0 -238
- package/skills/work-problems/test/work-problems-step-0d-outbound-responses-staleness-behavioural.bats +0 -174
- package/skills/work-problems/test/work-problems-step-2-5-routing.bats +0 -80
- package/skills/work-problems/test/work-problems-step-2-5b-cross-halt-routing.bats +0 -149
- package/skills/work-problems/test/work-problems-step-3-5-jtbd-ratification-predicate.bats +0 -191
- package/skills/work-problems/test/work-problems-step-5-bats-polling-discipline.bats +0 -91
- package/skills/work-problems/test/work-problems-step-5-delegation.bats +0 -333
- package/skills/work-problems/test/work-problems-step-5-idle-timeout-sigterm.bats +0 -421
- package/skills/work-problems/test/work-problems-step-5-is-error-transient-halt.bats +0 -278
- package/skills/work-problems/test/work-problems-step-5-iter-changeset-required.bats +0 -95
- package/skills/work-problems/test/work-problems-step-5-prompt-body-re-grounding.bats +0 -128
- package/skills/work-problems/test/work-problems-step-5-stream-timeout-salvage.bats +0 -251
- package/skills/work-problems/test/work-problems-step-6-5-always-drain.bats +0 -203
- package/skills/work-problems/test/work-problems-step-6-5-cache-refresh-chain.bats +0 -174
- package/skills/work-problems/test/work-problems-step-6-5-fix-and-continue.bats +0 -254
- package/skills/work-problems/test/work-problems-step-6-5-postrelease-kv-callback.bats +0 -209
- package/skills/work-problems/test/work-problems-stop-condition-questions.bats +0 -85
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# tdd-review: structural-permitted (justification: the doc-lint slice below
|
|
3
|
-
# asserts SKILL.md / ADR-032 prose contract — SKILL.md is the contract
|
|
4
|
-
# document per ADR-037 Permitted Exception; these guards catch prose drift
|
|
5
|
-
# away from the behavioural SALVAGE/HALT contract exercised above. The
|
|
6
|
-
# load-bearing core of this fixture is behavioural per ADR-052. harness-gap P012)
|
|
7
|
-
#
|
|
8
|
-
# Behavioural test: work-problems Step 5 exit-code semantics — the is_error:true
|
|
9
|
-
# stream-timeout SALVAGE carve-out (P261). When an iter subprocess returns
|
|
10
|
-
# `is_error: true` (e.g. `API Error: Stream idle timeout - partial response
|
|
11
|
-
# received`) AFTER staging coherent work but BEFORE `git commit`, the staged
|
|
12
|
-
# work survives in the working tree. The orchestrator's salvage decision logic
|
|
13
|
-
# is: IF is_error:true AND staged files exist AND iter-authored bats pass →
|
|
14
|
-
# SALVAGE (commit the staged work from the main turn with iter-attribution; the
|
|
15
|
-
# commit gate fires fresh). ELSE → HALT per the existing exit-code contract.
|
|
16
|
-
#
|
|
17
|
-
# This is a NEW recovery branch, distinct from:
|
|
18
|
-
# - P121 (SIGTERM idle-timeout — is_error:false clean exit-flush; subprocess
|
|
19
|
-
# HAD committed before going idle)
|
|
20
|
-
# - P147 (SIGTERM stuck-before-emit — exit 143 + 0-byte JSON; metadata lost)
|
|
21
|
-
# - P146 (bash-polling antipattern — the deadlock mechanism behind P147)
|
|
22
|
-
# The stream-timeout class preserves metadata in the JSON envelope AND the
|
|
23
|
-
# staged files; the iter exits on its own with is_error:true (no SIGTERM).
|
|
24
|
-
#
|
|
25
|
-
# The fake-stuck-shim below re-creates the production shape: it stages coherent
|
|
26
|
-
# work in the repo, then emits an is_error:true stream-timeout JSON envelope
|
|
27
|
-
# (no ITERATION_SUMMARY, no commit). The harness re-implements the orchestrator's
|
|
28
|
-
# SALVAGE-vs-HALT decision contract (faithful to SKILL.md Step 5) and asserts the
|
|
29
|
-
# branch outcome across the four input shapes. Adopters who copy the SKILL.md
|
|
30
|
-
# Step 5 exit-code block into their orchestrator should observe the same outcomes.
|
|
31
|
-
#
|
|
32
|
-
# @problem P261
|
|
33
|
-
# @jtbd JTBD-006
|
|
34
|
-
# @jtbd JTBD-001
|
|
35
|
-
#
|
|
36
|
-
# Cross-reference:
|
|
37
|
-
# P261 (iter subprocess API stream-timeout salvage path) — driver ticket
|
|
38
|
-
# ADR-032 (governance skill invocation patterns — is_error:true stream-timeout
|
|
39
|
-
# salvage sub-variant, P261 amendment) — the carved-out commit-authorship
|
|
40
|
-
# contract this fixture pins
|
|
41
|
-
# ADR-009 (gate-marker-lifecycle — is_error:true subprocess MUST NOT extend
|
|
42
|
-
# parent trust window; salvage commit fires the gate fresh on the
|
|
43
|
-
# orchestrator's own SESSION_ID)
|
|
44
|
-
# ADR-014 (single-commit grain — the salvage commit IS the iteration's one
|
|
45
|
-
# commit; amend-folding is inapplicable because no iter commit exists)
|
|
46
|
-
# ADR-037 / ADR-052 (skill testing strategy — behavioural default; doc-lint
|
|
47
|
-
# contract assertion is the Permitted Exception, marked above)
|
|
48
|
-
|
|
49
|
-
setup() {
|
|
50
|
-
TEST_TMP="$(mktemp -d)"
|
|
51
|
-
FAKE_BIN="${TEST_TMP}/bin"
|
|
52
|
-
mkdir -p "$FAKE_BIN"
|
|
53
|
-
|
|
54
|
-
# Fake `claude` binary simulating a stuck iteration subprocess of the
|
|
55
|
-
# stream-timeout class: it stages coherent work in the CWD git repo, then
|
|
56
|
-
# emits an is_error:true JSON envelope carrying the stream-timeout error
|
|
57
|
-
# string in `.result`. No ITERATION_SUMMARY; no commit. This matches the
|
|
58
|
-
# 2026-05-18 session-6 iter-4 shape captured in P261: 7 files staged, then
|
|
59
|
-
# `API Error: Stream idle timeout - partial response received`.
|
|
60
|
-
cat > "$FAKE_BIN/claude" <<'FAKE_EOF'
|
|
61
|
-
#!/usr/bin/env bash
|
|
62
|
-
# Test fake for work-problems Step 5 P261 stream-timeout salvage fixture.
|
|
63
|
-
# Stages coherent work, then emits is_error:true stream-timeout JSON.
|
|
64
|
-
if [ "${FAKE_STAGE_WORK:-1}" = "1" ]; then
|
|
65
|
-
printf 'salvaged SKILL amendment + bats fixture\n' > staged-iter-work.txt
|
|
66
|
-
git add staged-iter-work.txt 2>/dev/null || true
|
|
67
|
-
fi
|
|
68
|
-
if [ "${FAKE_IS_ERROR:-true}" = "true" ]; then
|
|
69
|
-
printf '%s\n' '{"is_error":true,"result":"API Error: Stream idle timeout - partial response received","total_cost_usd":12.91,"duration_ms":300000,"usage":{"input_tokens":1000,"output_tokens":2000,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}'
|
|
70
|
-
else
|
|
71
|
-
printf '%s\n' '{"is_error":false,"result":"ITERATION_SUMMARY\nticket_id: P000\naction: worked\noutcome: investigated\ncommitted: true\nremaining_backlog_count: 0\nnotes: normal exit","total_cost_usd":0.5,"duration_ms":1000,"usage":{"input_tokens":10,"output_tokens":20,"cache_creation_input_tokens":0,"cache_read_input_tokens":0}}'
|
|
72
|
-
fi
|
|
73
|
-
FAKE_EOF
|
|
74
|
-
chmod +x "$FAKE_BIN/claude"
|
|
75
|
-
|
|
76
|
-
# Fake `iter_bats` stub — stands in for running the iter-authored bats
|
|
77
|
-
# fixtures as the salvage path's step-1 structural sanity check. Its exit
|
|
78
|
-
# code is controlled by FAKE_BATS_EXIT (0 = green, 1 = fail) so the harness
|
|
79
|
-
# can exercise both the bats-green and bats-fail branches behaviourally.
|
|
80
|
-
cat > "$FAKE_BIN/iter_bats" <<'FAKE_EOF'
|
|
81
|
-
#!/usr/bin/env bash
|
|
82
|
-
exit "${FAKE_BATS_EXIT:-0}"
|
|
83
|
-
FAKE_EOF
|
|
84
|
-
chmod +x "$FAKE_BIN/iter_bats"
|
|
85
|
-
export PATH="$FAKE_BIN:$PATH"
|
|
86
|
-
|
|
87
|
-
# A throwaway git repo so staged-work detection + the salvage commit are real.
|
|
88
|
-
REPO="${TEST_TMP}/repo"
|
|
89
|
-
mkdir -p "$REPO"
|
|
90
|
-
git -C "$REPO" init -q
|
|
91
|
-
git -C "$REPO" config user.email "test@example.com"
|
|
92
|
-
git -C "$REPO" config user.name "Test"
|
|
93
|
-
git -C "$REPO" commit -q --allow-empty -m "root"
|
|
94
|
-
|
|
95
|
-
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
96
|
-
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
97
|
-
ADR_FILE="$(cd "${SKILL_DIR}/../../../.." && pwd)/docs/decisions/032-governance-skill-invocation-patterns.proposed.md"
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
teardown() {
|
|
101
|
-
if [ -n "${TEST_TMP:-}" ] && [ -d "$TEST_TMP" ]; then
|
|
102
|
-
rm -rf "$TEST_TMP"
|
|
103
|
-
fi
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
# Faithful re-implementation of SKILL.md Step 5's is_error:true salvage decision
|
|
107
|
-
# contract. Consumes the iter JSON envelope + the repo working-tree state and
|
|
108
|
-
# returns the orchestrator's branch decision. The SALVAGE branch performs the
|
|
109
|
-
# real 4-step path's commit (step 3) so the commit is observable; the bats
|
|
110
|
-
# sanity check (step 1) is exercised via the FAKE_BATS_EXIT-controlled stub.
|
|
111
|
-
salvage_decision() {
|
|
112
|
-
local json="$1"
|
|
113
|
-
local repo="$2"
|
|
114
|
-
|
|
115
|
-
local is_error
|
|
116
|
-
is_error=$(printf '%s' "$json" | python3 -c 'import json,sys; print(str(json.load(sys.stdin).get("is_error")).lower())')
|
|
117
|
-
|
|
118
|
-
# is_error:false → normal exit-code path; not the salvage branch.
|
|
119
|
-
if [ "$is_error" != "true" ]; then
|
|
120
|
-
printf 'DECISION=PARSE_SUMMARY\n'
|
|
121
|
-
return 0
|
|
122
|
-
fi
|
|
123
|
-
|
|
124
|
-
# is_error:true with no staged work → halt per the existing exit-code contract.
|
|
125
|
-
local staged
|
|
126
|
-
staged=$(git -C "$repo" diff --cached --name-only)
|
|
127
|
-
if [ -z "$staged" ]; then
|
|
128
|
-
printf 'DECISION=HALT reason=no-staged-work\n'
|
|
129
|
-
return 0
|
|
130
|
-
fi
|
|
131
|
-
|
|
132
|
-
# is_error:true with staged work → run the iter-authored bats as the
|
|
133
|
-
# structural sanity check (step 1). Green → SALVAGE; fail → HALT.
|
|
134
|
-
if iter_bats; then
|
|
135
|
-
# Step 3: commit the staged work from the orchestrator main turn with
|
|
136
|
-
# explicit iter-attribution. (Step 4 — fresh commit gate — is the runtime
|
|
137
|
-
# orchestrator's concern, asserted via the doc-lint slice below.)
|
|
138
|
-
git -C "$repo" commit -q -m "salvage(P000): iter hit API stream timeout before commit — committed staged work from orchestrator main turn; iter-authored bats green"
|
|
139
|
-
printf 'DECISION=SALVAGE\n'
|
|
140
|
-
else
|
|
141
|
-
printf 'DECISION=HALT reason=bats-fail\n'
|
|
142
|
-
fi
|
|
143
|
-
return 0
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
# ---------------------------------------------------------------------------
|
|
147
|
-
# Behavioural cases (the load-bearing core per ADR-052).
|
|
148
|
-
# ---------------------------------------------------------------------------
|
|
149
|
-
|
|
150
|
-
@test "P261: is_error:true + staged work + bats green -> SALVAGE (commit from main turn)" {
|
|
151
|
-
export FAKE_IS_ERROR=true FAKE_STAGE_WORK=1 FAKE_BATS_EXIT=0
|
|
152
|
-
local json
|
|
153
|
-
json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
|
|
154
|
-
run salvage_decision "$json" "$REPO"
|
|
155
|
-
[ "$status" -eq 0 ]
|
|
156
|
-
[[ "$output" == *"DECISION=SALVAGE"* ]]
|
|
157
|
-
# The salvage commit must have landed, carrying the staged work + attribution.
|
|
158
|
-
run git -C "$REPO" log -1 --format=%s
|
|
159
|
-
[[ "$output" == *"salvage"* ]]
|
|
160
|
-
[[ "$output" == *"orchestrator main turn"* ]]
|
|
161
|
-
run git -C "$REPO" show --stat HEAD
|
|
162
|
-
[[ "$output" == *"staged-iter-work.txt"* ]]
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
@test "P261: is_error:true + staged work + bats FAIL -> HALT (incoherent work not salvaged)" {
|
|
166
|
-
export FAKE_IS_ERROR=true FAKE_STAGE_WORK=1 FAKE_BATS_EXIT=1
|
|
167
|
-
local json
|
|
168
|
-
json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
|
|
169
|
-
run salvage_decision "$json" "$REPO"
|
|
170
|
-
[ "$status" -eq 0 ]
|
|
171
|
-
[[ "$output" == *"DECISION=HALT"* ]]
|
|
172
|
-
[[ "$output" == *"reason=bats-fail"* ]]
|
|
173
|
-
# No salvage commit landed — HEAD is still the root commit.
|
|
174
|
-
run git -C "$REPO" log --oneline
|
|
175
|
-
[ "$(printf '%s\n' "$output" | grep -c .)" -eq 1 ]
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
@test "P261: is_error:true + NO staged work -> HALT per existing exit-code contract" {
|
|
179
|
-
export FAKE_IS_ERROR=true FAKE_STAGE_WORK=0 FAKE_BATS_EXIT=0
|
|
180
|
-
local json
|
|
181
|
-
json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
|
|
182
|
-
run salvage_decision "$json" "$REPO"
|
|
183
|
-
[ "$status" -eq 0 ]
|
|
184
|
-
[[ "$output" == *"DECISION=HALT"* ]]
|
|
185
|
-
[[ "$output" == *"reason=no-staged-work"* ]]
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
@test "P261: is_error:false (normal exit) -> PARSE_SUMMARY, NOT the salvage branch" {
|
|
189
|
-
export FAKE_IS_ERROR=false FAKE_STAGE_WORK=0
|
|
190
|
-
local json
|
|
191
|
-
json=$( cd "$REPO" && claude -p --output-format json "TEST" < /dev/null )
|
|
192
|
-
run salvage_decision "$json" "$REPO"
|
|
193
|
-
[ "$status" -eq 0 ]
|
|
194
|
-
[[ "$output" == *"DECISION=PARSE_SUMMARY"* ]]
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
# ---------------------------------------------------------------------------
|
|
198
|
-
# Doc-lint contract assertions (Permitted Exception per ADR-037; structural
|
|
199
|
-
# slice marked at top of file per ADR-052 Surface 2). These guard the SKILL.md
|
|
200
|
-
# / ADR-032 prose against drift away from the behavioural contract above.
|
|
201
|
-
# ---------------------------------------------------------------------------
|
|
202
|
-
|
|
203
|
-
@test "P261: SKILL.md Step 5 exit-code semantics documents the is_error:true salvage carve-out" {
|
|
204
|
-
run grep -niE "is_error.{0,30}salvage|salvage.{0,40}is_error|stream.?idle.?timeout.{0,80}salvage|salvage.{0,80}stream.?(idle.?)?timeout" "$SKILL_FILE"
|
|
205
|
-
[ "$status" -eq 0 ]
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
@test "P261: SKILL.md salvage carve-out names the staged-work + bats-pass gate condition" {
|
|
209
|
-
run grep -niE "staged.{0,40}(file|work).{0,80}bats|bats.{0,80}(pass|green).{0,80}salvage|salvage.{0,120}staged" "$SKILL_FILE"
|
|
210
|
-
[ "$status" -eq 0 ]
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
@test "P261: SKILL.md salvage carve-out documents the commit-from-main-turn + fresh-gate steps" {
|
|
214
|
-
run grep -niE "(orchestrator|main turn).{0,80}commit.{0,120}(attribut|fresh)|commit gate fires fresh|fresh.{0,30}commit gate" "$SKILL_FILE"
|
|
215
|
-
[ "$status" -eq 0 ]
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
@test "P261: SKILL.md salvage carve-out distinguishes the class from P147 / P121 / P146" {
|
|
219
|
-
run grep -niE "P147" "$SKILL_FILE"
|
|
220
|
-
[ "$status" -eq 0 ]
|
|
221
|
-
run grep -niE "P146" "$SKILL_FILE"
|
|
222
|
-
[ "$status" -eq 0 ]
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
@test "P261: SKILL.md Step 5 cites P261 (salvage-carve-out driver)" {
|
|
226
|
-
run grep -nE "P261" "$SKILL_FILE"
|
|
227
|
-
[ "$status" -eq 0 ]
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
@test "P261: SKILL.md line ~486 orchestrator-commit rule carries the salvage exception cross-reference" {
|
|
231
|
-
# The 'orchestrator does NOT commit from its main turn' rule must no longer
|
|
232
|
-
# read as unqualified — it must name the salvage carve-out as the one
|
|
233
|
-
# bounded exception so SKILL.md and ADR-032 stay in agreement.
|
|
234
|
-
run grep -niE "orchestrator does NOT commit from its main turn.{0,200}(except|salvage)|salvage.{0,80}(except|one case).{0,120}main turn" "$SKILL_FILE"
|
|
235
|
-
[ "$status" -eq 0 ]
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
@test "P261: ADR-032 carries the is_error:true stream-timeout salvage sub-variant amendment" {
|
|
239
|
-
run grep -niE "is_error.{0,30}(stream.?timeout)?.{0,30}salvage|stream.?timeout salvage|P261 amendment" "$ADR_FILE"
|
|
240
|
-
[ "$status" -eq 0 ]
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
@test "P261: ADR-032 salvage amendment preserves one-commit-per-iteration grain (amend-folding inapplicable)" {
|
|
244
|
-
run grep -niE "amend.?(based)?.?folding.{0,80}(inapplicable|no iter commit|not apply)|salvage commit IS the iteration|no iter commit.{0,40}amend" "$ADR_FILE"
|
|
245
|
-
[ "$status" -eq 0 ]
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
@test "P261: ADR-032 salvage amendment confirms fresh-gate-marker behaviour per ADR-009" {
|
|
249
|
-
run grep -niE "ADR-009|fresh.{0,30}(gate|commit gate)|own SESSION_ID|trust window" "$ADR_FILE"
|
|
250
|
-
[ "$status" -eq 0 ]
|
|
251
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P250: /wr-itil:work-problems Step 6.5 release-cadence classification must
|
|
4
|
-
# pivot on releasable material, not residual band. The defective prior
|
|
5
|
-
# clause "Within appetite (≤ 3/25) — no drain needed" encoded
|
|
6
|
-
# accumulation-permitted-below-threshold semantics that violated the
|
|
7
|
-
# user's verbatim direction: "If it's low risk, you should release."
|
|
8
|
-
#
|
|
9
|
-
# Amended contract (three-band):
|
|
10
|
-
# 1. Above appetite (≥ 5/25) → ADR-042 auto-apply (unchanged).
|
|
11
|
-
# 2. Within appetite (≤ 4/25) AND releasable material → drain.
|
|
12
|
-
# 3. Within appetite (≤ 4/25) AND empty queue → no drain (no-op fast-path).
|
|
13
|
-
#
|
|
14
|
-
# The trigger for the drain action is *presence of releasable material*
|
|
15
|
-
# (any unpushed commits OR any .changeset/ entries). The residual band remains
|
|
16
|
-
# the safety check (above-appetite never releases) but is no longer the
|
|
17
|
-
# action gate for the within-appetite branch.
|
|
18
|
-
#
|
|
19
|
-
# Doc-lint contract assertions per ADR-037 Permitted Exception (contract-
|
|
20
|
-
# assertion class). The asserted prose IS the load-bearing policy surface
|
|
21
|
-
# — re-reading SKILL.md is the only way an AFK reader (and the iteration
|
|
22
|
-
# subprocess) learns the new classification. Behavioural verification
|
|
23
|
-
# would require executing the orchestrator's decision tree, which is not
|
|
24
|
-
# scriptable until the Phase 2 advisory-classifier from P081 ships. These
|
|
25
|
-
# tests function as regression guards against re-introducing the
|
|
26
|
-
# "Within appetite (≤ 3/25) — no drain needed" wording or any equivalent
|
|
27
|
-
# threshold-as-action-gate framing.
|
|
28
|
-
#
|
|
29
|
-
# @problem P250
|
|
30
|
-
# @adr ADR-018 (release-cadence policy parent — amended in same commit)
|
|
31
|
-
# @adr ADR-037 (skill-testing strategy — contract-assertion class)
|
|
32
|
-
# @adr ADR-042 (above-appetite branch — preserved unchanged)
|
|
33
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary)
|
|
34
|
-
# @jtbd JTBD-002 (Ship with Confidence — composes; small frequent releases)
|
|
35
|
-
|
|
36
|
-
setup() {
|
|
37
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
38
|
-
SKILL_MD="$REPO_ROOT/packages/itil/skills/work-problems/SKILL.md"
|
|
39
|
-
ADR_018="$REPO_ROOT/docs/decisions/018-inter-iteration-release-cadence-for-afk-loops.proposed.md"
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
# ── Preconditions ──────────────────────────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
@test "work-problems P250: SKILL.md exists" {
|
|
45
|
-
[ -f "$SKILL_MD" ]
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@test "work-problems P250: ADR-018 exists" {
|
|
49
|
-
[ -f "$ADR_018" ]
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# ── Regression guard: defective prior wording is gone ──────────────────────
|
|
53
|
-
|
|
54
|
-
@test "work-problems P250: SKILL.md no longer contains 'Within appetite (≤ 3/25) — no drain needed' clause" {
|
|
55
|
-
# The defective clause. Re-introducing it regresses to accumulation-
|
|
56
|
-
# permitted-below-threshold semantics.
|
|
57
|
-
run grep -nE 'Within appetite \(≤ 3/25\).*no drain needed' "$SKILL_MD"
|
|
58
|
-
[ "$status" -ne 0 ]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@test "work-problems P250: SKILL.md no longer treats '= 4/25' as a discrete drain trigger band" {
|
|
62
|
-
# The prior "At appetite (= 4/25) — drain" band is collapsed into the
|
|
63
|
-
# new "≤ 4/25 AND releasable material" branch. The discrete = 4/25
|
|
64
|
-
# framing should be absent from the Step 6.5 classification.
|
|
65
|
-
run grep -nE 'At appetite \(= 4/25\) — drain' "$SKILL_MD"
|
|
66
|
-
[ "$status" -ne 0 ]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
# ── Above-appetite branch preserved (ADR-042) ──────────────────────────────
|
|
70
|
-
|
|
71
|
-
@test "work-problems P250: Above-appetite (≥ 5/25) branch routes to ADR-042 auto-apply (preserved)" {
|
|
72
|
-
run grep -nE 'Above appetite \(≥ 5/25\).*Above-appetite branch' "$SKILL_MD"
|
|
73
|
-
[ "$status" -eq 0 ]
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@test "work-problems P250: Above-appetite branch references the auto-apply loop (ADR-042 intact)" {
|
|
77
|
-
run grep -nE 'auto-apply loop|ADR-042' "$SKILL_MD"
|
|
78
|
-
[ "$status" -eq 0 ]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# ── Within-appetite + releasable material drains ──────────────────────────
|
|
82
|
-
|
|
83
|
-
@test "work-problems P250: Within-appetite + releasable material triggers drain" {
|
|
84
|
-
# The load-bearing positive contract: within appetite AND any unpushed
|
|
85
|
-
# commits OR changeset entry → drain.
|
|
86
|
-
run grep -nE 'Within appetite \(≤ 4/25\) AND there is releasable material' "$SKILL_MD"
|
|
87
|
-
[ "$status" -eq 0 ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@test "work-problems P250: releasable-material clause enumerates unpushed commits" {
|
|
91
|
-
run grep -nE 'releasable material.*unpushed commits|unpushed commits.*releasable material|any unpushed commits' "$SKILL_MD"
|
|
92
|
-
[ "$status" -eq 0 ]
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
@test "work-problems P250: releasable-material clause enumerates .changeset/ entries" {
|
|
96
|
-
run grep -nE 'any entries in `\.changeset/`|`\.changeset/` non-empty|entries in `\.changeset/`' "$SKILL_MD"
|
|
97
|
-
[ "$status" -eq 0 ]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
# ── Within-appetite + empty queue no-op fast-path ─────────────────────────
|
|
101
|
-
|
|
102
|
-
@test "work-problems P250: Within-appetite + empty queue does NOT drain (no-op fast-path)" {
|
|
103
|
-
# The genuine fast-path: nothing to release. Gate is *absence of
|
|
104
|
-
# releasable material*, not residual band.
|
|
105
|
-
run grep -nE 'Within appetite \(≤ 4/25\) AND empty queue' "$SKILL_MD"
|
|
106
|
-
[ "$status" -eq 0 ]
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
@test "work-problems P250: empty-queue branch is framed as 'literally nothing to release', not a threshold deferral" {
|
|
110
|
-
# Regression guard: the no-drain branch must NOT be reframed as a
|
|
111
|
-
# threshold-based defer. The gate is queue emptiness, not residual.
|
|
112
|
-
run grep -nE 'literally nothing to release|nothing to release.*genuine no-op' "$SKILL_MD"
|
|
113
|
-
[ "$status" -eq 0 ]
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
# ── User-direction citation preserved ─────────────────────────────────────
|
|
117
|
-
|
|
118
|
-
@test "work-problems P250: amended classification cites user direction verbatim ('If it's low risk, you should release.')" {
|
|
119
|
-
# The user's verbatim direction is the load-bearing rationale. Future
|
|
120
|
-
# readers tracing the amendment back must find the citation without
|
|
121
|
-
# keyword-guessing.
|
|
122
|
-
run grep -nE 'If it.s low risk, you should release' "$SKILL_MD"
|
|
123
|
-
[ "$status" -eq 0 ]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
@test "work-problems P250: classification cites P250 by ticket ID" {
|
|
127
|
-
# ADR-022 amendment trail: the amended clause must self-identify
|
|
128
|
-
# so future readers tracing back from the ticket find it.
|
|
129
|
-
run grep -nE 'P250' "$SKILL_MD"
|
|
130
|
-
[ "$status" -eq 0 ]
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
# ── Non-Interactive Decision Making table reflects amendment ──────────────
|
|
134
|
-
|
|
135
|
-
@test "work-problems P250: Decision Making table carries the within-appetite-with-releasable-material row" {
|
|
136
|
-
# The decision table is the AFK reader's quick-reference; the
|
|
137
|
-
# amendment must surface here too, otherwise the table contradicts
|
|
138
|
-
# Step 6.5's classification.
|
|
139
|
-
run grep -nE '\| Pipeline risk within appetite \(≤ 4/25\) with releasable material' "$SKILL_MD"
|
|
140
|
-
[ "$status" -eq 0 ]
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
@test "work-problems P250: Decision Making table carries the empty-queue no-drain row" {
|
|
144
|
-
run grep -nE '\| Pipeline risk within appetite \(≤ 4/25\) AND empty queue' "$SKILL_MD"
|
|
145
|
-
[ "$status" -eq 0 ]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
@test "work-problems P250: Decision Making table row cites 'presence of releasable material', not 'residual reaching appetite'" {
|
|
149
|
-
# The trigger semantics must be explicit in the table row, not
|
|
150
|
-
# buried in Step 6.5 prose 100+ lines above.
|
|
151
|
-
run grep -nE 'presence of releasable material|releasable material.*not residual band|Trigger is.*presence' "$SKILL_MD"
|
|
152
|
-
[ "$status" -eq 0 ]
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
# ── ADR-018 amendment (in same commit per ADR-014) ────────────────────────
|
|
156
|
-
|
|
157
|
-
@test "work-problems P250: ADR-018 contains the 2026-05-18 Drain-trigger amendment heading" {
|
|
158
|
-
# ADR-014 single-unit-of-work: the ADR amendment lands in the same
|
|
159
|
-
# commit as the SKILL change. ADR-018's Mechanism without this
|
|
160
|
-
# amendment contradicts SKILL.md Step 6.5.
|
|
161
|
-
run grep -nE 'Amendment 2026-05-18.*Drain trigger is releasable material' "$ADR_018"
|
|
162
|
-
[ "$status" -eq 0 ]
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
@test "work-problems P250: ADR-018 amendment cites P250 by ticket ID" {
|
|
166
|
-
run grep -nE 'P250' "$ADR_018"
|
|
167
|
-
[ "$status" -eq 0 ]
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
@test "work-problems P250: ADR-018 amendment quotes the user direction" {
|
|
171
|
-
run grep -nE 'If it.s low risk, you should release' "$ADR_018"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
@test "work-problems P250: ADR-018 amendment encodes the new drain condition shape" {
|
|
176
|
-
# The amendment must contain the conjunction "≤ 4/25 AND (releasable
|
|
177
|
-
# material disjunct)" so future readers tracing the policy chain
|
|
178
|
-
# find the rule in the load-bearing ADR, not just in the SKILL.
|
|
179
|
-
run grep -nE 'residual ≤ 4/25 AND' "$ADR_018"
|
|
180
|
-
[ "$status" -eq 0 ]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
@test "work-problems P250: ADR-018 amendment preserves Above-appetite delegation to ADR-042" {
|
|
184
|
-
# The amendment MUST NOT touch the above-appetite invariant. ADR-042
|
|
185
|
-
# remains the safety gate.
|
|
186
|
-
run grep -nE 'Above-appetite states \(≥ 5/25\) route to ADR-042|Above-appetite.*ADR-042' "$ADR_018"
|
|
187
|
-
[ "$status" -eq 0 ]
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
# ── Cross-references intact ───────────────────────────────────────────────
|
|
191
|
-
|
|
192
|
-
@test "work-problems P250: SKILL.md Step 6.5 still cites ADR-018 (parent policy intact)" {
|
|
193
|
-
run grep -nE 'Step 6\.5.*ADR-018|ADR-018.*Step 6\.5|Release-cadence check.*ADR-018' "$SKILL_MD"
|
|
194
|
-
[ "$status" -eq 0 ]
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
@test "work-problems P250: SKILL.md Step 6.5 still cites P041 (accumulation root cause cross-reference)" {
|
|
198
|
-
# P041 is the ancestor that established Step 6.5 itself. The
|
|
199
|
-
# amendment refines P041's solution; the cross-reference must
|
|
200
|
-
# survive.
|
|
201
|
-
run grep -nE 'P041' "$SKILL_MD"
|
|
202
|
-
[ "$status" -eq 0 ]
|
|
203
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P233: /wr-itil:work-problems Step 6.5 Drain action must chain
|
|
4
|
-
# /install-updates AFTER successful release:watch so the next iter
|
|
5
|
-
# subprocess loads the just-shipped plugin from cache rather than the
|
|
6
|
-
# pre-release cached version.
|
|
7
|
-
#
|
|
8
|
-
# Empirical driver (briefing/afk-subprocess.md:18): iter subprocesses
|
|
9
|
-
# re-resolve plugin cache on spawn; without cache refresh between
|
|
10
|
-
# release:watch and next-iter dispatch, the just-shipped hook is
|
|
11
|
-
# inactive in the next iter — defeating the "ship a hook to prevent
|
|
12
|
-
# recurrence" pattern for the immediate-next-iter case.
|
|
13
|
-
#
|
|
14
|
-
# Doc-lint contract assertions per ADR-037 Permitted Exception
|
|
15
|
-
# (contract-assertion class — same shape as the P140 / P130 / P126 / P135
|
|
16
|
-
# sibling fixtures). The asserted prose IS the load-bearing policy
|
|
17
|
-
# surface — the chained invocation is documentation-only (the orchestrator
|
|
18
|
-
# is a prose-driven agent, not a script); the SKILL.md is the contract.
|
|
19
|
-
# Behavioural assertion would require a fixture project + real claude -p
|
|
20
|
-
# subprocess that observes a freshly-installed plugin — outside scope.
|
|
21
|
-
#
|
|
22
|
-
# @problem P233
|
|
23
|
-
# @adr ADR-013 (Rule 5 — policy-authorised silent action; chains the
|
|
24
|
-
# same authorisation that covers push:watch / release:watch)
|
|
25
|
-
# @adr ADR-014 (one-commit-per-iter; this edit lands in one commit)
|
|
26
|
-
# @adr ADR-018 (inter-iteration release cadence; this refines its
|
|
27
|
-
# Drain action sub-block with the post-release cache refresh)
|
|
28
|
-
# @adr ADR-030 (repo-local skills — install-updates is the chained
|
|
29
|
-
# skill)
|
|
30
|
-
# @adr ADR-037 (skill-testing strategy — contract-assertion class)
|
|
31
|
-
# @adr ADR-044 (decision-delegation contract — framework-resolution
|
|
32
|
-
# boundary; install-updates' AskUserQuestion-bearing branches
|
|
33
|
-
# fall through to its Non-interactive fallback under P130)
|
|
34
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — primary;
|
|
35
|
-
# outcome 7 "risk never silently accumulates across AFK iterations"
|
|
36
|
-
# extends to "just-shipped hooks effective on next iter")
|
|
37
|
-
# @jtbd JTBD-001 (Enforce Governance Without Slowing Down — composes;
|
|
38
|
-
# just-shipped governance hooks become effective immediately,
|
|
39
|
-
# not after manual /install-updates re-run)
|
|
40
|
-
# @jtbd JTBD-007 (Keep Plugins Current Across Projects — persona-level
|
|
41
|
-
# currency anchor that JTBD-006's AFK use case extends)
|
|
42
|
-
|
|
43
|
-
setup() {
|
|
44
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
45
|
-
SKILL_MD="$REPO_ROOT/packages/itil/skills/work-problems/SKILL.md"
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@test "work-problems P233: SKILL.md exists" {
|
|
49
|
-
[ -f "$SKILL_MD" ]
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# ── Cache-refresh chain identity ───────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
@test "work-problems P233: Step 6.5 Drain action carries a post-release cache-refresh subsection citing P233" {
|
|
55
|
-
# The amendment must self-identify so future readers tracing back from
|
|
56
|
-
# the ticket find the load-bearing prose without keyword-guessing.
|
|
57
|
-
run grep -nE 'cache.refresh.*P233|P233.*cache.refresh|post.release.cache.*P233|P233.*post.release.cache' "$SKILL_MD"
|
|
58
|
-
[ "$status" -eq 0 ]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@test "work-problems P233: Drain action chains /install-updates after successful release:watch" {
|
|
62
|
-
# Core contract: after release:watch returns success, the orchestrator
|
|
63
|
-
# invokes /install-updates to refresh the plugin cache. Without this
|
|
64
|
-
# chain, the next iter subprocess loads the pre-release cached version
|
|
65
|
-
# (P233's empirical root cause).
|
|
66
|
-
run grep -nE '/install-updates|install-updates skill' "$SKILL_MD"
|
|
67
|
-
[ "$status" -eq 0 ]
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@test "work-problems P233: cache-refresh is conditional on actual release (skipped when no changeset)" {
|
|
71
|
-
# The chain MUST NOT fire when release:watch was a no-op (empty
|
|
72
|
-
# .changeset/ after push). No new plugin version exists → nothing to
|
|
73
|
-
# refresh. Without this guard, the orchestrator burns wall-clock and
|
|
74
|
-
# noise on a no-op /install-updates invocation every iter.
|
|
75
|
-
run grep -niE 'only.*release.*actually|when.*release.*shipped|skip.*when.*no.changeset|conditional on.*release' "$SKILL_MD"
|
|
76
|
-
[ "$status" -eq 0 ]
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@test "work-problems P233: cache-refresh is non-blocking on /install-updates failure" {
|
|
80
|
-
# If /install-updates fails (cache miss + non-interactive fallback,
|
|
81
|
-
# marketplace fetch error, transient flake), the orchestrator MUST NOT
|
|
82
|
-
# halt the loop. Degrades to current behaviour — cache stays stale;
|
|
83
|
-
# equivalent to pre-amendment behaviour. Loop continues.
|
|
84
|
-
run grep -niE 'non.blocking.*install.updates|install.updates.*non.blocking|do not halt.*install.updates|install.updates.*failure.*continue' "$SKILL_MD"
|
|
85
|
-
[ "$status" -eq 0 ]
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
# ── Empirical evidence citation ────────────────────────────────────────────
|
|
89
|
-
|
|
90
|
-
@test "work-problems P233: cache-refresh subsection cites briefing/afk-subprocess.md evidence" {
|
|
91
|
-
# The architect FLAG resolution required the evidence that subprocesses
|
|
92
|
-
# re-resolve cache on spawn (rather than inherit parent-resolved
|
|
93
|
-
# plugins). The briefing entry is dispositive — cite it inline so
|
|
94
|
-
# future readers don't re-litigate the question.
|
|
95
|
-
run grep -nE 'afk-subprocess|briefing.*subprocess.*cache' "$SKILL_MD"
|
|
96
|
-
[ "$status" -eq 0 ]
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
# ── ADR-013 Rule 5 policy authorisation ────────────────────────────────────
|
|
100
|
-
|
|
101
|
-
@test "work-problems P233: cache-refresh chain rides ADR-013 Rule 5 (same authorisation as push:watch / release:watch)" {
|
|
102
|
-
# The chain MUST be silent — invocation between iters is a mechanical
|
|
103
|
-
# post-release step the framework has resolved. Same ADR-013 Rule 5
|
|
104
|
-
# citation already covers push:watch / release:watch in the within-
|
|
105
|
-
# appetite drain; the cache-refresh extends the same authorisation.
|
|
106
|
-
run grep -nE 'ADR-013 Rule 5|Rule 5 policy-authorised|policy-authorised.*ADR-013' "$SKILL_MD"
|
|
107
|
-
[ "$status" -eq 0 ]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
# ── Mid-loop ask discipline preservation (P130) ────────────────────────────
|
|
111
|
-
|
|
112
|
-
@test "work-problems P233: cache-refresh prose cites install-updates Non-interactive fallback for AskUserQuestion routing" {
|
|
113
|
-
# If install-updates' Step 5b/5c consent gate fires (cache miss /
|
|
114
|
-
# scope delta / INSTALL_UPDATES_RECONFIRM=1), the orchestrator main
|
|
115
|
-
# turn MUST NOT surface AskUserQuestion mid-loop per P130. Cite the
|
|
116
|
-
# install-updates Non-interactive fallback as the routing.
|
|
117
|
-
run grep -niE 'Non.interactive fallback|non-interactive fallback' "$SKILL_MD"
|
|
118
|
-
[ "$status" -eq 0 ]
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
@test "work-problems P233: cache-refresh prose cites ADR-044 framework-resolution boundary for AskUserQuestion-available-but-forbidden routing" {
|
|
122
|
-
# Architect advisory: cite ADR-044 alongside the Non-interactive
|
|
123
|
-
# fallback ref so future readers can trace the "AskUserQuestion-
|
|
124
|
-
# available-but-forbidden" reasoning back to the framework-resolution
|
|
125
|
-
# boundary — not just the install-updates-side dry-run mechanic.
|
|
126
|
-
run grep -nE 'ADR-044' "$SKILL_MD"
|
|
127
|
-
[ "$status" -eq 0 ]
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
# ── Composition with above-appetite branch ─────────────────────────────────
|
|
131
|
-
|
|
132
|
-
@test "work-problems P233: cache-refresh fires only after within-appetite Drain action (not after above-appetite Rule 5 halt)" {
|
|
133
|
-
# Above-appetite Rule 5 halt terminates without a release; no cache
|
|
134
|
-
# refresh fires. Within-appetite convergence loops back to Drain
|
|
135
|
-
# action; cache refresh fires there. The prose must not place the
|
|
136
|
-
# chain inside the above-appetite branch.
|
|
137
|
-
run grep -niE 'within.appetite.*drain.*cache|cache.refresh.*within.appetite|after.*drain.*action' "$SKILL_MD"
|
|
138
|
-
[ "$status" -eq 0 ]
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
# ── Non-Interactive Decision Making table row ──────────────────────────────
|
|
142
|
-
|
|
143
|
-
@test "work-problems P233: Decision Making table carries a post-release cache-refresh row" {
|
|
144
|
-
# The decision table is the AFK reader's quick-reference; without a
|
|
145
|
-
# row here the cache-refresh chain is buried in Step 6.5.
|
|
146
|
-
run grep -nE '\|.*[Pp]ost.release cache|\|.*[Cc]ache refresh|\|.*[Pp]lugin cache refresh' "$SKILL_MD"
|
|
147
|
-
[ "$status" -eq 0 ]
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@test "work-problems P233: Decision Making table row cites P233" {
|
|
151
|
-
# Per ADR-037 doc-lint pattern + existing P140 / P126 / P135 sibling
|
|
152
|
-
# rows — every Decision Making table row that documents a P-driven
|
|
153
|
-
# refinement cites the driver ticket.
|
|
154
|
-
run grep -nE '\|.*cache refresh.*P233|\|.*P233.*cache refresh|\|.*post.release.*P233|\|.*P233.*post.release' "$SKILL_MD"
|
|
155
|
-
[ "$status" -eq 0 ]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# ── Composition cross-references ───────────────────────────────────────────
|
|
159
|
-
|
|
160
|
-
@test "work-problems P233: cache-refresh prose cross-references P106 (claude plugin install no-op-when-already-installed)" {
|
|
161
|
-
# P106 is the compounding factor that makes /install-updates' explicit
|
|
162
|
-
# uninstall + install dance necessary (vs. naive claude plugin
|
|
163
|
-
# install which silent-no-ops). Cite it so future readers don't try
|
|
164
|
-
# to simplify the chain.
|
|
165
|
-
run grep -nE 'P106' "$SKILL_MD"
|
|
166
|
-
[ "$status" -eq 0 ]
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
@test "work-problems P233: cache-refresh prose cross-references P130 (orchestrator main-turn ask discipline preserved)" {
|
|
170
|
-
# P130 is the constraint the Non-interactive fallback routing exists
|
|
171
|
-
# to satisfy. Citation makes the dependency auditable.
|
|
172
|
-
run grep -nE 'P130' "$SKILL_MD"
|
|
173
|
-
[ "$status" -eq 0 ]
|
|
174
|
-
}
|