Skip to content

docs: document shell test-helper duplication and exit-code divergence as deliberate#853

Open
kyle-sexton wants to merge 11 commits into
mainfrom
docs/820-shell-helper-dedup-or-document
Open

docs: document shell test-helper duplication and exit-code divergence as deliberate#853
kyle-sexton wants to merge 11 commits into
mainfrom
docs/820-shell-helper-dedup-or-document

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes the design fork raised in #820: whether the shell assert-helper duplicated across
5 plugins (and the divergent per-script exit-code taxonomies alongside it) should be
consolidated into a shared mechanism, or documented as deliberate. This PR documents.

Fix

  • Adds docs/conventions/shell-test-helpers/README.md as the owner doc explaining why the
    duplication and divergence stay as-is, and registers it in docs/PLUGIN-PHILOSOPHY.md's
    convention registry table.
  • Adds a one-line pointer comment at each copy site back to the owner doc:
    guardrails/hooks/guardrails-test-helpers.sh, claude-ops/hooks/claude-ops-test-helpers.sh,
    source-control/scripts/test-helpers.sh, repo-hygiene/skills/clean/scripts/lib/test-helpers.sh,
    work-items/tools/work-item-tracker/tests/lib.sh.
  • Adds the same kind of pointer to scripts/check-skill-portability.test.sh, which opted out
    for an unrelated reason (it's repo tooling, not a plugin, so no plugin assertion library
    applies) — noted so the fork's second observation isn't left unexplained.
  • Bumps plugin.json + adds a CHANGELOG.md entry for every plugin whose helper file gained
    the pointer comment. Each has been re-derived from current main many times as sibling PRs
    merged or rebased mid-flight (see Related for the current picture):
    • repo-hygiene: 0.4.4→0.4.6
    • source-control: 0.15.7→0.16.1
    • claude-ops: 0.17.1→0.17.5
    • work-items: 0.18.1→0.20.1
    • guardrails: 0.9.5→0.9.6 (no open-PR collision at any point so far)

No behavior change anywhere — comments and docs only.

Decision

Chose Option B: document the per-plugin duplication and exit-code divergence as deliberate.
No shared helper introduced.

