@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,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural test for check-rfc-stories-ratified.sh (ADR-090 — an RFC may
|
|
3
|
-
# reference only RATIFIED stories). DRIFT-AWARE via the shared lazy-fingerprint
|
|
4
|
-
# lib: a listed story counts only when it is `confirmed` AND its stored
|
|
5
|
-
# oversight-hash matches current content. Composes with check-rfc-has-stories
|
|
6
|
-
# (ADR-089): has-stories checks >=1 exists; this checks each listed one is ratified.
|
|
7
|
-
#
|
|
8
|
-
# @adr ADR-090
|
|
9
|
-
# @problem P404 (implement ADR-089 + ADR-090) — Phase 2
|
|
10
|
-
|
|
11
|
-
setup() {
|
|
12
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
13
|
-
SCRIPT="${REPO_ROOT}/packages/itil/scripts/check-rfc-stories-ratified.sh"
|
|
14
|
-
MARK="${REPO_ROOT}/packages/itil/scripts/mark-story-oversight-confirmed.sh"
|
|
15
|
-
TMPD="$(mktemp -d)"
|
|
16
|
-
mkdir -p "$TMPD/stories/accepted"
|
|
17
|
-
}
|
|
18
|
-
teardown() { rm -rf "$TMPD"; }
|
|
19
|
-
|
|
20
|
-
mkstory() { # $1=id $2=confirmed|unconfirmed|none
|
|
21
|
-
local f="$TMPD/stories/accepted/$1-x.md"
|
|
22
|
-
case "$2" in
|
|
23
|
-
confirmed) printf -- '---\nstatus: accepted\n---\n# %s\n' "$1" > "$f"; bash "$MARK" "$f" ;;
|
|
24
|
-
unconfirmed) printf -- '---\nstatus: accepted\nhuman-oversight: unconfirmed\n---\n# %s\n' "$1" > "$f" ;;
|
|
25
|
-
none) printf -- '---\nstatus: accepted\n---\n# %s\n' "$1" > "$f" ;;
|
|
26
|
-
esac
|
|
27
|
-
}
|
|
28
|
-
mkrfc() { printf -- '---\nstatus: proposed\nstories: [%s]\n---\n# rfc\n' "$1" > "$TMPD/RFC.proposed.md"; }
|
|
29
|
-
|
|
30
|
-
@test "check-rfc-stories-ratified: empty stories: [] passes vacuously (exit 0)" {
|
|
31
|
-
printf -- '---\nstatus: proposed\nstories: []\n---\n# rfc\n' > "$TMPD/RFC.proposed.md"
|
|
32
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
33
|
-
[ "$status" -eq 0 ]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@test "check-rfc-stories-ratified: a ratified (confirmed+hash) story is ACCEPTED (exit 0)" {
|
|
37
|
-
mkstory STORY-020 confirmed
|
|
38
|
-
mkrfc STORY-020
|
|
39
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
40
|
-
[ "$status" -eq 0 ]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@test "check-rfc-stories-ratified: an unconfirmed story is REJECTED" {
|
|
44
|
-
mkstory STORY-020 unconfirmed
|
|
45
|
-
mkrfc STORY-020
|
|
46
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
47
|
-
[ "$status" -ne 0 ]
|
|
48
|
-
[[ "$output" == *"STORY-020"* ]]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@test "check-rfc-stories-ratified: a story with NO oversight marker is REJECTED" {
|
|
52
|
-
mkstory STORY-020 none
|
|
53
|
-
mkrfc STORY-020
|
|
54
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
55
|
-
[ "$status" -ne 0 ]
|
|
56
|
-
[[ "$output" == *"STORY-020"* ]]
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "check-rfc-stories-ratified: a confirmed-but-DRIFTED story is REJECTED" {
|
|
60
|
-
mkstory STORY-020 confirmed
|
|
61
|
-
printf '\nedit after ratify\n' >> "$TMPD/stories/accepted/STORY-020-x.md"
|
|
62
|
-
mkrfc STORY-020
|
|
63
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
64
|
-
[ "$status" -ne 0 ]
|
|
65
|
-
[[ "$output" == *"STORY-020"* ]]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@test "check-rfc-stories-ratified: a missing story file is REJECTED" {
|
|
69
|
-
mkrfc STORY-099
|
|
70
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
71
|
-
[ "$status" -ne 0 ]
|
|
72
|
-
[[ "$output" == *"STORY-099"* ]]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@test "check-rfc-stories-ratified: mixed — one ratified one unconfirmed is REJECTED" {
|
|
76
|
-
mkstory STORY-020 confirmed
|
|
77
|
-
mkstory STORY-021 unconfirmed
|
|
78
|
-
mkrfc "STORY-020, STORY-021"
|
|
79
|
-
run bash "$SCRIPT" "$TMPD/RFC.proposed.md" "$TMPD/stories"
|
|
80
|
-
[ "$status" -ne 0 ]
|
|
81
|
-
[[ "$output" == *"STORY-021"* ]]
|
|
82
|
-
}
|
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @problem P249 — no process for issue reporters to check for responses
|
|
4
|
-
# (symmetric gap to ADR-062 inbound discovery). Phase 1: us-as-upstream-
|
|
5
|
-
# reporter side — scan local tickets for `## Reported Upstream` back-
|
|
6
|
-
# link sections (written by `/wr-itil:report-upstream` Step 7), poll
|
|
7
|
-
# each upstream issue via `gh issue view`, diff against cache, surface
|
|
8
|
-
# new comments / state changes / label changes.
|
|
9
|
-
#
|
|
10
|
-
# Contract: `check-upstream-responses.sh [--problems-dir <dir>]
|
|
11
|
-
# [--cache-file <path>] [--audit-log <path>] [--force-recheck]
|
|
12
|
-
# [--ticket P<NNN>] [--gh-bin <path>]` is a foreground governance
|
|
13
|
-
# script that polls upstream issues, writes cache + audit-log, and
|
|
14
|
-
# emits a structured one-line-per-ticket report to stdout.
|
|
15
|
-
#
|
|
16
|
-
# Read-soft externally: only `gh issue view` (read-only) — no
|
|
17
|
-
# `gh issue comment` / `gh issue create`. Does NOT trip ADR-028
|
|
18
|
-
# external-comms gate. AFK-safe.
|
|
19
|
-
#
|
|
20
|
-
# Cache: `docs/problems/.outbound-responses-cache.json` (mirrors
|
|
21
|
-
# ADR-062 inbound cache shape under same dir per ADR-031 §"Cache
|
|
22
|
-
# files live under docs/problems/"). Committed for replay
|
|
23
|
-
# determinism; rebuild via --force-recheck.
|
|
24
|
-
#
|
|
25
|
-
# Audit-log: `docs/audits/outbound-responses-log.md` (mirrors
|
|
26
|
-
# ADR-062 inbound audit-log under docs/audits/ per CLAUDE.md P131).
|
|
27
|
-
#
|
|
28
|
-
# Exit codes:
|
|
29
|
-
# 0 = success (zero or more new responses surfaced; check stdout
|
|
30
|
-
# for per-ticket lines)
|
|
31
|
-
# 1 = error (cache file malformed, upstream URL malformed, gh CLI
|
|
32
|
-
# missing, problems-dir not found)
|
|
33
|
-
# 2 = partial — some upstream polls failed (network / 404); the
|
|
34
|
-
# successful ones are still written to cache + audit-log
|
|
35
|
-
#
|
|
36
|
-
# Structured stdout format (≤ 150 bytes per line per ADR-038
|
|
37
|
-
# progressive-disclosure budget):
|
|
38
|
-
# NEW P<NNN> <url> state=<state> new-comments=<N>
|
|
39
|
-
# STATE P<NNN> <url> state=<old>→<new>
|
|
40
|
-
# LABEL P<NNN> <url> labels-added=<csv> labels-removed=<csv>
|
|
41
|
-
# NONE P<NNN> <url> no-change-since=<last-checked>
|
|
42
|
-
# SKIP P<NNN> reason=no-reported-upstream-section
|
|
43
|
-
# FAIL P<NNN> <url> reason=<gh-error-short>
|
|
44
|
-
#
|
|
45
|
-
# @adr ADR-014 (governance skills commit their own work — cache +
|
|
46
|
-
# audit-log ride one commit per pass)
|
|
47
|
-
# @adr ADR-024 (back-link source of truth — `## Reported Upstream`
|
|
48
|
-
# URL field is what this script reads)
|
|
49
|
-
# @adr ADR-031 (cache file placement under docs/problems/)
|
|
50
|
-
# @adr ADR-032 (foreground synchronous skill — no AskUserQuestion)
|
|
51
|
-
# @adr ADR-038 (progressive disclosure — per-row byte budget on diff)
|
|
52
|
-
# @adr ADR-049 (script invoked via wr-itil-check-upstream-responses
|
|
53
|
-
# bin shim from SKILL.md)
|
|
54
|
-
# @adr ADR-062 (inbound discovery pattern — this script is the
|
|
55
|
-
# outbound symmetric counterpart)
|
|
56
|
-
# @jtbd JTBD-004 (cross-repo coordination — primary anchor)
|
|
57
|
-
# @jtbd JTBD-006 (AFK-safe surface)
|
|
58
|
-
# @jtbd JTBD-001 (governance without slowing down — eliminates
|
|
59
|
-
# manual upstream polling)
|
|
60
|
-
# @jtbd JTBD-201 (audit trail — outbound-responses-log.md replay)
|
|
61
|
-
|
|
62
|
-
setup() {
|
|
63
|
-
SCRIPTS_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
64
|
-
SCRIPT="$SCRIPTS_DIR/check-upstream-responses.sh"
|
|
65
|
-
FIXTURE_DIR="$(mktemp -d)"
|
|
66
|
-
PROBLEMS_DIR="$FIXTURE_DIR/problems"
|
|
67
|
-
AUDITS_DIR="$FIXTURE_DIR/audits"
|
|
68
|
-
GHFAKE_DIR="$FIXTURE_DIR/ghfake"
|
|
69
|
-
mkdir -p "$PROBLEMS_DIR" "$AUDITS_DIR" "$GHFAKE_DIR"
|
|
70
|
-
CACHE_FILE="$PROBLEMS_DIR/.outbound-responses-cache.json"
|
|
71
|
-
AUDIT_LOG="$AUDITS_DIR/outbound-responses-log.md"
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
teardown() {
|
|
75
|
-
rm -rf "$FIXTURE_DIR"
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
# ── Helper: install a fake `gh` binary that prints a canned JSON
|
|
79
|
-
# ── response keyed by upstream URL. Tests prime $GHFAKE_DIR/<url-hash>
|
|
80
|
-
# ── with the JSON they want returned.
|
|
81
|
-
|
|
82
|
-
make_fake_gh() {
|
|
83
|
-
cat > "$GHFAKE_DIR/gh" <<'EOF'
|
|
84
|
-
#!/usr/bin/env bash
|
|
85
|
-
# Fake gh shim. Recognised invocations:
|
|
86
|
-
# gh issue view <url> --json comments,state,labels,updatedAt
|
|
87
|
-
# Looks up canned response by url-hash from $GHFAKE_DATA dir.
|
|
88
|
-
if [ "$1" = "issue" ] && [ "$2" = "view" ]; then
|
|
89
|
-
URL="$3"
|
|
90
|
-
HASH=$(echo -n "$URL" | shasum | awk '{print $1}')
|
|
91
|
-
if [ -f "$GHFAKE_DATA/$HASH.json" ]; then
|
|
92
|
-
cat "$GHFAKE_DATA/$HASH.json"
|
|
93
|
-
exit 0
|
|
94
|
-
else
|
|
95
|
-
echo "could not resolve issue: $URL" >&2
|
|
96
|
-
exit 1
|
|
97
|
-
fi
|
|
98
|
-
fi
|
|
99
|
-
echo "fake-gh: unrecognised invocation: $*" >&2
|
|
100
|
-
exit 1
|
|
101
|
-
EOF
|
|
102
|
-
chmod +x "$GHFAKE_DIR/gh"
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
prime_gh_response() {
|
|
106
|
-
local url="$1"
|
|
107
|
-
local payload="$2"
|
|
108
|
-
local hash
|
|
109
|
-
hash=$(echo -n "$url" | shasum | awk '{print $1}')
|
|
110
|
-
printf '%s' "$payload" > "$GHFAKE_DIR/$hash.json"
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
# ── Existence + executable ──────────────────────────────────────────────────
|
|
114
|
-
|
|
115
|
-
@test "check-upstream-responses: script exists" {
|
|
116
|
-
[ -f "$SCRIPT" ]
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
@test "check-upstream-responses: script is executable" {
|
|
120
|
-
[ -x "$SCRIPT" ]
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
# ── Behavioural: ticket with `## Reported Upstream` is polled ───────────────
|
|
124
|
-
|
|
125
|
-
@test "ticket with Reported Upstream section is polled and surfaces NEW state on first check" {
|
|
126
|
-
cat > "$PROBLEMS_DIR/100-foo.open.md" <<'EOF'
|
|
127
|
-
# Problem 100: Foo
|
|
128
|
-
|
|
129
|
-
**Status**: Open
|
|
130
|
-
|
|
131
|
-
## Description
|
|
132
|
-
|
|
133
|
-
Some description.
|
|
134
|
-
|
|
135
|
-
## Reported Upstream
|
|
136
|
-
|
|
137
|
-
- **URL**: https://github.com/example/repo/issues/42
|
|
138
|
-
- **Reported**: 2026-05-01
|
|
139
|
-
- **Template used**: bug_report.yml
|
|
140
|
-
- **Disclosure path**: public issue
|
|
141
|
-
- **Cross-reference confirmed**: yes
|
|
142
|
-
EOF
|
|
143
|
-
|
|
144
|
-
make_fake_gh
|
|
145
|
-
prime_gh_response "https://github.com/example/repo/issues/42" '{"state":"OPEN","comments":[{"id":1,"author":{"login":"someone"},"createdAt":"2026-05-10T10:00:00Z","body":"thanks"}],"labels":[{"name":"triage"}],"updatedAt":"2026-05-10T10:00:00Z"}'
|
|
146
|
-
|
|
147
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
148
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
149
|
-
[ "$status" -eq 0 ]
|
|
150
|
-
echo "$output" | grep -qE "^NEW *P100"
|
|
151
|
-
echo "$output" | grep -q "https://github.com/example/repo/issues/42"
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
# ── Behavioural: ticket without Reported Upstream is skipped ────────────────
|
|
155
|
-
|
|
156
|
-
@test "ticket without Reported Upstream section is skipped" {
|
|
157
|
-
cat > "$PROBLEMS_DIR/101-bar.open.md" <<'EOF'
|
|
158
|
-
# Problem 101: Bar
|
|
159
|
-
|
|
160
|
-
**Status**: Open
|
|
161
|
-
|
|
162
|
-
## Description
|
|
163
|
-
|
|
164
|
-
No upstream link here.
|
|
165
|
-
EOF
|
|
166
|
-
|
|
167
|
-
make_fake_gh
|
|
168
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
169
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
170
|
-
[ "$status" -eq 0 ]
|
|
171
|
-
# P101 should not appear in output at all (no Reported Upstream → silently skipped).
|
|
172
|
-
! echo "$output" | grep -q "P101"
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
# ── Behavioural: cache fresh → no new responses surfaced ────────────────────
|
|
176
|
-
|
|
177
|
-
@test "ticket with cached state matching upstream surfaces NONE" {
|
|
178
|
-
cat > "$PROBLEMS_DIR/102-baz.open.md" <<'EOF'
|
|
179
|
-
# Problem 102: Baz
|
|
180
|
-
|
|
181
|
-
**Status**: Open
|
|
182
|
-
|
|
183
|
-
## Reported Upstream
|
|
184
|
-
|
|
185
|
-
- **URL**: https://github.com/example/repo/issues/77
|
|
186
|
-
- **Reported**: 2026-05-01
|
|
187
|
-
- **Template used**: structured default
|
|
188
|
-
- **Disclosure path**: public issue
|
|
189
|
-
- **Cross-reference confirmed**: yes
|
|
190
|
-
EOF
|
|
191
|
-
|
|
192
|
-
# Seed cache to match upstream state.
|
|
193
|
-
cat > "$CACHE_FILE" <<'EOF'
|
|
194
|
-
{
|
|
195
|
-
"last_checked": "2026-05-15T00:00:00Z",
|
|
196
|
-
"tickets": {
|
|
197
|
-
"P102": {
|
|
198
|
-
"upstream_url": "https://github.com/example/repo/issues/77",
|
|
199
|
-
"last_checked_at": "2026-05-15T00:00:00Z",
|
|
200
|
-
"last_seen_state": "OPEN",
|
|
201
|
-
"last_seen_comment_count": 3,
|
|
202
|
-
"last_seen_labels": ["triage"],
|
|
203
|
-
"last_seen_updated_at": "2026-05-14T12:00:00Z"
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
EOF
|
|
208
|
-
|
|
209
|
-
make_fake_gh
|
|
210
|
-
prime_gh_response "https://github.com/example/repo/issues/77" '{"state":"OPEN","comments":[{"id":1},{"id":2},{"id":3}],"labels":[{"name":"triage"}],"updatedAt":"2026-05-14T12:00:00Z"}'
|
|
211
|
-
|
|
212
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
213
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
214
|
-
[ "$status" -eq 0 ]
|
|
215
|
-
echo "$output" | grep -qE "^NONE *P102"
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
# ── Behavioural: new comments surface as NEW with delta count ───────────────
|
|
219
|
-
|
|
220
|
-
@test "ticket with new comments since last check surfaces NEW with count" {
|
|
221
|
-
cat > "$PROBLEMS_DIR/103-qux.open.md" <<'EOF'
|
|
222
|
-
# Problem 103: Qux
|
|
223
|
-
|
|
224
|
-
**Status**: Open
|
|
225
|
-
|
|
226
|
-
## Reported Upstream
|
|
227
|
-
|
|
228
|
-
- **URL**: https://github.com/example/repo/issues/88
|
|
229
|
-
- **Reported**: 2026-05-01
|
|
230
|
-
- **Template used**: bug_report.yml
|
|
231
|
-
- **Disclosure path**: public issue
|
|
232
|
-
- **Cross-reference confirmed**: yes
|
|
233
|
-
EOF
|
|
234
|
-
|
|
235
|
-
cat > "$CACHE_FILE" <<'EOF'
|
|
236
|
-
{
|
|
237
|
-
"last_checked": "2026-05-15T00:00:00Z",
|
|
238
|
-
"tickets": {
|
|
239
|
-
"P103": {
|
|
240
|
-
"upstream_url": "https://github.com/example/repo/issues/88",
|
|
241
|
-
"last_checked_at": "2026-05-15T00:00:00Z",
|
|
242
|
-
"last_seen_state": "OPEN",
|
|
243
|
-
"last_seen_comment_count": 1,
|
|
244
|
-
"last_seen_labels": [],
|
|
245
|
-
"last_seen_updated_at": "2026-05-14T12:00:00Z"
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
EOF
|
|
250
|
-
|
|
251
|
-
make_fake_gh
|
|
252
|
-
prime_gh_response "https://github.com/example/repo/issues/88" '{"state":"OPEN","comments":[{"id":1},{"id":2},{"id":3}],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
253
|
-
|
|
254
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
255
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
256
|
-
[ "$status" -eq 0 ]
|
|
257
|
-
echo "$output" | grep -qE "^NEW *P103"
|
|
258
|
-
echo "$output" | grep -q "new-comments=2"
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
# ── Behavioural: state change surfaces STATE marker ─────────────────────────
|
|
262
|
-
|
|
263
|
-
@test "ticket with state change OPEN to CLOSED surfaces STATE marker" {
|
|
264
|
-
cat > "$PROBLEMS_DIR/104-baz.open.md" <<'EOF'
|
|
265
|
-
# Problem 104: Baz
|
|
266
|
-
|
|
267
|
-
**Status**: Open
|
|
268
|
-
|
|
269
|
-
## Reported Upstream
|
|
270
|
-
|
|
271
|
-
- **URL**: https://github.com/example/repo/issues/99
|
|
272
|
-
- **Reported**: 2026-05-01
|
|
273
|
-
- **Template used**: structured default
|
|
274
|
-
- **Disclosure path**: public issue
|
|
275
|
-
- **Cross-reference confirmed**: yes
|
|
276
|
-
EOF
|
|
277
|
-
|
|
278
|
-
cat > "$CACHE_FILE" <<'EOF'
|
|
279
|
-
{
|
|
280
|
-
"last_checked": "2026-05-15T00:00:00Z",
|
|
281
|
-
"tickets": {
|
|
282
|
-
"P104": {
|
|
283
|
-
"upstream_url": "https://github.com/example/repo/issues/99",
|
|
284
|
-
"last_checked_at": "2026-05-15T00:00:00Z",
|
|
285
|
-
"last_seen_state": "OPEN",
|
|
286
|
-
"last_seen_comment_count": 2,
|
|
287
|
-
"last_seen_labels": [],
|
|
288
|
-
"last_seen_updated_at": "2026-05-14T12:00:00Z"
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
EOF
|
|
293
|
-
|
|
294
|
-
make_fake_gh
|
|
295
|
-
prime_gh_response "https://github.com/example/repo/issues/99" '{"state":"CLOSED","comments":[{"id":1},{"id":2}],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
296
|
-
|
|
297
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
298
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
299
|
-
[ "$status" -eq 0 ]
|
|
300
|
-
echo "$output" | grep -qE "^STATE *P104"
|
|
301
|
-
echo "$output" | grep -q "state=OPEN.*CLOSED"
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
# ── Behavioural: cache file is created/updated after a pass ─────────────────
|
|
305
|
-
|
|
306
|
-
@test "cache file is written with the latest state after the pass" {
|
|
307
|
-
cat > "$PROBLEMS_DIR/105-quux.open.md" <<'EOF'
|
|
308
|
-
# Problem 105: Quux
|
|
309
|
-
|
|
310
|
-
**Status**: Open
|
|
311
|
-
|
|
312
|
-
## Reported Upstream
|
|
313
|
-
|
|
314
|
-
- **URL**: https://github.com/example/repo/issues/55
|
|
315
|
-
- **Reported**: 2026-05-01
|
|
316
|
-
- **Template used**: structured default
|
|
317
|
-
- **Disclosure path**: public issue
|
|
318
|
-
- **Cross-reference confirmed**: yes
|
|
319
|
-
EOF
|
|
320
|
-
|
|
321
|
-
make_fake_gh
|
|
322
|
-
prime_gh_response "https://github.com/example/repo/issues/55" '{"state":"OPEN","comments":[{"id":1},{"id":2}],"labels":[{"name":"triage"},{"name":"bug"}],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
323
|
-
|
|
324
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
325
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
326
|
-
[ "$status" -eq 0 ]
|
|
327
|
-
[ -f "$CACHE_FILE" ]
|
|
328
|
-
# Cache file contains P105 entry with the current state.
|
|
329
|
-
grep -q '"P105"' "$CACHE_FILE"
|
|
330
|
-
grep -q '"upstream_url": *"https://github.com/example/repo/issues/55"' "$CACHE_FILE"
|
|
331
|
-
grep -q '"last_seen_state": *"OPEN"' "$CACHE_FILE"
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
# ── Behavioural: audit-log file is appended after the pass ──────────────────
|
|
335
|
-
|
|
336
|
-
@test "audit-log file is appended with a timestamped pass heading" {
|
|
337
|
-
cat > "$PROBLEMS_DIR/106-corge.open.md" <<'EOF'
|
|
338
|
-
# Problem 106: Corge
|
|
339
|
-
|
|
340
|
-
**Status**: Open
|
|
341
|
-
|
|
342
|
-
## Reported Upstream
|
|
343
|
-
|
|
344
|
-
- **URL**: https://github.com/example/repo/issues/66
|
|
345
|
-
- **Reported**: 2026-05-01
|
|
346
|
-
- **Template used**: structured default
|
|
347
|
-
- **Disclosure path**: public issue
|
|
348
|
-
- **Cross-reference confirmed**: yes
|
|
349
|
-
EOF
|
|
350
|
-
|
|
351
|
-
make_fake_gh
|
|
352
|
-
prime_gh_response "https://github.com/example/repo/issues/66" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
353
|
-
|
|
354
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
355
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
356
|
-
[ "$status" -eq 0 ]
|
|
357
|
-
[ -f "$AUDIT_LOG" ]
|
|
358
|
-
# Audit-log contains a heading line matching the ISO timestamp pattern + pass summary.
|
|
359
|
-
grep -qE '^## [0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z' "$AUDIT_LOG"
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
# ── Behavioural: --ticket filter restricts to one ticket ────────────────────
|
|
363
|
-
|
|
364
|
-
@test "--ticket filter restricts polling to the named ticket only" {
|
|
365
|
-
cat > "$PROBLEMS_DIR/107-grault.open.md" <<'EOF'
|
|
366
|
-
# Problem 107: Grault
|
|
367
|
-
|
|
368
|
-
## Reported Upstream
|
|
369
|
-
|
|
370
|
-
- **URL**: https://github.com/example/repo/issues/107
|
|
371
|
-
- **Reported**: 2026-05-01
|
|
372
|
-
- **Template used**: structured default
|
|
373
|
-
- **Disclosure path**: public issue
|
|
374
|
-
- **Cross-reference confirmed**: yes
|
|
375
|
-
EOF
|
|
376
|
-
|
|
377
|
-
cat > "$PROBLEMS_DIR/108-garply.open.md" <<'EOF'
|
|
378
|
-
# Problem 108: Garply
|
|
379
|
-
|
|
380
|
-
## Reported Upstream
|
|
381
|
-
|
|
382
|
-
- **URL**: https://github.com/example/repo/issues/108
|
|
383
|
-
- **Reported**: 2026-05-01
|
|
384
|
-
- **Template used**: structured default
|
|
385
|
-
- **Disclosure path**: public issue
|
|
386
|
-
- **Cross-reference confirmed**: yes
|
|
387
|
-
EOF
|
|
388
|
-
|
|
389
|
-
make_fake_gh
|
|
390
|
-
prime_gh_response "https://github.com/example/repo/issues/107" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
391
|
-
prime_gh_response "https://github.com/example/repo/issues/108" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
392
|
-
|
|
393
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
394
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh" --ticket P107
|
|
395
|
-
[ "$status" -eq 0 ]
|
|
396
|
-
echo "$output" | grep -q "P107"
|
|
397
|
-
! echo "$output" | grep -q "P108"
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
# ── Behavioural: dual-tolerant subdir layout (RFC-002) ──────────────────────
|
|
401
|
-
|
|
402
|
-
@test "ticket in per-state subdir is discovered and polled" {
|
|
403
|
-
mkdir -p "$PROBLEMS_DIR/open"
|
|
404
|
-
cat > "$PROBLEMS_DIR/open/109-waldo.md" <<'EOF'
|
|
405
|
-
# Problem 109: Waldo
|
|
406
|
-
|
|
407
|
-
## Reported Upstream
|
|
408
|
-
|
|
409
|
-
- **URL**: https://github.com/example/repo/issues/109
|
|
410
|
-
- **Reported**: 2026-05-01
|
|
411
|
-
- **Template used**: structured default
|
|
412
|
-
- **Disclosure path**: public issue
|
|
413
|
-
- **Cross-reference confirmed**: yes
|
|
414
|
-
EOF
|
|
415
|
-
|
|
416
|
-
make_fake_gh
|
|
417
|
-
prime_gh_response "https://github.com/example/repo/issues/109" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
418
|
-
|
|
419
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
420
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
421
|
-
[ "$status" -eq 0 ]
|
|
422
|
-
echo "$output" | grep -q "P109"
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
# ── Behavioural: gh failure for one URL doesn't kill the pass ───────────────
|
|
426
|
-
|
|
427
|
-
@test "gh failure on one URL is surfaced as FAIL; pass continues for other tickets" {
|
|
428
|
-
cat > "$PROBLEMS_DIR/110-broken.open.md" <<'EOF'
|
|
429
|
-
# Problem 110: Broken
|
|
430
|
-
|
|
431
|
-
## Reported Upstream
|
|
432
|
-
|
|
433
|
-
- **URL**: https://github.com/example/repo/issues/110
|
|
434
|
-
- **Reported**: 2026-05-01
|
|
435
|
-
- **Template used**: structured default
|
|
436
|
-
- **Disclosure path**: public issue
|
|
437
|
-
- **Cross-reference confirmed**: yes
|
|
438
|
-
EOF
|
|
439
|
-
|
|
440
|
-
cat > "$PROBLEMS_DIR/111-working.open.md" <<'EOF'
|
|
441
|
-
# Problem 111: Working
|
|
442
|
-
|
|
443
|
-
## Reported Upstream
|
|
444
|
-
|
|
445
|
-
- **URL**: https://github.com/example/repo/issues/111
|
|
446
|
-
- **Reported**: 2026-05-01
|
|
447
|
-
- **Template used**: structured default
|
|
448
|
-
- **Disclosure path**: public issue
|
|
449
|
-
- **Cross-reference confirmed**: yes
|
|
450
|
-
EOF
|
|
451
|
-
|
|
452
|
-
make_fake_gh
|
|
453
|
-
# Only prime 111; 110 will fail.
|
|
454
|
-
prime_gh_response "https://github.com/example/repo/issues/111" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T08:00:00Z"}'
|
|
455
|
-
|
|
456
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
457
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh"
|
|
458
|
-
# Exit 2 = partial (some polls failed).
|
|
459
|
-
[ "$status" -eq 2 ]
|
|
460
|
-
echo "$output" | grep -qE "^FAIL *P110"
|
|
461
|
-
echo "$output" | grep -q "P111"
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
# ── Behavioural: --force-recheck ignores cache and re-emits NEW ─────────────
|
|
465
|
-
|
|
466
|
-
@test "--force-recheck re-emits ticket as new even when cache matches" {
|
|
467
|
-
cat > "$PROBLEMS_DIR/112-fresh.open.md" <<'EOF'
|
|
468
|
-
# Problem 112: Fresh
|
|
469
|
-
|
|
470
|
-
## Reported Upstream
|
|
471
|
-
|
|
472
|
-
- **URL**: https://github.com/example/repo/issues/112
|
|
473
|
-
- **Reported**: 2026-05-01
|
|
474
|
-
- **Template used**: structured default
|
|
475
|
-
- **Disclosure path**: public issue
|
|
476
|
-
- **Cross-reference confirmed**: yes
|
|
477
|
-
EOF
|
|
478
|
-
|
|
479
|
-
cat > "$CACHE_FILE" <<'EOF'
|
|
480
|
-
{
|
|
481
|
-
"last_checked": "2026-05-17T00:00:00Z",
|
|
482
|
-
"tickets": {
|
|
483
|
-
"P112": {
|
|
484
|
-
"upstream_url": "https://github.com/example/repo/issues/112",
|
|
485
|
-
"last_checked_at": "2026-05-17T00:00:00Z",
|
|
486
|
-
"last_seen_state": "OPEN",
|
|
487
|
-
"last_seen_comment_count": 0,
|
|
488
|
-
"last_seen_labels": [],
|
|
489
|
-
"last_seen_updated_at": "2026-05-17T00:00:00Z"
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
EOF
|
|
494
|
-
|
|
495
|
-
make_fake_gh
|
|
496
|
-
prime_gh_response "https://github.com/example/repo/issues/112" '{"state":"OPEN","comments":[],"labels":[],"updatedAt":"2026-05-17T00:00:00Z"}'
|
|
497
|
-
|
|
498
|
-
export GHFAKE_DATA="$GHFAKE_DIR"
|
|
499
|
-
run "$SCRIPT" --problems-dir "$PROBLEMS_DIR" --cache-file "$CACHE_FILE" --audit-log "$AUDIT_LOG" --gh-bin "$GHFAKE_DIR/gh" --force-recheck
|
|
500
|
-
[ "$status" -eq 0 ]
|
|
501
|
-
# With --force-recheck, the line is emitted as NEW regardless of cache match.
|
|
502
|
-
echo "$output" | grep -qE "^NEW *P112"
|
|
503
|
-
}
|