Skip to content

fix(topic-docs): the self-ignore guard does not run where no checkout is detected - #2756

Merged
kyle-sexton merged 17 commits into
mainfrom
fix/self-ignore-guard-no-checkout
Aug 15, 2026
Merged

fix(topic-docs): the self-ignore guard does not run where no checkout is detected#2756
kyle-sexton merged 17 commits into
mainfrom
fix/self-ignore-guard-no-checkout

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #2715, which merged while this clause was still under review. Split onto its own branch off main.

No linked issue — this closes no GitHub issue. It repairs a self-contradiction in a convention doc that #2715's merge left live on main.

The defect

docs/conventions/topic-docs/README.md contradicts itself on its own default path.

Its no-project-root fallback routes non-interactive runs to ${CLAUDE_PLUGIN_DATA}/topic-docs/<slug>/ — a destination outside every checkout — and non-interactive is the normal condition for forked subagents, dispatched workers, and headless runs. Its self-ignore-guard bullet nonetheless spoke unconditionally about that same destination, so every consumer reaching that surface ran create-when-absent against a root no checkout governs.

This closes a gap rather than carving an exception, and it binds every topic-docs consumer — review:fanout included, not only detector producers.

The rule

Two outcomes bind the guard:

  • A — a memory-tier write is never picked up by a checkout that governs the destination.
  • B — no plugin ever modifies content tracked in any checkout.

The guard is the means to A wherever a governing checkout is found. Where none is detected it buys nothing toward A, and its create-when-absent rule can violate B. So it does not run there.

"Not detected" stays a detection claim and never shades into "none exists" — the branch is entered precisely where detection can be wrong, which is why the rule is do not write rather than nothing is at risk.

Why blanket, by derivation rather than generalization

A .gitignore absent from disk is either:

  • untracked in some undetected checkout — creating it is harmless, even mitigating; or
  • tracked there — creating it overwrites committed content and cannot hide the change, since a tracked file is exempt from its own pattern.

Separating those requires querying a checkout, and this branch is defined by having found none — the index check that would decide it is the one check that cannot run. The costs are unequal: guessing "untracked" and being wrong modifies content committed in a repository the producer cannot see; guessing "tracked" and being wrong forgoes a mitigation for a harm that is reachable rather than automatic. Undecidable test with asymmetric outcomes yields do not write.

The tracked-file case was measured on the core.worktree topology, where a repository governs a tree with no .git in the destination's path and nothing in the environment to find: the guard replaced committed content, and check-ignore returned exit 1 on its own file. That measurement is one route into the state, not its definition${CLAUDE_PLUGIN_DATA} is another, and is reached by default.

Two dependents

  • detector-findings/README.md — its consequence sentence was false in this case, and is corrected rather than softened, because a consequence sentence is exactly what belongs there. Untracked is not committed: where detection missed a checkout, the findings file lands there untracked, reachable by a later git add -A, not committed by this producer's action.
  • mutation-testing's spoke — drops its local derivation for a pointer, now that the rule has an owner. Behavior unchanged; mutation-testing 0.2.0 → 0.2.1 (patch), since the parity gate reads any edit under a plugin directory as requiring a bump and 0.2.0 is published.

Gates

Gate Result
markdownlint-cli2 0 issues
typos over docs/conventions + the plugin exit 0
check-contract-clause-coverage.py passed — 4 canonical surfaces, 14 tagged restatements, 16 pointing
check-contract-slice-prune.sh --check-diff origin/main passed
check-shell-portability.sh --paths no unexcused GNU-only constructs
check-changed-skills.sh origin/main PASS — 0 errors
check-changelog-parity.sh --check / --check-bump / --check-preserved all pass

Convention version: topic-docs 2.4.2 → 2.5.0 (additive rule).

Related

🤖 Generated with Claude Code

…t is detected

The convention already routes non-interactive runs to a destination outside
every checkout by default (the no-project-root fallback, and non-interactive is
the normal condition for forked subagents, dispatched workers, and headless
runs), while the self-ignore-guard bullet still spoke unconditionally about that
same destination. The document contradicted itself on its own default path, so
this closes a gap rather than carving an exception.

Two outcomes bind the guard: a memory-tier write is never picked up by a
checkout governing the destination, and no plugin ever modifies content tracked
in any checkout. The guard is the means to the first wherever a governing
checkout is found; where none is detected it buys nothing toward it and its
create-when-absent rule can violate the second.

The rule is blanket by derivation rather than by generalizing from the measured
case. A `.gitignore` absent from disk is either untracked in some undetected
checkout, where creating it is harmless and even mitigating, or tracked there,
where creating it overwrites committed content and cannot hide the change since
a tracked file is exempt from its own pattern. Separating those requires
querying a checkout, and the branch is defined by having found none — the index
check that would decide it is the one check that cannot run. Guessing untracked
and being wrong modifies content committed in a repository the producer cannot
see; guessing tracked and being wrong forgoes a mitigation for a harm that is
reachable rather than automatic. Undecidable test, asymmetric costs, so: do not
write.

"Not detected" is stated as a detection claim and never as a claim that none
exists — the branch is entered precisely where detection can be wrong.

Two dependents. detector-findings' consequence sentence was false in this case
and stays a consequence, corrected rather than softened: where detection missed
a checkout the findings file lands there untracked, reachable by a later
`git add -A`, not committed by this producer's action. And mutation-testing's
spoke drops its local derivation for a pointer, now that the rule has an owner.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:security-review)
  • Review diff for security-relevant surface
  • Post findings / summary

