@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,71 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Contract assertions for manage-problem's `review` subcommand forwarder (P071 split slice 2).
|
|
3
|
-
#
|
|
4
|
-
# Per ADR-010 amended (Skill Granularity section) + P071 phased plan:
|
|
5
|
-
# `/wr-itil:manage-problem review` delegates to the new
|
|
6
|
-
# `/wr-itil:review-problems` skill via a thin-router forwarder. Original
|
|
7
|
-
# skill carries `deprecated-arguments: true` frontmatter (asserted in
|
|
8
|
-
# the list-forwarder bats); this file asserts the review-forwarder-specific
|
|
9
|
-
# contract.
|
|
10
|
-
#
|
|
11
|
-
# Structural assertion — Permitted Exception to the source-grep ban
|
|
12
|
-
# (ADR-005 / P011 / ADR-037 contract-assertion pattern).
|
|
13
|
-
#
|
|
14
|
-
# @problem P071
|
|
15
|
-
# @jtbd JTBD-001 (enforce governance without slowing down)
|
|
16
|
-
# @jtbd JTBD-101 (extend the suite with clear patterns)
|
|
17
|
-
#
|
|
18
|
-
# Cross-reference:
|
|
19
|
-
# P071: docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md
|
|
20
|
-
# ADR-010 amended — split naming + forwarder contract + deprecated-arguments flag
|
|
21
|
-
# ADR-013 Rule 1 — structured user interaction (forwarder emits systemMessage, not AskUserQuestion)
|
|
22
|
-
# ADR-037 — contract-assertion bats pattern
|
|
23
|
-
|
|
24
|
-
setup() {
|
|
25
|
-
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
26
|
-
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@test "manage-problem Step 1 forwards 'review' argument to /wr-itil:review-problems (P071)" {
|
|
30
|
-
# The forwarder names the target skill explicitly so the router is legible
|
|
31
|
-
# at the contract level. ADR-010's canonical shape: "invokes the new
|
|
32
|
-
# named skill via the Skill tool, not via re-prompting the user".
|
|
33
|
-
run grep -inE "/wr-itil:review-problems" "$SKILL_FILE"
|
|
34
|
-
[ "$status" -eq 0 ]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@test "manage-problem Step 1 emits the canonical review deprecation notice (ADR-010 amended)" {
|
|
38
|
-
# ADR-010's canonical deprecation-notice template:
|
|
39
|
-
# "/wr-<plugin>:<old> <arg> is deprecated; use /wr-<plugin>:<new>
|
|
40
|
-
# directly. This forwarder will be removed in <plugin>'s next major
|
|
41
|
-
# version."
|
|
42
|
-
# The notice MUST be emitted as a systemMessage (not AskUserQuestion)
|
|
43
|
-
# because deprecation is informational, not decisional (ADR-013 Rule 1
|
|
44
|
-
# structured-interaction scope). The review-forwarder notice is
|
|
45
|
-
# distinct from the list-forwarder notice; both must co-exist verbatim.
|
|
46
|
-
run grep -inE "is deprecated.*use /wr-itil:review-problems|deprecated.*review-problems|removed in .* next major version" "$SKILL_FILE"
|
|
47
|
-
[ "$status" -eq 0 ]
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@test "manage-problem Step 1 review-forwarder does not re-implement the review logic (P071 regression guard)" {
|
|
51
|
-
# The forwarder must not duplicate the review logic — it must delegate.
|
|
52
|
-
# Per ADR-010: "thin-router forwarder re-invokes the new named skill
|
|
53
|
-
# via the Skill tool". If the forwarder grows its own re-scoring or
|
|
54
|
-
# README-refresh logic, the deprecation window will harden into a
|
|
55
|
-
# permanent fork. Guard against this by asserting the forwarder block
|
|
56
|
-
# mentions "delegate" or "Skill tool" language near the
|
|
57
|
-
# review-problems reference.
|
|
58
|
-
run grep -inE "delegate.*review-problems|Skill tool.*review-problems|review-problems.*Skill tool" "$SKILL_FILE"
|
|
59
|
-
[ "$status" -eq 0 ]
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@test "manage-problem review-forwarder Step 1 parser no longer runs review logic inline (P071 slice 2)" {
|
|
63
|
-
# Slice 2's defining behaviour: Step 1's `review` branch must
|
|
64
|
-
# delegate, not run Step 9 inline. The parser line must say
|
|
65
|
-
# "delegate to /wr-itil:review-problems", matching the shape the
|
|
66
|
-
# list-forwarder uses in slice 1. A stale "run the review (step 9)"
|
|
67
|
-
# line would indicate the forwarder was added without updating the
|
|
68
|
-
# parser (common slip).
|
|
69
|
-
run grep -nE "^- If arguments contain \"review\", \*\*delegate to \`/wr-itil:review-problems\`\*\*" "$SKILL_FILE"
|
|
70
|
-
[ "$status" -eq 0 ]
|
|
71
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
#
|
|
3
|
-
# packages/itil/skills/manage-problem/test/manage-problem-step-9d-recovery-path.bats
|
|
4
|
-
#
|
|
5
|
-
# Behavioural tests for manage-problem Step 9d's recovery-path
|
|
6
|
-
# documentation (P135 Phase 2 / R5 / ADR-044).
|
|
7
|
-
#
|
|
8
|
-
# Step 9d closes verifying tickets on evidence WITHOUT firing
|
|
9
|
-
# AskUserQuestion (per ADR-044 framework-resolution boundary).
|
|
10
|
-
# Mirrors the run-retro Step 4a recovery-path contract.
|
|
11
|
-
#
|
|
12
|
-
# tdd-review: structural-permitted (justification: skill behavioural
|
|
13
|
-
# harness pending P012 + P081 Phase 2; SKILL.md contract assertions
|
|
14
|
-
# bridge until then; expected to migrate to behavioural form once
|
|
15
|
-
# the harness exists)
|
|
16
|
-
#
|
|
17
|
-
# @problem P135 Phase 2 R5
|
|
18
|
-
# @adr ADR-044 (Decision-Delegation Contract — closes are reversible)
|
|
19
|
-
# @adr ADR-022 (verification-pending lifecycle)
|
|
20
|
-
# @adr ADR-026 (cost-source grounding for in-session evidence)
|
|
21
|
-
# @adr ADR-005 / ADR-037 (testing strategy — bridge during harness build)
|
|
22
|
-
# @jtbd JTBD-001 / JTBD-006 / JTBD-201
|
|
23
|
-
|
|
24
|
-
SKILL_FILE="${BATS_TEST_DIRNAME}/../SKILL.md"
|
|
25
|
-
|
|
26
|
-
setup() {
|
|
27
|
-
[ -f "$SKILL_FILE" ]
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
# ── Step 9d's close-on-evidence contract ────────────────────────────────────
|
|
31
|
-
|
|
32
|
-
@test "Step 9d SKILL.md cites /wr-itil:transition-problem as the close-on-evidence dispatch target" {
|
|
33
|
-
# Bound the search to Step 9d (not the entire file)
|
|
34
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
35
|
-
[ "$status" -eq 0 ]
|
|
36
|
-
[[ "$output" == *"/wr-itil:transition-problem"* ]]
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@test "Step 9d SKILL.md names ADR-044 framework-resolution boundary as the rationale for no-AskUserQuestion close" {
|
|
40
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
41
|
-
[ "$status" -eq 0 ]
|
|
42
|
-
[[ "$output" == *"ADR-044"* ]]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
@test "Step 9d SKILL.md cites ADR-026 grounding requirement for in-session evidence" {
|
|
46
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
47
|
-
[ "$status" -eq 0 ]
|
|
48
|
-
[[ "$output" == *"ADR-026"* ]]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@test "Step 9d SKILL.md cites ADR-022 verification-pending lifecycle semantics" {
|
|
52
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
53
|
-
[ "$status" -eq 0 ]
|
|
54
|
-
[[ "$output" == *"ADR-022"* ]]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
# ── Recovery-path contract ──────────────────────────────────────────────────
|
|
58
|
-
|
|
59
|
-
@test "Step 9d SKILL.md documents that closes are reversible" {
|
|
60
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
61
|
-
[ "$status" -eq 0 ]
|
|
62
|
-
[[ "$output" == *"reversible"* ]]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
@test "Step 9d SKILL.md names the recovery invocation (transition-problem known-error)" {
|
|
66
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
67
|
-
[ "$status" -eq 0 ]
|
|
68
|
-
[[ "$output" == *"known-error"* ]]
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@test "Step 9d SKILL.md cites 2026-04-27 P124 verifying-flip-back precedent" {
|
|
72
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
73
|
-
[ "$status" -eq 0 ]
|
|
74
|
-
[[ "$output" == *"P124"* ]]
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
# ── Ambiguous-evidence preservation (no auto-close on weak evidence) ────────
|
|
78
|
-
|
|
79
|
-
@test "Step 9d SKILL.md preserves the ambiguous-evidence path (left as Verification Pending)" {
|
|
80
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
81
|
-
[ "$status" -eq 0 ]
|
|
82
|
-
[[ "$output" == *"ambiguous"* ]] || [[ "$output" == *"Verification Pending"* ]]
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@test "Step 9d SKILL.md routes user disagreement through authentic-correction surface" {
|
|
86
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
87
|
-
[ "$status" -eq 0 ]
|
|
88
|
-
[[ "$output" == *"authentic-correction"* ]] || [[ "$output" == *"P078"* ]]
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
# ── Step 9d output contract ─────────────────────────────────────────────────
|
|
92
|
-
|
|
93
|
-
@test "Step 9d SKILL.md says output table records each close action with citation" {
|
|
94
|
-
run awk '/^\*\*Step 9d:/,/^\*\*Step 9e:/ {print}' "$SKILL_FILE"
|
|
95
|
-
[ "$status" -eq 0 ]
|
|
96
|
-
[[ "$output" == *"citation"* ]] || [[ "$output" == *"output table"* ]]
|
|
97
|
-
}
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Contract assertions for manage-problem's `<NNN> <status>` transition forwarder (P071 split slice 4).
|
|
3
|
-
#
|
|
4
|
-
# Per ADR-010 amended (Skill Granularity section) + P071 phased plan:
|
|
5
|
-
# `/wr-itil:manage-problem <NNN> known-error` (and the sibling close
|
|
6
|
-
# form) delegates to the new `/wr-itil:transition-problem` skill via
|
|
7
|
-
# a thin-router forwarder. Original skill already carries
|
|
8
|
-
# `deprecated-arguments: true` frontmatter from slice 1; this file
|
|
9
|
-
# asserts the transition-forwarder-specific contract.
|
|
10
|
-
#
|
|
11
|
-
# Note on shape: the transition forwarders are the trickiest of the
|
|
12
|
-
# P071 phased set because the argument is `<NNN> <word>` (data +
|
|
13
|
-
# verb). The parser must route on the PRESENCE of the verb token
|
|
14
|
-
# (`known-error` / `verifying` / `close`) AFTER the data parameter
|
|
15
|
-
# `<NNN>`. A bare `<NNN>` remains the legitimate update flow — it
|
|
16
|
-
# must NOT forward. This test locks the distinction in.
|
|
17
|
-
#
|
|
18
|
-
# Structural assertion — Permitted Exception to the source-grep ban
|
|
19
|
-
# (ADR-005 / P011 / ADR-037 contract-assertion pattern).
|
|
20
|
-
#
|
|
21
|
-
# @problem P071
|
|
22
|
-
# @jtbd JTBD-001 (enforce governance without slowing down)
|
|
23
|
-
# @jtbd JTBD-101 (extend the suite with clear patterns)
|
|
24
|
-
#
|
|
25
|
-
# Cross-reference:
|
|
26
|
-
# P071: docs/problems/071-argument-based-skill-subcommands-are-not-discoverable.open.md
|
|
27
|
-
# ADR-010 amended — split naming + forwarder contract + deprecated-arguments flag
|
|
28
|
-
# ADR-013 Rule 1 — structured user interaction (forwarder emits systemMessage, not AskUserQuestion)
|
|
29
|
-
# ADR-022 — Verification Pending is a first-class status; .verifying.md suffix on release
|
|
30
|
-
# ADR-037 — contract-assertion bats pattern
|
|
31
|
-
|
|
32
|
-
setup() {
|
|
33
|
-
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
34
|
-
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@test "manage-problem Step 1 forwards '<NNN> known-error' argument to /wr-itil:transition-problem (P071 slice 4)" {
|
|
38
|
-
# The forwarder names the target skill explicitly so the router is
|
|
39
|
-
# legible at the contract level. ADR-010's canonical shape: "invokes
|
|
40
|
-
# the new named skill via the Skill tool, not via re-prompting the
|
|
41
|
-
# user".
|
|
42
|
-
run grep -inE "/wr-itil:transition-problem" "$SKILL_FILE"
|
|
43
|
-
[ "$status" -eq 0 ]
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@test "manage-problem Step 1 emits the canonical known-error transition deprecation notice (ADR-010 amended)" {
|
|
47
|
-
# ADR-010's canonical deprecation-notice template:
|
|
48
|
-
# "/wr-<plugin>:<old> <arg> is deprecated; use /wr-<plugin>:<new>
|
|
49
|
-
# directly. This forwarder will be removed in <plugin>'s next major
|
|
50
|
-
# version."
|
|
51
|
-
# The notice MUST be emitted as a systemMessage (not AskUserQuestion)
|
|
52
|
-
# because deprecation is informational, not decisional (ADR-013
|
|
53
|
-
# Rule 1 scope). The transition-forwarder notice is distinct from
|
|
54
|
-
# list + review + work forwarders; all four must co-exist verbatim.
|
|
55
|
-
run grep -inE "is deprecated.*use /wr-itil:transition-problem|deprecated.*transition-problem|removed in .* next major version" "$SKILL_FILE"
|
|
56
|
-
[ "$status" -eq 0 ]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "manage-problem Step 1 transition-forwarder does not re-implement Step 7 transition logic (P071 regression guard)" {
|
|
60
|
-
# The forwarder must not duplicate the transition logic — it must
|
|
61
|
-
# delegate. Per ADR-010: "thin-router forwarder re-invokes the new
|
|
62
|
-
# named skill via the Skill tool". If the forwarder grows its own
|
|
63
|
-
# pre-flight + P057 + P063 + P062 stack, the deprecation window
|
|
64
|
-
# will harden into a permanent fork.
|
|
65
|
-
run grep -inE "delegate.*transition-problem|Skill tool.*transition-problem|transition-problem.*Skill tool" "$SKILL_FILE"
|
|
66
|
-
[ "$status" -eq 0 ]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@test "manage-problem Step 1 parser distinguishes bare <NNN> (update) from <NNN> <status> (transition)" {
|
|
70
|
-
# Critical safety rule: a bare `<NNN>` argument must REMAIN the
|
|
71
|
-
# update flow — it must not accidentally forward to
|
|
72
|
-
# transition-problem. Only the `<NNN> <status>` shape (where
|
|
73
|
-
# <status> ∈ {known-error, verifying, close}) triggers the
|
|
74
|
-
# transition forwarder. The parser block must name both branches
|
|
75
|
-
# so the distinction is legible at the contract level.
|
|
76
|
-
run grep -inE "known-error|verifying|close" "$SKILL_FILE"
|
|
77
|
-
[ "$status" -eq 0 ]
|
|
78
|
-
# And the bare-NNN update path is still documented.
|
|
79
|
-
run grep -inE "bare .NNN.|update flow|<NNN>.*update" "$SKILL_FILE"
|
|
80
|
-
[ "$status" -eq 0 ]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "manage-problem transition-forwarder covers known-error, verifying, and close (lifecycle completeness)" {
|
|
84
|
-
# ADR-022 codifies three transition destinations: known-error,
|
|
85
|
-
# verifying (Verification Pending), and closed. All three must
|
|
86
|
-
# appear in the forwarder contract so users can rely on the
|
|
87
|
-
# forwarder for the full lifecycle during the deprecation window.
|
|
88
|
-
# Missing any destination would force users back onto inline
|
|
89
|
-
# execution for that one case.
|
|
90
|
-
run grep -inE "known-error" "$SKILL_FILE"
|
|
91
|
-
[ "$status" -eq 0 ]
|
|
92
|
-
run grep -inE "verifying|verification.pending" "$SKILL_FILE"
|
|
93
|
-
[ "$status" -eq 0 ]
|
|
94
|
-
run grep -inE "\bclose\b" "$SKILL_FILE"
|
|
95
|
-
[ "$status" -eq 0 ]
|
|
96
|
-
}
|
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Contract + behavioural tests: manage-problem SKILL.md must define a
|
|
3
|
-
# transitive-dependency rule for WSJF effort, extend Step 9b with
|
|
4
|
-
# dependency-graph traversal, and the problem-ticket template must carry
|
|
5
|
-
# a `## Dependencies` section.
|
|
6
|
-
#
|
|
7
|
-
# Mixed shape — structural assertions (ADR-037 Permitted Exception) for
|
|
8
|
-
# the contract prose Claude interprets at invocation time, AND one
|
|
9
|
-
# behavioural fixture test that exercises the transitive-closure
|
|
10
|
-
# algorithm directly so the rule is not merely "keyword present" (P081
|
|
11
|
-
# pressure — behavioural where feasible).
|
|
12
|
-
#
|
|
13
|
-
# Cross-reference:
|
|
14
|
-
# @problem P076 — docs/problems/076-wsjf-does-not-model-transitive-dependencies.open.md
|
|
15
|
-
# ADR-022: verification-pending status carve-out from the closure
|
|
16
|
-
# ADR-014: governance-skills commit their own work
|
|
17
|
-
# ADR-037: contract-assertion bats pattern for SKILL.md prose contracts
|
|
18
|
-
# @jtbd JTBD-001 (solo-developer — enforce governance without slowing down)
|
|
19
|
-
# @jtbd JTBD-006 (solo-developer — progress the backlog while I'm away)
|
|
20
|
-
# @jtbd JTBD-201 (tech-lead — restore service fast with an audit trail)
|
|
21
|
-
|
|
22
|
-
setup() {
|
|
23
|
-
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
24
|
-
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
25
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
teardown() {
|
|
29
|
-
[ -n "${FIXTURE_DIR:-}" ] && [ -d "$FIXTURE_DIR" ] && rm -rf "$FIXTURE_DIR"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
33
|
-
# Contract: WSJF section defines the transitive-dependency rule
|
|
34
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
35
|
-
|
|
36
|
-
@test "SKILL.md WSJF section has a Transitive dependencies subsection (P076)" {
|
|
37
|
-
# The rule must live in a discoverable subsection so Claude finds it
|
|
38
|
-
# when interpreting the WSJF scoring contract.
|
|
39
|
-
run grep -nE "^### .*[Tt]ransitive [Dd]ependenc" "$SKILL_FILE"
|
|
40
|
-
[ "$status" -eq 0 ]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@test "SKILL.md transitive rule defines effort as max(marginal, blocked-by closure) (P076)" {
|
|
44
|
-
# The core rule: Effort(T)_transitive = max(marginal, max{blocked-by})
|
|
45
|
-
# The prose must make the max-of relationship explicit so a dependent
|
|
46
|
-
# ticket inherits upstream effort.
|
|
47
|
-
run grep -inE "max.*marginal|marginal.*max|transitive.*effort|effort.*transitive" "$SKILL_FILE"
|
|
48
|
-
[ "$status" -eq 0 ]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@test "SKILL.md transitive rule cites Blocked by as the dependency signal (P076)" {
|
|
52
|
-
# Blocked_by is the formally-scoped edge in the ticket-dependency graph.
|
|
53
|
-
# The rule must name it (not just generic "dependencies") so Claude knows
|
|
54
|
-
# which `## Dependencies` row drives the effort propagation.
|
|
55
|
-
run grep -inE "Blocked[[:space:]-]?by" "$SKILL_FILE"
|
|
56
|
-
[ "$status" -eq 0 ]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "SKILL.md transitive rule carves Composes with OUT of the closure (P076)" {
|
|
60
|
-
# Compositional overlap does NOT strictly block — sibling work that
|
|
61
|
-
# shares surface should not inflate the dependent's effort.
|
|
62
|
-
run grep -inE "[Cc]omposes[[:space:]]with.*not|not.*[Cc]omposes|[Cc]omposes[[:space:]]with.*does NOT|[Cc]omposes[[:space:]]with.*excluded" "$SKILL_FILE"
|
|
63
|
-
[ "$status" -eq 0 ]
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@test "SKILL.md transitive rule carves .closed / .verifying / .parked OUT of the closure (architect note)" {
|
|
67
|
-
# Architect correction: already-done or user-blocked upstreams contribute
|
|
68
|
-
# zero marginal dev effort — otherwise a ticket blocked by a closed
|
|
69
|
-
# ticket would inherit XL forever.
|
|
70
|
-
run grep -inE "(\.closed\.md|\.verifying\.md|\.parked\.md).*(contribut|0|zero|exclud)|contribut.*0.*(\.closed|\.verifying|\.parked)" "$SKILL_FILE"
|
|
71
|
-
[ "$status" -eq 0 ]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@test "SKILL.md transitive rule documents cycle bundling (shared WSJF as computed artefact) (P076)" {
|
|
75
|
-
# Cycles (e.g. P038/P064 mutual composition) must be handled — bundle's
|
|
76
|
-
# effort = max of members' marginals; shared WSJF surfaced in review
|
|
77
|
-
# output, not written as a field per-ticket (ADR-022 suffix-based pattern).
|
|
78
|
-
run grep -inE "cycle|bundle" "$SKILL_FILE"
|
|
79
|
-
[ "$status" -eq 0 ]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
@test "SKILL.md transitive rule carries a worked example (P076)" {
|
|
83
|
-
# Worked example: P073 marginal S blocked by P038 XL → transitive XL →
|
|
84
|
-
# WSJF drops to match P038. The number-grounded example keeps the rule
|
|
85
|
-
# out of hand-wavy territory (ADR-026 grounded output).
|
|
86
|
-
run grep -inE "[Ww]orked[[:space:]]example|example.*transitive|transitive.*example" "$SKILL_FILE"
|
|
87
|
-
[ "$status" -eq 0 ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@test "SKILL.md transitive rule notes reassessment-criteria for future ADR extraction (architect note)" {
|
|
91
|
-
# Architect guidance: keep a pointer for when another skill adopts the
|
|
92
|
-
# `## Dependencies` convention — at that point, extract to a sibling ADR.
|
|
93
|
-
# Inline note now avoids speculative ADR authoring today.
|
|
94
|
-
run grep -inE "[Rr]eassessment|[Ee]xtract.*ADR|sibling ADR|future ADR" "$SKILL_FILE"
|
|
95
|
-
[ "$status" -eq 0 ]
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
99
|
-
# Contract: Step 9b review extends to dependency-graph traversal
|
|
100
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
101
|
-
|
|
102
|
-
@test "SKILL.md Step 9b describes a dependency-graph traversal pass (P076)" {
|
|
103
|
-
# After per-ticket marginal scoring, Step 9b must walk the graph and
|
|
104
|
-
# propagate effort up. The prose must name the traversal explicitly so
|
|
105
|
-
# Claude performs the second pass, not just the first.
|
|
106
|
-
run grep -inE "dependency[[:space:]-]?graph|graph traversal|topological.*sort|propagate.*effort|effort.*propagat" "$SKILL_FILE"
|
|
107
|
-
[ "$status" -eq 0 ]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
@test "SKILL.md Step 9b reports transitive re-rates in the review summary (P076 + JTBD-006)" {
|
|
111
|
-
# The AFK orchestrator (JTBD-006) and the audit-trail persona (JTBD-201)
|
|
112
|
-
# depend on Step 9b emitting a visible re-rate line — not a silent
|
|
113
|
-
# update.
|
|
114
|
-
run grep -inE "transitive.*(re-?rate|rerat|re-?estimat)|report.*transitive|re-?rate.*transitive" "$SKILL_FILE"
|
|
115
|
-
[ "$status" -eq 0 ]
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@test "SKILL.md Step 9b re-rate message format is concrete (architect note — bats-assertable shape)" {
|
|
119
|
-
# Architect correction 4: specify a concrete message shape so the
|
|
120
|
-
# contract can be grepped. Format: P<NNN>: Effort <OLD> → <NEW>
|
|
121
|
-
# (transitive via <UPSTREAM>).
|
|
122
|
-
run grep -inE "Effort.*→.*transitive via|transitive via.*P[0-9]" "$SKILL_FILE"
|
|
123
|
-
[ "$status" -eq 0 ]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
127
|
-
# Contract: Step 5 problem-ticket template includes `## Dependencies`
|
|
128
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
129
|
-
|
|
130
|
-
@test "SKILL.md Step 5 template includes a ## Dependencies section (P076)" {
|
|
131
|
-
# New tickets must carry an explicit dependency list so the graph is
|
|
132
|
-
# legible. Empty lists are allowed (default: no deps).
|
|
133
|
-
run grep -nE "^## Dependencies" "$SKILL_FILE"
|
|
134
|
-
[ "$status" -eq 0 ]
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
@test "SKILL.md Dependencies template lists Blocks / Blocked by / Composes with rows (P076)" {
|
|
138
|
-
# The three row labels must all be present in the template so the
|
|
139
|
-
# author knows which semantics apply. Blocks = downstream; Blocked by =
|
|
140
|
-
# drives effort propagation; Composes with = overlap without blocking.
|
|
141
|
-
run grep -inE "\*\*Blocks\*\*|\*\*Blocked by\*\*|\*\*Composes with\*\*" "$SKILL_FILE"
|
|
142
|
-
[ "$status" -eq 0 ]
|
|
143
|
-
# All three labels must be present.
|
|
144
|
-
blocks_hits=$(grep -cE "\*\*Blocks\*\*" "$SKILL_FILE" || true)
|
|
145
|
-
blocked_hits=$(grep -cE "\*\*Blocked by\*\*" "$SKILL_FILE" || true)
|
|
146
|
-
composes_hits=$(grep -cE "\*\*Composes with\*\*" "$SKILL_FILE" || true)
|
|
147
|
-
[ "$blocks_hits" -ge 1 ]
|
|
148
|
-
[ "$blocked_hits" -ge 1 ]
|
|
149
|
-
[ "$composes_hits" -ge 1 ]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@test "SKILL.md Dependencies rows use bare ticket IDs (architect note Q1)" {
|
|
153
|
-
# Bare IDs (P038) beat link syntax (`[P038](./038-...)`) — less
|
|
154
|
-
# maintenance; review output renders to links on demand. The template
|
|
155
|
-
# example must show bare-ID form (not `[P038](./038-...)`).
|
|
156
|
-
# Canonical shape: `- **Blocked by**: P<NNN>, P<NNN>` — match either
|
|
157
|
-
# bold-markdown label form or plain-label form, asserting the ID is
|
|
158
|
-
# bare (not bracketed).
|
|
159
|
-
run grep -inE "Blocked by\*{0,2}:[[:space:]]*P[0-9]" "$SKILL_FILE"
|
|
160
|
-
[ "$status" -eq 0 ]
|
|
161
|
-
# Assert the example does NOT use link syntax `[PNNN](./...)`.
|
|
162
|
-
! grep -E "Blocked by\*{0,2}:[[:space:]]*\[P[0-9]" "$SKILL_FILE"
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
166
|
-
# Traceability: P076 cited
|
|
167
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
168
|
-
|
|
169
|
-
@test "SKILL.md cites P076 in the transitive-dependencies prose (traceability)" {
|
|
170
|
-
# Every governance-contract change must cite the problem ticket that
|
|
171
|
-
# motivated it — audit trail per ADR-014.
|
|
172
|
-
run grep -n "P076" "$SKILL_FILE"
|
|
173
|
-
[ "$status" -eq 0 ]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
177
|
-
# Behavioural: exercise the transitive-closure rule with fixture tickets
|
|
178
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
179
|
-
# These tests build a minimal fixture backlog and run a bash transcription
|
|
180
|
-
# of the transitive-closure rule against it. The rule's executable form is
|
|
181
|
-
# small enough to bash-implement; we assert the output matches the rule's
|
|
182
|
-
# spec so a prose drift (e.g. accidentally documenting `min` instead of
|
|
183
|
-
# `max`) would be caught at test time.
|
|
184
|
-
|
|
185
|
-
# Bash transcription of the transitive-closure rule — effort map is
|
|
186
|
-
# keyed by ticket ID, value is the integer divisor from the SKILL.md
|
|
187
|
-
# effort table (S=1, M=2, L=4, XL=8).
|
|
188
|
-
transitive_effort() {
|
|
189
|
-
local ticket="$1"
|
|
190
|
-
local backlog_dir="$2"
|
|
191
|
-
local file
|
|
192
|
-
file=$(ls "$backlog_dir"/${ticket}-*.md 2>/dev/null | head -1)
|
|
193
|
-
[ -z "$file" ] && { echo 0; return; }
|
|
194
|
-
|
|
195
|
-
# Extract marginal effort from the Effort line. The line shape matches
|
|
196
|
-
# the SKILL.md Priority/Effort convention: "**Effort**: <bucket> — ..."
|
|
197
|
-
local marginal_bucket
|
|
198
|
-
marginal_bucket=$(grep -oE '\*\*Effort\*\*: [SMLXL]+' "$file" | head -1 | grep -oE '[SMLXL]+' | head -1)
|
|
199
|
-
local marginal_divisor
|
|
200
|
-
case "$marginal_bucket" in
|
|
201
|
-
S) marginal_divisor=1 ;;
|
|
202
|
-
M) marginal_divisor=2 ;;
|
|
203
|
-
L) marginal_divisor=4 ;;
|
|
204
|
-
XL) marginal_divisor=8 ;;
|
|
205
|
-
*) marginal_divisor=2 ;; # default M
|
|
206
|
-
esac
|
|
207
|
-
|
|
208
|
-
# .closed.md / .verifying.md / .parked.md upstreams contribute 0 (architect carve-out)
|
|
209
|
-
case "$file" in
|
|
210
|
-
*.closed.md|*.verifying.md|*.parked.md)
|
|
211
|
-
echo 0
|
|
212
|
-
return
|
|
213
|
-
;;
|
|
214
|
-
esac
|
|
215
|
-
|
|
216
|
-
# Extract `Blocked by:` dependency IDs (bare, comma-separated).
|
|
217
|
-
# The template shape is `- **Blocked by**: P<NNN>, P<NNN>` (markdown
|
|
218
|
-
# list item under `## Dependencies`) — match the label with optional
|
|
219
|
-
# leading list marker.
|
|
220
|
-
local blocked_by_line
|
|
221
|
-
blocked_by_line=$(grep -E "^[[:space:]]*-?[[:space:]]*\*\*Blocked by\*\*:" "$file" | head -1 | sed 's/.*\*\*Blocked by\*\*://')
|
|
222
|
-
local max_upstream=0
|
|
223
|
-
local dep
|
|
224
|
-
for dep in $(echo "$blocked_by_line" | grep -oE 'P[0-9]+'); do
|
|
225
|
-
local upstream_effort
|
|
226
|
-
upstream_effort=$(transitive_effort "$dep" "$backlog_dir")
|
|
227
|
-
[ "$upstream_effort" -gt "$max_upstream" ] && max_upstream="$upstream_effort"
|
|
228
|
-
done
|
|
229
|
-
|
|
230
|
-
# Transitive = max(marginal, upstream closure)
|
|
231
|
-
if [ "$max_upstream" -gt "$marginal_divisor" ]; then
|
|
232
|
-
echo "$max_upstream"
|
|
233
|
-
else
|
|
234
|
-
echo "$marginal_divisor"
|
|
235
|
-
fi
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
@test "behavioural: dependent ticket inherits upstream XL when blocked by XL ticket (P076 worked example)" {
|
|
239
|
-
# Fixture: P200 (marginal S) Blocked by: P201 (XL)
|
|
240
|
-
# Expected: transitive effort for P200 = XL divisor = 8
|
|
241
|
-
cat > "$FIXTURE_DIR/P201-upstream-xl.open.md" <<'EOF'
|
|
242
|
-
# Problem 201: upstream XL ticket
|
|
243
|
-
**Status**: Open
|
|
244
|
-
**Effort**: XL — multi-day cross-package work
|
|
245
|
-
|
|
246
|
-
## Dependencies
|
|
247
|
-
- **Blocked by**: (none)
|
|
248
|
-
EOF
|
|
249
|
-
cat > "$FIXTURE_DIR/P200-dependent-small.open.md" <<'EOF'
|
|
250
|
-
# Problem 200: dependent with small marginal effort
|
|
251
|
-
**Status**: Open
|
|
252
|
-
**Effort**: S — one-line surface add
|
|
253
|
-
|
|
254
|
-
## Dependencies
|
|
255
|
-
- **Blocked by**: P201
|
|
256
|
-
EOF
|
|
257
|
-
result=$(transitive_effort "P200" "$FIXTURE_DIR")
|
|
258
|
-
[ "$result" = "8" ]
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
@test "behavioural: self-contained ticket keeps marginal effort (P076 no-op path)" {
|
|
262
|
-
# Fixture: P210 (marginal M) with empty Blocked by.
|
|
263
|
-
# Expected: transitive = marginal M divisor = 2.
|
|
264
|
-
cat > "$FIXTURE_DIR/P210-solo-m.open.md" <<'EOF'
|
|
265
|
-
# Problem 210: self-contained
|
|
266
|
-
**Status**: Open
|
|
267
|
-
**Effort**: M — couple of files
|
|
268
|
-
|
|
269
|
-
## Dependencies
|
|
270
|
-
- **Blocked by**: (none)
|
|
271
|
-
EOF
|
|
272
|
-
result=$(transitive_effort "P210" "$FIXTURE_DIR")
|
|
273
|
-
[ "$result" = "2" ]
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
@test "behavioural: closed upstream contributes 0 to the closure (architect carve-out)" {
|
|
277
|
-
# Fixture: P220 (marginal S) Blocked by: P221 (was XL, now closed).
|
|
278
|
-
# Expected: transitive = marginal S = 1 (closed upstream contributes 0;
|
|
279
|
-
# otherwise P220 would inherit XL forever).
|
|
280
|
-
cat > "$FIXTURE_DIR/P221-closed-xl.closed.md" <<'EOF'
|
|
281
|
-
# Problem 221: closed upstream (was XL)
|
|
282
|
-
**Status**: Closed
|
|
283
|
-
**Effort**: XL
|
|
284
|
-
EOF
|
|
285
|
-
cat > "$FIXTURE_DIR/P220-dependent-on-closed.open.md" <<'EOF'
|
|
286
|
-
# Problem 220: dependent on closed
|
|
287
|
-
**Status**: Open
|
|
288
|
-
**Effort**: S
|
|
289
|
-
|
|
290
|
-
## Dependencies
|
|
291
|
-
- **Blocked by**: P221
|
|
292
|
-
EOF
|
|
293
|
-
result=$(transitive_effort "P220" "$FIXTURE_DIR")
|
|
294
|
-
[ "$result" = "1" ]
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
@test "behavioural: marginal effort wins when upstream is smaller (P076 max-of semantics)" {
|
|
298
|
-
# Fixture: P230 (marginal L = 4) Blocked by: P231 (S = 1)
|
|
299
|
-
# Expected: transitive = max(L, S) = L divisor = 4.
|
|
300
|
-
# (Contrast: a buggy implementation using min or sum would produce 1 or 5.)
|
|
301
|
-
cat > "$FIXTURE_DIR/P231-small-upstream.open.md" <<'EOF'
|
|
302
|
-
# Problem 231: small upstream
|
|
303
|
-
**Status**: Open
|
|
304
|
-
**Effort**: S
|
|
305
|
-
EOF
|
|
306
|
-
cat > "$FIXTURE_DIR/P230-big-dependent.open.md" <<'EOF'
|
|
307
|
-
# Problem 230: bigger dependent
|
|
308
|
-
**Status**: Open
|
|
309
|
-
**Effort**: L
|
|
310
|
-
|
|
311
|
-
## Dependencies
|
|
312
|
-
- **Blocked by**: P231
|
|
313
|
-
EOF
|
|
314
|
-
result=$(transitive_effort "P230" "$FIXTURE_DIR")
|
|
315
|
-
[ "$result" = "4" ]
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
@test "behavioural: transitive propagates across two hops (P076 closure semantics)" {
|
|
319
|
-
# Fixture: P240 (S) → blocked by P241 (S) → blocked by P242 (XL)
|
|
320
|
-
# Expected: transitive(P240) = max(S, transitive(P241)) = max(S, max(S, XL)) = XL = 8.
|
|
321
|
-
cat > "$FIXTURE_DIR/P242-deepest-xl.open.md" <<'EOF'
|
|
322
|
-
# Problem 242: deepest XL
|
|
323
|
-
**Status**: Open
|
|
324
|
-
**Effort**: XL
|
|
325
|
-
EOF
|
|
326
|
-
cat > "$FIXTURE_DIR/P241-middle-s.open.md" <<'EOF'
|
|
327
|
-
# Problem 241: middle S
|
|
328
|
-
**Status**: Open
|
|
329
|
-
**Effort**: S
|
|
330
|
-
|
|
331
|
-
## Dependencies
|
|
332
|
-
- **Blocked by**: P242
|
|
333
|
-
EOF
|
|
334
|
-
cat > "$FIXTURE_DIR/P240-top-s.open.md" <<'EOF'
|
|
335
|
-
# Problem 240: top S
|
|
336
|
-
**Status**: Open
|
|
337
|
-
**Effort**: S
|
|
338
|
-
|
|
339
|
-
## Dependencies
|
|
340
|
-
- **Blocked by**: P241
|
|
341
|
-
EOF
|
|
342
|
-
result=$(transitive_effort "P240" "$FIXTURE_DIR")
|
|
343
|
-
[ "$result" = "8" ]
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
@test "behavioural: verification-pending upstream contributes 0 (architect carve-out for .verifying.md)" {
|
|
347
|
-
# Fixture: P250 (marginal S) Blocked by: P251 (was XL, now verifying).
|
|
348
|
-
# Expected: transitive = marginal S = 1 (verifying contributes 0 — the
|
|
349
|
-
# remaining work is user-side verification, not dev effort).
|
|
350
|
-
cat > "$FIXTURE_DIR/P251-verifying-xl.verifying.md" <<'EOF'
|
|
351
|
-
# Problem 251: verification pending (was XL)
|
|
352
|
-
**Status**: Verification Pending
|
|
353
|
-
**Effort**: XL
|
|
354
|
-
EOF
|
|
355
|
-
cat > "$FIXTURE_DIR/P250-dependent-on-verifying.open.md" <<'EOF'
|
|
356
|
-
# Problem 250: dependent on verifying
|
|
357
|
-
**Status**: Open
|
|
358
|
-
**Effort**: S
|
|
359
|
-
|
|
360
|
-
## Dependencies
|
|
361
|
-
- **Blocked by**: P251
|
|
362
|
-
EOF
|
|
363
|
-
result=$(transitive_effort "P250" "$FIXTURE_DIR")
|
|
364
|
-
[ "$result" = "1" ]
|
|
365
|
-
}
|