Investigation before deciding:

  • This repo already has one sanctioned cross-plugin shared-source mechanism: a canonical file
    under lib/ (e.g. lib/hook-utils.sh), copied — not imported — into each carrying plugin by
    a dedicated scripts/sync-*.sh, tracked in scripts/cross-plugin-source-registry.txt, and
    drift-checked by scripts/check-cross-plugin-source-drift.sh --check.
  • That mechanism is scoped to clusters meant to stay byte-identical. Running
    check-cross-plugin-source-drift.sh discover confirms it never even flags the five
    assert-helper files as a cluster candidate — they live at different paths per plugin and
    are not byte-identical, so they fall outside that mechanism's scope entirely.
  • Reading all five files: they are already three genuinely different shapes, not one library
    that drifted — a hook-contract shape (guardrails/claude-ops: ok/bad, PASS/FAIL,
    make_sink/wait_for_sink), a skill-script shape (source-control/repo-hygiene: pass/fail,
    FAILED/CASE_NUM, file-existence assertions), and a vendored-seam shape (work-items: same
    primitives, but owned by the seam itself so it stays correct wherever the seam is resolved
    from, independent of this repo's tooling).
  • Consolidating would mean designing a fourth, unified assertion API and rewriting every
    existing *.test.sh onto it — a bigger, riskier change than the coupling it would remove,
    and it would cross the plugin-independence boundary docs/PLUGIN-PHILOSOPHY.md's design
    boundary section already draws (no plugin imports files from a sibling plugin).
  • Exit-code taxonomies (remove-path.sh 0/1/2/3/4, git-tree-reset-batch.sh 0/1/2 forwarding
    a child's 5/7, check-skill-portability.sh 0/1/2) encode genuinely different per-script
    contracts, not arbitrary numbering — each script already documents its own Exit: line, and
    a shared usage/exit helper would either flatten those contracts or grow per-caller branching.
  • Deferred, not rejected: guardrails-test-helpers.sh and claude-ops-test-helpers.sh are the
    one pair that already share a shape closely. If they converge to byte-identical, vendoring
    just that pair through the existing lib/ + sync-*.sh + registry mechanism is the smaller,
    precedented move — recorded as the trigger in the owner doc rather than acted on now.

Verification

  • shellcheck clean on all 6 edited shell files.
  • Full check-skill-portability.test.sh suite: 16/16 pass.
  • check-cross-plugin-source-drift.sh --check: no unregistered or drifted clusters.
  • check-changelog-parity.sh --check: passes with every version bump.
  • Ran every *.test.sh that sources an edited helper (repo-hygiene/clean, guardrails hooks,
    claude-ops hooks, work-items adapters/lib) — all green, confirming the comment-only edits
    changed no behavior.
  • markdownlint-cli2 and lychee clean on the new and modified docs.

Related

Closes #820

Work-class: C2 (mechanical) — attended triage 2026-07-23, operator-ratified. 🤖

… as deliberate

Resolves the fork in #820: the per-plugin shell assert-helper copies (guardrails,
claude-ops, source-control, repo-hygiene, work-items) and their divergent per-script
exit-code taxonomies stay as-is rather than being consolidated into a shared
mechanism. The existing lib/ + sync-*.sh vendoring precedent (hook-utils.sh) only
covers clusters meant to stay byte-identical; these five copies are three genuinely
different shapes already, so forcing them onto one shared library would mean a
bigger, riskier redesign than the coupling it removes — and would cross the
plugin-independence boundary the plugin philosophy already draws.

Adds docs/conventions/shell-test-helpers/README.md as the owner doc, registers it
in PLUGIN-PHILOSOPHY.md's convention registry, and adds a one-line pointer at each
copy site (plus scripts/check-skill-portability.test.sh, which opted out for an
unrelated reason: it is repo tooling, not a plugin).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@kyle-sexton kyle-sexton added the automated Opened by automation. label Jul 21, 2026
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 11s —— View job


PR #853 Review

  • Gather context and understand the PR
  • Review changed files
  • Check documentation accuracy and consistency
  • Verify version bumps and CHANGELOG entries
  • Post review findings

Summary

This is a clean docs-only PR. No behavior changes anywhere — all 141 additions are comments and documentation. The architecture decision is well-reasoned and the execution is careful. A few minor observations below, none blocking.


Documentation (docs/conventions/shell-test-helpers/README.md)

Accurate and complete. The three-shape taxonomy (hook-contract, skill-script, vendored-seam) maps correctly to the five files. The "Deferred, not rejected" trigger condition is precise and actionable. The "Why not the existing vendoring mechanism" section correctly explains why check-cross-plugin-source-drift.sh discover would never flag these as an unregistered cluster.

One minor clarity gap: the Conformance section states "each copy site above carries a one-line pointer back to this doc," but scripts/check-skill-portability.test.sh also received a pointer yet isn't listed as a copy site anywhere in the doc. The earlier prose does explain its opt-out reason, but a reader scanning Conformance only would wonder why there's a pointer at that file if it isn't named. A one-sentence rider like "scripts/check-skill-portability.test.sh carries a pointer for the opt-out reason documented above, but is not a copy site" would close the loop. Not blocking — the information is present, just split across sections.

Permalink: docs/conventions/shell-test-helpers/README.md#L65-L72


Pointer comments in helper files

All six files received the same consistent wording. The pointer in the five plugin helpers:

# Duplicated across plugins by design, not drift — see
# docs/conventions/shell-test-helpers/README.md at the repo root.

The pointer in scripts/check-skill-portability.test.sh correctly names the opt-out reason ("repo tooling, not a plugin") before forwarding to the owner doc.

All correct. The # shellcheck disable=SC2016 pragma in check-skill-portability.test.sh remains directly before set -uo pipefail after the insertion — the new comment block doesn't disturb the directive's effectiveness.


Version bumps

All five bumps are patch (x.y.z → x.y.z+1), correct for docs-only changes:

Plugin Before After
repo-hygiene 0.4.4 0.4.5
source-control 0.15.7 0.15.8
guardrails 0.9.5 0.9.6
claude-ops 0.17.1 0.17.2
work-items 0.18.1 0.18.2

The merge-order race condition flagged in the PR description (competing bumps in #826, #839, #840, #844) is real, but it's correctly flagged and requires a rebase after those land — not a defect in this PR.


CHANGELOG entries

All five entries follow the established format: ## [x.y.z]### Documentation → one-paragraph description ending with "No behavior change." Consistent across all five plugins. No issues.


Relative path correctness

  • README links (../../../plugins/...) are correct from docs/conventions/shell-test-helpers/ (three levels up to repo root).
  • docs/PLUGIN-PHILOSOPHY.md link (conventions/shell-test-helpers/README.md) is correct relative to docs/.
  • Shell file pointer comments use repo-root-anchored prose ("at the repo root"), appropriate for shell comments where relative paths would be meaningless.

Verdict

Approve. No correctness issues, no security concerns, no behavior changes. The one minor observation (Conformance section doesn't explicitly name check-skill-portability.test.sh) is a documentation clarity nit, not a defect. The architecture reasoning in the README is sound and gives future contributors a clear trigger for when to revisit the guardrails/claude-ops pair consolidation.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 7s —— View job


Security Review

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications for injection or unsafe patterns
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

This PR is verifiably documentation and comments only. Here is what each category of change does and why none carries security risk:

Shell scripts (6 files modified): Each change adds exactly 3–4 lines of shell comments (#-prefixed). Comments are never executed by the shell. The added text is static prose referencing a relative internal path; it is not passed to any command, eval, source, or file operation anywhere in the changed lines or surrounding context.

New markdown doc (docs/conventions/shell-test-helpers/README.md): Pure prose and relative markdown links. All links point inward to paths within this repo (no external URLs). No executable content, no credentials, no template expressions.

PLUGIN-PHILOSOPHY.md: One additional table row with a relative link. Same assessment as above.

plugin.json files (5 files): Each changes only the version field by one patch increment. No new permissions, dependencies, mcpServers, remote URLs, or other security-relevant fields are touched.

CHANGELOG.md files (5 files): Plain text changelog entries. No executable content.

The attack surface of this diff is zero: no executable code paths are added or modified, no external resources are introduced, no trust boundaries are crossed, and no secrets or credentials appear anywhere in the changes.

…de-ops, work-items

Re-checked open PRs touching these plugins' plugin.json right before the version-bump
collision protocol requires it: source-control carries #839 (0.15.8) and #840 (0.15.9),
claude-ops carries #844 (0.17.2), work-items carries #826 (0.18.2) — all still open.
Bumps this PR's claims one past each plugin's current highest open-PR claim
(source-control 0.15.10, claude-ops 0.17.3, work-items 0.18.3) so this PR does not
collide at merge time regardless of which sibling lands first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@kyle-sexton kyle-sexton added the do-not-merge Hard merge gate: do not merge while applied. label Jul 21, 2026
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 47s —— View job


PR #853 Review

  • Gather context and understand the PR
  • Review PR diff (updated branch — 2 commits)
  • Check version bump accuracy (fix commit)
  • Verify documentation consistency
  • Post review findings

What changed since the last review

The branch gained one new commit — ae5c5aa fix: bump past highest open-PR version claim for source-control, claude-ops, work-items — which re-checked competing open PRs right before merge and bumped this PR's version claims past each plugin's highest claimed version:

Plugin Prior claim Competing PRs New claim
source-control 0.15.8 #839 → 0.15.8, #840 → 0.15.9 0.15.10
claude-ops 0.17.2 #844 → 0.17.2 0.17.3
work-items 0.18.2 #826 → 0.18.2 0.18.3
guardrails 0.9.6 (none) 0.9.6 (unchanged)
repo-hygiene 0.4.5 (none) 0.4.5 (unchanged)

The math is correct in each case: max(competing claims) + 1 patch → 0.15.10 for source-control (skipping 0.15.9 because #840 holds it), 0.17.3 for claude-ops, 0.18.3 for work-items. The CHANGELOG headers were updated in sync with the plugin.json bumps.


Documentation (docs/conventions/shell-test-helpers/README.md)

Unchanged since prior review. Still accurate and complete. The three-shape taxonomy, "Deferred, not rejected" trigger, and "Why not the existing vendoring mechanism" sections all hold. The minor Conformance-section gap noted in the previous review (the check-skill-portability.test.sh pointer isn't named in the Conformance list even though it received one) is still present and still minor — the information is present in the preceding prose.


CHANGELOG version gaps

The fix commit produces non-sequential CHANGELOG entries for three plugins:

These gaps are the intended consequence of the collision-avoidance strategy and will close when the sibling PRs land. If a sibling PR is ever closed without merging, there will be a permanent gap in the sequence. This is an accepted cost of the "bump past highest" approach and isn't a defect — worth being aware of when reviewing those sibling PRs later, but nothing to fix here.


Shell comment pointers

All six edited shell files were reviewed at HEAD. Pointer wording is consistent across the five plugin helpers:

# Duplicated across plugins by design, not drift — see
# docs/conventions/shell-test-helpers/README.md at the repo root.

The check-skill-portability.test.sh pointer correctly names the opt-out reason before forwarding to the owner doc. The fix commit touched none of the shell files — comments are correct at both commits.


Verdict

Approve. The fix commit is correct. Version arithmetic matches the stated competing-PR state, CHANGELOG headers track plugin.json, and no other files were affected. The base documentation change (commit 056cb9c) was already reviewed and found clean. No correctness issues, no security concerns, no behavior changes anywhere in the diff.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 19s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

This PR is verifiably comments and documentation only. The full diff was audited category by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments only — static prose pointing to the owner doc. Comments are never executed. None of the added lines are passed to any command, eval, source, or substitution in the changed or surrounding context.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. All links point to paths within this repo (no external URLs). No executable content, no secrets, no template expressions.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version field. No new permissions, dependencies, mcpServers, remote URLs, or other security-relevant fields are touched. Note: the actual version increments (claude-ops 0.17.1→0.17.3, source-control 0.15.7→0.15.10, work-items 0.18.1→0.18.3) are larger than the PR description's patch-increment claim; this is explained by the "bump past highest open-PR version claim" fix commit and carries no security implication.

CHANGELOG.md files (5 files): Plain-text changelog entries with no executable content.

The effective attack surface of this diff is zero: no executable code paths added or modified, no external resources introduced, no trust boundaries crossed, no secrets or credentials present anywhere in the changes.

Resolves conflicts on source-control and work-items plugin.json/CHANGELOG.md:
main advanced source-control to 0.15.8 (#839, merged) and work-items to 0.18.2
(#826, merged) since this branch was last rebased. Also re-checked live open
PRs at merge time and found work-items now carries a new open claim, #857 at
0.19.0 (Jira adapter) — re-bumped this branch's work-items claim from 0.18.3
to 0.19.1 to stay ahead of it. source-control's 0.15.10 and claude-ops's
0.17.3 remain valid (still one past #840/#860's 0.15.9 and #844/#860's 0.17.2
open claims, respectively).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 16s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (branch synchronize)
  • Review current diff
  • Post findings

What's new since the last review

The branch gained one commit — 11ac0f0 Merge branch 'main' into docs/820-shell-helper-dedup-or-document. No new content commits; the substantive work (056cb9c docs commit and ae5c5aa fix commit) is unchanged.

The merge resolved conflicts on source-control and work-items plugin.json/CHANGELOG.md. Two things changed as a result:

1. #826 (work-items 0.18.2) and #839 (source-control 0.15.8) have since merged. Main now carries those as its base. The merge re-anchored this branch's claims against the new base correctly.

2. New open PR #857 (Jira adapter, claims work-items 0.19.0) appeared. This PR's work-items claim was re-bumped from 0.18.3 → 0.19.1 to stay ahead of it. The CHANGELOG entry documents the jump explicitly.


Version arithmetic at HEAD

Plugin main base Highest open claim This PR claims Math
source-control 0.15.8 #840, #860 → 0.15.9 0.15.10 max + 1 ✓
claude-ops 0.17.1 #844, #860 → 0.17.2 0.17.3 max + 1 ✓
work-items 0.18.2 #857 → 0.19.0 0.19.1 max + 1 ✓
guardrails 0.9.5 (none) 0.9.6 base + 1 ✓
repo-hygiene 0.4.4 (none) 0.4.5 base + 1 ✓

All correct.


One thing worth noting: work-items lands as a minor version

The work-items claim is now 0.19.1 — a minor version release — for what is semantically a patch-level docs-only change. This is the unavoidable consequence of the "bump past highest open claim" strategy when the blocking PR (#857) happens to occupy a minor slot. The CHANGELOG entry calls it out explicitly:

"Version re-bumped past #857's open 0.19.0 claim (Jira adapter) to avoid a collision."

This is not a defect — the strategy is correctly applied and self-documented — but it means work-items consumers will see 0.18.x → 0.19.1 with no features between those versions. Accepted cost of the approach, consistent with how the prior bumps were handled.


PR description do-not-merge conditions are now partially stale

The PR body lists the holds as:

The conditions in the body don't match the current state. This won't block the merge — the do-not-merge label is the actual gate — but whoever removes the label should verify against current open PRs rather than the body. Worth a quick note before unlabeling.


Documentation and shell files

Unchanged since ae5c5aa. The review from that commit still holds: core docs accurate, pointer comments consistent across all six files, relative paths correct, the minor Conformance-section gap (check-skill-portability.test.sh not explicitly named in the Conformance list) remains a documentation nit, not a defect.


Verdict

Approve. The merge is clean. Version math is correct. The work-items minor-version jump is documented and expected. The only action item before removing do-not-merge is verifying the current open-PR state (not the body) — #840, #857, #860, and #844 should all be confirmed merged or withdrawn before unlabeling.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 33s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

This PR is verifiably documentation and comments only. Full audit by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added lines contain no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing. Verified: all new text sits between a # and the next newline in each file. The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh is correctly preserved immediately before set -uo pipefail after the insertion.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. Scanned all links: every one resolves to a path within this repo — no external URLs anywhere in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields are present. Full manifest for work-items (the only one with an unusual version jump to 0.19.1) was read and confirmed clean — userConfig fields are unchanged, no new egress surface.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No workflow permission changes, no pull_request_target/workflow_run patterns introduced, no script injection vectors.

The effective attack surface of this diff is zero.

repo-hygiene had no open-PR collision at this PR's original open, but #860
(chore/skill-shell-declaration) opened since and claims 0.4.5 exactly, matching
this branch's prior claim. Bump to 0.4.6 to stay ahead of it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 48s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications for injection or unsafe patterns
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

This PR is verifiably documentation and comments only. Full audit by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added text contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing. The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh is correctly preserved immediately before set -uo pipefail after the insertion.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. All links resolve to paths within this repo — no external URLs anywhere in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields. Full manifests were reviewed — no egress surface changes.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files modified. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 25s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (841a1bf)
  • Review current diff
  • Post findings

What's new since the last review

One new commit: 841a1bf fix: bump repo-hygiene past a newly-opened collision (#860)

PR #860 (chore/skill-shell-declaration) opened after the prior sync and claimed repo-hygiene 0.4.5 — exactly matching this branch's prior claim. The fix bumps the repo-hygiene version to 0.4.6 and updates the CHANGELOG header and trailing note to name the collision.

Only two files changed: plugins/repo-hygiene/.claude-plugin/plugin.json and plugins/repo-hygiene/CHANGELOG.md. No documentation, shell files, or other plugin manifests were touched.


Version arithmetic at HEAD

Plugin main base Highest open claim This PR claims Math
repo-hygiene 0.4.4 #860 → 0.4.5 0.4.6 max + 1 ✓
guardrails 0.9.5 (none) 0.9.6 base + 1 ✓
source-control 0.15.8 #840, #860 → 0.15.9 0.15.10 max + 1 ✓
claude-ops 0.17.1 #844 → 0.17.2 0.17.3 max + 1 ✓
work-items 0.18.2 #857 → 0.19.0 0.19.1 max + 1 ✓

All correct.


CHANGELOG update

The prior ## [0.4.5] header became ## [0.4.6] and the entry body gained the note:

"Version bumped past #860's open 0.4.5 claim to avoid a collision."

Consistent with how the same note was added for source-control, claude-ops, and work-items in the earlier fix commit. Pattern is uniform across all five plugins.


Documentation and shell files

Unchanged since ae5c5aa. Prior review findings still hold — the three-shape taxonomy, pointer comments, relative path correctness, and the minor Conformance-section nit (that check-skill-portability.test.sh is noted in prose but not listed in the Conformance table) are all as previously reviewed.


Do-not-merge holds (updated)

#860 is now a blocker for both source-control (claims 0.15.9) and repo-hygiene (claims 0.4.5). Before removing the label, confirm merged or withdrawn:


Verdict

Approve. The fix commit is correct and minimal — two files, right version numbers, CHANGELOG updated in sync with the stated reason. All prior review findings unchanged. No correctness issues, no security concerns, no behavior changes anywhere in the diff.

Re-syncs onto main after #860 (fleet-wide `shell: bash` declaration sweep)
merged, which bumped source-control to 0.15.9, claude-ops to 0.17.2, and
repo-hygiene to 0.4.5. Resolved conflicts on those three plugins' plugin.json
and CHANGELOG.md; re-derived each held version against the new main plus a
fresh live-open-PR check rather than assuming the prior numbers still held:

- source-control 0.15.10: still one past main's 0.15.9 and #840's live 0.15.9
  claim.
- claude-ops 0.17.3: still one past main's 0.17.2 and #844's live 0.17.2
  claim.
- repo-hygiene 0.4.6: still one past main's new 0.4.5 (#860, now merged); no
  open-PR collision remains for this plugin.
- work-items 0.19.1 and guardrails 0.9.6 were untouched by this merge (no
  conflict) and remain correct against #857/#861 (both still 0.19.0, open)
  and no open collision, respectively.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 20s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (841a1bf)
  • Review current diff and version arithmetic
  • Post findings

What's new since the last review

One new commit: e96e9a6 Merge branch 'main' into docs/820-shell-helper-dedup-or-document

The merge pulled in #860 (chore: declare shell: bash on every skill with dynamic-context injections), which bumped source-control → 0.15.9, claude-ops → 0.17.2, and repo-hygiene → 0.4.5 on main. Conflicts were resolved on those three plugins' plugin.json and CHANGELOG.md.


Version arithmetic at HEAD

Plugin Main (7688ae7) Open holds This PR claims Math
source-control 0.15.9 #840 → 0.15.9 0.15.10 max + 1 ✓
claude-ops 0.17.2 #844 → 0.17.2 0.17.3 max + 1 ✓
repo-hygiene 0.4.5 (none remaining) 0.4.6 main + 1 ✓
work-items 0.18.2 #857 → 0.19.0 0.19.1 max + 1 ✓
guardrails 0.9.5 (none) 0.9.6 main + 1 ✓

All correct. The merge commit message documents the re-derivation reasoning against the new main baseline — the logic holds up.


One minor observation: claude-ops CHANGELOG attribution

The [0.17.3] entry says "Version bumped past #844's open 0.17.2 claim to avoid a collision." This is slightly imprecise: #860 (now merged) is what established 0.17.2 on main, not just a competing claim. The version choice (0.17.3) is correct regardless — the number passes the max+1 arithmetic — but the note credits only the still-open #844 when the merged #860 is equally the reason that slot is taken. Not blocking, and the version number is what actually matters at merge time.


Do-not-merge hold picture (updated after this sync)

With #860 now merged, one hold has cleared:

Plugin Prior holds After this sync
source-control #840, #860 #840 only (0.15.9)
claude-ops #844, #860 #844 only (0.17.2)
repo-hygiene #860 none — cleared
work-items #857 #857 (0.19.0) — still open
guardrails none none

Before removing do-not-merge, confirm #840, #844, and #857 are merged or withdrawn. repo-hygiene no longer has a live competing claim.


Documentation and shell files

Unchanged since ae5c5aa. All prior review findings hold: three-shape taxonomy accurate, pointer comments consistent across all six shell files, relative paths correct, the minor Conformance-section nit (check-skill-portability.test.sh pointer noted in prose but not in the Conformance list) is still present and still non-blocking.


Verdict

Approve. The merge is clean. Version arithmetic is correct against the new main baseline established by #860. The only pending do-not-merge conditions are the three still-open sibling PRs (#840, #844, #857) — verify those are settled before unlabeling.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 7s —— View job


Security Review — PR #853

  • Gather PR diff
  • Read changed shell files
  • Audit markdown, JSON, and docs changes
  • Post findings

No security issues found.

All 18 changed files were read and audited. This PR adds comments and documentation only — no new executable code paths anywhere in the diff. Category-by-category breakdown:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments. Shell comments are never executed. The added text is static prose pointing to an internal doc path; it contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing. The pre-existing make_sink bodies in guardrails-test-helpers.sh (which writes arbitrary caller-supplied content as a temporary executable) and claude-ops-test-helpers.sh (which uses %q to shell-quote a path into a generated cat > redirect) are unchanged — this PR's changes to those files are the pointer comment block only. The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh remains directly before set -uo pipefail after the insertion.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. All links resolve to paths within this repo — no external URLs in the file. No executable content, no credentials, no template expressions.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields. All five manifests were read; work-items (the one with the largest version jump to 0.19.1) shows no egress surface changes — userConfig fields are unchanged.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

kyle-sexton and others added 3 commits July 21, 2026 13:33
#840 rebased since this branch's last check and re-derived its own claim
from 0.15.9 to 0.15.10, so this PR's prior 0.15.10 now collides exactly.
Bump to 0.15.11 (one past #840's current live claim). claude-ops (0.17.3),
work-items (0.19.1), repo-hygiene (0.4.6), and guardrails (0.9.6) were
independently re-verified against current main and all live open PRs and
remain correct — no change needed for those four.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
#857 (Jira Cloud adapter) merged into main since this branch's last rebase,
bumping work-items to 0.19.0. Resolved the resulting conflict, keeping this
branch's 0.19.1 (already one past both the new main and #861's still-open
0.19.0 claim, so no further bump needed). Re-verified all 5 plugins fresh
against current main and every live open PR (#840 0.15.10, #844 0.17.2, #861
0.19.0): source-control 0.15.11, claude-ops 0.17.3, repo-hygiene 0.4.6, and
guardrails 0.9.6 all remain correct with no change required.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
An unrelated claude-ops docs PR (#877, closing #864) merged since this
branch's last rebase and landed at exactly 0.17.3 — the same version this
branch was claiming. Re-bumped claude-ops to 0.17.4 to clear the exact
collision (plugin.json auto-merged to an identical-looking "0.17.3" string
without flagging a conflict, since both sides happened to write the same
literal text for unrelated reasons; caught by diffing main's version history
directly, not by trusting a clean auto-merge). CHANGELOG.md split into two
sections (0.17.3 for #877's actual change, 0.17.4 for this PR's).

Also swept for new open PRs against all 5 plugins post-merge: #870
(feat/800-audit-instructions) newly touches repo-hygiene (claims 0.4.5) and
claude-ops (claims 0.17.2) — both below this branch's current claims
(0.4.6 / 0.17.4), no collision. source-control (0.15.11), work-items
(0.19.1), and guardrails (0.9.6) re-confirmed against current main and every
live open PR (#840 0.15.10, #844 0.17.2, #861 0.19.0) — unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 12s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (e96e9a6)
  • Review current diff and version arithmetic
  • Post findings

What's new since the last review

Two new commits since e96e9a6:


Notable: silent auto-merge collision on claude-ops

#877 merged onto main at exactly 0.17.3 — the same version this branch was claiming. Git auto-merged the plugin.json cleanly (both sides wrote the identical string for unrelated reasons, so no conflict was flagged). The commit message documents that the collision was caught by diffing main's version history directly rather than trusting the clean merge.

The fix is correct: claude-ops bumped to 0.17.4, and the CHANGELOG was split into two entries — [0.17.3] for #877's actual change (now already on main, preserved verbatim in the CHANGELOG body) and [0.17.4] for this PR's pointer comment. This is the cleanest possible handling of this scenario — no version gap, each change attributed to the right entry.

This catch was non-trivial: without the manual diff, a clean merge would have silently shipped two unrelated changes under a single version number. Worth flagging as a process observation, not a defect: the "bump past highest claim" strategy is necessary but not sufficient when a sibling lands at exactly your claimed version — the merge itself won't warn you.


Version arithmetic at HEAD

Plugin main Highest open claim This PR Math
claude-ops 0.17.3 (post-#877) #844 → 0.17.2 (below main) 0.17.4 main+1 ✓
source-control 0.15.9 #840 → 0.15.10 0.15.11 max+1 ✓
work-items 0.19.0 (post-#857) #861 → 0.19.0 (matches main) 0.19.1 max+1 ✓
repo-hygiene 0.4.5 #870 → 0.4.5 (matches main) 0.4.6 max+1 ✓
guardrails 0.9.5 none 0.9.6 main+1 ✓

All correct.


CHANGELOG structure


Do-not-merge holds (updated)

Plugin Live holds
claude-ops #844 (0.17.2 — needs to rebase above main's 0.17.3 before merging)
source-control #840 (0.15.10)
work-items #861 (0.19.0 — matches main; must resolve before this PR lands at 0.19.1)
repo-hygiene #870 (0.4.5 — matches main; same situation)
guardrails none

Before removing do-not-merge: confirm #840, #844, #861, and #870 are each merged or withdrawn (not just that they haven't conflicted in git — the version slots must also be settled).


Documentation and shell files

Unchanged since ae5c5aa. All prior findings hold: three-shape taxonomy accurate, pointer comments consistent across all six shell files, relative paths correct, minor Conformance-section nit unchanged.


Verdict

Approve. The two new commits are correct and handle a genuinely tricky edge case (silent same-string auto-merge) well. Version arithmetic is clean across all five plugins. The CHANGELOG split for claude-ops is the best outcome possible given the collision. No correctness issues, no security concerns, no behavior changes anywhere in the diff.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 10s —— View job


Security Review — PR #853 (post-sync)

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

All 18 changed files were read and audited against the HEAD commit (93294e6). Full breakdown by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added text contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing. The pre-existing # shellcheck disable=SC2016 directive in check-skill-portability.test.sh remains correctly positioned immediately before set -uo pipefail after the insertion.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. Every link resolves to a path within this repo — no external URLs appear anywhere in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. The version numbers differ from what prior reviews reported — source-control now claims 0.15.11 (skipping 0.15.10) and claude-ops claims 0.17.4 (past the previously-reviewed 0.17.3) — both explained by additional sibling PRs merging between sync cycles. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields. All five manifests were read in full; no egress surface changes.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

kyle-sexton added a commit that referenced this pull request Jul 21, 2026
Resolves the claude-ops CHANGELOG.md conflict by keeping #860's
0.17.2 entry as-is and moving this PR's fix under a new 0.17.4
heading. Re-bumps plugin.json past both main's 0.17.2 (landed via
#860) and PR #853's pending 0.17.3 claim.
claude-ops: #844 rebased and re-derived its claim from 0.17.2 to 0.17.4,
colliding exactly with this branch's prior 0.17.4. Bump to 0.17.5.

source-control: a new PR, #882 (fix/511-babysit-self-identity-decouple),
claims 0.16.0 — a minor bump above this branch's prior 0.15.11 and above
#840's 0.15.10. Bump to 0.16.1 to stay ahead of both.

repo-hygiene (0.4.6), guardrails (0.9.6), and work-items (0.19.1) were
re-verified fresh against current main and every live open PR
(main: repo-hygiene 0.4.5, guardrails 0.9.5, work-items 0.19.0; #861 0.19.0)
and remain correct, no change needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 39s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (93294e6)
  • Review current diff and version arithmetic
  • Post findings

What's new since the last review

One new commit: 7fd0258 fix: re-bump claude-ops and source-control past new live collisions

Two plugins were affected — claude-ops and source-control. Four files changed (two plugin.json, two CHANGELOG.md). No other files touched.

claude-ops: #844 re-derived after #877 merged and moved its version claim from 0.17.2 to 0.17.4. That collided with this branch's prior 0.17.4 claim, so this PR bumped to 0.17.5. The CHANGELOG attribution was updated to note #844's current claim, not the stale pre-rebase one.

source-control: A newly opened #882 claims 0.16.0, which jumped past this branch's prior 0.15.11 claim. This PR responded by claiming 0.16.1 — the first value above the new highest claimant.


Version arithmetic at HEAD

Plugin main Highest open claim This PR Math
claude-ops 0.17.3 #844 → 0.17.4 0.17.5 max + 1 ✓
source-control 0.15.9 #882 → 0.16.0, #840 → 0.15.10 0.16.1 max(0.16.0) + 1 ✓
work-items 0.19.0 #861 → 0.19.0 0.19.1 max + 1 ✓
repo-hygiene 0.4.5 (none noted) 0.4.6 main + 1 ✓
guardrails 0.9.5 (none) 0.9.6 main + 1 ✓

All correct.


Notable: second minor-version jump in the series

source-control now claims 0.16.1 for a docs-only patch change — a minor version bump forced by #882's 0.16.0 claim. This is the same pattern as work-items earlier in this PR's history (0.18.x → 0.19.x when #857 held a minor slot). The CHANGELOG entry documents it explicitly. Accepted cost of the collision-avoidance strategy; not a defect.

The source-control CHANGELOG now skips from [0.16.1] directly to [0.15.9] — a gap of three slots (0.15.10, 0.15.11, 0.16.0), the largest gap in the series so far. These will be filled by the sibling PRs when they land. The entry body explains the jump, consistent with the established pattern.


CHANGELOG attribution accuracy

  • claude-ops [0.17.5]: Credits #844's current 0.17.4 claim (re-derived after #877 merged). Correct — the prior version note was stale; this update accurately reflects the live reason.
  • source-control [0.16.1]: Credits #882's open 0.16.0 claim and notes it supersedes #840's 0.15.10. Correct — both blockers named, arithmetic justified.

Do-not-merge holds (updated)

Plugin Live holds
source-control #840 (0.15.10) and #882 (0.16.0)
claude-ops #844 (0.17.4)
work-items #861 (0.19.0)
repo-hygiene none (last verified at prior sync; re-check)
guardrails none

Before removing do-not-merge, confirm #840, #844, #861, and #882 are each merged or withdrawn — and verify repo-hygiene hasn't picked up a new collision, given how fast this set is moving.


Documentation and shell files

Unchanged since ae5c5aa. All prior review findings hold: three-shape taxonomy accurate, pointer comments consistent across all six shell files, relative paths correct, the minor Conformance-section nit (check-skill-portability.test.sh pointer is noted in prose but not listed in the Conformance table) remains non-blocking.


Verdict

Approve. The fix commit is correct and minimal — four files, version math checks out, CHANGELOG attribution updated to match the live collision state. The source-control minor-version jump is documented and expected. No correctness issues, no security concerns, no behavior changes anywhere in the diff.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 23s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications for injection or unsafe patterns
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

All 18 changed files were read and audited against HEAD (7fd0258). The latest commit (fix: re-bump claude-ops and source-control past new live collisions) is version-number-only changes. Full breakdown by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added text contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing. The pre-existing make_sink body in guardrails-test-helpers.sh (line 68–78, which writes arbitrary caller-supplied content as a temporary executable) and in claude-ops-test-helpers.sh (line 51–61, which uses %q to shell-quote a path into a generated cat > redirect) are unchanged — this PR's changes to those files are the pointer comment block only. The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh is correctly preserved immediately before set -uo pipefail after the insertion.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. All links resolve to paths within this repo — no external URLs anywhere in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field — claude-ops now at 0.17.5, source-control at 0.16.1 after the latest re-bump. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields. Both manifests were read in full; no egress surface changes.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

#844 (claude-ops) merged into main at exactly 0.17.4, which this branch's
prior 0.17.5 was already one past — kept as-is, no re-bump needed for the
number itself, just resolved the resulting plugin.json/CHANGELOG.md conflict.

Full fresh collision sweep after the merge found claude-ops now has NO open-PR
collision at all. It also found #861 (work-items) re-derived its own claim
from 0.19.0 to 0.20.0 since the last check (following #857's Jira-adapter
minor bump into main) — colliding with this branch's prior 0.19.1. Re-bumped
work-items to 0.20.1.

source-control (0.16.1, held behind #882's 0.16.0 and #840's 0.15.10),
repo-hygiene (0.4.6, no collision), and guardrails (0.9.6, no collision)
re-verified against current main and all live open PRs — unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 43s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (7fd0258)
  • Review current diff and version arithmetic
  • Post findings

What's new since the last review

One new merge commit: e75e45e Merge branch 'main' into docs/820-shell-helper-dedup-or-document

The merge pulled in e926c22 (docs(ruff-format): add hook-telemetry data schema + registry row #886) — unrelated to this PR's scope. Two things were resolved during the merge:

1. claude-ops conflict resolved without re-bump. #844 merged into main at exactly 0.17.4 — which this branch's 0.17.5 was already one past. The plugin.json/CHANGELOG.md conflict was resolved in place; no re-bump needed. Result: claude-ops now has no open-PR collision.

2. work-items re-bumped 0.19.1 → 0.20.1. #861 re-derived its claim from 0.19.0 to 0.20.0 (following #857's Jira adapter minor bump onto main), colliding with this branch's prior 0.19.1. The CHANGELOG entry correctly documents the reason.


Version arithmetic at HEAD

Plugin main Highest open claim This PR Math
claude-ops 0.17.4 (none — #844 merged) 0.17.5 main + 1 ✓
guardrails 0.9.5 (none) 0.9.6 main + 1 ✓
repo-hygiene 0.4.5 (none) 0.4.6 main + 1 ✓
source-control 0.15.9 #882 → 0.16.0, #840 → 0.15.10 0.16.1 max(0.16.0) + 1 ✓
work-items 0.19.0 #861 → 0.20.0 0.20.1 max(0.20.0) + 1 ✓

All correct.


Notable: work-items minor-version jump is now the largest in the series

work-items claims 0.20.1 for a docs-only patch change, with main at 0.19.0 — a gap driven by the #857 (0.19.0) → #861 (re-derived 0.20.0) cascade. The CHANGELOG documents the reason explicitly, consistent with the established pattern. Accepted cost of the collision-avoidance strategy; not a defect.


Do-not-merge holds (updated)

With #844 now merged, the open holds have narrowed:

Plugin Prior holds After this sync
claude-ops #844 none — cleared
source-control #840, #882 #840 (0.15.10), #882 (0.16.0) — still open
work-items #861 #861 (0.20.0) — still open
repo-hygiene none none
guardrails none none

Before removing do-not-merge, confirm #840, #861, and #882 are each merged or withdrawn — and immediately re-run the full collision protocol (as the PR body warns) since this set can produce new collisions faster than any snapshot stays current.


Documentation and shell files

Unchanged since ae5c5aa. All prior review findings hold: three-shape taxonomy accurate, pointer comments consistent across all six shell files, relative paths correct. The minor Conformance-section nit (check-skill-portability.test.sh pointer is noted in the preceding prose but not listed in the Conformance table) remains present and non-blocking.


Verdict

Approve. The merge commit is correct and self-documenting. Version arithmetic checks out at HEAD. The work-items minor-version jump is documented and expected. claude-ops has cleared its last open-PR hold. The only remaining gate before unlabeling is confirming #840, #861, and #882 are settled — verify fresh against live open PRs, not this snapshot.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 14s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff
  • Read changed shell files
  • Read new markdown doc and JSON changes
  • Post findings

No security issues found.

All 18 changed files were read and audited against HEAD (e75e45e). The full diff was fetched and inspected line by line. This PR is verifiably documentation and comments only. Breakdown by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added text in every file contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing.

The two files with the most security-sensitive pre-existing bodies were read in full to confirm the change boundary:

  • guardrails-test-helpers.sh — The make_sink body (lines 68–78) writes caller-supplied shell content to a temp executable under $TEST_TMPDIR. That body is unchanged by this PR; the only addition is the two-line pointer comment at lines 7–8.
  • claude-ops-test-helpers.sh — The make_sink body (lines 51–61) uses %q-formatted printf to shell-quote a capture-file path into a generated cat > redirect. Also unchanged; only the pointer comment at lines 7–8 is new.

The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh is correctly preserved immediately before set -uo pipefail after the insertion — the new comment block does not disturb the directive's position or effectiveness.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. Every link resolves to a path within this repo — no external URLs in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields are present. All five manifests were inspected; no egress surface changes.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

#882 (source-control) merged into main at 0.16.0, which this branch's prior
0.16.1 was already one past — resolved the resulting plugin.json/CHANGELOG.md
conflict, kept as-is.

Full fresh collision sweep after the merge found source-control now carries
TWO additional open PRs beyond #840: #895 (fix/548-babysit-worktree-head-safety,
claims 0.15.10) and #898 (feat/399-shared-worktree-helper, claims 0.17.0 — a
minor bump above this branch's prior 0.16.1). Re-bumped source-control to
0.17.1 to stay ahead of all three (#898's 0.17.0, #895's and #840's 0.15.10).

claude-ops (0.17.5, no collision), work-items (0.20.1, held behind #861's
0.20.0), repo-hygiene (0.4.6, no collision), and guardrails (0.9.6, no
collision) re-verified against current main and all live open PRs — unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 3m 9s —— View job


PR #853 Review (post-sync)

  • Gather context
  • Check what changed since last review (e75e45e)
  • Review current diff and version arithmetic
  • Post findings

What's new since the last review

One new commit: 24a1605 Merge branch 'main' into docs/820-shell-helper-dedup-or-document

The merge pulled in main changes including ce1c50c (claude-config eval case, unrelated to this PR's scope) and at least one source-control sibling. The most consequential effect: #882 has merged, bringing source-control from 0.15.90.16.0 on main. Two more open PRs (#895 and #898) appeared targeting source-control while the merge was integrating — the merge commit resolved the conflicts and re-bumped this PR's source-control claim to 0.17.1 to clear all three.


Version arithmetic at HEAD

Plugin main Highest open claim This PR Math
source-control 0.16.0 #898 → 0.17.0, #895/#840 → 0.15.10 0.17.1 max(0.17.0) + 1 ✓
claude-ops 0.17.4 #844 → 0.17.4 (merged) 0.17.5 main + 1 ✓
work-items 0.19.0 #861 → 0.20.0 0.20.1 max(0.20.0) + 1 ✓
repo-hygiene 0.4.5 #860 → 0.4.5 (merged) 0.4.6 main + 1 ✓
guardrails 0.9.5 (none) 0.9.6 main + 1 ✓

All correct. CHANGELOG entries for all five plugins match their plugin.json versions.


Notable: source-control now has the largest version gap in this PR's history

source-control claims 0.17.1 for a docs-only pointer comment, with main at 0.16.0. The gap — skipping 0.16.1 through 0.17.0 — is the widest this PR has produced. The CHANGELOG entry at [0.17.1] documents the jump explicitly, naming both the primary blocker (#898 at 0.17.0) and the secondary ones (#895/#840 at 0.15.10). Accepted cost of the collision-avoidance strategy; not a defect. Consumers upgrading source-control will see 0.16.0 → 0.17.1 with no features between those versions.


Documentation and shell files

Unchanged since ae5c5aa. All prior review findings hold: three-shape taxonomy accurate, pointer comments consistent across all six shell files, relative paths correct, the minor Conformance-section nit (check-skill-portability.test.sh pointer is noted in prose but not listed in the Conformance table) remains present and non-blocking.


Do-not-merge holds (updated)

Plugin Live holds
source-control #898 (0.17.0), #895 (0.15.10), #840 (0.15.10)
work-items #861 (0.20.0)
claude-ops none (#844 merged at 0.17.4; this claim is 0.17.5)
repo-hygiene none (#860 merged)
guardrails none

Before removing do-not-merge, confirm #840, #861, #895, and #898 are each merged or withdrawn — and immediately re-run the full collision protocol (per the PR body's warning) since a new source-control open PR has appeared in nearly every prior sync cycle.


Verdict

Approve. The merge commit is correct. Version arithmetic checks out at HEAD. The source-control version gap (0.16.0 → 0.17.1) is the largest yet but is documented and correctly attributed. The remaining gate before unlabeling is confirming the four open holds are settled — verify fresh, not from this snapshot.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 21s —— View job


Security Review — PR #853

  • Gather context
  • Fetch PR diff and read changed files
  • Audit shell script modifications for injection or unsafe patterns
  • Audit new markdown doc and JSON changes
  • Post findings

No security issues found.

All 18 changed files were read and audited against HEAD (24a1605). This PR adds comments and documentation only — no new executable code paths anywhere in the diff. Full breakdown by category:

Shell scripts (6 files modified): Each change adds 3–4 lines of #-prefixed comments — static prose pointing to an internal doc path. Shell comments are never executed. The added text in every file contains no command substitutions, variable expansions, heredoc terminators, escape sequences, or control characters that could influence shell parsing.

The two files with the most security-sensitive pre-existing bodies were read in full to confirm the change boundary:

  • guardrails-test-helpers.sh — The make_sink body (lines 68–78) writes caller-supplied shell content as a temporary executable under $TEST_TMPDIR. That body is unchanged by this PR; the only addition is the pointer comment at lines 7–8.
  • claude-ops-test-helpers.sh — The make_sink body (lines 51–61) uses %q-formatted printf to shell-quote a capture-file path into a generated cat > redirect. Also unchanged; only the pointer comment at lines 7–8 is new.

The # shellcheck disable=SC2016 directive in check-skill-portability.test.sh is correctly preserved on line 12, immediately before set -uo pipefail on line 13 — the new comment block at lines 9–11 does not disturb the directive's position or effectiveness.

New markdown doc (docs/conventions/shell-test-helpers/README.md): 72 lines of prose and relative markdown links. Every link resolves to a path within this repo — no external URLs in the file. No executable content, no credentials, no template expressions, no CDN or remote resource references.

docs/PLUGIN-PHILOSOPHY.md: One additional table row with a single relative internal link. Same assessment.

plugin.json files (5 files): Each modifies only the version string field. No new or modified permissions, dependencies, mcpServers, hooks, allowedTools, remote URLs, or other capability-granting fields. All five manifests were read in full. The source-control version jump to 0.17.1 (larger than the PR description's last-stated 0.16.1) reflects additional sibling-PR collision avoidance since the prior sync — this carries no security implication.

CHANGELOG.md files (5 files): Plain-text changelog entries. No executable content.

GitHub Actions: No .github/workflows/ files are modified in this PR. No pull_request_target/workflow_run patterns, no script injection through the github context, no permission-widening changes, no supply-chain risk from loosened or unpinned action pins.

The effective attack surface of this diff is zero.

kyle-sexton added a commit that referenced this pull request Jul 22, 2026
…th live labels (#922)

## Summary

`plugins/work-items/skills/triage/SKILL.md` had two docs-match-reality
gaps against shipped state:

- The "Attention view (no number)" bucket list named only the
status-axis raw marker (`status:needs-triage`), leaving a repo that
files raw intake on the priority axis (`priority:needs-triage`, per PR
#802's already-merged dual-axis Scope wording) invisible to the no-arg
attention view.
- `status:needs-decision` is a live, actively-used label (e.g. issue
#505, per CHANGELOG `[0.16.1]`/`#562`), and the closing invariant
already referenced it as a routing outcome that clears the raw marker —
but the state machine itself never introduced it as a side exit, unlike
`needs-info`, human-gated, and close.

## Fix

- Attention-view bucket 2 now reads "Raw marker — `status:needs-triage`
/ `priority:needs-triage`, whichever axis the repo files it under",
mirroring the Scope section's exact dual-axis wording (SKILL.md line
35).
- The "Side exits from any state" sentence and the state-machine ASCII
diagram now name `status:needs-decision` ("awaiting a human or
maintainer judgment call" — the label's live GitHub description)
alongside the existing side exits.
- Version-bumped `work-items` 0.21.0 → 0.21.1 (patch, matching the
`#562` precedent for the same doc-only shape) with a matching CHANGELOG
entry.

Scope note: the raw-state table row (line 48, `unlabeled or
status:needs-triage`) is intentionally left single-axis — broader
raw-marker axis canonicalization across that table, evals, and reference
docs is issue #818's job, not this one. Also intentionally out of scope:
adding `needs-decision` to step 2's "Target state" list or step 5's
outcome table — doing so would require defining when triage applies it
vs. the human-gated role, which the label's live usage does not settle
(it appears both with and without `needs-human` across open issues) and
which this issue scoped as pure docs-match-reality, not a design
decision.

## Verification

- Confirmed PR #802's merged Scope-section wording verbatim (`gh pr view
802`): "carrying the raw marker (`status:needs-triage` /
`priority:needs-triage`, whichever axis the repo files it under)" — the
attention-view bucket now mirrors this exactly.
- Confirmed `status:needs-decision` is a live label via `gh issue list
--label "status: needs-decision"` (21+ open/closed issues, e.g. #881,
#718, #664, #551) and confirmed its GitHub description ("Awaiting a
human or maintainer judgment call") used verbatim in the new SKILL.md
text.
- Confirmed issue #505's prior routing to `status:needs-decision` via
the plugin's own CHANGELOG `[0.16.1]` entry (`#562`), which already
treated `needs-decision` as a routing outcome in the closing invariant —
this PR closes the gap between that reference and the state machine's
own introduction of the label.
- Traced the ASCII diagram's pipe/branch alignment by hand to confirm
the new `status:needs-decision` line reads correctly as a side exit at
the same indentation level as `close`.

Closes #817

## Related

- #817 (this fix)
- #802 (source of the dual-axis raw-marker wording mirrored here)
- #505 (live example of `status:needs-decision` usage; see also
CHANGELOG `#562`)
- #818 — separate, unopened-PR item covering raw-marker axis
canonicalization across the state table, evals, and reference docs;
deliberately not touched here to avoid overlap. Re-checked immediately
before opening this PR: no PR exists yet for #818.
- #853 — open draft PR (labeled `do-not-merge`, stale at plugin version
0.19.0) also touches `plugins/work-items/.claude-plugin/plugin.json` and
`CHANGELOG.md` for an unrelated shell-test-helper doc change. Re-checked
immediately before opening this PR: no version-bump collision — #853 is
stale relative to current `main` (0.21.0) and will need to rebase
regardless of this PR.

Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Jul 23, 2026
…triage docs + evals (#923)

## Summary

The live raw-intake marker is applied on whichever axis a consuming repo
files it under — `priority: needs-triage` (the current live label,
applied by `.github/workflows/issue-triage-label.yml`) or `status:
needs-triage`. `SKILL.md`'s "Scope: raw intake only" section already
documents this dual-axis treatment (landed in #802), but several other
spots in the same skill, its evals, and reference docs still described
or asserted the marker as status-axis-only — a priority-axis label
documented as status-only.

## Fix

Brought every remaining occurrence in line with #802's already-merged
dual-axis wording (`status:needs-triage` / `priority:needs-triage`,
whichever axis the repo files it under):

- `plugins/work-items/skills/triage/SKILL.md` — Triage-states table
(`raw` row) and Attention-view bucket 2, both previously
`status:needs-triage` only.
- `plugins/work-items/reference/dogfood-filing.md` — step 4 ("Label
`needs-triage`, then hand off") previously instructed filers to always
`Apply status:needs-triage`; now applies the raw marker on whichever
axis the repo files it under, resolved from the live label set.
- `plugins/work-items/reference/label-taxonomy.md` and
`plugins/work-items/reference/tracker-seam.md` — the axis-grammar tables
listed `needs-triage` as a Status-axis example only; added a note that
it is dual-axis with a pointer to SKILL.md's "Scope: raw intake only".
- `plugins/work-items/skills/triage/evals/evals.json` — evals 4 and 5
asserted "clears `status:needs-triage`" without acknowledging the
marker's dual-axis nature; reworded to "clears the raw-intake marker
(here `status:needs-triage`)" so the assertion doesn't imply that's the
only valid axis.
- Version bump `work-items` `0.21.0` → `0.21.1` + matching
`CHANGELOG.md` entry.

No routing logic changed — this is a doc/eval consistency fix matching
an already-ratified decision.

## Verification

- `skill-quality:check` static contract gate (18 checks) over the
`triage` skill: **PASS — 0 errors, 1 warning** (pre-existing "no Gotchas
surface" warning, unrelated to this change). All 9 base-ref trigger
phrases preserved; markdownlint clean.
- `check-jsonschema` against the bundled `evals.schema.json`: `ok --
validation done`.
- Manually cross-checked every edit against PR #802's diff to confirm
the dual-axis phrasing (`status:needs-triage` / `priority:needs-triage`,
whichever axis the repo files it under) is reused verbatim, not
reinvented.
- Confirmed the live label is priority-axis via
`.github/workflows/issue-triage-label.yml` ("Applies the `priority:
needs-triage` floor label...").

Closes #818

## Related

- #818 — this fix. The issue body already carries a ratified/defaulted
decision (dual-axis treatment, maintainer-vetoable alternative was
single-canonical-axis migration — not implemented here per the issue's
explicit instruction), satisfying rule 4d's citation requirement.
- #802 — the ratifying source for the dual-axis wording; this PR's
phrasing is copied verbatim from its already-merged "Scope: raw intake
only" section.
- **Version-bump collision with PR #922 (issue #817):** #922 also bumps
`work-items` `0.21.0` → `0.21.1` and touches `SKILL.md`'s
state-machine/attention-view sections — the same lines this PR's
dual-axis fix touches, since the marker lives in those sections. Both
PRs are currently open against the same `0.21.0` base. Opening this PR
as **draft + `do-not-merge`** until the version numbers and any
overlapping `SKILL.md` lines are reconciled by whoever merges second
(normal git-merge conflict resolution, per the collision-serialization
protocol).
- PR #853 (issue #820, unrelated) also touches `work-items/plugin.json`
and `CHANGELOG.md` with a stale bump (`0.19.0` → `0.20.1`, already
behind current `origin/main`) — noted for visibility, not a live
collision with this change.

Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o
@kyle-sexton kyle-sexton removed the do-not-merge Hard merge gate: do not merge while applied. label Jul 23, 2026
@kyle-sexton
kyle-sexton marked this pull request as ready for review July 23, 2026 07:38
kyle-sexton added a commit that referenced this pull request Jul 23, 2026
… FLEET_STATE_HOOK_UTILS source footgun (#907)

## Summary

`fleet-state.sh` sourced `hook-utils.sh` from a caller-supplied
`FLEET_STATE_HOOK_UTILS` path, guarded only by an existence check
(`[[ -f "$HOOK_UTILS" ]]`). Any process able to set that env var — a
project
`.claude/settings.json` env block, an inherited shell environment,
another hook
that exports it — could redirect `source` at an arbitrary file, executed
with
the script's ambient permissions. The guard checked only that the path
existed,
never that it was the trusted default.

This removes the override entirely and loads `hook-utils.sh`
unconditionally
from the script-relative plugin root.

## Fix

`hook-utils.sh` is a fixed sibling shipped inside the plugin, always at
`<plugin-root>/hooks/hook-utils.sh` relative to the script. The fix
resolves it
from the script's own location (`PLUGIN_ROOT_DEFAULT`, derived from
`BASH_SOURCE`), which no environment variable can influence:

```bash
HOOK_UTILS="$PLUGIN_ROOT_DEFAULT/hooks/hook-utils.sh"
```

`CLAUDE_PLUGIN_ROOT` is no longer consulted for this sibling file (it
equals the
script-relative root in production, and tests set it to a *fake* value
to
exercise marketplace self-resolution). It remains in use for marketplace
self-resolution further down the script — that concern legitimately
needs the
install-metadata env var; locating a shipped sibling file does not.

### Options considered

The issue proposed two remediations; I document both and why Option A
wins:

- **Option 1 — gate the override behind a test-context flag.** No such
flag
  exists in this repo's convention; the test harness sets the individual
`FLEET_STATE_*` override vars directly. Adding one would be a new
abstraction
  invented solely to keep an override alive.
- **Option 2 — validate the sourced path against an expected location
before
sourcing.** Once the trusted baseline is the script-relative default, an
override is honored *only* when it canonically equals that default. Both
  existing test call sites already resolved to exactly that file, and an
attacker path is rejected — so both branches source the identical file
and the
  override cannot even inject a mock. The seam is provably dead code.
- **Option A — remove the override (chosen).** Since a validated
override could
only ever equal the trusted default, the override carries no capability
worth
keeping. Removing it is the root-cause fix: it fully closes the
arbitrary-file
`source` with no new abstraction and no dead seam. The three
now-redundant
`FLEET_STATE_HOOK_UTILS=` lines in the test harness (which already
pointed at
  the real file) and the doc-comment entry were removed with it.

No behavior change in production: `PLUGIN_ROOT_DEFAULT` and
`CLAUDE_PLUGIN_ROOT`
resolve to the same directory there, so the same real `hook-utils.sh`
loads.

## Verification

**Existing test suite (`fleet-state.test.sh`) — full pass on the
committed code:**

```
23 cases, 0 failed
```

(Later re-runs on this Windows host intermittently exceed the command
timeout on
the `git init` and binary-copy cases from AV/disk contention; that is
environmental, not a test failure — the suite completes green on the
exact
committed tree.)

**Exploit path closed — malicious override in a non-test context:**

```
=== BEFORE (origin/main) — malicious override in a NON-test context ===
PWNED: attacker code executed via FLEET_STATE_HOOK_UTILS
=== AFTER (fixed) — same malicious override ===
(no PWNED — override ignored, exploit closed)
```

The repro sets `FLEET_STATE_HOOK_UTILS` to a script that echoes a
marker, then
runs `fleet-state.sh --marketplace nope` with no test env. Before: the
attacker
file is sourced. After: the override is ignored and the trusted sibling
loads.

Closes #797

## Related

- #797 — this issue.
- #795 (`fix/254-fleet-state-review-gaps`) — the security-review pass
that
surfaced this as a pre-existing, out-of-scope finding and deferred it
here.
- #853 (`docs/820-shell-helper-dedup-or-document`) — open draft
(do-not-merge)
  that also bumps `plugins/claude-ops/.claude-plugin/plugin.json` +
`CHANGELOG.md` (no code overlap with this PR). This PR is provisionally
parked
behind #853's unresolved cross-plugin version/CHANGELOG bump: a
merge-drive
  must re-diff the version claim before either PR flips ready. Carrying
  `do-not-merge` until then.

Claude-Session: https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@kyle-sexton kyle-sexton added the agent-ready Fully specified and briefed; eligible for autonomous pickup from the frontier. label Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-ready Fully specified and briefed; eligible for autonomous pickup from the frontier. automated Opened by automation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

disk-hygiene/clean: document per-plugin shell-helper + exit-code divergence as deliberate

1 participant