@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,374 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# @rfc RFC-002 T3 — Bats fixture audit + dual-tolerant assertions
|
|
4
|
-
# @adr ADR-031 (Problem-ticket directory layout — per-state subdirs)
|
|
5
|
-
# @adr ADR-051 (load-bearing-from-the-start — each SKILL-prescribed
|
|
6
|
-
# enumeration pipeline ships with a behavioural enforcement test
|
|
7
|
-
# exercised against per-state-layout synthetic fixtures, not later
|
|
8
|
-
# by graceful drift discovery during the T5 migration cutover)
|
|
9
|
-
# @adr ADR-052 (behavioural-bats default — these tests run the actual
|
|
10
|
-
# shell pipelines the SKILL.md sites prescribe against synthetic
|
|
11
|
-
# fixtures and assert observable enumeration. They do NOT structurally
|
|
12
|
-
# grep SKILL.md prose for the dual-pattern string, which would be
|
|
13
|
-
# P081-class structural-test-disguised-as-behavioural and was
|
|
14
|
-
# explicitly excluded from T2 per architect finding 3)
|
|
15
|
-
# @adr ADR-014 (single-purpose: one mechanical contract — the
|
|
16
|
-
# SKILL-prescribed pipelines compose with per-state-layout fixtures)
|
|
17
|
-
# @adr ADR-060 (Phase 1 Slice 5 forward-dogfood — T3 commit grain)
|
|
18
|
-
# @problem P069 (driving — flat layout unskimmable; the migration this
|
|
19
|
-
# contract guards is the relief)
|
|
20
|
-
# @problem P081 (no structural-grep on SKILL.md content — this test
|
|
21
|
-
# is the behavioural alternative)
|
|
22
|
-
# @jtbd JTBD-001 (extended scope — multi-commit RFC-grain coordinated
|
|
23
|
-
# change governance; T3 is one of 11 RFC-002 sub-tasks; behavioural
|
|
24
|
-
# coverage is how per-edit governance stays trustworthy across the
|
|
25
|
-
# migration window)
|
|
26
|
-
# @jtbd JTBD-006 (work-backlog-AFK — dual-tolerant pipelines preserve
|
|
27
|
-
# AFK-loop continuity during the T2-to-T6 migration window; without
|
|
28
|
-
# this contract, mid-migration AFK iterations silently miss tickets
|
|
29
|
-
# in the un-migrated layout half)
|
|
30
|
-
# @jtbd JTBD-008 (decompose-fix-into-coordinated-changes — RFC-002 T3
|
|
31
|
-
# is the load-bearing test artefact for the coordinated-change
|
|
32
|
-
# sub-workstream; visible as an RFC-002-T3 entity rather than
|
|
33
|
-
# diffusing across 14 existing files per JTBD review)
|
|
34
|
-
# @jtbd JTBD-101 (extend-the-suite — adopter projects consuming
|
|
35
|
-
# @windyroad/itil at the T2-shipped state must enumerate correctly
|
|
36
|
-
# against their flat-layout tickets AND post-auto-migration per-state
|
|
37
|
-
# tickets; T3 proves both halves)
|
|
38
|
-
#
|
|
39
|
-
# Contract: every SKILL.md call site updated in T2 (commit `0795e91`,
|
|
40
|
-
# 14 SKILL.md surfaces) prescribes a shell pipeline of canonical shape:
|
|
41
|
-
#
|
|
42
|
-
# ls docs/problems/*.<state>.md docs/problems/<state>/*.md 2>/dev/null
|
|
43
|
-
# ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null
|
|
44
|
-
# ls docs/problems/<ID>-*.md docs/problems/*/<ID>-*.md 2>/dev/null
|
|
45
|
-
#
|
|
46
|
-
# T2's `dual-tolerant-glob-rfc-002-t2.bats` exercises the canonical
|
|
47
|
-
# pattern shapes generically. T3 extends that coverage to the
|
|
48
|
-
# end-to-end SKILL-prescribed PIPELINES — the next-ID compute pipeline
|
|
49
|
-
# (`ls X Y | sed | grep -oE | sort -n | tail -1`), the multi-state
|
|
50
|
-
# union form (4-pathspec for open + known-error backlog scan), the
|
|
51
|
-
# verifying-state filter as run-retro Step 4a dispatches it, and the
|
|
52
|
-
# brace-expansion ID + state-set form report-upstream uses. Each test
|
|
53
|
-
# runs the pipeline against three synthetic fixture shapes (flat-only,
|
|
54
|
-
# per-state-only, mixed) and asserts observable enumeration.
|
|
55
|
-
#
|
|
56
|
-
# T6 (post-T5 verification) drops the flat-layout half. This test
|
|
57
|
-
# updates at T6 to single-pattern (per-state only), NOT removed — the
|
|
58
|
-
# contract narrows but the behavioural enforcement remains.
|
|
59
|
-
#
|
|
60
|
-
# CONTRACT NOTE: when one half of the dual-pattern has zero matches
|
|
61
|
-
# in the current fixture (single-layout fixtures), `ls X Y 2>/dev/null`
|
|
62
|
-
# exits nonzero — the unmatched literal pathname propagates to ls's
|
|
63
|
-
# argv and `2>/dev/null` only suppresses the stderr noise, not the
|
|
64
|
-
# exit code. SKILL.md call sites MUST treat STDOUT emptiness as the
|
|
65
|
-
# canonical "no tickets" signal, NOT exit code zero. Test assertions
|
|
66
|
-
# probe stdout content via `run` (which absorbs the exit code into
|
|
67
|
-
# `$status`); `$status` is asserted only in the empty-fixture and
|
|
68
|
-
# missing-ID cases where nonzero exit is the intended contract.
|
|
69
|
-
|
|
70
|
-
setup() {
|
|
71
|
-
REPO_ROOT="$(mktemp -d)"
|
|
72
|
-
cd "$REPO_ROOT"
|
|
73
|
-
mkdir -p docs/problems
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
teardown() {
|
|
77
|
-
cd /
|
|
78
|
-
rm -rf "$REPO_ROOT"
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
# ── fixture builders ─────────────────────────────────────────────────────────
|
|
82
|
-
|
|
83
|
-
build_flat_layout() {
|
|
84
|
-
cat > docs/problems/100-foo.open.md <<'EOF'
|
|
85
|
-
# Problem 100: Foo
|
|
86
|
-
**Status**: Open
|
|
87
|
-
**WSJF**: 5.0
|
|
88
|
-
EOF
|
|
89
|
-
cat > docs/problems/101-bar.known-error.md <<'EOF'
|
|
90
|
-
# Problem 101: Bar
|
|
91
|
-
**Status**: Known Error
|
|
92
|
-
**WSJF**: 4.0
|
|
93
|
-
EOF
|
|
94
|
-
cat > docs/problems/102-baz.verifying.md <<'EOF'
|
|
95
|
-
# Problem 102: Baz
|
|
96
|
-
**Status**: Verification Pending
|
|
97
|
-
EOF
|
|
98
|
-
cat > docs/problems/103-qux.parked.md <<'EOF'
|
|
99
|
-
# Problem 103: Qux
|
|
100
|
-
**Status**: Parked
|
|
101
|
-
EOF
|
|
102
|
-
cat > docs/problems/104-quux.closed.md <<'EOF'
|
|
103
|
-
# Problem 104: Quux
|
|
104
|
-
**Status**: Closed
|
|
105
|
-
EOF
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
build_per_state_layout() {
|
|
109
|
-
mkdir -p docs/problems/open docs/problems/known-error docs/problems/verifying docs/problems/parked docs/problems/closed
|
|
110
|
-
cat > docs/problems/open/200-foo2.md <<'EOF'
|
|
111
|
-
# Problem 200: Foo2
|
|
112
|
-
**Status**: Open
|
|
113
|
-
**WSJF**: 6.0
|
|
114
|
-
EOF
|
|
115
|
-
cat > docs/problems/known-error/201-bar2.md <<'EOF'
|
|
116
|
-
# Problem 201: Bar2
|
|
117
|
-
**Status**: Known Error
|
|
118
|
-
**WSJF**: 3.5
|
|
119
|
-
EOF
|
|
120
|
-
cat > docs/problems/verifying/202-baz2.md <<'EOF'
|
|
121
|
-
# Problem 202: Baz2
|
|
122
|
-
**Status**: Verification Pending
|
|
123
|
-
EOF
|
|
124
|
-
cat > docs/problems/parked/203-qux2.md <<'EOF'
|
|
125
|
-
# Problem 203: Qux2
|
|
126
|
-
**Status**: Parked
|
|
127
|
-
EOF
|
|
128
|
-
cat > docs/problems/closed/204-quux2.md <<'EOF'
|
|
129
|
-
# Problem 204: Quux2
|
|
130
|
-
**Status**: Closed
|
|
131
|
-
EOF
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
build_mixed_layout() {
|
|
135
|
-
build_flat_layout
|
|
136
|
-
build_per_state_layout
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
# ── Pipeline 1: Next-ID compute (manage-problem Step 3 + capture-problem Step 3)
|
|
140
|
-
#
|
|
141
|
-
# SKILL.md prescribes the recursive local_max formula:
|
|
142
|
-
# ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null \
|
|
143
|
-
# | sed 's|.*/||' \
|
|
144
|
-
# | grep -oE '^[0-9]+' \
|
|
145
|
-
# | sort -n | tail -1
|
|
146
|
-
#
|
|
147
|
-
# Architect finding 2 (T2): the recursive enumeration MUST contribute
|
|
148
|
-
# tickets from BOTH layouts to max-ID, otherwise a per-state ticket at
|
|
149
|
-
# ID 204 is invisible to a flat-only-enumerating capture-problem and
|
|
150
|
-
# the next ID re-allocates an already-taken slot. T3 exercises the
|
|
151
|
-
# pipeline against per-state-only AND mixed fixtures to prove the
|
|
152
|
-
# dual-pathspec composes with the downstream sed/grep/sort pipeline.
|
|
153
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
154
|
-
|
|
155
|
-
@test "next-ID pipeline: flat-only fixture yields max ID 104" {
|
|
156
|
-
build_flat_layout
|
|
157
|
-
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
158
|
-
[ "$output" = "104" ]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
@test "next-ID pipeline: per-state-only fixture yields max ID 204" {
|
|
162
|
-
build_per_state_layout
|
|
163
|
-
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
164
|
-
[ "$output" = "204" ]
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
@test "next-ID pipeline: mixed fixture yields max ID 204 (recursive enumeration spans both layouts)" {
|
|
168
|
-
# Architect finding 2: a per-state ticket at ID 204 MUST contribute
|
|
169
|
-
# to max-ID even when flat-layout 104 also exists. Drop the per-state
|
|
170
|
-
# half of the dual-pathspec and this test fails — capture-problem
|
|
171
|
-
# would re-allocate ID 105 instead of advancing to 205.
|
|
172
|
-
build_mixed_layout
|
|
173
|
-
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
174
|
-
[ "$output" = "204" ]
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
@test "next-ID pipeline: empty fixture yields empty result" {
|
|
178
|
-
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
179
|
-
[ -z "$output" ]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
# ── Pipeline 2: Open + known-error multi-state union
|
|
183
|
-
# (work-problems Step 1, list-problems live scan)
|
|
184
|
-
#
|
|
185
|
-
# SKILL.md prescribes the 4-pathspec form:
|
|
186
|
-
# ls docs/problems/*.open.md docs/problems/*.known-error.md \
|
|
187
|
-
# docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null
|
|
188
|
-
#
|
|
189
|
-
# This is wider than T2's single-state filter — it unions two states
|
|
190
|
-
# across two layouts in one ls invocation. The prove-out shape: the
|
|
191
|
-
# union enumerates open + known-error from BOTH layouts and excludes
|
|
192
|
-
# verifying / parked / closed from BOTH layouts.
|
|
193
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
194
|
-
|
|
195
|
-
@test "open+known-error union: per-state-only fixture enumerates 200 and 201" {
|
|
196
|
-
build_per_state_layout
|
|
197
|
-
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
198
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
199
|
-
[[ "$output" == *"known-error/201-bar2.md"* ]]
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
@test "open+known-error union: per-state-only fixture excludes verifying/parked/closed" {
|
|
203
|
-
build_per_state_layout
|
|
204
|
-
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
205
|
-
[[ "$output" != *"202-baz2"* ]]
|
|
206
|
-
[[ "$output" != *"203-qux2"* ]]
|
|
207
|
-
[[ "$output" != *"204-quux2"* ]]
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
@test "open+known-error union: mixed fixture enumerates all four (100, 101, 200, 201)" {
|
|
211
|
-
build_mixed_layout
|
|
212
|
-
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
213
|
-
[[ "$output" == *"100-foo.open.md"* ]]
|
|
214
|
-
[[ "$output" == *"101-bar.known-error.md"* ]]
|
|
215
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
216
|
-
[[ "$output" == *"known-error/201-bar2.md"* ]]
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
@test "open+known-error union: mixed fixture excludes verifying/parked/closed from BOTH layouts" {
|
|
220
|
-
build_mixed_layout
|
|
221
|
-
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
222
|
-
[[ "$output" != *"102-baz"* ]]
|
|
223
|
-
[[ "$output" != *"103-qux"* ]]
|
|
224
|
-
[[ "$output" != *"104-quux"* ]]
|
|
225
|
-
[[ "$output" != *"202-baz2"* ]]
|
|
226
|
-
[[ "$output" != *"203-qux2"* ]]
|
|
227
|
-
[[ "$output" != *"204-quux2"* ]]
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
# ── Pipeline 3: Verifying-state filter (run-retro Step 4a)
|
|
231
|
-
#
|
|
232
|
-
# SKILL.md prescribes:
|
|
233
|
-
# ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null
|
|
234
|
-
#
|
|
235
|
-
# run-retro Step 4a uses this to surface verification-close candidates
|
|
236
|
-
# from the session-context evidence. T3 proves the pipeline finds the
|
|
237
|
-
# verifying ticket in BOTH layouts independently.
|
|
238
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
239
|
-
|
|
240
|
-
@test "verifying-state pipeline: flat-only fixture finds 102" {
|
|
241
|
-
build_flat_layout
|
|
242
|
-
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
243
|
-
[[ "$output" == *"102-baz.verifying.md"* ]]
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
@test "verifying-state pipeline: per-state-only fixture finds 202" {
|
|
247
|
-
build_per_state_layout
|
|
248
|
-
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
249
|
-
[[ "$output" == *"verifying/202-baz2.md"* ]]
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
@test "verifying-state pipeline: mixed fixture finds 102 AND 202" {
|
|
253
|
-
build_mixed_layout
|
|
254
|
-
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
255
|
-
[[ "$output" == *"102-baz.verifying.md"* ]]
|
|
256
|
-
[[ "$output" == *"verifying/202-baz2.md"* ]]
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
# ── Pipeline 4: ID-anchored ticket lookup
|
|
260
|
-
# (manage-problem ticket-by-ID, link-incident, close-incident,
|
|
261
|
-
# transition-problem Step 2, capture-problem Step 2 dup-detect)
|
|
262
|
-
#
|
|
263
|
-
# SKILL.md prescribes:
|
|
264
|
-
# ls docs/problems/<ID>-*.md docs/problems/*/<ID>-*.md 2>/dev/null
|
|
265
|
-
#
|
|
266
|
-
# T3 exercises lookup of a known-existing ID across both layouts and
|
|
267
|
-
# the missing-ID case (asserts empty stdout + nonzero exit).
|
|
268
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
269
|
-
|
|
270
|
-
@test "ID-anchored pipeline: per-state-only fixture finds 200 in subdir" {
|
|
271
|
-
build_per_state_layout
|
|
272
|
-
run bash -c 'ls docs/problems/200-*.md docs/problems/*/200-*.md 2>/dev/null'
|
|
273
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
@test "ID-anchored pipeline: mixed fixture finds 100 (flat) and 200 (per-state)" {
|
|
277
|
-
build_mixed_layout
|
|
278
|
-
run bash -c 'ls docs/problems/100-*.md docs/problems/*/100-*.md 2>/dev/null'
|
|
279
|
-
[[ "$output" == *"100-foo.open.md"* ]]
|
|
280
|
-
run bash -c 'ls docs/problems/200-*.md docs/problems/*/200-*.md 2>/dev/null'
|
|
281
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
@test "ID-anchored pipeline: missing ID yields empty stdout + nonzero exit" {
|
|
285
|
-
build_per_state_layout
|
|
286
|
-
run bash -c 'ls docs/problems/999-*.md docs/problems/*/999-*.md 2>/dev/null'
|
|
287
|
-
[ -z "$output" ]
|
|
288
|
-
[ "$status" -ne 0 ]
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
# ── Pipeline 5: Brace-expansion ID + state-set (report-upstream)
|
|
292
|
-
#
|
|
293
|
-
# SKILL.md prescribes:
|
|
294
|
-
# ls docs/problems/<ID>-*.{open,known-error,verifying,closed}.md \
|
|
295
|
-
# docs/problems/*/<ID>-*.md 2>/dev/null
|
|
296
|
-
#
|
|
297
|
-
# The flat half restricts to a state-set (excludes parked); the
|
|
298
|
-
# per-state half is unrestricted (no state filter). T3 proves the
|
|
299
|
-
# brace expansion composes with the per-state pathspec without false
|
|
300
|
-
# positives across the migration window.
|
|
301
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
302
|
-
|
|
303
|
-
@test "brace-id-state pipeline: per-state-only fixture finds 200 via per-state half" {
|
|
304
|
-
build_per_state_layout
|
|
305
|
-
run bash -c 'ls docs/problems/200-*.{open,known-error,verifying,closed}.md docs/problems/*/200-*.md 2>/dev/null'
|
|
306
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
@test "brace-id-state pipeline: mixed fixture finds flat 100 (open) and per-state 200 (open)" {
|
|
310
|
-
build_mixed_layout
|
|
311
|
-
run bash -c 'ls docs/problems/100-*.{open,known-error,verifying,closed}.md docs/problems/*/100-*.md 2>/dev/null'
|
|
312
|
-
[[ "$output" == *"100-foo.open.md"* ]]
|
|
313
|
-
run bash -c 'ls docs/problems/200-*.{open,known-error,verifying,closed}.md docs/problems/*/200-*.md 2>/dev/null'
|
|
314
|
-
[[ "$output" == *"open/200-foo2.md"* ]]
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
@test "brace-id-state pipeline: parked ticket excluded from flat half but matched in per-state half" {
|
|
318
|
-
# Flat 103 is parked (excluded by the brace state-set); per-state 203
|
|
319
|
-
# is parked but the per-state pathspec is state-unrestricted, so it
|
|
320
|
-
# MUST surface. This is the contract architect finding 2 codifies.
|
|
321
|
-
build_mixed_layout
|
|
322
|
-
run bash -c 'ls docs/problems/103-*.{open,known-error,verifying,closed}.md docs/problems/*/103-*.md 2>/dev/null'
|
|
323
|
-
[[ "$output" != *"103-qux.parked.md"* ]]
|
|
324
|
-
run bash -c 'ls docs/problems/203-*.{open,known-error,verifying,closed}.md docs/problems/*/203-*.md 2>/dev/null'
|
|
325
|
-
[[ "$output" == *"parked/203-qux2.md"* ]]
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
# ── Pipeline 6: Closed-ticket ID-anchored lookup
|
|
329
|
-
# (review-problems Step 5: closed-section rendering uses
|
|
330
|
-
# `docs/problems/*.closed.md docs/problems/closed/*.md`)
|
|
331
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
332
|
-
|
|
333
|
-
@test "closed-ticket pipeline: mixed fixture enumerates flat 104 and per-state 204" {
|
|
334
|
-
build_mixed_layout
|
|
335
|
-
run bash -c 'ls docs/problems/*.closed.md docs/problems/closed/*.md 2>/dev/null'
|
|
336
|
-
[[ "$output" == *"104-quux.closed.md"* ]]
|
|
337
|
-
[[ "$output" == *"closed/204-quux2.md"* ]]
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
@test "closed-ticket pipeline: per-state-only fixture excludes other-state subdirs" {
|
|
341
|
-
build_per_state_layout
|
|
342
|
-
run bash -c 'ls docs/problems/*.closed.md docs/problems/closed/*.md 2>/dev/null'
|
|
343
|
-
[[ "$output" == *"closed/204-quux2.md"* ]]
|
|
344
|
-
[[ "$output" != *"open/200"* ]]
|
|
345
|
-
[[ "$output" != *"known-error/201"* ]]
|
|
346
|
-
[[ "$output" != *"verifying/202"* ]]
|
|
347
|
-
[[ "$output" != *"parked/203"* ]]
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
# ── Pipeline 7: Parked-state filter (review-problems Step 3 parked section)
|
|
351
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
352
|
-
|
|
353
|
-
@test "parked-state pipeline: mixed fixture enumerates flat 103 and per-state 203" {
|
|
354
|
-
build_mixed_layout
|
|
355
|
-
run bash -c 'ls docs/problems/*.parked.md docs/problems/parked/*.md 2>/dev/null'
|
|
356
|
-
[[ "$output" == *"103-qux.parked.md"* ]]
|
|
357
|
-
[[ "$output" == *"parked/203-qux2.md"* ]]
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
# ── Composition: ls-with-2>/dev/null exit-code semantics
|
|
361
|
-
# (mirrors T2's empty-fixture contract; proves the SKILL.md contract
|
|
362
|
-
# remains "stdout content is the signal, not exit code")
|
|
363
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
364
|
-
|
|
365
|
-
@test "all pipelines: empty fixture produces empty stdout across every shape" {
|
|
366
|
-
run bash -c "ls docs/problems/*.md docs/problems/*/*.md 2>/dev/null | sed 's|.*/||' | grep -oE '^[0-9]+' | sort -n | tail -1"
|
|
367
|
-
[ -z "$output" ]
|
|
368
|
-
run bash -c 'ls docs/problems/*.open.md docs/problems/*.known-error.md docs/problems/open/*.md docs/problems/known-error/*.md 2>/dev/null'
|
|
369
|
-
[ -z "$output" ]
|
|
370
|
-
run bash -c 'ls docs/problems/*.verifying.md docs/problems/verifying/*.md 2>/dev/null'
|
|
371
|
-
[ -z "$output" ]
|
|
372
|
-
run bash -c 'ls docs/problems/100-*.md docs/problems/*/100-*.md 2>/dev/null'
|
|
373
|
-
[ -z "$output" ]
|
|
374
|
-
}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Behavioural test for lib/story-oversight.sh — ADR-090 lazy-fingerprint helpers.
|
|
3
|
-
# The hash EXCLUDES the marker lines (so writing the marker is idempotent), and
|
|
4
|
-
# "ratified" = confirmed marker AND stored hash matches current content. Any
|
|
5
|
-
# content edit drifts the hash → not ratified (ADR-090 drift-invalidation).
|
|
6
|
-
#
|
|
7
|
-
# @adr ADR-090
|
|
8
|
-
# @problem P404 (Phase 2)
|
|
9
|
-
|
|
10
|
-
setup() {
|
|
11
|
-
REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
|
|
12
|
-
LIB="${REPO_ROOT}/packages/itil/lib/story-oversight.sh"
|
|
13
|
-
TMPD="$(mktemp -d)"
|
|
14
|
-
# shellcheck source=/dev/null
|
|
15
|
-
source "$LIB"
|
|
16
|
-
}
|
|
17
|
-
teardown() { rm -rf "$TMPD"; }
|
|
18
|
-
|
|
19
|
-
@test "oversight_content_hash: identical content → identical hash" {
|
|
20
|
-
printf '# body\nline two\n' > "$TMPD/a"; printf '# body\nline two\n' > "$TMPD/b"
|
|
21
|
-
[ "$(oversight_content_hash "$TMPD/a")" = "$(oversight_content_hash "$TMPD/b")" ]
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
@test "oversight_content_hash: adding/changing the marker lines does NOT change the hash" {
|
|
25
|
-
printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/f"
|
|
26
|
-
before="$(oversight_content_hash "$TMPD/f")"
|
|
27
|
-
printf -- '---\nstatus: accepted\nhuman-oversight: confirmed\noversight-hash: %064d\n---\n# body\n' 0 > "$TMPD/f"
|
|
28
|
-
[ "$before" = "$(oversight_content_hash "$TMPD/f")" ]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@test "oversight_content_hash: a real content edit DOES change the hash" {
|
|
32
|
-
printf '# body\n' > "$TMPD/f"; before="$(oversight_content_hash "$TMPD/f")"
|
|
33
|
-
printf '# body EDITED\n' > "$TMPD/f"
|
|
34
|
-
[ "$before" != "$(oversight_content_hash "$TMPD/f")" ]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
@test "oversight_content_hash: ticking an acceptance-criterion checkbox does NOT drift (lifecycle progress)" {
|
|
38
|
-
printf -- '---\nstatus: accepted\n---\n- [ ] a criterion\n' > "$TMPD/f"; before="$(oversight_content_hash "$TMPD/f")"
|
|
39
|
-
printf -- '---\nstatus: accepted\n---\n- [x] a criterion\n' > "$TMPD/f"
|
|
40
|
-
[ "$before" = "$(oversight_content_hash "$TMPD/f")" ]
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@test "oversight_content_hash: advancing frontmatter status: does NOT drift (lifecycle)" {
|
|
44
|
-
printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/f"; before="$(oversight_content_hash "$TMPD/f")"
|
|
45
|
-
printf -- '---\nstatus: done\n---\n# body\n' > "$TMPD/f"
|
|
46
|
-
[ "$before" = "$(oversight_content_hash "$TMPD/f")" ]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@test "oversight_content_hash: changing criterion TEXT DOES drift (substance)" {
|
|
50
|
-
printf -- '---\nstatus: accepted\n---\n- [ ] original\n' > "$TMPD/f"; before="$(oversight_content_hash "$TMPD/f")"
|
|
51
|
-
printf -- '---\nstatus: accepted\n---\n- [ ] a DIFFERENT criterion\n' > "$TMPD/f"
|
|
52
|
-
[ "$before" != "$(oversight_content_hash "$TMPD/f")" ]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@test "oversight_content_hash: advancing slice data-status does NOT drift (HTML map lifecycle)" {
|
|
56
|
-
printf '<a class="slice" data-story-id="STORY-1" data-status="draft">x</a>\n' > "$TMPD/m.html"; before="$(oversight_content_hash "$TMPD/m.html")"
|
|
57
|
-
printf '<a class="slice" data-story-id="STORY-1" data-status="done">x</a>\n' > "$TMPD/m.html"
|
|
58
|
-
[ "$before" = "$(oversight_content_hash "$TMPD/m.html")" ]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
@test "is_story_map_ratified: confirmed + matching hash → ratified (md)" {
|
|
62
|
-
printf -- '---\nstatus: accepted\n---\n# body\n' > "$TMPD/f"
|
|
63
|
-
h="$(oversight_content_hash "$TMPD/f")"
|
|
64
|
-
printf -- '---\nstatus: accepted\nhuman-oversight: confirmed\noversight-hash: %s\n---\n# body\n' "$h" > "$TMPD/f"
|
|
65
|
-
run is_story_map_ratified "$TMPD/f"; [ "$status" -eq 0 ]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@test "is_story_map_ratified: confirmed but STALE hash (drifted) → not ratified" {
|
|
69
|
-
printf -- '---\nhuman-oversight: confirmed\noversight-hash: %064d\n---\n# body EDITED AFTER RATIFY\n' 1 > "$TMPD/f"
|
|
70
|
-
run is_story_map_ratified "$TMPD/f"; [ "$status" -ne 0 ]
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@test "is_story_map_ratified: confirmed with NO hash (legacy hand-ratified) → not ratified" {
|
|
74
|
-
printf -- '---\nhuman-oversight: confirmed\n---\n# body\n' > "$TMPD/f"
|
|
75
|
-
run is_story_map_ratified "$TMPD/f"; [ "$status" -ne 0 ]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
@test "is_story_map_ratified: unconfirmed → not ratified" {
|
|
79
|
-
printf -- '---\nhuman-oversight: unconfirmed\n---\n# body\n' > "$TMPD/f"
|
|
80
|
-
run is_story_map_ratified "$TMPD/f"; [ "$status" -ne 0 ]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@test "is_story_map_ratified: HTML map confirmed + matching hash → ratified" {
|
|
84
|
-
printf '<h1>map</h1>\n' > "$TMPD/m.html"
|
|
85
|
-
h="$(oversight_content_hash "$TMPD/m.html")"
|
|
86
|
-
printf '<meta name="human-oversight" content="confirmed">\n<meta name="oversight-hash" content="%s">\n<h1>map</h1>\n' "$h" > "$TMPD/m.html"
|
|
87
|
-
run is_story_map_ratified "$TMPD/m.html"; [ "$status" -eq 0 ]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# --- P474 / STORY-055: the extraction must not move a single hash --------------
|
|
91
|
-
#
|
|
92
|
-
# `oversight_content_hash` and `oversight_content_hash_excluding_stories` shared a
|
|
93
|
-
# verbatim grep|sed filter, which is why the P474 mirror had to be removed twice
|
|
94
|
-
# and why a third copy could have been missed. The filter is now extracted.
|
|
95
|
-
#
|
|
96
|
-
# The extraction boundary is the whole risk. The two functions' INPUT paths are
|
|
97
|
-
# NOT equivalent and must stay that way: one passes the file to grep directly,
|
|
98
|
-
# the other round-trips through $(cat) — which strips all trailing newlines —
|
|
99
|
-
# then printf '%s\n' re-adds exactly one. So trailing blank lines are preserved
|
|
100
|
-
# by the first and collapsed by the second. Extract the filter only; unify the
|
|
101
|
-
# input paths "for symmetry" and the hash silently changes for any artefact with
|
|
102
|
-
# anomalous trailing whitespace, un-ratifying every stored fingerprint at once.
|
|
103
|
-
#
|
|
104
|
-
# `_ref_*` below are VERBATIM copies of the pre-extraction implementation. They
|
|
105
|
-
# exist to be compared against, so do NOT refactor them to call the new helper —
|
|
106
|
-
# that would make the equivalence assertions circular and worthless.
|
|
107
|
-
|
|
108
|
-
_ref_hash() {
|
|
109
|
-
grep -vE '^(human-oversight|oversight-hash|oversight-basis|status):|<meta[^>]*name="(human-oversight|oversight-hash|oversight-basis|status)"' "$1" \
|
|
110
|
-
| sed -E 's/- \[[ xX]\]/- [ ]/g; s/data-status="[^"]*"/data-status=""/g' \
|
|
111
|
-
| shasum -a 256 | awk '{print $1}'
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
_ref_hash_excluding() {
|
|
115
|
-
local f="$1"; shift
|
|
116
|
-
local filtered id
|
|
117
|
-
filtered="$(cat "$f")"
|
|
118
|
-
for id in "$@"; do
|
|
119
|
-
[ -n "$id" ] || continue
|
|
120
|
-
filtered="$(printf '%s\n' "$filtered" | grep -vF "data-story-id=\"${id}\"" || true)"
|
|
121
|
-
done
|
|
122
|
-
printf '%s\n' "$filtered" \
|
|
123
|
-
| grep -vE '^(human-oversight|oversight-hash|oversight-basis|status):|<meta[^>]*name="(human-oversight|oversight-hash|oversight-basis|status)"' \
|
|
124
|
-
| sed -E 's/- \[[ xX]\]/- [ ]/g; s/data-status="[^"]*"/data-status=""/g' \
|
|
125
|
-
| shasum -a 256 | awk '{print $1}'
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
@test "extraction: byte-identical to the frozen reference across edge shapes" {
|
|
129
|
-
# No final newline.
|
|
130
|
-
printf -- '---\nstatus: draft\n---\nbody' > "$TMPD/a"
|
|
131
|
-
# Multiple trailing blank lines — the shape the input-path divergence hinges on.
|
|
132
|
-
printf -- '---\nstatus: draft\n---\nbody\n\n\n\n' > "$TMPD/b"
|
|
133
|
-
# CRLF.
|
|
134
|
-
printf -- '---\r\nstatus: draft\r\n---\r\nbody\r\n' > "$TMPD/c"
|
|
135
|
-
# Empty file.
|
|
136
|
-
: > "$TMPD/d"
|
|
137
|
-
# A criterion tick and a data-status, both normalised.
|
|
138
|
-
printf -- '- [x] done\n<a data-status="done">x</a>\n' > "$TMPD/e"
|
|
139
|
-
# Every excluded key present, in both encodings.
|
|
140
|
-
printf -- 'human-oversight: confirmed\noversight-hash: deadbeef\noversight-basis: pure-decomposition\nstatus: accepted\n<meta name="status" content="draft">\nbody\n' > "$TMPD/f"
|
|
141
|
-
# Only a newline.
|
|
142
|
-
printf '\n' > "$TMPD/g"
|
|
143
|
-
|
|
144
|
-
for n in a b c d e f g; do
|
|
145
|
-
[ "$(oversight_content_hash "$TMPD/$n")" = "$(_ref_hash "$TMPD/$n")" ] || {
|
|
146
|
-
echo "oversight_content_hash diverged on fixture $n"; false
|
|
147
|
-
}
|
|
148
|
-
done
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
@test "extraction: map variant byte-identical, including the id-exclusion loop" {
|
|
152
|
-
printf -- '<meta name="status" content="draft">\n<a data-story-id="STORY-05">short</a>\n<a data-story-id="STORY-054">long</a>\n<a class="slice" data-status="done">s</a>\nbody\n\n\n' \
|
|
153
|
-
> "$TMPD/m.html"
|
|
154
|
-
# Zero ids, one id, and the prefix-collision pair — STORY-05 must not strip
|
|
155
|
-
# STORY-054's card, which is what the closing-quote anchor buys.
|
|
156
|
-
[ "$(oversight_content_hash_excluding_stories "$TMPD/m.html")" = "$(_ref_hash_excluding "$TMPD/m.html")" ]
|
|
157
|
-
[ "$(oversight_content_hash_excluding_stories "$TMPD/m.html" STORY-054)" = "$(_ref_hash_excluding "$TMPD/m.html" STORY-054)" ]
|
|
158
|
-
[ "$(oversight_content_hash_excluding_stories "$TMPD/m.html" STORY-05)" = "$(_ref_hash_excluding "$TMPD/m.html" STORY-05)" ]
|
|
159
|
-
[ "$(oversight_content_hash_excluding_stories "$TMPD/m.html" STORY-05 STORY-054)" = "$(_ref_hash_excluding "$TMPD/m.html" STORY-05 STORY-054)" ]
|
|
160
|
-
# And the divergence itself is preserved rather than accidentally unified.
|
|
161
|
-
[ "$(oversight_content_hash_excluding_stories "$TMPD/m.html")" != "$(oversight_content_hash "$TMPD/m.html")" ]
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
# Golden hashes are pinned over FIXTURES, never over live artefacts. Pinning to
|
|
165
|
-
# the corpus would redden this suite on every later legitimate artefact edit —
|
|
166
|
-
# ADR-052's refactor-blocking failure mode. Their job is to catch the frozen
|
|
167
|
-
# reference itself rotting, which the equivalence cases above cannot.
|
|
168
|
-
@test "extraction: pinned golden hashes over a canonical fixture" {
|
|
169
|
-
printf -- '---\nstatus: draft\nhuman-oversight: confirmed\n---\n\n# STORY-900: canonical\n\n**Reported**: 2026-07-30\n\n- [ ] a criterion\n' \
|
|
170
|
-
> "$TMPD/golden.md"
|
|
171
|
-
[ "$(oversight_content_hash "$TMPD/golden.md")" = "1a18f2501f7092b64316a1566795e64860f90893c2b4d0d36cd9a783ada21414" ]
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@test "extraction: the excluded-key accessor agrees with the operative pattern both ways" {
|
|
175
|
-
local keys; keys="$(oversight_excluded_keys)"
|
|
176
|
-
[ -n "$keys" ]
|
|
177
|
-
# Every accessor key appears as an alternation branch in the operative filter.
|
|
178
|
-
for k in $keys; do
|
|
179
|
-
grep -qF -- "$k" "$LIB" || { echo "accessor key '$k' absent from the lib pattern"; false; }
|
|
180
|
-
done
|
|
181
|
-
# And every branch in the operative pattern appears in the accessor — the
|
|
182
|
-
# direction that catches a key ADDED to the regex but not to the accessor,
|
|
183
|
-
# which would leave the corpus lint blind to it.
|
|
184
|
-
local branch
|
|
185
|
-
for branch in $(grep -oE '\^\(([a-z-]+\|)+[a-z-]+\):' "$LIB" | head -1 | tr -d '^():' | tr '|' ' '); do
|
|
186
|
-
printf '%s\n' "$keys" | grep -qx -- "$branch" || {
|
|
187
|
-
echo "pattern branch '$branch' missing from oversight_excluded_keys()"; false
|
|
188
|
-
}
|
|
189
|
-
done
|
|
190
|
-
}
|