Skip gate applied: all four changed files are documentation prose only —
docs/conventions/detector-findings/README.md, docs/conventions/topic-docs/CHANGELOG.md,
docs/conventions/topic-docs/README.md, and plugins/mutation-testing/skills/audit/context/persist-findings.md.
The diff adds/edits explanatory text about when a "self-ignore guard" convention does or does not run;
it contains no executable code, scripts, GitHub Actions config, permissions changes, credential handling,
or injection surfaces. This matches skip-gate condition 2 ("change has no security-relevant surface after
reading the diff"), so no deep review or findings follow.

No security issues found.

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown

Last security-reviewed head: 2cf73d1a5fe1767c3e3e67a9e0fb23a45ba3e71e. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c2091869d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/conventions/detector-findings/README.md Outdated
The parity gate reads any change under a plugin's directory as requiring a
version bump and a matching entry, and this change set edits the audit skill's
spoke. 0.2.0 is published, so editing under it in place reuses a released
number.

Patch rather than minor: no behavior changes. The permissive-branch guard rule
moved to the topic-docs convention that owns the guard, and the spoke now cites
it instead of deriving it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:security-review)
  • Review diff for security-relevant surface
  • Post findings / summary

Skip gate applied (condition 2 — no security-relevant surface): this run covers the push since the last reviewed head (0c20918), which is a single trivial commit (d20945e) touching only plugins/mutation-testing/.claude-plugin/plugin.json (version bump 0.2.00.2.1) and plugins/mutation-testing/CHANGELOG.md (changelog entry). No executable code, scripts, GitHub Actions config, permissions, or credential handling changed.

Reviewing the PR as a whole reaches the same conclusion: all six changed files (docs/conventions/detector-findings/README.md, docs/conventions/topic-docs/CHANGELOG.md, docs/conventions/topic-docs/README.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/context/persist-findings.md) are documentation/config prose describing when a "self-ignore guard" convention runs — no injection surfaces, no trust-boundary changes, no dangerous Actions patterns.

No security issues found.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


CI code review (/review:code-review)

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:code-review)
  • Review diff for correctness/maintainability
  • Post findings / summary

Skip gate: does not apply — this is a substantive, non-trivial doc change with real review surface (a contract-behavior correction plus two dependent updates).

This is a documentation-only PR in a repo where prose is the contract, so I reviewed it for logical/internal consistency the same way I'd review code: cross-checking the corrected rule against its two named dependents, the changelog/version discipline the convention itself mandates, and other consumers of the same rule.

Findings

1. [Inline, docs/conventions/detector-findings/README.md:63] The self-ignore-guard bullet is substantively rewritten, but docs/conventions/detector-findings/CHANGELOG.md isn't touched and no version is bumped. The doc's own "Versioning" section says a docs-only clarification is at least a patch bump — this PR is otherwise careful about that (topic-docs 2.4.2 → 2.5.0, mutation-testing 0.2.0 → 0.2.1), but misses it for detector-findings' own contract text.

2. Cross-file gap — other consumers still restate the pre-fix rule, one in executable code:
plugins/session-flow/reference/topic-docs.md locally restates the self-ignore guard (not just a pointer) without the new "no checkout detected" invalid case:

write the observer runs the contract's self-ignore guard on the resolved memory root — ensuring
`<memory_dir>/.gitignore` contains a bare `*` (creating or amending it as needed) so the memory-tier
output is never committed — and, when the memory root is itself a repo root, refuses and does not write
the ledger there; it never edits the consumer's
root `.gitignore`.

— and explicitly documents the non-interactive fallback landing at ${CLAUDE_PLUGIN_DATA}/topic-docs/handoffs/ (a destination outside every checkout, same pattern this PR fixes) paired with unconditional "ensuring .gitignore … creating … as needed."

That restatement has a real implementation in plugins/session-flow/skills/running-retro/scripts/observer.py's _ensure_memory_root_ignored:

def _ensure_memory_root_ignored(self) -> bool:
"""Self-ignore the resolved memory root; return whether it is safe to write.
Mirrors the topic-docs contract's self-ignore guard: the memory root
(default `.work`, the parent of `running-retros/`) must contain a
`.gitignore` with a bare `*` so the memory-tier output is never committed.
Returns True only when that is guaranteed. Returns False -- and the caller
must NOT write -- when the memory root is a repo root (its `.gitignore`
would be the consumer's, which no plugin may touch) or the guard cannot be
established, so autonomous ledgers never land as untracked committable
files under the repo.
"""
memory_root = self.ledger_dir.parent
if (memory_root / ".git").exists():
self.log("memory root is a repo root; refusing the memory-tier write "
"(would leave an untracked committable ledger under the repo)")
return False
gi = memory_root / ".gitignore"
try:
memory_root.mkdir(parents=True, exist_ok=True)
content = gi.read_text(encoding="utf-8") if gi.exists() else ""
# Verify a bare `*`/`**` line is present -- not merely that the file
# exists (a repo-created .gitignore may hold only comments/exceptions).
if not any(ln.strip() in ("*", "**") for ln in content.splitlines()):
prefix = content if content.endswith("\n") or not content else content + "\n"
gi.write_text(prefix + "*\n", encoding="utf-8")
self.log(f"ensured memory-root self-ignore '*' in {gi}")
except OSError as e:
self.log(f"self-ignore guard could not be established ({e}); refusing write")
return False
return True

