@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,93 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Contract-assertion bats for work-problems Step 0 session-continuity
|
|
3
|
-
# detection — staleness filter on .afk-run-state/iter-*.json error markers
|
|
4
|
-
# (per P333).
|
|
5
|
-
#
|
|
6
|
-
# Per ADR-037 SKILL.md is a contract document; these assertions check the
|
|
7
|
-
# contract strings the skill prose authoritatively pins for the staleness
|
|
8
|
-
# filter that distinguishes load-bearing partial-work markers from stale
|
|
9
|
-
# residuals. Companion to work-problems-preflight-session-continuity.bats
|
|
10
|
-
# (which covers the broader signal-enumeration + interactive/AFK routing
|
|
11
|
-
# invariants from P109).
|
|
12
|
-
#
|
|
13
|
-
# Cross-reference:
|
|
14
|
-
# @problem P333 (Step 0 session-continuity has no staleness filter on
|
|
15
|
-
# .afk-run-state/iter-*.json error markers — stale residuals
|
|
16
|
-
# indefinitely false-positive the halt/ask gate)
|
|
17
|
-
# @problem P109 (parent session-continuity detection extension)
|
|
18
|
-
# ADR-019 (AFK orchestrator preflight — extension surface)
|
|
19
|
-
# ADR-032 (subprocess artefact contract — iter-*.json shape)
|
|
20
|
-
# ADR-037 (skill testing strategy — contract-assertion framing)
|
|
21
|
-
# @jtbd JTBD-006 (Progress the Backlog While I'm Away — false-positive
|
|
22
|
-
# halts violate the AFK forward-progress outcome)
|
|
23
|
-
|
|
24
|
-
setup() {
|
|
25
|
-
SKILL_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
26
|
-
SKILL_FILE="${SKILL_DIR}/SKILL.md"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
@test "SKILL.md exists" {
|
|
30
|
-
[ -f "$SKILL_FILE" ]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@test "SKILL.md Step 0 cites P333 as the staleness-filter driver" {
|
|
34
|
-
# Contract criterion: the staleness predicate is traceable to its
|
|
35
|
-
# driver ticket so a reader can find the failure mode the filter
|
|
36
|
-
# closes.
|
|
37
|
-
run grep -nE "P333" "$SKILL_FILE"
|
|
38
|
-
[ "$status" -eq 0 ]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
@test "SKILL.md Step 0 names the staleness filter for iter-*.json markers" {
|
|
42
|
-
# Contract criterion: the iter-*.json error-marker row names a
|
|
43
|
-
# staleness / freshness predicate (not merely the is_error /
|
|
44
|
-
# api_error_status field check).
|
|
45
|
-
run grep -niE "stale|staleness|freshness|fresh per" "$SKILL_FILE"
|
|
46
|
-
[ "$status" -eq 0 ]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@test "SKILL.md Step 0 names mtime + HEAD-commit-time as the staleness primitive" {
|
|
50
|
-
# Contract criterion: the staleness predicate is specified as mtime
|
|
51
|
-
# vs HEAD-commit-time (the engineering primitive). The "more
|
|
52
|
-
# permissive of two" disjunction is asserted in a sibling test below.
|
|
53
|
-
run grep -niE "mtime" "$SKILL_FILE"
|
|
54
|
-
[ "$status" -eq 0 ]
|
|
55
|
-
run grep -niE "HEAD.commit|HEAD's commit|commit.time" "$SKILL_FILE"
|
|
56
|
-
[ "$status" -eq 0 ]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "SKILL.md Step 0 names the 24h fallback for the staleness predicate" {
|
|
60
|
-
# Contract criterion: the "OR within 24h" disjunction protects the
|
|
61
|
-
# fresh-repo-no-commits-since-marker edge case.
|
|
62
|
-
run grep -niE "24h|24 hour|last 24" "$SKILL_FILE"
|
|
63
|
-
[ "$status" -eq 0 ]
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
@test "SKILL.md Step 0 names the silent-skip directive for stale residuals" {
|
|
67
|
-
# Contract criterion: the action on stale-classified markers is
|
|
68
|
-
# silent-skip, not halt-with-report. This is the directional
|
|
69
|
-
# asymmetry the contract pins (fresh = halt, stale = skip).
|
|
70
|
-
run grep -niE "skip.*silent|silently.*skip|silent skip" "$SKILL_FILE"
|
|
71
|
-
[ "$status" -eq 0 ]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@test "SKILL.md Step 0 retains the is_error / api_error_status field names alongside the staleness filter" {
|
|
75
|
-
# Contract criterion: the existing P109 signal field-name contract
|
|
76
|
-
# MUST coexist with the new staleness predicate — the staleness
|
|
77
|
-
# filter narrows the load-bearing signal, it does not replace the
|
|
78
|
-
# field check.
|
|
79
|
-
run grep -niE "is_error.*true|api_error_status" "$SKILL_FILE"
|
|
80
|
-
[ "$status" -eq 0 ]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "SKILL.md Step 0 names the iter-summary annotation for skipped stale markers" {
|
|
84
|
-
# Contract criterion per JTBD-006 audit-trail outcome (line 34 of
|
|
85
|
-
# docs/jtbd/developer/JTBD-006.md): "every action taken during AFK
|
|
86
|
-
# mode should be traceable via git history and the progress
|
|
87
|
-
# summary". A silent-skip without an iter-summary annotation drops
|
|
88
|
-
# an action from the audit trail; the contract names the annotation
|
|
89
|
-
# shape so a stale-skipped-but-actually-load-bearing marker is
|
|
90
|
-
# recoverable on user return.
|
|
91
|
-
run grep -niE "stale iter.error|stale.*marker.*skip|iter.error.markers? skipped" "$SKILL_FILE"
|
|
92
|
-
[ "$status" -eq 0 ]
|
|
93
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Step 0b behavioural fixture per ADR-062 § JTBD-006 driver:
|
|
4
|
-
# work-problems pre-flights /wr-itil:review-problems when the
|
|
5
|
-
# upstream inbound-discovery cache is stale or missing. The
|
|
6
|
-
# staleness decision lives in
|
|
7
|
-
# `packages/itil/lib/check-upstream-cache-staleness.sh::should_promote_inbound_discovery_preflight`
|
|
8
|
-
# so the SKILL.md Step 0b prose is a thin source-and-call wrapper
|
|
9
|
-
# around a behaviorally-testable shell function (P081 / user
|
|
10
|
-
# feedback: prefer behavioural over structural-grep tests).
|
|
11
|
-
#
|
|
12
|
-
# Cases covered:
|
|
13
|
-
# 1. No channels-config file → "no-channels-config" (downstream-adopter non-obligation, ADR-062 § Downstream-adopter contract).
|
|
14
|
-
# 2. Channels-config present, cache file absent → "first-run-cache-absent".
|
|
15
|
-
# 3. Channels-config present, cache present, last_checked null → "first-run-last-checked-null".
|
|
16
|
-
# 4. Channels-config present, cache fresh within TTL → "fresh-within-ttl".
|
|
17
|
-
# 5. Channels-config present, cache older than TTL → "ttl-expiry" (with age + ttl in the reason).
|
|
18
|
-
# 6. Custom ttl_seconds in channels-config is respected (not hardcoded default).
|
|
19
|
-
|
|
20
|
-
setup() {
|
|
21
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
22
|
-
HELPER="$REPO_ROOT/packages/itil/lib/check-upstream-cache-staleness.sh"
|
|
23
|
-
|
|
24
|
-
FIXTURE="$(mktemp -d)"
|
|
25
|
-
mkdir -p "$FIXTURE/docs/problems"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
teardown() {
|
|
29
|
-
rm -rf "$FIXTURE"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
@test "helper exists at the contracted path" {
|
|
33
|
-
[ -f "$HELPER" ]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@test "case 1: no channels-config → no-channels-config" {
|
|
37
|
-
# shellcheck disable=SC1090
|
|
38
|
-
source "$HELPER"
|
|
39
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
40
|
-
[ "$status" -eq 0 ]
|
|
41
|
-
[ "$output" = "no-channels-config" ]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@test "case 2: channels-config present, cache absent → first-run-cache-absent" {
|
|
45
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
46
|
-
{ "channels": [], "ttl_seconds": 86400 }
|
|
47
|
-
EOF
|
|
48
|
-
# shellcheck disable=SC1090
|
|
49
|
-
source "$HELPER"
|
|
50
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
51
|
-
[ "$status" -eq 0 ]
|
|
52
|
-
[ "$output" = "first-run-cache-absent" ]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@test "case 3: cache present, last_checked null → first-run-last-checked-null" {
|
|
56
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
57
|
-
{ "channels": [], "ttl_seconds": 86400 }
|
|
58
|
-
EOF
|
|
59
|
-
cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<'EOF'
|
|
60
|
-
{ "last_checked": null, "channels": [] }
|
|
61
|
-
EOF
|
|
62
|
-
# shellcheck disable=SC1090
|
|
63
|
-
source "$HELPER"
|
|
64
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
65
|
-
[ "$status" -eq 0 ]
|
|
66
|
-
[ "$output" = "first-run-last-checked-null" ]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@test "case 4: cache fresh within TTL → fresh-within-ttl (silent-pass)" {
|
|
70
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
71
|
-
{ "channels": [], "ttl_seconds": 86400 }
|
|
72
|
-
EOF
|
|
73
|
-
# last_checked 1 hour ago — well within 24h TTL.
|
|
74
|
-
local recent_iso
|
|
75
|
-
recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
76
|
-
cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
|
|
77
|
-
{ "last_checked": "$recent_iso", "channels": [] }
|
|
78
|
-
EOF
|
|
79
|
-
# shellcheck disable=SC1090
|
|
80
|
-
source "$HELPER"
|
|
81
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
82
|
-
[ "$status" -eq 0 ]
|
|
83
|
-
[ "$output" = "fresh-within-ttl" ]
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
@test "case 5: cache older than TTL → ttl-expiry with age + ttl in the reason" {
|
|
87
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
88
|
-
{ "channels": [], "ttl_seconds": 86400 }
|
|
89
|
-
EOF
|
|
90
|
-
# last_checked 2 days ago — past 24h TTL.
|
|
91
|
-
local stale_iso
|
|
92
|
-
stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
93
|
-
cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
|
|
94
|
-
{ "last_checked": "$stale_iso", "channels": [] }
|
|
95
|
-
EOF
|
|
96
|
-
# shellcheck disable=SC1090
|
|
97
|
-
source "$HELPER"
|
|
98
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
99
|
-
[ "$status" -eq 0 ]
|
|
100
|
-
# Format: "ttl-expiry age=<N>s ttl=<M>s"
|
|
101
|
-
[[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=86400s$ ]]
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
@test "case 6: custom ttl_seconds is honored (not hardcoded default)" {
|
|
105
|
-
# 1-hour TTL; last_checked 90 minutes ago → stale under the custom TTL,
|
|
106
|
-
# but would be FRESH under the 86400s default. Confirms the helper reads
|
|
107
|
-
# ttl_seconds from channels-config rather than hardcoding 86400.
|
|
108
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
109
|
-
{ "channels": [], "ttl_seconds": 3600 }
|
|
110
|
-
EOF
|
|
111
|
-
local mid_iso
|
|
112
|
-
mid_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=90)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
113
|
-
cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
|
|
114
|
-
{ "last_checked": "$mid_iso", "channels": [] }
|
|
115
|
-
EOF
|
|
116
|
-
# shellcheck disable=SC1090
|
|
117
|
-
source "$HELPER"
|
|
118
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
119
|
-
[ "$status" -eq 0 ]
|
|
120
|
-
[[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=3600s$ ]]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
@test "case 7: missing ttl_seconds field defaults to 86400 (24h)" {
|
|
124
|
-
cat > "$FIXTURE/docs/problems/.upstream-channels.json" <<'EOF'
|
|
125
|
-
{ "channels": [] }
|
|
126
|
-
EOF
|
|
127
|
-
# last_checked 1 hour ago — fresh under the default 86400s TTL.
|
|
128
|
-
local recent_iso
|
|
129
|
-
recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
130
|
-
cat > "$FIXTURE/docs/problems/.upstream-cache.json" <<EOF
|
|
131
|
-
{ "last_checked": "$recent_iso", "channels": [] }
|
|
132
|
-
EOF
|
|
133
|
-
# shellcheck disable=SC1090
|
|
134
|
-
source "$HELPER"
|
|
135
|
-
run should_promote_inbound_discovery_preflight "$FIXTURE"
|
|
136
|
-
[ "$status" -eq 0 ]
|
|
137
|
-
[ "$output" = "fresh-within-ttl" ]
|
|
138
|
-
}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Step 0c behavioural fixture per P271:
|
|
4
|
-
# work-problems pre-flights /wr-itil:review-problems when deferred-placeholder
|
|
5
|
-
# tickets accumulate AND the docs/problems/README.md "Last reviewed" line is
|
|
6
|
-
# stale. Mirrors the Step 0b cache-staleness shape (helper-in-lib + 5-outcome
|
|
7
|
-
# enum + behavioural bats) so the SKILL.md Step 0c prose stays a thin
|
|
8
|
-
# source-and-call wrapper around a behaviorally-testable shell function.
|
|
9
|
-
#
|
|
10
|
-
# Trigger rule — two-axis AND per P271 § Recommended fix shape (architect
|
|
11
|
-
# Condition 2 — both axes are load-bearing; either alone over-fires):
|
|
12
|
-
# - count of deferred-placeholder tickets ≥ 3 (signal: there is work to
|
|
13
|
-
# re-rate), AND
|
|
14
|
-
# - README.md "Last reviewed" line-3 age > 7 days (signal: cadence has
|
|
15
|
-
# slipped).
|
|
16
|
-
#
|
|
17
|
-
# Cases covered:
|
|
18
|
-
# 1. No deferred placeholders → "no-deferred-placeholders"
|
|
19
|
-
# 2. Count below threshold (1 or 2) → "below-threshold count=<N> threshold=3"
|
|
20
|
-
# 3. Count ≥ 3 + README absent → "no-readme count=<N>"
|
|
21
|
-
# 4. Count ≥ 3 + README fresh (< 7 days) → "fresh-readme count=<N> age=<X>s threshold=<Y>s"
|
|
22
|
-
# 5. Count ≥ 3 + README stale (> 7 days) → "stale-readme count=<N> age=<X>s threshold=<Y>s"
|
|
23
|
-
# 6. Dual-tolerant glob (per ADR-031 RFC-002 migration window — both flat
|
|
24
|
-
# docs/problems/<NNN>-*.<state>.md AND per-state docs/problems/<state>/<NNN>-*.md
|
|
25
|
-
# contribute to count)
|
|
26
|
-
|
|
27
|
-
setup() {
|
|
28
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
29
|
-
HELPER="$REPO_ROOT/packages/itil/lib/check-deferred-placeholder-staleness.sh"
|
|
30
|
-
|
|
31
|
-
FIXTURE="$(mktemp -d)"
|
|
32
|
-
mkdir -p "$FIXTURE/docs/problems/open"
|
|
33
|
-
mkdir -p "$FIXTURE/docs/problems/known-error"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
teardown() {
|
|
37
|
-
rm -rf "$FIXTURE"
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# Helper — write a problem ticket with the deferred-placeholder marker.
|
|
41
|
-
write_deferred_ticket() {
|
|
42
|
-
local path="$1"
|
|
43
|
-
cat > "$path" <<'EOF'
|
|
44
|
-
# Problem 999: test
|
|
45
|
-
|
|
46
|
-
**Status**: Open
|
|
47
|
-
**Priority**: 3 (Medium) — Impact: 3 x Likelihood: 1 (deferred — re-rate at next /wr-itil:review-problems)
|
|
48
|
-
**Effort**: M (deferred — re-rate at next /wr-itil:review-problems)
|
|
49
|
-
|
|
50
|
-
## Description
|
|
51
|
-
|
|
52
|
-
test fixture
|
|
53
|
-
EOF
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
# Helper — write a non-deferred (already-rated) ticket.
|
|
57
|
-
write_rated_ticket() {
|
|
58
|
-
local path="$1"
|
|
59
|
-
cat > "$path" <<'EOF'
|
|
60
|
-
# Problem 998: test
|
|
61
|
-
|
|
62
|
-
**Status**: Open
|
|
63
|
-
**Priority**: 6 (Medium) — Impact: 3 x Likelihood: 2
|
|
64
|
-
**Effort**: S
|
|
65
|
-
|
|
66
|
-
## Description
|
|
67
|
-
|
|
68
|
-
test fixture
|
|
69
|
-
EOF
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
# Helper — write a README.md with a known "Last reviewed" date on line 3.
|
|
73
|
-
write_readme_with_date() {
|
|
74
|
-
local path="$1"
|
|
75
|
-
local iso_date="$2"
|
|
76
|
-
cat > "$path" <<EOF
|
|
77
|
-
# Problem Backlog
|
|
78
|
-
|
|
79
|
-
> Last reviewed: $iso_date **review** — test fixture
|
|
80
|
-
> Run \`/wr-itil:review-problems\` to refresh WSJF rankings.
|
|
81
|
-
|
|
82
|
-
## WSJF Rankings
|
|
83
|
-
EOF
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
@test "helper exists at the contracted path" {
|
|
87
|
-
[ -f "$HELPER" ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
@test "case 1: no deferred placeholders → no-deferred-placeholders" {
|
|
91
|
-
write_rated_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
92
|
-
write_rated_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
93
|
-
# shellcheck disable=SC1090
|
|
94
|
-
source "$HELPER"
|
|
95
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
96
|
-
[ "$status" -eq 0 ]
|
|
97
|
-
[ "$output" = "no-deferred-placeholders" ]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
@test "case 2: count below threshold (1) → below-threshold" {
|
|
101
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
102
|
-
write_rated_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
103
|
-
# shellcheck disable=SC1090
|
|
104
|
-
source "$HELPER"
|
|
105
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
106
|
-
[ "$status" -eq 0 ]
|
|
107
|
-
[[ "$output" =~ ^below-threshold\ count=1\ threshold=3$ ]]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
@test "case 2b: count below threshold (2) → below-threshold" {
|
|
111
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
112
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
113
|
-
# shellcheck disable=SC1090
|
|
114
|
-
source "$HELPER"
|
|
115
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
116
|
-
[ "$status" -eq 0 ]
|
|
117
|
-
[[ "$output" =~ ^below-threshold\ count=2\ threshold=3$ ]]
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
@test "case 3: count ≥ 3 + README absent → no-readme (first-run dispatch trigger)" {
|
|
121
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
122
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
123
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
|
|
124
|
-
# No README written.
|
|
125
|
-
# shellcheck disable=SC1090
|
|
126
|
-
source "$HELPER"
|
|
127
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
128
|
-
[ "$status" -eq 0 ]
|
|
129
|
-
[[ "$output" =~ ^no-readme\ count=3$ ]]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
@test "case 4: count ≥ 3 + README fresh (< 7 days) → fresh-readme silent-pass" {
|
|
133
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
134
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
135
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
|
|
136
|
-
# README dated 3 days ago — fresh under 7-day threshold.
|
|
137
|
-
local recent_iso
|
|
138
|
-
recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=3)).strftime('%Y-%m-%d'))")"
|
|
139
|
-
write_readme_with_date "$FIXTURE/docs/problems/README.md" "$recent_iso"
|
|
140
|
-
# shellcheck disable=SC1090
|
|
141
|
-
source "$HELPER"
|
|
142
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
143
|
-
[ "$status" -eq 0 ]
|
|
144
|
-
[[ "$output" =~ ^fresh-readme\ count=3\ age=[0-9]+s\ threshold=604800s$ ]]
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
@test "case 5: count ≥ 3 + README stale (> 7 days) → stale-readme (dispatch trigger)" {
|
|
148
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
149
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
150
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
|
|
151
|
-
# README dated 14 days ago — stale under 7-day threshold.
|
|
152
|
-
local stale_iso
|
|
153
|
-
stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=14)).strftime('%Y-%m-%d'))")"
|
|
154
|
-
write_readme_with_date "$FIXTURE/docs/problems/README.md" "$stale_iso"
|
|
155
|
-
# shellcheck disable=SC1090
|
|
156
|
-
source "$HELPER"
|
|
157
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
158
|
-
[ "$status" -eq 0 ]
|
|
159
|
-
[[ "$output" =~ ^stale-readme\ count=3\ age=[0-9]+s\ threshold=604800s$ ]]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@test "case 6: dual-tolerant glob — per-state subdir layout (ADR-031 post-migration)" {
|
|
163
|
-
# Per-state subdir tickets (post-RFC-002-migration shape — the dominant
|
|
164
|
-
# shape in this monorepo).
|
|
165
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/100-foo.md"
|
|
166
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/101-bar.md"
|
|
167
|
-
write_deferred_ticket "$FIXTURE/docs/problems/known-error/102-baz.md"
|
|
168
|
-
# No README → first-run dispatch.
|
|
169
|
-
# shellcheck disable=SC1090
|
|
170
|
-
source "$HELPER"
|
|
171
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
[[ "$output" =~ ^no-readme\ count=3$ ]]
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
@test "case 6b: dual-tolerant glob — flat layout (ADR-031 pre-migration window)" {
|
|
177
|
-
# Flat-layout tickets (pre-RFC-002-migration shape — the legacy shape).
|
|
178
|
-
write_deferred_ticket "$FIXTURE/docs/problems/200-foo.open.md"
|
|
179
|
-
write_deferred_ticket "$FIXTURE/docs/problems/201-bar.open.md"
|
|
180
|
-
write_deferred_ticket "$FIXTURE/docs/problems/202-baz.known-error.md"
|
|
181
|
-
# No README → first-run dispatch.
|
|
182
|
-
# shellcheck disable=SC1090
|
|
183
|
-
source "$HELPER"
|
|
184
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
185
|
-
[ "$status" -eq 0 ]
|
|
186
|
-
[[ "$output" =~ ^no-readme\ count=3$ ]]
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
@test "case 6c: dual-tolerant glob — mixed layout (RFC-002 migration in progress)" {
|
|
190
|
-
# Mixed-layout tickets — both shapes contribute to the count.
|
|
191
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/100-foo.md"
|
|
192
|
-
write_deferred_ticket "$FIXTURE/docs/problems/200-bar.open.md"
|
|
193
|
-
write_deferred_ticket "$FIXTURE/docs/problems/known-error/300-baz.md"
|
|
194
|
-
# shellcheck disable=SC1090
|
|
195
|
-
source "$HELPER"
|
|
196
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
197
|
-
[ "$status" -eq 0 ]
|
|
198
|
-
[[ "$output" =~ ^no-readme\ count=3$ ]]
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@test "case 7: README missing 'Last reviewed' line → no-readme (defensive fallback)" {
|
|
202
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/001-foo.md"
|
|
203
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/002-bar.md"
|
|
204
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/003-baz.md"
|
|
205
|
-
# README exists but no "Last reviewed:" marker on line 3.
|
|
206
|
-
cat > "$FIXTURE/docs/problems/README.md" <<'EOF'
|
|
207
|
-
# Problem Backlog
|
|
208
|
-
|
|
209
|
-
Some other line that does not have the Last reviewed marker.
|
|
210
|
-
|
|
211
|
-
## WSJF Rankings
|
|
212
|
-
EOF
|
|
213
|
-
# shellcheck disable=SC1090
|
|
214
|
-
source "$HELPER"
|
|
215
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
216
|
-
[ "$status" -eq 0 ]
|
|
217
|
-
# Defensive: parse failure routes to no-readme (forces a fresh dispatch
|
|
218
|
-
# rather than silently silent-passing on malformed README).
|
|
219
|
-
[[ "$output" =~ ^no-readme\ count=3$ ]]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
@test "case 8: closed and verifying tickets do NOT contribute to count" {
|
|
223
|
-
# Only open + known-error tickets are eligible re-rate candidates.
|
|
224
|
-
# .verifying.md and .closed.md tickets carry no WSJF (excluded from
|
|
225
|
-
# dev-work ranking per ADR-022); their deferred-placeholders must not
|
|
226
|
-
# influence the dispatch.
|
|
227
|
-
mkdir -p "$FIXTURE/docs/problems/closed"
|
|
228
|
-
mkdir -p "$FIXTURE/docs/problems/verifying"
|
|
229
|
-
write_deferred_ticket "$FIXTURE/docs/problems/closed/100-foo.md"
|
|
230
|
-
write_deferred_ticket "$FIXTURE/docs/problems/verifying/101-bar.md"
|
|
231
|
-
write_deferred_ticket "$FIXTURE/docs/problems/open/102-baz.md"
|
|
232
|
-
# shellcheck disable=SC1090
|
|
233
|
-
source "$HELPER"
|
|
234
|
-
run should_promote_review_problems_dispatch "$FIXTURE"
|
|
235
|
-
[ "$status" -eq 0 ]
|
|
236
|
-
# Only the open/ ticket counts → below threshold.
|
|
237
|
-
[[ "$output" =~ ^below-threshold\ count=1\ threshold=3$ ]]
|
|
238
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Step 0d behavioural fixture per P220 + ADR-062 § JTBD-006 driver:
|
|
4
|
-
# work-problems pre-flights /wr-itil:check-upstream-responses when the
|
|
5
|
-
# outbound-responses cache is stale or missing AND there exist local
|
|
6
|
-
# tickets carrying `## Reported Upstream` back-link sections. The
|
|
7
|
-
# staleness decision lives in
|
|
8
|
-
# `packages/itil/lib/check-outbound-responses-staleness.sh::should_promote_outbound_responses_preflight`
|
|
9
|
-
# so the SKILL.md Step 0d prose is a thin source-and-call wrapper
|
|
10
|
-
# around a behaviorally-testable shell function (P081 / user feedback:
|
|
11
|
-
# prefer behavioural over structural-grep tests).
|
|
12
|
-
#
|
|
13
|
-
# Cases covered (symmetric to Step 0b cases plus the back-link discovery
|
|
14
|
-
# axis that replaces channels-config):
|
|
15
|
-
# 1. No tickets with `## Reported Upstream` section → "no-back-link-tickets"
|
|
16
|
-
# (downstream-adopter non-obligation; analogue to no-channels-config).
|
|
17
|
-
# 2. Back-link ticket present, cache absent → "first-run-cache-absent".
|
|
18
|
-
# 3. Back-link ticket present, cache present, last_checked null → "first-run-last-checked-null".
|
|
19
|
-
# 4. Back-link ticket present, cache fresh within TTL → "fresh-within-ttl".
|
|
20
|
-
# 5. Back-link ticket present, cache older than TTL → "ttl-expiry" (with age + ttl in the reason).
|
|
21
|
-
# 6. Custom ttl_seconds in cache honored (not hardcoded default).
|
|
22
|
-
# 7. Missing ttl_seconds field defaults to 86400 (24h symmetric with inbound).
|
|
23
|
-
|
|
24
|
-
setup() {
|
|
25
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../../.." && pwd)"
|
|
26
|
-
HELPER="$REPO_ROOT/packages/itil/lib/check-outbound-responses-staleness.sh"
|
|
27
|
-
|
|
28
|
-
FIXTURE="$(mktemp -d)"
|
|
29
|
-
mkdir -p "$FIXTURE/docs/problems"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
teardown() {
|
|
33
|
-
rm -rf "$FIXTURE"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# Helper: write a back-link ticket fixture under docs/problems/.
|
|
37
|
-
_write_backlink_ticket() {
|
|
38
|
-
local ticket_path="$1"
|
|
39
|
-
cat > "$ticket_path" <<'EOF'
|
|
40
|
-
# Problem 999: example back-link fixture
|
|
41
|
-
|
|
42
|
-
**Status**: Open
|
|
43
|
-
|
|
44
|
-
## Description
|
|
45
|
-
|
|
46
|
-
Fixture for Step 0d behavioural test.
|
|
47
|
-
|
|
48
|
-
## Reported Upstream
|
|
49
|
-
|
|
50
|
-
- **Repo**: example/upstream
|
|
51
|
-
- **URL**: https://github.com/example/upstream/issues/999
|
|
52
|
-
- **Filed**: 2026-06-08
|
|
53
|
-
EOF
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@test "helper exists at the contracted path" {
|
|
57
|
-
[ -f "$HELPER" ]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@test "case 1: no back-link tickets → no-back-link-tickets" {
|
|
61
|
-
# shellcheck disable=SC1090
|
|
62
|
-
source "$HELPER"
|
|
63
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
64
|
-
[ "$status" -eq 0 ]
|
|
65
|
-
[ "$output" = "no-back-link-tickets" ]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@test "case 1b: tickets without ## Reported Upstream section → no-back-link-tickets" {
|
|
69
|
-
cat > "$FIXTURE/docs/problems/100-no-back-link.open.md" <<'EOF'
|
|
70
|
-
# Problem 100: no upstream link
|
|
71
|
-
|
|
72
|
-
## Description
|
|
73
|
-
|
|
74
|
-
Local-only ticket.
|
|
75
|
-
EOF
|
|
76
|
-
# shellcheck disable=SC1090
|
|
77
|
-
source "$HELPER"
|
|
78
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
79
|
-
[ "$status" -eq 0 ]
|
|
80
|
-
[ "$output" = "no-back-link-tickets" ]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "case 2: back-link ticket present, cache absent → first-run-cache-absent" {
|
|
84
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
85
|
-
# shellcheck disable=SC1090
|
|
86
|
-
source "$HELPER"
|
|
87
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
88
|
-
[ "$status" -eq 0 ]
|
|
89
|
-
[ "$output" = "first-run-cache-absent" ]
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@test "case 2b: back-link in per-state subdir layout (RFC-002) is discovered" {
|
|
93
|
-
mkdir -p "$FIXTURE/docs/problems/known-error"
|
|
94
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/known-error/220-cadence-gap.md"
|
|
95
|
-
# shellcheck disable=SC1090
|
|
96
|
-
source "$HELPER"
|
|
97
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
98
|
-
[ "$status" -eq 0 ]
|
|
99
|
-
[ "$output" = "first-run-cache-absent" ]
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
@test "case 3: cache present, last_checked null → first-run-last-checked-null" {
|
|
103
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
104
|
-
cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<'EOF'
|
|
105
|
-
{ "last_checked": null, "tickets": {} }
|
|
106
|
-
EOF
|
|
107
|
-
# shellcheck disable=SC1090
|
|
108
|
-
source "$HELPER"
|
|
109
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
110
|
-
[ "$status" -eq 0 ]
|
|
111
|
-
[ "$output" = "first-run-last-checked-null" ]
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@test "case 4: cache fresh within TTL → fresh-within-ttl (silent-pass)" {
|
|
115
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
116
|
-
# last_checked 1 hour ago — well within 24h default TTL.
|
|
117
|
-
local recent_iso
|
|
118
|
-
recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
119
|
-
cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
|
|
120
|
-
{ "last_checked": "$recent_iso", "tickets": {} }
|
|
121
|
-
EOF
|
|
122
|
-
# shellcheck disable=SC1090
|
|
123
|
-
source "$HELPER"
|
|
124
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
125
|
-
[ "$status" -eq 0 ]
|
|
126
|
-
[ "$output" = "fresh-within-ttl" ]
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
@test "case 5: cache older than TTL → ttl-expiry with age + ttl in the reason" {
|
|
130
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
131
|
-
# last_checked 2 days ago — past 24h default TTL.
|
|
132
|
-
local stale_iso
|
|
133
|
-
stale_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
134
|
-
cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
|
|
135
|
-
{ "last_checked": "$stale_iso", "tickets": {} }
|
|
136
|
-
EOF
|
|
137
|
-
# shellcheck disable=SC1090
|
|
138
|
-
source "$HELPER"
|
|
139
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
140
|
-
[ "$status" -eq 0 ]
|
|
141
|
-
# Format: "ttl-expiry age=<N>s ttl=<M>s"
|
|
142
|
-
[[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=86400s$ ]]
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
@test "case 6: custom ttl_seconds in cache is honored (not hardcoded default)" {
|
|
146
|
-
# 1-hour TTL; last_checked 90 minutes ago → stale under the custom TTL,
|
|
147
|
-
# but would be FRESH under the 86400s default. Confirms the helper reads
|
|
148
|
-
# ttl_seconds from cache rather than hardcoding 86400.
|
|
149
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
150
|
-
local mid_iso
|
|
151
|
-
mid_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(minutes=90)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
152
|
-
cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
|
|
153
|
-
{ "last_checked": "$mid_iso", "tickets": {}, "ttl_seconds": 3600 }
|
|
154
|
-
EOF
|
|
155
|
-
# shellcheck disable=SC1090
|
|
156
|
-
source "$HELPER"
|
|
157
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
158
|
-
[ "$status" -eq 0 ]
|
|
159
|
-
[[ "$output" =~ ^ttl-expiry\ age=[0-9]+s\ ttl=3600s$ ]]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@test "case 7: missing ttl_seconds defaults to 86400 (symmetric with inbound)" {
|
|
163
|
-
_write_backlink_ticket "$FIXTURE/docs/problems/100-back-link.open.md"
|
|
164
|
-
local recent_iso
|
|
165
|
-
recent_iso="$(python3 -c "import datetime; print((datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).strftime('%Y-%m-%dT%H:%M:%SZ'))")"
|
|
166
|
-
cat > "$FIXTURE/docs/problems/.outbound-responses-cache.json" <<EOF
|
|
167
|
-
{ "last_checked": "$recent_iso", "tickets": {} }
|
|
168
|
-
EOF
|
|
169
|
-
# shellcheck disable=SC1090
|
|
170
|
-
source "$HELPER"
|
|
171
|
-
run should_promote_outbound_responses_preflight "$FIXTURE"
|
|
172
|
-
[ "$status" -eq 0 ]
|
|
173
|
-
[ "$output" = "fresh-within-ttl" ]
|
|
174
|
-
}
|