@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/itil",
|
|
3
|
-
"version": "0.61.
|
|
3
|
+
"version": "0.61.2",
|
|
4
4
|
"description": "ITIL-aligned IT service management for Claude Code (problem, and future incident/change skills)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-itil": "./bin/install.mjs"
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
"scripts/",
|
|
28
28
|
".claude-plugin/",
|
|
29
29
|
"lib/",
|
|
30
|
-
"!skills/*/eval/"
|
|
30
|
+
"!skills/*/eval/",
|
|
31
|
+
"!agents/test/",
|
|
32
|
+
"!hooks/test/",
|
|
33
|
+
"!lib/test/",
|
|
34
|
+
"!scripts/test/",
|
|
35
|
+
"!skills/*/test/"
|
|
31
36
|
]
|
|
32
37
|
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Behavioural fixture 2: genuinely-new capture (PROCEED_NEW)
|
|
2
|
-
|
|
3
|
-
Validates that the agent does NOT spuriously fold a genuinely-new capture into a candidate just because the mechanical pre-filter surfaced one.
|
|
4
|
-
|
|
5
|
-
## Input 1: New capture description
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
The `claude plugin marketplace update` command silently caches plugin
|
|
9
|
-
metadata for 24 hours without surfacing the cache state in any UI. Adopters
|
|
10
|
-
attempting to refresh after a release wait 24h not knowing the cache is
|
|
11
|
-
serving stale data. Need a manual cache-bust flag or a TTL surface in the
|
|
12
|
-
marketplace command's output. Affects every adopter waiting on a release.
|
|
13
|
-
Verifiable by: invoke `claude plugin marketplace update` immediately after a
|
|
14
|
-
release; observe no version-bump surface; wait 24h; observe version bump.
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Input 2: Filtered candidate set
|
|
18
|
-
|
|
19
|
-
| Candidate | Title | Path | Matching signals |
|
|
20
|
-
|-----------|-------|------|------------------|
|
|
21
|
-
| P106 | `claude plugin install` is a silent no-op when already installed at any version | `docs/problems/open/106-...md` | shared `claude plugin` command surface; both touch the install/marketplace cache layer |
|
|
22
|
-
|
|
23
|
-
## Expected verdict
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
PROCEED_NEW
|
|
27
|
-
|
|
28
|
-
**Rationale**: P106's root cause is the `claude plugin install` command being
|
|
29
|
-
a no-op when already installed at any version (no version-equality check).
|
|
30
|
-
The new capture's root cause is a different surface: `claude plugin
|
|
31
|
-
marketplace update`'s opaque 24-hour metadata cache. The two share the
|
|
32
|
-
upstream "claude plugin marketplace cache layer" but operate at different
|
|
33
|
-
commands with different observable symptoms and different fix loci. Folding
|
|
34
|
-
the new capture into P106 would dilute P106's single-purpose anchor.
|
|
35
|
-
|
|
36
|
-
**Per-candidate explanation**:
|
|
37
|
-
- P106 (claude plugin install silent no-op) — different command (`install` vs
|
|
38
|
-
`marketplace update`); different observable (no version bump on already-
|
|
39
|
-
installed plugin vs no version bump because metadata cache is stale);
|
|
40
|
-
different fix locus (per-project install logic vs marketplace metadata
|
|
41
|
-
TTL/surfacing). Surface signals overlap (both touch the marketplace cache
|
|
42
|
-
layer) but the captured friction is genuinely distinct.
|
|
43
|
-
```
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Behavioural fixture 3: subtle sibling-vs-parent (PROCEED_NEW with reasoned rationale)
|
|
2
|
-
|
|
3
|
-
Validates that the agent reasons cleanly about sibling-vs-parent shape — two tickets sharing surface signals where neither is the other's parent.
|
|
4
|
-
|
|
5
|
-
## Input 1: New capture description
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
`/wr-itil:report-upstream` SKILL.md surface — the report-upstream skill's
|
|
9
|
-
generated GitHub issue body sometimes carries our internal P<NNN> ticket IDs
|
|
10
|
-
verbatim instead of stripping them. Adopters reporting upstream see opaque
|
|
11
|
-
references they can't resolve. Should redact internal IDs before posting or
|
|
12
|
-
include a "for our records" footer separating internal vs upstream
|
|
13
|
-
references. Affects every outbound issue from /wr-itil:report-upstream.
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Input 2: Filtered candidate set
|
|
17
|
-
|
|
18
|
-
| Candidate | Title | Path | Matching signals |
|
|
19
|
-
|-----------|-------|------|------------------|
|
|
20
|
-
| P070 | `/wr-itil:report-upstream` doesn't deduplicate against existing upstream issues | `docs/problems/verifying/070-...md` | shared `/wr-itil:report-upstream` SKILL reference; both about outbound surfaces on the same SKILL |
|
|
21
|
-
|
|
22
|
-
## Expected verdict
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
PROCEED_NEW
|
|
26
|
-
|
|
27
|
-
**Rationale**: P070's root cause is the report-upstream SKILL not checking
|
|
28
|
-
the upstream repo for an existing issue before posting (deduplication gap).
|
|
29
|
-
The new capture's root cause is the report-upstream SKILL leaking
|
|
30
|
-
maintainer-internal P<NNN> references in the generated issue body (privacy /
|
|
31
|
-
adopter-confusion gap). The two are siblings — both surface on
|
|
32
|
-
`/wr-itil:report-upstream`'s outbound generation flow — but neither is the
|
|
33
|
-
other's parent. The shared SKILL surface is coincidental; the fix loci are
|
|
34
|
-
distinct (upstream-repo-state lookup vs body-text scrubbing). P070's scope
|
|
35
|
-
does not name internal-ID-leakage as deferred follow-up. Recommend
|
|
36
|
-
PROCEED_NEW; let `/wr-itil:review-problems` cluster them as sibling-class at
|
|
37
|
-
the next cluster pass if a common parent emerges.
|
|
38
|
-
|
|
39
|
-
**Per-candidate explanation**:
|
|
40
|
-
- P070 (report-upstream deduplication gap) — same SKILL surface, but
|
|
41
|
-
different observable (duplicate upstream issues vs leaked internal IDs in
|
|
42
|
-
the body), different fix locus (gh API state lookup vs string scrubbing on
|
|
43
|
-
the body template), different lifecycle stage (P070 is Verifying with a
|
|
44
|
-
shipping fix; the new capture is fresh discovery on a different code
|
|
45
|
-
surface in the same file). Folding would dilute P070's single-purpose
|
|
46
|
-
anchor and force its Verifying transition to wait on un-related work.
|
|
47
|
-
```
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Behavioural fixture 1 (canonical regression): P347-vs-P346
|
|
2
|
-
|
|
3
|
-
This is the canonical regression case for the `wr-itil:hang-off-check` agent. It captures the 2026-05-31 P347 wrongly-captured-sibling-of-P346 incident. If the agent receives this fixture's inputs and returns anything other than `HANG_OFF: P346`, the SKILL is insufficient and the regression has re-opened.
|
|
4
|
-
|
|
5
|
-
Behavioural execution lands under RFC-012 (promptfoo eval harness, proposed). Until RFC-012 ships, this fixture is the documentation of the expected behaviour; the bats fixtures at `../hang-off-check.bats` are structural assertions on the agent's prose contract per ADR-052 Surface 2 carve-out.
|
|
6
|
-
|
|
7
|
-
## Input 1: New capture description
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
P346 + ADR-079 Phase 2 — empirical foreground relevance-scan today (5 batches,
|
|
11
|
-
14 closes) revealed 4 evidence shapes Phase 1 doesn't implement, plus the
|
|
12
|
-
1 shape Phase 1 does implement had the highest false-positive rate. The four
|
|
13
|
-
shapes: ADR-shipped-with-`human-oversight: confirmed`, named-skill-or-feature-
|
|
14
|
-
exists, self-marker-in-body (P289-class), driver-child-ticket-closed (P155 →
|
|
15
|
-
P014). Phase 1 false-positive fixes needed for state-suffix, sibling-file, and
|
|
16
|
-
rename detection (via `git log --follow`). Behavioural bats extension from 18
|
|
17
|
-
to 33 fixtures. `evaluate-relevance.sh` extension. Update
|
|
18
|
-
`/wr-itil:review-problems` SKILL.md Step 4.6 + `/wr-itil:manage-problem`
|
|
19
|
-
lifecycle table.
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Input 2: Filtered candidate set
|
|
23
|
-
|
|
24
|
-
| Candidate | Title | Path | Matching signals |
|
|
25
|
-
|-----------|-------|------|------------------|
|
|
26
|
-
| P346 | `/wr-itil:review-problems` has no path to close tickets that are no longer relevant (evidence-based, NOT age-based) — structural outflow gap drives monotonic backlog growth | `docs/problems/open/346-...md` | shared ADR-079 ref; shared `packages/itil/scripts/evaluate-relevance.sh` path; shared `/wr-itil:review-problems` SKILL ref; shared `/wr-itil:manage-problem` SKILL ref; candidate's `## Multi-phase scope` section explicitly names Phase 2 as in-scope |
|
|
27
|
-
|
|
28
|
-
## Expected verdict
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
HANG_OFF: P346
|
|
32
|
-
|
|
33
|
-
**Rationale**: P346 is the master ticket for the framework's backlog-flow-control
|
|
34
|
-
mechanisms with an explicit Multi-phase scope section. The new capture's
|
|
35
|
-
description IS Phase 2 of P346 (additional evidence shapes + Phase 1
|
|
36
|
-
false-positive fixes for the `evaluate-relevance.sh` script that P346 Phase 1
|
|
37
|
-
introduced). P346's body already names Phase 2 work as in-scope.
|
|
38
|
-
|
|
39
|
-
**Signals matched**: shared ADR-079 reference; shared
|
|
40
|
-
`packages/itil/scripts/evaluate-relevance.sh` file path; shared
|
|
41
|
-
`/wr-itil:review-problems` SKILL reference; shared `/wr-itil:manage-problem`
|
|
42
|
-
SKILL reference; candidate's `## Multi-phase scope` section explicitly names
|
|
43
|
-
Phase 2 as in-scope.
|
|
44
|
-
|
|
45
|
-
**Where to absorb**: amend P346's Investigation Tasks checklist with the 4
|
|
46
|
-
new evidence shapes + Phase 1 false-positive fix items; add a `### Phase 2 —
|
|
47
|
-
evidence shape expansion + Phase 1 false-positive fixes` section under the
|
|
48
|
-
existing Multi-phase scope section; the shipped commits' attribution
|
|
49
|
-
references this absorption.
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Why this fixture is canonical
|
|
53
|
-
|
|
54
|
-
The wrongly-captured P347 sibling of P346 on 2026-05-31 motivated the entire Phase 3 deliverable (this agent's existence). If a future change to the agent's prose contract regresses the verdict on this fixture, the SKILL no longer fulfils its driver. This is the binary tripwire.
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
# Doc-lint guard: wr-itil:hang-off-check agent contract — the agent MUST
|
|
3
|
-
# carry the verdict format (HANG_OFF: P<NNN> | PROCEED_NEW), the
|
|
4
|
-
# fresh-context subagent rationale, the JTBD-301 maintainer-side firewall,
|
|
5
|
-
# the AFK safe-default (PROCEED_NEW on ambiguous), the rationale-citation
|
|
6
|
-
# requirement, and the three canonical fixture files. Closes P346 Phase 3
|
|
7
|
-
# deliverable — the SKILL's behavioural intent is documented and
|
|
8
|
-
# verifiable.
|
|
9
|
-
#
|
|
10
|
-
# Structural assertion — ADR-052 Surface 2 (structural-justified) +
|
|
11
|
-
# P176 harness gap. Behavioural execution of the three canonical fixtures
|
|
12
|
-
# lands under RFC-012 (promptfoo eval harness, proposed). Upgrade these
|
|
13
|
-
# to behavioural fixtures when RFC-012 ships.
|
|
14
|
-
#
|
|
15
|
-
# Cross-reference:
|
|
16
|
-
# P346 (review-problems backlog-flow-control master ticket; Phase 3
|
|
17
|
-
# deliverable this agent fulfils)
|
|
18
|
-
# P347 (closed as duplicate-of-P346; canonical regression case driving
|
|
19
|
-
# fixture 1)
|
|
20
|
-
# P176 (agent-side I2 / harness gap — Surface 2 carve-out precedent)
|
|
21
|
-
# ADR-032 (5th invocation pattern — fresh-context-subagent-as-decision-
|
|
22
|
-
# arbiter; P346 amendment 2026-05-31 codifies this agent's shape)
|
|
23
|
-
# ADR-052 (behavioural-tests default; Surface 2 carve-out)
|
|
24
|
-
# ADR-075 (promptfoo as agent-prose verdict harness — future home)
|
|
25
|
-
# RFC-012 (promptfoo retrofit — behavioural eval harness)
|
|
26
|
-
# RFC-013 (P346 multi-phase trace per ADR-071)
|
|
27
|
-
# @jtbd JTBD-001 (enforce governance without slowing down)
|
|
28
|
-
# @jtbd JTBD-006 (progress backlog while I'm away — AFK safe-default)
|
|
29
|
-
# @jtbd JTBD-101 (extend suite with new plugins — pattern reuse)
|
|
30
|
-
# @jtbd JTBD-201 (restore service fast with an audit trail — rationale)
|
|
31
|
-
|
|
32
|
-
setup() {
|
|
33
|
-
AGENT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
34
|
-
AGENT_FILE="${AGENT_DIR}/hang-off-check.md"
|
|
35
|
-
FIXTURES_DIR="${AGENT_DIR}/test/fixtures"
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
# ----- Contract surface: verdict format + structure -----
|
|
39
|
-
|
|
40
|
-
@test "agent.md exists at packages/itil/agents/hang-off-check.md" {
|
|
41
|
-
[ -f "$AGENT_FILE" ]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@test "agent.md frontmatter declares name: hang-off-check" {
|
|
45
|
-
run grep -nE "^name: hang-off-check$" "$AGENT_FILE"
|
|
46
|
-
[ "$status" -eq 0 ]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@test "agent.md frontmatter limits tools to read-only set (Read, Glob, Grep)" {
|
|
50
|
-
# No Edit, no Write, no Bash — read-only reviewer per ADR-032 5th pattern
|
|
51
|
-
run grep -nE "tools:" "$AGENT_FILE"
|
|
52
|
-
[ "$status" -eq 0 ]
|
|
53
|
-
run grep -nE "^ - (Read|Glob|Grep)$" "$AGENT_FILE"
|
|
54
|
-
[ "$status" -eq 0 ]
|
|
55
|
-
# Forbid Edit / Write / Bash in the tools list
|
|
56
|
-
! grep -nE "^ - (Edit|Write|Bash|MultiEdit|NotebookEdit)$" "$AGENT_FILE"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@test "agent.md declares HANG_OFF: P<NNN> verdict shape" {
|
|
60
|
-
run grep -nE 'HANG_OFF:\s*P<NNN>' "$AGENT_FILE"
|
|
61
|
-
[ "$status" -eq 0 ]
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@test "agent.md declares PROCEED_NEW verdict shape" {
|
|
65
|
-
run grep -nE "PROCEED_NEW" "$AGENT_FILE"
|
|
66
|
-
[ "$status" -eq 0 ]
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@test "agent.md requires a Rationale section on every verdict" {
|
|
70
|
-
run grep -nE "\*\*Rationale\*\*" "$AGENT_FILE"
|
|
71
|
-
[ "$status" -eq 0 ]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
@test "agent.md requires Signals matched citation on HANG_OFF (rationale-grounding per ADR-026)" {
|
|
75
|
-
run grep -nE "\*\*Signals matched\*\*" "$AGENT_FILE"
|
|
76
|
-
[ "$status" -eq 0 ]
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
@test "agent.md requires Where to absorb directive on HANG_OFF (calling-skill action contract)" {
|
|
80
|
-
run grep -nE "\*\*Where to absorb\*\*" "$AGENT_FILE"
|
|
81
|
-
[ "$status" -eq 0 ]
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
@test "agent.md requires Per-candidate explanation on PROCEED_NEW" {
|
|
85
|
-
run grep -nE "\*\*Per-candidate explanation\*\*" "$AGENT_FILE"
|
|
86
|
-
[ "$status" -eq 0 ]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
# ----- Driver / context-isolation rationale -----
|
|
90
|
-
|
|
91
|
-
@test "agent.md cites the fresh-context / session-context-bias driver" {
|
|
92
|
-
run grep -niE "(session-context bias|fresh context|context isolation)" "$AGENT_FILE"
|
|
93
|
-
[ "$status" -eq 0 ]
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@test "agent.md cites the P347-vs-P346 canonical regression in the driver section" {
|
|
97
|
-
run grep -nE "P347" "$AGENT_FILE"
|
|
98
|
-
[ "$status" -eq 0 ]
|
|
99
|
-
run grep -nE "P346" "$AGENT_FILE"
|
|
100
|
-
[ "$status" -eq 0 ]
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
@test "agent.md cites ADR-032 5th-pattern codification (P346 amendment)" {
|
|
104
|
-
run grep -nE "ADR-032" "$AGENT_FILE"
|
|
105
|
-
[ "$status" -eq 0 ]
|
|
106
|
-
run grep -niE "5th (invocation )?pattern" "$AGENT_FILE"
|
|
107
|
-
[ "$status" -eq 0 ]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
# ----- Decision rule -----
|
|
111
|
-
|
|
112
|
-
@test "agent.md names master-ticket / multi-phase as a HANG_OFF signal" {
|
|
113
|
-
run grep -niE "(master ticket|multi-phase|scope expansion)" "$AGENT_FILE"
|
|
114
|
-
[ "$status" -eq 0 ]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
@test "agent.md names false-negative-cheaper-than-false-positive safe-default" {
|
|
118
|
-
run grep -niE "false[-]positive.*cheap|cheap.*false[-]positive" "$AGENT_FILE"
|
|
119
|
-
[ "$status" -eq 0 ]
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@test "agent.md cites Rule 6 fail-safe / AFK safe-default (ambiguous → PROCEED_NEW)" {
|
|
123
|
-
run grep -niE "(ambiguous.*PROCEED_NEW|--no-prompt|AFK propagation)" "$AGENT_FILE"
|
|
124
|
-
[ "$status" -eq 0 ]
|
|
125
|
-
run grep -nE "ADR-013" "$AGENT_FILE"
|
|
126
|
-
[ "$status" -eq 0 ]
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
@test "agent.md explicitly forbids AskUserQuestion invocation (Rule 6)" {
|
|
130
|
-
run grep -niE "(never|do not|MUST NOT).*(AskUserQuestion|invoke.*AskUserQuestion)" "$AGENT_FILE"
|
|
131
|
-
[ "$status" -eq 0 ]
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
# ----- Scope / firewalls -----
|
|
135
|
-
|
|
136
|
-
@test "agent.md names the JTBD-301 maintainer-side firewall" {
|
|
137
|
-
run grep -nE "JTBD-301" "$AGENT_FILE"
|
|
138
|
-
[ "$status" -eq 0 ]
|
|
139
|
-
run grep -niE "maintainer-side|maintainer-internal" "$AGENT_FILE"
|
|
140
|
-
[ "$status" -eq 0 ]
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
@test "agent.md excludes plugin-user-side intake from the dispatch (firewall)" {
|
|
144
|
-
run grep -niE "plugin-user-side|problem-report\.yml" "$AGENT_FILE"
|
|
145
|
-
[ "$status" -eq 0 ]
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
@test "agent.md excludes manage-problem ingestion-of-plugin-user-reports path" {
|
|
149
|
-
run grep -niE "ingestion[- ]of[- ]plugin[- ]user[- ]reports" "$AGENT_FILE"
|
|
150
|
-
[ "$status" -eq 0 ]
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
@test "agent.md scopes cardinality to one verdict per invocation" {
|
|
154
|
-
run grep -niE "one verdict per invocation|cardinality" "$AGENT_FILE"
|
|
155
|
-
[ "$status" -eq 0 ]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# ----- Output formatting (matches architect / jtbd output formatting convention) -----
|
|
159
|
-
|
|
160
|
-
@test "agent.md carries Output Formatting section requiring human-readable IDs" {
|
|
161
|
-
run grep -nE "## Output Formatting" "$AGENT_FILE"
|
|
162
|
-
[ "$status" -eq 0 ]
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
# ----- JTBD annotation (per JTBD review nit 5) -----
|
|
166
|
-
|
|
167
|
-
@test "agent.md carries @jtbd annotation citing JTBD-001/006/101/201" {
|
|
168
|
-
run grep -nE "^# @jtbd .*JTBD-001.*JTBD-006.*JTBD-101.*JTBD-201" "$AGENT_FILE"
|
|
169
|
-
[ "$status" -eq 0 ]
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
# ----- Canonical behavioural fixtures (RFC-012 future-home) -----
|
|
173
|
-
|
|
174
|
-
@test "fixture 1 (canonical P347-vs-P346 regression) exists" {
|
|
175
|
-
[ -f "${FIXTURES_DIR}/regression-p347-vs-p346.md" ]
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
@test "fixture 1 names HANG_OFF: P346 as the expected verdict" {
|
|
179
|
-
run grep -nE "HANG_OFF: P346" "${FIXTURES_DIR}/regression-p347-vs-p346.md"
|
|
180
|
-
[ "$status" -eq 0 ]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
@test "fixture 1 cites P347 as the wrongly-captured-sibling motivator" {
|
|
184
|
-
run grep -nE "P347" "${FIXTURES_DIR}/regression-p347-vs-p346.md"
|
|
185
|
-
[ "$status" -eq 0 ]
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
@test "fixture 2 (genuinely-new) exists" {
|
|
189
|
-
[ -f "${FIXTURES_DIR}/proceed-new-genuinely-new.md" ]
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
@test "fixture 2 names PROCEED_NEW as the expected verdict" {
|
|
193
|
-
run grep -nE "PROCEED_NEW" "${FIXTURES_DIR}/proceed-new-genuinely-new.md"
|
|
194
|
-
[ "$status" -eq 0 ]
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
@test "fixture 3 (subtle sibling-vs-parent) exists" {
|
|
198
|
-
[ -f "${FIXTURES_DIR}/proceed-new-subtle-sibling.md" ]
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@test "fixture 3 names PROCEED_NEW with reasoned per-candidate rationale" {
|
|
202
|
-
run grep -nE "PROCEED_NEW" "${FIXTURES_DIR}/proceed-new-subtle-sibling.md"
|
|
203
|
-
[ "$status" -eq 0 ]
|
|
204
|
-
run grep -niE "Per-candidate explanation" "${FIXTURES_DIR}/proceed-new-subtle-sibling.md"
|
|
205
|
-
[ "$status" -eq 0 ]
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
# ----- RFC-012 forward-reference -----
|
|
209
|
-
|
|
210
|
-
@test "agent.md cross-references RFC-012 as future behavioural-eval home" {
|
|
211
|
-
run grep -nE "RFC-012" "$AGENT_FILE"
|
|
212
|
-
[ "$status" -eq 0 ]
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
# ----- Cross-references to dispatch sites -----
|
|
216
|
-
|
|
217
|
-
@test "agent.md cross-references /wr-itil:capture-problem as primary dispatch site" {
|
|
218
|
-
run grep -nE "/wr-itil:capture-problem" "$AGENT_FILE"
|
|
219
|
-
[ "$status" -eq 0 ]
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
@test "agent.md cross-references /wr-itil:manage-problem as secondary dispatch site" {
|
|
223
|
-
run grep -nE "/wr-itil:manage-problem" "$AGENT_FILE"
|
|
224
|
-
[ "$status" -eq 0 ]
|
|
225
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# P123: packages/itil/hooks/lib/block-list.sh shared helper for the
|
|
4
|
-
# inbound-report block-list mechanism. Per ADR-046 §v1 implementation
|
|
5
|
-
# contract — audit-log-only — the helper exposes four functions:
|
|
6
|
-
# is_blocked(<reporter-id-hash>)
|
|
7
|
-
# add_block(<reporter-id-hash> <evidence-ticket-P###> <provenance>)
|
|
8
|
-
# remove_block(<reporter-id-hash> <reason>)
|
|
9
|
-
# list_blocks()
|
|
10
|
-
#
|
|
11
|
-
# Per ADR-046 §Decision Outcome §Identifier, the entry shape is the
|
|
12
|
-
# SHA-256 hash of the GitHub numeric user ID. Per architect verdict
|
|
13
|
-
# (this iter), the helper does NOT compute the hash — caller supplies
|
|
14
|
-
# an opaque hex string; helper validates hex shape only. This keeps
|
|
15
|
-
# the helper GitHub-agnostic so non-GitHub channel adoption (out-of-
|
|
16
|
-
# scope per ADR-046 §Reassessment) wouldn't require helper changes.
|
|
17
|
-
#
|
|
18
|
-
# Audit log: sibling JSONL file `docs/blocked-reporters.audit.jsonl`.
|
|
19
|
-
# Append-only; one JSON object per line per the five-field shape
|
|
20
|
-
# adopted in ADR-046 Q2: {type, reporter_id_hash, evidence_ticket,
|
|
21
|
-
# timestamp, author}.
|
|
22
|
-
#
|
|
23
|
-
# Per feedback_behavioural_tests.md (P081) — behavioural assertions on
|
|
24
|
-
# observable outcomes (file state, exit codes, helper-emitted output).
|
|
25
|
-
# No source-grep on helper text. Per ADR-005 (plugin testing strategy)
|
|
26
|
-
# + ADR-037 (skill testing strategy) hook bats live under
|
|
27
|
-
# packages/itil/hooks/test/ and assert behaviour, not implementation.
|
|
28
|
-
|
|
29
|
-
setup() {
|
|
30
|
-
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
31
|
-
HELPER="$SCRIPT_DIR/lib/block-list.sh"
|
|
32
|
-
ORIG_DIR="$PWD"
|
|
33
|
-
TEST_DIR=$(mktemp -d)
|
|
34
|
-
cd "$TEST_DIR"
|
|
35
|
-
mkdir -p docs
|
|
36
|
-
# Mirror the per-repo on-disk shape ADR-046 names.
|
|
37
|
-
echo "[]" > docs/blocked-reporters.json
|
|
38
|
-
# Source the helper. Functions become callable in this shell.
|
|
39
|
-
# shellcheck source=/dev/null
|
|
40
|
-
source "$HELPER"
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
teardown() {
|
|
44
|
-
cd "$ORIG_DIR"
|
|
45
|
-
rm -rf "$TEST_DIR"
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
# Canonical fixture hash — 64 hex chars (SHA-256 width). Real callers
|
|
49
|
-
# would compute this from a GitHub numeric user ID; the helper does
|
|
50
|
-
# not care about provenance, only that the input is hex-shaped.
|
|
51
|
-
HASH_A="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
52
|
-
HASH_B="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
53
|
-
|
|
54
|
-
# --- Round-trip: add_block then is_blocked ---
|
|
55
|
-
|
|
56
|
-
@test "add_block + is_blocked round-trip: hash present after add" {
|
|
57
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
58
|
-
run is_blocked "$HASH_A"
|
|
59
|
-
[ "$status" -eq 0 ]
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@test "is_blocked: returns non-zero for hash never added" {
|
|
63
|
-
run is_blocked "$HASH_B"
|
|
64
|
-
[ "$status" -ne 0 ]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
# --- list_blocks output shape ---
|
|
68
|
-
|
|
69
|
-
@test "list_blocks: prints each blocked hash on its own line" {
|
|
70
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
71
|
-
add_block "$HASH_B" "P124" "test@example.com"
|
|
72
|
-
run list_blocks
|
|
73
|
-
[ "$status" -eq 0 ]
|
|
74
|
-
[[ "$output" == *"$HASH_A"* ]]
|
|
75
|
-
[[ "$output" == *"$HASH_B"* ]]
|
|
76
|
-
# Two distinct hashes — output should have at least two non-empty lines.
|
|
77
|
-
line_count=$(printf '%s\n' "$output" | grep -c .)
|
|
78
|
-
[ "$line_count" -ge 2 ]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
@test "list_blocks: empty list on empty docs/blocked-reporters.json" {
|
|
82
|
-
run list_blocks
|
|
83
|
-
[ "$status" -eq 0 ]
|
|
84
|
-
# No hash strings; either empty output or whitespace only.
|
|
85
|
-
[[ "$output" != *"$HASH_A"* ]]
|
|
86
|
-
[[ "$output" != *"$HASH_B"* ]]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
# --- Idempotent add ---
|
|
90
|
-
|
|
91
|
-
@test "add_block: adding the same hash twice is idempotent (one entry)" {
|
|
92
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
93
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
94
|
-
run list_blocks
|
|
95
|
-
[ "$status" -eq 0 ]
|
|
96
|
-
occurrences=$(printf '%s\n' "$output" | grep -c "$HASH_A")
|
|
97
|
-
[ "$occurrences" -eq 1 ]
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
# --- remove_block path ---
|
|
101
|
-
|
|
102
|
-
@test "remove_block: hash absent from is_blocked after remove" {
|
|
103
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
104
|
-
remove_block "$HASH_A" "wrongly-classified"
|
|
105
|
-
run is_blocked "$HASH_A"
|
|
106
|
-
[ "$status" -ne 0 ]
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
# --- Audit log presence (ADR-046 Q2 five-field shape) ---
|
|
110
|
-
|
|
111
|
-
@test "add_block: appends entry to docs/blocked-reporters.audit.jsonl" {
|
|
112
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
113
|
-
[ -f docs/blocked-reporters.audit.jsonl ]
|
|
114
|
-
run cat docs/blocked-reporters.audit.jsonl
|
|
115
|
-
[[ "$output" == *"\"type\""* ]]
|
|
116
|
-
[[ "$output" == *"\"block\""* ]]
|
|
117
|
-
[[ "$output" == *"$HASH_A"* ]]
|
|
118
|
-
[[ "$output" == *"P123"* ]]
|
|
119
|
-
[[ "$output" == *"test@example.com"* ]]
|
|
120
|
-
# Five-field shape names: type, reporter_id_hash, evidence_ticket,
|
|
121
|
-
# timestamp, author. Assert each label is present.
|
|
122
|
-
[[ "$output" == *"reporter_id_hash"* ]]
|
|
123
|
-
[[ "$output" == *"evidence_ticket"* ]]
|
|
124
|
-
[[ "$output" == *"timestamp"* ]]
|
|
125
|
-
[[ "$output" == *"author"* ]]
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
@test "remove_block: appends an unblock entry to the audit log" {
|
|
129
|
-
add_block "$HASH_A" "P123" "test@example.com"
|
|
130
|
-
remove_block "$HASH_A" "wrongly-classified"
|
|
131
|
-
run cat docs/blocked-reporters.audit.jsonl
|
|
132
|
-
[[ "$output" == *"\"unblock\""* ]]
|
|
133
|
-
# The reason field rides under evidence_ticket per the five-field shape
|
|
134
|
-
# (audit log is type-tagged; the reason slot reuses evidence_ticket
|
|
135
|
-
# for unblock provenance per the helper's contract).
|
|
136
|
-
[[ "$output" == *"wrongly-classified"* ]]
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
# --- Hashed-ID handling: helper validates hex shape ---
|
|
140
|
-
|
|
141
|
-
@test "add_block: rejects non-hex input (non-zero exit, no entry written)" {
|
|
142
|
-
run add_block "not-a-hash" "P123" "test@example.com"
|
|
143
|
-
[ "$status" -ne 0 ]
|
|
144
|
-
# State unchanged.
|
|
145
|
-
run is_blocked "not-a-hash"
|
|
146
|
-
[ "$status" -ne 0 ]
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
@test "add_block: rejects wrong-length hex (non-SHA-256-width input)" {
|
|
150
|
-
# 32 hex chars (half of SHA-256 width) — wrong length.
|
|
151
|
-
run add_block "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "P123" "test@example.com"
|
|
152
|
-
[ "$status" -ne 0 ]
|
|
153
|
-
}
|