It only refuses when memory_root itself is a repo root (.git directly inside it); it never walks ancestors or does rev-parse, so it cannot distinguish "no checkout governs at all" from "a checkout governs via an ancestor" — for the former case (exactly the state this PR's new invalid case forbids), it still unconditionally writes .gitignore. plugins/architecture/reference/topic-docs.md has a lighter version of the same staleness (restates guard creation with no invalid cases at all).

Neither file is in this PR's diff, so this isn't a blocker for merging the doc fix itself, but the PR body's framing ("it binds every topic-docs consumer") isn't yet true in practice for these two — worth a fast follow so the fix this PR makes to the rule actually reaches the one place it's compiled into code.

Not flagged

  • Codex's inline comment arguing the findings-file write itself should be refused on the permissive branch: the PR's own reasoning (asymmetric-outcome analysis in the topic-docs README/CHANGELOG) already addresses this tradeoff deliberately, and the risk is materially smaller for the findings file than for a fixed-name .gitignore since the filename is a unique UTC timestamp, making an index-tracked-deletion collision effectively impossible. Judgment call already made and argued in the PR, not a correctness bug.
  • Cross-references, relative-path depths (../../../../../ in persist-findings.md, ../../ in the plugin CHANGELOG), and the topic-docs 2.4.2 → 2.5.0 minor-bump classification all check out.

…-no-checkout

#2737 landed the rule-id crosswalk and took mutation-testing 0.2.0 -> 0.3.0,
colliding with this branch's 0.2.1. Both conflicts were version races, not
content: 0.2.1 becomes 0.3.1 above their 0.3.0, and both changelog entries are
kept in order.

The feared collision did not occur. #2737 edited detector-findings/README.md
elsewhere in the file, so the self-ignore-guard bullet this branch rewrites
auto-merged intact, and the spoke's pointer survived unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:security-review)
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: the trigger is a synchronize that landed 28b37cd — a merge of origin/main into the branch. The merge itself contributes no PR-authored content; diffing the PR's own commits (0c20918, d20945e) against their base confirms the PR's net changes are unchanged from what was already reviewed at head d20945e, and match the six files GitHub reports for this PR:

  • docs/conventions/detector-findings/README.md
  • docs/conventions/topic-docs/CHANGELOG.md
  • docs/conventions/topic-docs/README.md
  • plugins/mutation-testing/.claude-plugin/plugin.json
  • plugins/mutation-testing/CHANGELOG.md
  • plugins/mutation-testing/skills/audit/context/persist-findings.md

Skip gate applied (condition 2 — no security-relevant surface): every one of these is documentation/config prose (a convention README, two CHANGELOGs, a plugin manifest version bump, and a skill context doc) describing/pointing to when a "self-ignore guard" runs. No executable code, no GitHub Actions config, no permissions, credential handling, or injection surface changed. The detector-findings/README.md content newly visible in 28b37cd beyond the PR's own hunk comes from origin/main (PR #2737, already reviewed independently on its own branch) — not from this PR.

On the Codex review comment ("Refuse artifact writes when checkout detection fails"): this raises a documentation-soundness question about whether persist-findings.md should refuse the findings-file write (not just skip the .gitignore guard) when checkout detection fails on the core.worktree topology. That's a correctness/design argument about the doc's internal consistency, not an exploitable vulnerability, injection surface, or trust-boundary gap — it's out of scope for this security lane and better suited to /review:code-review or the PR author's own judgment on the rule's derivation.

No security issues found.

Comment thread docs/conventions/detector-findings/README.md Outdated
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

…conditional

#2737 added an owner table naming this binding as owning the self-ignore guard,
so a reader now arrives here first. The bullet restated create-when-absent and
ended "per the contract" but named none of the roots at which the contract says
the guard does not run — so through that doorway it reads as unconditional.

The omission predates this branch: root-equivalence has been in the convention
for a long time and this bullet never carried it. The clause adds a second
omission to an already-incomplete restatement rather than creating the defect.

Deference, not a copy. The bullet now states that invalid roots exist and points
at the convention's Runtime guards for them, enumerating none. Copying the list
would put one rule in two places — the shape that left the aridity bar stated six
ways — and would still omit root-equivalence, making the binding a differently
incomplete copy. A pointer cannot drift.

Not touched: fanout/SKILL.md and fix-pass-mode.md INVOKE the guard rather than
defining it, so an invocation resolves to the repaired definition. Editing them
would be a third and fourth copy of a rule that should exist once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:security-review)
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed 30f81be (fix(review): defer on the guard's invalid roots instead of reading unconditional), on top of the previously-reviewed head. That commit touches exactly three files:

  • plugins/review/.claude-plugin/plugin.json — version bump 0.21.00.21.1
  • plugins/review/CHANGELOG.md — changelog entry for the bump
  • plugins/review/reference/topic-docs.mdself-ignore-guard bullet reworded to defer to the convention's "Runtime guards" section for the guard's invalid-root cases, instead of restating (and omitting) them locally

Skip gate applied (condition 2 — no security-relevant surface): all three are documentation prose and a version/changelog bump. The topic-docs.md edit removes an incomplete local restatement of a rule and replaces it with a pointer to the canonical convention doc — no executable code, no GitHub Actions config, no permissions, credential handling, or injection surface changed.

Reviewing the PR as a whole reaches the same conclusion: all nine changed files (docs/conventions/detector-findings/README.md, docs/conventions/topic-docs/CHANGELOG.md, docs/conventions/topic-docs/README.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/context/persist-findings.md, plugins/review/.claude-plugin/plugin.json, plugins/review/CHANGELOG.md, plugins/review/reference/topic-docs.md) are documentation/config prose describing or pointing to when a "self-ignore guard" convention runs — no injection surfaces, no trust-boundary changes, no dangerous Actions patterns.

No security issues found.

…-no-checkout

#2753 published mutation-testing 0.3.1 for the Stryker4s --since correction and
the write-regime column, taking the number this branch had claimed. Renumbered
to 0.3.2 above it; both entries kept, theirs under the released 0.3.1 heading
and mine under a new one, so no published heading is reused or dropped.

No content collision. #2753 edited principles/reference/tooling.md, which this
branch does not touch, and its write-regime column complements Phase 0's
three-regime resolution in SKILL.md rather than restating it — the table gives
the per-tool key to read, the skill gives what to do with it. The guard clause,
the deference clause, and the spoke pointer are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


CI code review (/review:code-review)

  • Gather context (PR diff, changed files)
  • Load and follow /review:code-review skill instructions
  • Review diff for correctness/maintainability
  • Post findings / summary

Scope: reviewed the full PR diff against origin/main (via gh pr diff 2756) at head 30f81be, covering all 9 changed files. The two commits landed since the lane's last review at d20945e (28b37cd — merge of origin/main, contributing no PR-authored content; 30f81be — the review-plugin fix itself) were reviewed directly.

30f81be checked for correctness: it edits plugins/review/reference/topic-docs.md's self-ignore-guard bullet to point at topic-docs/README.md "Runtime guards" for the invalid-root cases instead of restating create-when-absent unconditionally. I verified the premise against docs/conventions/detector-findings/README.md's owner table (line 380), which does name plugins/review/reference/topic-docs.md as the guard's owner-by-pointer — so this file was in fact the reachable-through-the-new-owner-table doorway the commit message describes, and the fix is correctly targeted. Version bump (0.21.00.21.1) and CHANGELOG entry are present, correctly ordered, and consistent with the plugin's existing format. The raw.githubusercontent.com link style (no in-page anchor, since raw markdown has none) matches the established pattern used by every other plugin's reference/topic-docs.md in this repo — not a new inconsistency.

Finding (posted inline)

1. docs/conventions/detector-findings/README.md:58 — the self-ignore-guard bullet is substantively rewritten (the guard's create-when-absent claim is now conditioned on whether a checkout governs the destination) but docs/conventions/detector-findings/CHANGELOG.md still carries no entry for it, and the contract stays at version 2.0.0. The doc's own "Versioning" section requires at least a patch bump for a docs-only clarification — this PR is careful about that for topic-docs (2.4.2 → 2.5.0) and mutation-testing (0.3.0 → 0.3.1), but misses it for detector-findings' own contract text. Confirmed check-changelog-parity.sh --check-bump doesn't cover this case: its docs/conventions/* handling only tracks changelog presence/ordering, not "content changed without a changelog entry," so nothing mechanical catches it. (This was raised in an earlier review round at a prior head and remains unaddressed at current HEAD.)

Not re-flagged (unchanged from a prior round, out of this PR's diff)

plugins/session-flow/reference/topic-docs.md and plugins/architecture/reference/topic-docs.md still locally restate the guard without the new invalid case, and session-flow's observer.py _ensure_memory_root_ignored still can't distinguish "no checkout governs" from "a checkout governs via an ancestor." Neither file is touched by this PR, so this isn't a blocker for merging the doc fix — noted previously and still true, worth a fast follow.
· branch fix/self-ignore-guard-no-checkout

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Apply skip gate (/review:security-review)
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed 45aa5f9 (Merge remote-tracking branch 'origin/main' into fix/self-ignore-guard-no-checkout), on top of the previously-reviewed head 30f81be. The merge commit's own message confirms the only conflict was a version-number collision: #2753 published mutation-testing 0.3.1 on main for an unrelated Stryker4s fix, taking the number this branch had claimed, so the merge renumbers this branch's entry to 0.3.2 — "the guard clause, the deference clause, and the spoke pointer are untouched."

I confirmed this directly: git diff origin/main...HEAD for this PR (via gh pr diff 2756) shows the same nine files and the same substantive hunks already reviewed at 30f81be — the topic-docs guard's second invalid case, its dependents in detector-findings/README.md and persist-findings.md, and the review plugin's pointer update — with only the mutation-testing plugin/CHANGELOG version numerals shifted (0.3.10.3.2) to sit above the now-published 0.3.1 on main. No new content, no executable code, no GitHub Actions config, permissions, or credential handling changed.

Skip gate applied: condition 3 (this head already has a successful security review that still applies) — the diff content is unchanged from the prior review; condition 2 also holds independently, since every changed file remains documentation/config prose (convention docs, CHANGELOGs, plugin manifest version bumps, a skill context doc) describing when the "self-ignore guard" runs.

No security issues found.

Comment thread docs/conventions/detector-findings/README.md
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


CI code review (/review:code-review)

  • Gather context (PR diff, changed files)
  • Invoke /review:code-review and follow its instructions
  • Review diff for correctness/maintainability
  • Post findings as inline comments / summary

Skip gate: does not apply — the diff since the last code-review pass (d20945e) adds a real fix (plugins/review/reference/topic-docs.md) with its own review surface, and this is a fresh push (synchronize to 45aa5f9), not a repeat of an already-reviewed head.

This is a documentation-as-contract PR, so I reviewed the current diff (git diff via gh pr diff, base origin/main) for internal consistency and cross-reference correctness the same way I'd review code.

Findings (posted inline)

  1. docs/conventions/detector-findings/README.md:58 — the self-ignore-guard bullet is substantively rewritten (correcting a previously-unconditional claim), but docs/conventions/detector-findings/CHANGELOG.md still isn't touched and no version is bumped, contrary to the doc's own "Versioning" rule. This was flagged on an earlier head of this PR and remains unresolved at the current head.
  2. plugins/review/reference/topic-docs.md:72 — the new "Runtime guards" link points at the whole doc via a raw.githubusercontent.com URL with no section anchor (and that host can't support one, since it serves unrendered plain text). The repo's established pattern for section-specific cross-references is a rendered blob/main/...#anchor URL, used consistently elsewhere in the codebase.

Not flagged (informational only)

  • Cross-file staleness in plugins/session-flow/reference/topic-docs.md and plugins/architecture/reference/topic-docs.md (noted on an earlier pass): neither is touched by this PR's diff, so it's out of scope for this lane, but the rule fix still hasn't reached those two compiled consumers.
  • Relative-path depth in persist-findings.md (../../../../../docs/conventions/topic-docs/README.md) — verified correct (5 levels from plugins/mutation-testing/skills/audit/context/ to repo root).
  • Version bumps and CHANGELOG entries for topic-docs (2.4.2 → 2.5.0), mutation-testing (0.3.1 → 0.3.2), and review (0.21.0 → 0.21.1) all check out.
    · branch fix/self-ignore-guard-no-checkout

… too

Second plugin binding restating the self-ignore guard unconditionally, same
shape as review's before its deference clause. This plugin resolves through the
same convention and so reaches the same no-project-root default, where its
readers met text saying the guard always creates.

Same form as review's: state that invalid roots exist, point at the convention's
Runtime guards, enumerate none. Copying the list would put one rule in a third
place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread docs/conventions/detector-findings/README.md
Comment thread plugins/review/reference/topic-docs.md Outdated
…-no-checkout

Fourth collision, and the first that was not a version race: #2760 published
topic-docs 2.4.3 correcting the prune-recovery pointer for squash-merge, in the
same CHANGELOG this branch adds 2.5.0 to. Both entries kept, 2.5.0 above 2.4.3.

The README auto-merged, which is the case worth checking rather than trusting:
#2760 edited the contract-slice lifecycle, this branch edits Runtime guards, and
a diff of the merged file against origin/main shows the guard clause as the ONLY
delta — so their correction is intact and nothing of theirs was reverted by an
older copy winning silently.

Same check applied to the other two shared files: every line this branch removes
against main is its own superseded text, none of main's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed 5987fee (merge of origin/main into this branch), on top of the previously-reviewed head 45aa5f9. git log 45aa5f9..5987fee shows two commits: a560ef2, a merge-in of origin/main (PR #2760, unrelated topic-docs prune-recovery doc fix, already on main and outside this PR's diff against origin/main), and bc8f111fix(architecture): defer on the guard's invalid roots in this binding too, the only PR-authored content in this push.

bc8f111 touches exactly three files, same shape as the previously-reviewed review plugin fix:

  • plugins/architecture/.claude-plugin/plugin.json — version bump 0.5.20.5.3
  • plugins/architecture/CHANGELOG.md — changelog entry for the bump
  • plugins/architecture/reference/topic-docs.md — Guards section reworded to defer to topic-docs/README.md's "Runtime guards" section for the guard's invalid-root cases, instead of stating the guard unconditionally

Skip gate applied (condition 2 — no security-relevant surface): all three are documentation prose and a version/changelog bump. No executable code, no GitHub Actions config, no permissions, credential handling, or injection surface changed.

Reviewing the PR as a whole (git diff origin/main...HEAD --stat, confirmed against merge-base a560ef2) reaches the same conclusion: all 12 changed files (docs/conventions/detector-findings/README.md, docs/conventions/topic-docs/CHANGELOG.md, docs/conventions/topic-docs/README.md, plugins/architecture/.claude-plugin/plugin.json, plugins/architecture/CHANGELOG.md, plugins/architecture/reference/topic-docs.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/context/persist-findings.md, plugins/review/.claude-plugin/plugin.json, plugins/review/CHANGELOG.md, plugins/review/reference/topic-docs.md) are documentation/config prose describing or pointing to when a "self-ignore guard" convention runs — no injection surfaces, no trust-boundary changes, no dangerous Actions patterns.

Note: the code-review lane's finding on docs/conventions/detector-findings/README.md (missing CHANGELOG bump for that contract) and on the raw.githubusercontent.com link pattern (now also present in bc8f111's architecture/reference/topic-docs.md) are doc-consistency/correctness concerns, not security findings — out of scope for this lane.

No security issues found.
· branch fix/self-ignore-guard-no-checkout

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


CI code review (/review:code-review)

  • Gather context (PR diff, changed files)
  • Load and follow /review:code-review skill instructions
  • Review diff for correctness/maintainability
  • Post findings (inline + summary)

Skip gate: does not apply — since the last review round (head 45aa5f9), the branch gained a real content commit, bc8f111 ("fix(architecture): defer on the guard's invalid roots in this binding too"), which extends this PR's fix to a third plugin binding (plugins/architecture/reference/topic-docs.md), plus its version bump and CHANGELOG entry.

Scope: reviewed the full PR diff (12 changed files) against origin/main, with particular attention to the new architecture plugin commit since it repeats a pattern from an already-flagged file.

Findings (posted inline)

  1. plugins/architecture/reference/topic-docs.md:38 — new in this round's commit. The "Runtime guards" link text points at a raw.githubusercontent.com URL with no #runtime-guards fragment; raw content is unrendered plain text, so it can't support one anyway. This is the exact same defect already flagged on plugins/review/reference/topic-docs.md:72 in an earlier round — now duplicated into the new architecture binding rather than fixed. The repo's established pattern for a section-specific cross-reference is a rendered blob/main/...#anchor URL (verified #runtime-guards is a real heading in docs/conventions/topic-docs/README.md:377).
  2. docs/conventions/detector-findings/README.md:58 — still unresolved from three earlier heads: the self-ignore-guard bullet is substantively corrected, but docs/conventions/detector-findings/CHANGELOG.md carries no entry and the contract stays at 2.0.0, contrary to this doc's own "Versioning" rule. The PR is careful about this discipline for every contract it fully owns (topic-docs, mutation-testing, review, and now architecture), but misses it here.

Not re-flagged (unresolved but already covered by a prior round's inline comment, not reposted to avoid duplicate threads)

  • plugins/review/reference/topic-docs.md:72 — same raw-link-without-anchor issue as finding 1 above, flagged inline on an earlier head, still unresolved at current HEAD.
  • plugins/session-flow/reference/topic-docs.md and its observer.py implementation, plus plugins/architecture/reference/topic-docs.md's prior lighter staleness — both noted in earlier rounds as out-of-diff fast-follow items; the architecture file is now in-diff and fixed by bc8f111 for the guard text itself (see finding 1 for the residual link issue).
    · branch fix/self-ignore-guard-no-checkout

Comment thread plugins/architecture/reference/topic-docs.md Outdated
Comment thread docs/conventions/detector-findings/README.md
Resolve topic-docs CHANGELOG with both 2.5.0 (this PR) and 2.4.4 (main).
Bump detector-findings to 2.0.1 for the rewritten self-ignore bullet.
Point Runtime guards citations at the blob URL with fragment.
Bump mutation-testing to 0.3.3 so it stacks after the arid-bar 0.3.2 lane.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@kyle-sexton

Copy link
Copy Markdown
Contributor Author

Addressed review threads on this head:

  • Merged main and resolved the topic-docs CHANGELOG conflict (kept 2.5.0 + 2.4.4).
  • Bumped detector-findings to 2.0.1 with a CHANGELOG entry for the rewritten self-ignore bullet.
  • Pointed architecture/review Runtime guards citations at the blob URL with #runtime-guards.
  • Clarified the missed-checkout findings-write residual (index-tracked deletion) instead of widening to a blanket refuse that would also block ${CLAUDE_PLUGIN_DATA}.
  • Bumped mutation-testing to 0.3.3 so it stacks after the arid-bar 0.3.2 lane (fix(mutation-testing): grade the node-kind bar and stop stating aridity two ways #2759).

… to govern

A P2 on #2756 is right, and measurement confirms it: the undecidability that
stops the self-ignore guard binds the findings file too. Reproduced — commit a
findings-file path, delete it from disk, write it again: ` M <path>`, a modified
tracked file, not the untracked one the text claimed. So on the branch where
neither signal finds a governing checkout, this producer now writes NOTHING and
reports the resolved destination instead. "Read-only with respect to tracked
source" admits no write that may land on a tracked deletion.

The convention states the general form: the same undecidability binds every
write on that branch, and a surface whose artifact must not modify tracked
content refuses the artifact write too. A surface that can tolerate an untracked
path being staged later may proceed — the two outcomes differ in what they
protect, and only the first is absolute.

detector-findings gains its missing version bump (2.0.0 -> 2.0.1, docs-only per
its own Versioning section) and its consequence sentence drops the "untracked"
claim the same measurement falsified.

Both binding pointers move from raw.githubusercontent.com to the rendered
blob URL with a #runtime-guards fragment: raw serves plain text with no anchor
ids, so link text promising a section could not reach it. That is the repo's
established cross-reference form.

Swept for text the refusal invalidates: the "Where the file goes" obligation now
names the second invalid case two sections before the rule, the at-most-two-writes
preamble and step 1 say the empty-signals branch writes nothing, the bare-repo
case is relabelled a conservative refusal it cannot distinguish from
core.worktree, and SKILL.md, the plugin CHANGELOG and eval 13 follow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
kyle-sexton and others added 6 commits August 15, 2026 17:35
…ions, not a blanket refuse

A concurrent push answered the same P2 differently, and its counterargument is
decisive: a blanket refusal on the no-checkout branch would also refuse the
${CLAUDE_PLUGIN_DATA} fallback, which the convention routes rootless
non-interactive runs to and which sits outside every checkout BY CONSTRUCTION.
That destination cannot be a tracked deletion, so refusing it protects nothing
and strands the one path such a run is meant to use.

Neither side was wholly right. Their text kept "it lands untracked", which
measurement falsifies — commit a findings path, delete it, write it again, and
git reports a modified tracked file. My text refused every write, which
over-corrects into the fallback.

Resolved to the distinction both halves imply: refuse where a RESOLVED ROOT has
no governing checkout, write where the destination is the plugin-data surface.
Stated once in the convention, read by detector-findings, and applied by the
spoke; SKILL.md, the plugin CHANGELOG and eval 13 follow.

Also restores the "Where the file goes" carve-out pointer lost in an earlier
revert, so the obligation a reader meets first names the case that qualifies it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep mutation-testing 0.3.3 (pointer) stacked on 0.3.2 (arid bar).
Bump detector-findings docs to 2.0.2 for the self-ignore bullet after
2.0.1's aridity-row patch from #2759.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…crimination

#2759 merged, bringing the guard-conditioning restorations, the aridity-bar
work and eval fixes onto main. Five conflicts, all resolved toward whichever
side was later or measured rather than by side:

- SKILL.md contract item 1: main's wording, which already conditions the guard
  on a governing checkout.
- SKILL.md Phase 6: both, composed — main's guard condition plus this branch's
  findings-file withholding and the plugin-data exception.
- evals.json: main's file taken WHOLE, then eval 13's clause re-applied. My
  version would have dropped four of main's eval corrections; a --ours resolve
  here was wrong and is why the file was rebuilt from main instead.
- Versions: main published mutation-testing 0.3.2 and detector-findings 2.0.1,
  so this branch moves to 0.3.3 and 2.0.2 above them. No published heading
  reused; --check-preserved compares 80 across 5 changelogs.

Post-merge check run on every shared file per the lesson from the seven-site
revert: every line this branch removes against main is its own superseded text.
The `raw.githubusercontent.com` pointers it drops are replaced by blob URLs with
a #runtime-guards fragment; the guard-obligation and Phase 6 sentences it drops
are replaced by conditioned forms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…n-sync paths

Both this branch and a concurrent push synced the same origin/main, producing a
criss-cross whose changelog conflicts nested to three levels. Resolved by
keeping every entry once, in version order: detector-findings 2.0.2 above the
2.0.1 main published, and mutation-testing 0.3.3 above main's 0.3.2.

No entry from either side is dropped; --check-preserved compares 82 headings
across 5 changelogs against the merged main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed bd4a2e5, on top of the previously-reviewed head 5987fee. git log 5987fee..bd4a2e5 shows several merge commits pulling in unrelated main changes plus two PR-authored commits:

  • 2fcf1b9 (fix(conventions): withhold every write where no checkout can be shown to govern) — extends the self-ignore-guard fix to also refuse the findings-file write itself on the undecidable branch (addressing Codex's P2 comment), adds the missing detector-findings CHANGELOG bump (2.0.0 → 2.0.1), and repoints the architecture/review binding links to the rendered blob URL with a #runtime-guards fragment.
  • 676fef2 — trivial CHANGELOG lint fix (removes a duplicate blank line).

Reviewing the full PR diff against origin/main at head bd4a2e5 (git diff origin/main...HEAD --stat) confirms all 15 changed files match what GitHub reports for this PR:

docs/conventions/detector-findings/{CHANGELOG,README}.md, docs/conventions/topic-docs/{CHANGELOG,README}.md, plugins/architecture/.claude-plugin/plugin.json, plugins/architecture/CHANGELOG.md, plugins/architecture/reference/topic-docs.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/SKILL.md, plugins/mutation-testing/skills/audit/context/persist-findings.md, plugins/mutation-testing/skills/audit/evals/evals.json, plugins/review/.claude-plugin/plugin.json, plugins/review/CHANGELOG.md, plugins/review/reference/topic-docs.md.

Skip gate applied (condition 2 — no security-relevant surface): every file is documentation/config prose or JSON eval-fixture text:

  • The three plugin.json diffs are version-number bumps only (verified line-by-line).
  • persist-findings.md, SKILL.md, and evals.json are markdown skill instructions and eval prompt/expected-output strings describing when a producer writes a findings file or .gitignore and under what conditions it refuses — no shell scripts, no executable code, no parsing/execution logic that a runtime interprets. The refusal behavior these files newly describe (do not write when neither ancestor-walk nor git rev-parse finds a governing checkout) tightens the write surface rather than loosening it — the security-relevant direction of this change is strictly more conservative than what shipped before.
  • No GitHub Actions workflow, permissions, credential handling, or injection surface changed anywhere in the diff.

No security issues found.
· branch fix/self-ignore-guard-no-checkout

…rvives the refusal

The "at most two writes" framing and the carve-out pointer were restored earlier
in this branch, but the argument under them was not: that the write taken on the
no-checkout branch is PROVEN rather than merely permitted.

It needed restating rather than restoring, because the rule changed under it. At
a resolved root the branch now refuses both writes, so the surviving write is the
${CLAUDE_PLUGIN_DATA} fallback — and what proves that one safe is step 1 itself.
Two independent signals agreeing that no checkout governs the path IS the proof
that none can track it: there is no ignore rule to satisfy and nothing for
check-ignore to answer. A proof, not an exemption, which is why step 1 needs both
signals and why a single-signal version would be fail-open rather than weaker.

Also corrects the carve-out pointer to say "a resolved root" — "writes nothing at
all" was inexact once the plugin-data fallback became an explicit exception.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


CI code review (/review:code-review)

  • Gather context (PR diff, changed files)
  • Load and follow /review:code-review skill instructions
  • Review diff for correctness/maintainability
  • Post findings (inline + summary)

Scope: reviewed the full PR diff (origin/main...HEAD, 15 files) at head e6bcd8f, with focus on what changed since the last review round (5987fee): 2fcf1b9 (extends the guard's refusal to the findings-file write itself, addressing Codex's P2) and e6bcd8f (restates the step-1 proof for the surviving ${CLAUDE_PLUGIN_DATA} write). All previously-flagged issues from earlier rounds — the missing detector-findings CHANGELOG bump and the raw.githubusercontent.com anchor links — are resolved at this head.

Finding (posted inline)

1. plugins/mutation-testing/skills/audit/evals/evals.json:19 — a merge commit in this branch's history (dd46871, merging c5ad5cf from origin/main) silently reverted eval cases 3, 9, and 11 back to text mutation-testing 0.3.2 (already published on main, PR #2759) explicitly fixed. That 0.3.2 CHANGELOG entry even names this exact failure mode — "guard-conditioning statements restored after a merge reverted them" — and now it's recurred in this branch for three different cases:

  • Case 3 loses the node-kind-vocabulary requirement for an arid claim, though SKILL.md still states and enforces it — the eval no longer grades it.
  • Case 9 loses the "does not run it at all where no checkout governs the destination" clause — this PR's own topic, dropped from the eval that's supposed to certify it.
  • Case 11's prompt reverts to unqualified "one arid", reintroducing a prompt/expectation disagreement 0.3.2 fixed (a correct reading of the prompt now produces 3 rows against an expectation asserting exactly 2).

Details, the exact commits, and a fix pointer are in the inline comment.

Not flagged (verified, no issues)

  • docs/conventions/detector-findings/README.md / CHANGELOG.md (now 2.0.2) and docs/conventions/topic-docs/README.md / CHANGELOG.md (now 2.5.0): the corrected self-ignore-guard rule, its derivation, and the new ${CLAUDE_PLUGIN_DATA}-fallback exception read consistently between the convention and its dependents.
  • plugins/mutation-testing/skills/audit/context/persist-findings.md and SKILL.md: the "at most two writes" framing, the per-write proof order, and the ${CLAUDE_PLUGIN_DATA} exception's "proof, not exemption" argument are internally consistent and match the convention.
  • plugins/architecture/reference/topic-docs.md and plugins/review/reference/topic-docs.md: both now link "Runtime guards" to the rendered blob URL with a #runtime-guards fragment (previously flagged as pointing at unanchored raw content — fixed).
  • Version bumps and CHANGELOG entries for topic-docs (2.5.0), detector-findings (2.0.2), mutation-testing (0.3.3), architecture (0.5.3), and review (0.21.1) all check out and stack correctly above what's currently published on main.
    · branch fix/self-ignore-guard-no-checkout

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed e6bcd8f (fix(mutation-testing): restate the step-1 proof for the write that survives the refusal), on top of the previously-reviewed head bd4a2e5. git diff bd4a2e5..e6bcd8f --stat shows exactly one file touched:

  • plugins/mutation-testing/skills/audit/context/persist-findings.md (+11/-3)

The edit rewords the "Prove the destination is outside tracked space before writing to it" section: it clarifies that step 1's "no write happens" applies at a resolved root, and adds a paragraph explaining why the one write that does survive that branch (the ${CLAUDE_PLUGIN_DATA} fallback) is safe — because the destination sits outside every checkout, so there's no tracked-content ignore rule to satisfy in the first place. This is a textual clarification of an already-reviewed refusal rule, not a behavior change: it doesn't touch which writes happen or don't, only how the proof for the surviving write is explained.

Skip gate applied (condition 2 — no security-relevant surface): the change is prose in a markdown skill-context doc — no executable code, no shell/script logic, no GitHub Actions config, no permissions, credential handling, or injection surface.

Reviewing the PR as a whole (git diff origin/main...HEAD --stat) reaches the same conclusion: all 15 changed files (docs/conventions/detector-findings/{CHANGELOG,README}.md, docs/conventions/topic-docs/{CHANGELOG,README}.md, plugins/architecture/.claude-plugin/plugin.json, plugins/architecture/CHANGELOG.md, plugins/architecture/reference/topic-docs.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/SKILL.md, plugins/mutation-testing/skills/audit/context/persist-findings.md, plugins/mutation-testing/skills/audit/evals/evals.json, plugins/review/.claude-plugin/plugin.json, plugins/review/CHANGELOG.md, plugins/review/reference/topic-docs.md) are documentation/config prose, JSON eval fixtures, or version-number bumps describing when a "self-ignore guard" convention does or does not run. No injection surfaces, no trust-boundary changes, no dangerous Actions patterns. The behavior these docs describe (refuse writes when no governing checkout can be shown) remains, as in prior rounds, strictly more conservative than what shipped before this PR.

No security issues found.
· branch fix/self-ignore-guard-no-checkout

Comment thread plugins/mutation-testing/skills/audit/evals/evals.json Outdated
…ssed for the new rule

The P2 on #2756 is right about case 9. The pushed commit e6bcd8f states the
self-ignore guard unconditionally, losing both qualifications #2759 published in
0.3.2: "where a checkout governs that root" and "does not run it at all where no
checkout governs the destination". Verified by count against the commit, not the
working tree: 1 on origin/main, 0 at e6bcd8f.

That is a genuine revert, not supersession — the destination discrimination makes
the unqualified form MORE wrong, not less, since the run now refuses every write
at an ungoverned resolved root. A graded case on this branch would have certified
behavior this PR forbids.

Restored from origin/main and then re-expressed, because main's text alone is
still wrong under the new rule: it went on to assert "Writes exactly one file"
unconditionally. Case 9 now carries the refusal and the ${CLAUDE_PLUGIN_DATA}
exception.

Case 13 is NOT a revert and is left as-is: main's "SHAPED around it / skipping
the guard makes that topology harmless" grades the OLD rule the P2 falsified.

Swept all 14 cases against origin/main programmatically rather than by
inspection: 14/14 present, only 9 and 13 differ, both deliberate. No other case
of main's work was dropped by the earlier rebuild.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

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


Security review — no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Review diff for security-relevant surface
  • Post findings / summary

Scope for this run: trigger is the push that landed 2cf73d1 (fix(mutation-testing): restore case 9's guard qualification, re-expressed for the new rule), on top of the previously-reviewed head e6bcd8f. git diff e6bcd8f..HEAD --stat shows exactly one file touched:

  • plugins/mutation-testing/skills/audit/evals/evals.json (+5/-5)

This is a follow-up to the eval-content regression flagged in an earlier review round (a merge had silently reverted guard-conditioning text in eval cases 3, 9, 11, and 13 back to pre-fix wording). Diffing the change confirms all four cases are now restored to reflect this PR's own rule:

  • Case 3 — the arid-claim node-kind-vocabulary requirement is back (whose claim binds a node kind from the closed enumerated vocabulary AND whose reason names...).
  • Case 9 — the "does not run it at all where no checkout governs the destination" clause is restored, with the ${CLAUDE_PLUGIN_DATA} fallback carved out explicitly as the one write that still proceeds.
  • Case 11 — the prompt is re-qualified (one arid with a complete proposed suppression entry whose claim names a node kind...), resolving the prompt/expected-output disagreement noted previously.
  • Case 13 — reworded consistently with the current per-write, checkout-conditioned proof (guard's .gitignore only "where a governing checkout was found"; findings file is the sole write otherwise).

Skip gate applied (condition 2 — no security-relevant surface): the sole changed file is JSON eval fixture text — prompt/expected_output strings used to grade a skill's documentation-following behavior. No executable code, no shell/script logic, no GitHub Actions config, no permissions, credential handling, or injection surface. The content change tightens what the eval grades (restoring guard-conditioning and vocabulary requirements that were dropped) rather than loosening any behavior.

Reviewing the PR as a whole reaches the same conclusion as prior rounds: all 15 changed files (docs/conventions/detector-findings/{CHANGELOG,README}.md, docs/conventions/topic-docs/{CHANGELOG,README}.md, plugins/architecture/.claude-plugin/plugin.json, plugins/architecture/CHANGELOG.md, plugins/architecture/reference/topic-docs.md, plugins/mutation-testing/.claude-plugin/plugin.json, plugins/mutation-testing/CHANGELOG.md, plugins/mutation-testing/skills/audit/SKILL.md, plugins/mutation-testing/skills/audit/context/persist-findings.md, plugins/mutation-testing/skills/audit/evals/evals.json, plugins/review/.claude-plugin/plugin.json, plugins/review/CHANGELOG.md, plugins/review/reference/topic-docs.md) are documentation/config prose, JSON eval fixtures, or version-number bumps describing when a "self-ignore guard" convention does or does not run. No injection surfaces, no trust-boundary changes, no dangerous Actions patterns. The write behavior these docs describe (refuse writes when no governing checkout can be shown) remains, as in prior rounds, strictly more conservative than what shipped before this PR.

No security issues found.
· branch fix/self-ignore-guard-no-checkout

@kyle-sexton
kyle-sexton merged commit 79e3892 into main Aug 15, 2026
41 checks passed
@kyle-sexton
kyle-sexton deleted the fix/self-ignore-guard-no-checkout branch August 15, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants