Skip to content

docs(disk-hygiene): fix run-directory, fan-out brief and --project-dir wording - #5571

Merged
kyle-sexton merged 16 commits into
mainfrom
docs/5520-clean-run-dir-brief-wording
Sep 30, 2026
Merged

kyle-sexton merged 16 commits into
mainfrom
docs/5520-clean-run-dir-brief-wording

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

Closes #5520

Summary

/disk-hygiene:clean docs said the agent creates the run directory (the engine does), the fan-out worker brief used ${...} tokens a subagent cannot expand, and every template showed --project-dir although it is optional.

Fix

  • skills/clean/SKILL.md section 1: choose a unique run-directory path; the engine creates it.
  • skills/clean/reference/fan-out-worker-brief.md: new parent step fills <hook-python>, <engine>, <data-root>, <run-dir> and optional <project-dir> with literal absolute values before spawning; templates use those placeholders; --project-dir is documented as optional. The engine-gate wording (item 3) was already correct on main.
  • disk-hygiene 0.29.0 to 0.29.1 with a CHANGELOG entry.

Verification

  • scripts/check-changelog-parity.sh --check --check-order: passes.
  • scripts/validate-plugins.sh: all manifests and the catalog validate.
  • Docs-only change; no engine code touched, so no tests affected.

Related

Split from #5214. Related: #4215, #4009.

🤖 Generated with Claude Code

…r wording

Refs #5520

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review September 30, 2026 04:38
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-30T04:48:42.704621Z fae2dc2 Draft marked ready
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: fae2dc29d6

ℹ️ 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 plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md Outdated
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Run /review:security-review criteria against the diff
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Post findings

This is a docs-only change (SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump) for the disk-hygiene plugin's /disk-hygiene:clean skill. No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

What changed, security-relevant angle:

  • The fan-out worker brief now has the parent fill <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before spawning a worker, since a worker can't expand ${...} shell tokens. This is a tightening, not a weakening: it stops workers from silently no-op'ing on unexpanded ${CLAUDE_PLUGIN_DATA}-style tokens by requiring the parent to supply real values it already holds from the guard-values note / kill-switch probe.
  • --project-dir is now documented as optional rather than required. I checked hygiene.py (standing_policy_paths/load_policy, ~L772-843, L4364-4369): --project-dir was already optional in the engine's argparse and only adds an extra project-level policy overlay (<project-dir>/.claude/disk-hygiene.json) on top of the always-loaded home policy. It is not part of the fail-closed VCS/checkout-evidence gating. So the doc now matches actual engine behavior rather than removing a real control.
  • The line describing the plugin-level engine gate changed from "checks any call that names hygiene.py" to "checks any call that names the engine" — purely descriptive wording about an out-of-diff mechanism (destructive_guard.py / engine_grammar.py), which this PR does not modify.

Instruction-surface deletion lens: I checked this diff's wording changes to SKILL.md and fan-out-worker-brief.md against the instruction exception register (Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority). None of the reworded lines remove or soften a rule in those classes — the mutation-guard rules ("no apply/preview/handoff-verify/rm/del/moves", "no compound shells", "single invocation" contract) are all preserved verbatim in the diff (see fan-out-worker-brief.md).

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Code review in progress

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

View job run

Renumber disk-hygiene to 0.29.2 above main's 0.29.1 and lower the fan-out
brief spoke-plugin-root baseline to its current count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Run /review:security-review criteria against the diff
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Diff this head against the previously-reviewed commit to scope what's new
  • Post findings

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill (SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

Scoping this run: 271d431 (current head) is a merge of origin/main into this branch. Diffing it against fae2dc2 (the commit an earlier security-review pass on this same PR already reviewed and cleared) shows the only changes since are a version renumber (0.29.1 → 0.29.2, to avoid colliding with an unrelated disk-hygiene fix that landed on main in the interim), the matching CHANGELOG.md entry, and a scripts/spoke-plugin-root-baseline.txt count update. SKILL.md and fan-out-worker-brief.md are byte-identical to the already-reviewed commit — no new security-relevant surface from the merge.

Content review (unchanged from the prior pass, re-verified here):

  • plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md#L7-L30: the new "fill the placeholders before spawning" step has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn. This is a tightening, not a weakening — it stops a worker from silently no-op'ing (or mis-scanning) on an unexpanded ${CLAUDE_PLUGIN_DATA}-style token, since a subagent can't expand shell variables. The mutation-guard rules directly below it (no apply/preview/handoff-verify/rm/del/moves, no compound shells, single invocation) are preserved verbatim, and the command templates keep every substituted value double-quoted, so this doesn't introduce a new injection surface beyond what was already there.
  • plugins/disk-hygiene/skills/clean/SKILL.md#L160-L168: "the engine creates it" instead of telling the agent to create the run directory — a factual correction, not a control change; the engine still owns the fail-closed path validation.
  • --project-dir is now documented as optional rather than always-passed. Confirmed against hygiene.py's standing_policy_paths/load_policy: --project-dir was already optional in the engine's argparse and only adds an extra project-level policy overlay on top of the always-loaded home policy — it isn't part of the fail-closed VCS/checkout-evidence gating, so the doc now matches actual engine behavior rather than removing a real control.

Instruction-surface deletion lens: none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in the protected classes (irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority) — the mutation-guard contract is carried forward unchanged. This PR adds a new instruction (fill placeholders before spawning) rather than deleting one.

Out of scope for this lane: Codex's review-comment finding on this PR (missing Claim/Basis/As-of/Recheck record for the "workers never receive the guard-values note" assumption) is a documentation-process concern under .claude/rules/skill-bodies-state-current-rules.md, not a security vulnerability — it belongs to /review:doc-drift-detector or /review:code-review, not this security pass.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

…ed record

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Run /review:security-review criteria against the diff
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Diff this head against the previously-reviewed commit to scope what's new
  • Post findings

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill. No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

Scoping this run: current head ce630c2 adds one commit on top of 271d431 (a commit already covered by the prior security-review pass on this PR). The only change since is to fan-out-worker-brief.md: it replaces the earlier unverified claim ("never receives the guard-values note, which a hook emits only when a person types the command") with a narrower claim ("sees only its spawn prompt, not the guard-values note in your context") plus a pointer to the verified record in safety-model.md ("Handing the values over up front," verified 2026-09-27 against the UserPromptExpansion hook docs).

This is exactly the fix for Codex's earlier P1 finding on this PR (missing Claim/Basis/As-of/Recheck record for the volatile hook-delivery assumption) — it's a documentation-accuracy correction, not a security-relevant change. It doesn't touch the mutation-guard rules (no apply/preview/handoff-verify/rm/del/moves, no compound shells, single invocation), doesn't weaken any control, and doesn't introduce a new injection surface.

Content review (unchanged from prior passes on this PR, re-verified here):

  • The "fill the placeholders before spawning" step still has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn — a tightening, not a weakening.
  • --project-dir documented as optional matches hygiene.py's actual argparse/load_policy behavior; it's an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.

Instruction-surface deletion lens: no removed or softened rule in the protected classes (irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority). The mutation-guard contract is carried forward verbatim; this commit only re-scopes a factual claim to a verified source.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

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

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill (SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump, scripts/spoke-plugin-root-baseline.txt). Reviewed origin/main...HEAD via gh pr diff 5571, scoped to changed files only, against CLAUDE.md/AGENTS.md and .claude/rules/skill-bodies-state-current-rules.md (loaded automatically since this PR touches skill/reference bodies).

1 finding, posted inline on fan-out-worker-brief.md lines 9–11: the latest commit (ce630c2) reworded the volatile claim that a worker "sees only its spawn prompt, not the guard-values note in your context" and pointed it at safety-model.md's "Handing the values over up front" section in response to Codex's P1 finding on the prior commit. I read that target section (safety-model.md lines 261–294) and it only verifies that the UserPromptExpansion hook fires and posts additionalContext to the invoking session — it never mentions subagents, workers, or spawn isolation. A grep of the whole file for subagent|worker|spawn|isolat turned up nothing else that covers it. So the citation satisfies the rule's letter (a pointer to a source with a dated four-part record) but not its substance: the record it points to doesn't verify the actual claim being cited for. Codex's original P1 is not yet closed.

Other things I checked, no findings:

  • scripts/spoke-plugin-root-baseline.txt: the count for fan-out-worker-brief.md (3 → 1) matches the actual remaining ${CLAUDE_PLUGIN_ROOT} occurrences in the file (verified with grep -c) — correct and consistent with scripts/check-spoke-plugin-root.sh's ratchet rule.
  • CHANGELOG.md entry and plugin.json version bump (0.29.1 → 0.29.2) are consistent with each other and accurately describe the diff.
  • The --project-dir optionality change and the three scan templates in fan-out-worker-brief.md are internally consistent (--data-root "<data-root>" [--project-dir "<project-dir>"] used uniformly).
  • SKILL.md's own code block in section 1 still shows --project-dir "${CLAUDE_PROJECT_DIR}" unbracketed — but that block is untouched by this PR (only the prose above it changed), so it's out of scope for this review (pre-existing, not a regression introduced here).
  • The gate-description wording change ("names hygiene.py" → "names the engine") is accurate: <engine> resolves to hygiene.py, and destructive_guard.py's _ENGINE_MARKER = "hygiene.py" confirms the described behavior; this is just indirection through the doc's own placeholder vocabulary, not an accuracy regression.

Author-claimed, not independently verified by me: scripts/check-changelog-parity.sh --check --check-order and scripts/validate-plugins.sh passing, per the PR's Verification section.

Out of scope for this lane: the security angle of the same diff was already covered by the security-review lane on this PR (no issues found, twice).

Comment thread plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md Outdated
Renumber disk-hygiene to 0.30.1 above main's 0.30.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

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

Reviewed origin/main...HEAD at 1829db6 (docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill: SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump, scripts/spoke-plugin-root-baseline.txt), scoped to changed files, against CLAUDE.md/AGENTS.md and .claude/rules/skill-bodies-state-current-rules.md (auto-loaded since this PR touches a skill reference body).

1 finding, posted inline on fan-out-worker-brief.md lines 9–11: the fix for Codex's earlier P1 (ce630c2) reworded the claim that a worker "sees only its spawn prompt, not the guard-values note in your context" and pointed it at safety-model.md's "Handing the values over up front" section. I read that section (lines 264–273): it verifies only that the UserPromptExpansion hook fires and posts additionalContext to the invoking session — it says nothing about whether a Task-spawned subagent inherits or is excluded from that context. A grep of safety-model.md for subagent|worker|spawn|isolat|Task tool found no other passage covering it. This file is byte-identical to ce630c2 at the current head, so the gap is unresolved, not new.

Other changed files, no findings:

  • SKILL.md: "the engine creates it (it creates the parent of --output)" — verified against hygiene.py's write_json() (path.parent.mkdir(parents=True, exist_ok=True)), accurate.
  • --project-dir documented as optional in fan-out-worker-brief.md's three scan templates — internally consistent (--data-root "<data-root>" [--project-dir "<project-dir>"] used uniformly).
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (3 → 1) matches the file's actual remaining ${CLAUDE_PLUGIN_ROOT} occurrences.
  • CHANGELOG.md/plugin.json: 0.30.0 → 0.30.1, correctly ordered above the prior entry and consistent with the diff described.
  • SKILL.md's own code block still shows --project-dir "${CLAUDE_PROJECT_DIR}" unbracketed — pre-existing, untouched by this PR's diff, so out of scope here.

Author-claimed, not independently re-run by me: scripts/check-changelog-parity.sh --check --check-order and scripts/validate-plugins.sh passing, per the PR's Verification section.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Run /review:security-review criteria against the diff
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Independently verify engine-gate marker and --project-dir optionality against the engine source
  • Post findings

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill (plugin.json version bump 0.30.0 → 0.30.1, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched at this head (1829db6).

Content review:

  • fan-out-worker-brief.md#L7-L14: the "fill the placeholders before spawning" step has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn, since a subagent can't expand ${...} shell tokens. This is a tightening, not a weakening — it prevents a worker from silently mis-scanning on an unexpanded token. The mutation-guard rules directly below (no apply/preview/handoff-verify/rm/del/moves, no compound shells, single invocation) are preserved verbatim, and every substituted value stays double-quoted in the templates, so this doesn't add a new injection surface.
  • fan-out-worker-brief.md#L19-L20: "checks any call that names the engine" (was "names hygiene.py"). Verified against destructive_guard.py:512,575,685 — the gate still keys off the literal hygiene.py marker and <engine> resolves to that filename, so the reworded gate description is accurate, not a weakened mechanism.
  • fan-out-worker-brief.md#L28-L30 and SKILL.md#L167-L175: --project-dir is now documented as optional rather than always-passed, and the run directory is described as engine-created rather than agent-created. Checked hygiene.py's standing_policy_paths/load_policy (~L779-856, ~L4603-4604): --project-dir was already optional in the engine's argparse and only adds an additive project-level policy overlay on top of the always-loaded home policy — it is not part of the fail-closed VCS/checkout-evidence gating. So this doc change matches actual engine behavior rather than removing a real control.

Instruction-surface deletion lens (register, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract (no apply/preview/handoff-verify/rm/del/moves, no compound shells, single invocation) is carried forward verbatim, and this diff only adds a new instruction (fill placeholders before spawning) rather than deleting one.

Out of scope for this lane: the open code-review thread on whether the safety-model.md citation at fan-out-worker-brief.md:9-11 substantively verifies the "worker doesn't receive the guard-values note" claim is a documentation-accuracy question under .claude/rules/skill-bodies-state-current-rules.md, not a security vulnerability — it belongs to /review:code-review / /review:doc-drift-detector, which have already covered it on this PR.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

Comment thread plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md Outdated
kyle-sexton and others added 3 commits September 30, 2026 09:43
… brief

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Renumber disk-hygiene to 0.31.1 above main's 0.31.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

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

Reviewed at head 6f8ec07 (docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill: SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump, scripts/spoke-plugin-root-baseline.txt), scoped to changed files, against CLAUDE.md/AGENTS.md and .claude/rules/skill-bodies-state-current-rules.md (auto-loaded since this PR touches a skill reference body). 6f8ec07 is just a merge of origin/main; the last PR-authored content commit is 3305b397 (confirmed via git diff 3305b397..HEAD -- plugins/disk-hygiene/ — only version renumbering and unrelated main-branch content moved through).

1 finding, posted inline on fan-out-worker-brief.md lines 9–13: the "fill the placeholders before spawning" step's closing clause attributes all five placeholders (<hook-python>, <engine>, <data-root>, <run-dir>, <project-dir>) to "the guard-values note or the kill-switch probe in SKILL.md," but per SKILL.md (~L118–124) that source only carries two of them (hook_python, data_root). <engine> is derived from ${CLAUDE_PLUGIN_ROOT} (per the very same line's own parenthetical), <run-dir> is the path the parent chose in SKILL.md §1, and <project-dir> is ${CLAUDE_PROJECT_DIR} — none of those three come from the note or probe.

Good news on the prior open thread: Codex's and this lane's earlier P1 (cited record for "worker sees only its spawn prompt, not the guard-values note" didn't verify subagent isolation) is resolved — 3305b397 dropped that claim entirely rather than re-citing it. The brief now states only the mechanical, verifiable fact that a worker can't expand ${...} tokens, which matches safety-model.md's "rejects every Bash expansion family" record.

Other changed content, no findings:

  • SKILL.md#L167-L169: "the engine creates it (it creates the parent of --output)" — accurate per hygiene.py's write_json().
  • --project-dir documented as optional in the three scan templates — internally consistent, and matches hygiene.py's actual optional-argparse/load_policy behavior (already verified by the security lane on this PR).
  • scripts/spoke-plugin-root-baseline.txt: fan-out-worker-brief.md count (3 → 1) matches the file's one remaining ${CLAUDE_PLUGIN_ROOT} occurrence (line 11).
  • CHANGELOG.md/plugin.json: 0.31.1, correctly ordered above 0.31.0 and consistent with the diff.
  • SKILL.md's own scan template (L177) still shows --project-dir "${CLAUDE_PROJECT_DIR}" unbracketed rather than optional-style — untouched by this PR's diff (not even in the hunk context), so out of scope per this lane's "pre-existing issues on untouched lines" exclusion, consistent with what prior review passes on this PR already concluded.

Author-claimed, not independently re-run by me: scripts/check-changelog-parity.sh --check --check-order and scripts/validate-plugins.sh passing, per the PR's Verification section.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

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

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill (plugin.json version bump, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched at this head (6f8ec07).

Content review:

  • fan-out-worker-brief.md#L7-L13: the "fill the placeholders before spawning" step has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn, since a subagent can't expand ${...} shell tokens. This is a tightening, not a weakening — it prevents a worker from silently mis-scanning on an unexpanded token. The mutation-guard rules directly below (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are preserved verbatim, and every substituted value stays double-quoted in the templates, so no new injection surface.
  • The prior P1 finding from Codex and from this lane (fae2dc2 → ce630c2) — an unverifiable claim about whether a hook-delivered guard-values note reaches a spawned worker's context — is now resolved by removal rather than by re-citation: commit 3305b39 dropped the claim entirely, so line 9 now asserts only that a worker can't expand ${...} tokens, which needs no external verification record. No open volatile-specific gap remains here under .claude/rules/skill-bodies-state-current-rules.md.
  • fan-out-worker-brief.md#L18-L19: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that filename, and destructive_guard.py's marker check still keys off it, so this is accurate wording, not a weakened gate.
  • fan-out-worker-brief.md#L27-L29 and SKILL.md#L167-L169: --project-dir documented as optional, and the run directory as engine-created. Checked against hygiene.py's standing_policy_paths/load_policy and write_json() (path.parent.mkdir(...)): --project-dir was already optional in the engine's argparse and only adds an additive project-policy overlay — it is not part of the fail-closed VCS/checkout-evidence gating. The doc now matches actual engine behavior rather than removing a real control.

Instruction-surface deletion lens (register, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim; this diff adds a new instruction (fill placeholders before spawning) and removes an unverifiable claim, rather than deleting an enforced rule.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

Comment thread plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md Outdated
kyle-sexton and others added 2 commits September 30, 2026 11:31
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Post findings

Reviewed at the pinned HEAD_SHA c443e87971c1678754121a1e3e7ef78863c26031. Local git history for this SHA and origin/main has no common ancestor in this shallow checkout, so I read file content directly via git show <ref>:<path> / the blob SHAs from the changed-files list rather than a merge-base diff, and confirmed those blobs match c443e87's tree (plugin.json reads 0.32.0 there, matching the pre-renumber state — the later 1516eeb "resolve changelog conflict and renumber to 0.32.1" commit isn't in scope for this pinned SHA).

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill (plugin.json version bump, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

Content review:

  • fan-out-worker-brief.md#L7-L13: the new "Parent: fill the placeholders before spawning" step has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn, since a subagent can't expand ${...} shell tokens. This is a tightening, not a weakening — it stops a worker from silently mis-scanning on an unexpanded token. Every substituted value stays double-quoted in the templates below, so this doesn't add a new injection surface.
  • fan-out-worker-brief.md#L18-L19: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that filename, and destructive_guard.py's marker check still keys off it. Accurate wording, not a weakened gate.
  • The mutation-guard rules ("no apply/preview/handoff-verify/catalog/rm/del/moves", "no compound shells", "single invocation") are preserved verbatim in the diff.
  • --project-dir is now documented as optional rather than required. hygiene.py's standing_policy_paths/load_policy argparse already treats it as optional; it only adds an additive project-policy overlay, not part of the fail-closed VCS/checkout-evidence gating. The doc now matches actual engine behavior rather than removing a real control.
  • SKILL.md#L167-L169: "the engine creates it (it creates the parent of --output)" instead of telling the agent to create the run directory — a factual correction, not a control change.

Instruction-surface deletion lens (register, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded or removed lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The dropped claim about what a worker "sees" of the guard-values note (removed in an earlier commit on this PR, per its review history) was an unverifiable descriptive claim, not an enforced control. The mutation-guard contract is carried forward verbatim.

Out of scope for this lane: the earlier code-review thread on whether the "guard-values note or the kill-switch probe" attribution covers all five placeholders is a documentation-accuracy question under .claude/rules/skill-bodies-state-current-rules.md, not a security vulnerability.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

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

Reviewed at head 1516eeb (docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill: SKILL.md, fan-out-worker-brief.md, CHANGELOG.md, plugin.json version bump, scripts/spoke-plugin-root-baseline.txt), scoped to changed files, against CLAUDE.md/AGENTS.md and .claude/rules/skill-bodies-state-current-rules.md (auto-loaded since this PR touches a skill reference body). The last PR-authored content commit is 1516eeb itself (resolves a CHANGELOG.md merge conflict from rebasing onto main and renumbers 0.31.1 → 0.32.1); c443e87 is the substantive content fix before it.

No findings — every issue raised earlier in this PR's review history is resolved at this head:

  • The "overstated source" finding from the prior code-review pass (all five placeholders attributed to "the guard-values note or the kill-switch probe") is fixed in c443e87. fan-out-worker-brief.md#L9-L14 now attributes only <hook-python> and <data-root> to the note/probe, and separately names ${CLAUDE_PLUGIN_ROOT} for <engine>, the chosen path for <run-dir>, and ${CLAUDE_PROJECT_DIR} for <project-dir> — I checked each against SKILL.md (~L118-124 for the note/probe fields, the ${CLAUDE_PLUGIN_ROOT}/skills/clean/scripts/hygiene.py path in the §1 code block, and the --project-dir "${CLAUDE_PROJECT_DIR}" usage there) and all four attributions are accurate.
  • Codex's and this lane's earlier P1 (an unverifiable claim about whether a hook-delivered guard-values note reaches a spawned worker's context) was resolved by removal in 3305b39, carried forward unchanged here — line 9 now asserts only the mechanical, verifiable fact that a worker can't expand ${...} tokens.
  • --project-dir documented as optional: independently re-verified against engine_grammar.py:165 (Flag("--project-dir", example="project-dir"), no required=True, and Flag.required defaults to False) and hygiene.py's load_policy/standing_policy_paths — a missing --project-dir only skips the additive project-policy overlay, not the fail-closed gating. Doc matches engine behavior.
  • SKILL.md#L167-L169 ("the engine creates it — it creates the parent of --output"): verified against hygiene.py's write_json() (path.parent.mkdir(parents=True, exist_ok=True), line 337). Accurate.
  • The engine-gate wording ("names the engine" vs. the old "names hygiene.py"): <engine> resolves to that literal filename everywhere it's used, so this is accurate indirection, not a weakened description.
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) matches the file's one actual remaining ${CLAUDE_PLUGIN_ROOT} occurrence (line 12).
  • CHANGELOG.md/plugin.json: 0.32.1, correctly ordered above 0.32.0, one entry for disk-hygiene: fix run-directory, fan-out brief and --project-dir wording #5520 (no duplicates left over from the rebase), and its wording matches the final diff.
  • No merge-conflict markers remain in any file this PR touches.
  • SKILL.md's own scan template still shows --project-dir "${CLAUDE_PROJECT_DIR}" unbracketed rather than optional-style — pre-existing, untouched by this PR's diff (same conclusion prior review passes on this PR reached), so out of scope here.

Author-claimed, not independently re-run by me (Bash tool required approval I didn't have in this session): scripts/check-changelog-parity.sh --check --check-order and scripts/validate-plugins.sh passing, per the PR's Verification section. I did independently verify the specific facts the diff's prose depends on (engine flag requiredness, write_json parent-dir creation, the hygiene.py marker) by reading the engine source directly.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Run /review:security-review criteria against the diff
  • Check instruction-surface deletion lens (SKILL.md / fan-out-worker-brief.md edits)
  • Diff this head against the previously-reviewed commit to scope what's new
  • Post findings

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill at head 1516eeb (plugin.json version bump 0.32.0 → 0.32.1, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

Scoping this run: confirmed via gh pr diff 5571 that the only changes since the last-reviewed content commit are the 0.32.1 version/changelog bump (administrative, from resolving a changelog conflict with an unrelated disk-hygiene PR that landed on main) and the doc-accuracy narrowing in fan-out-worker-brief.md#L7-L14 that resolves the last open code-review finding.

Content review:

  • fan-out-worker-brief.md#L7-L14: the "fill the placeholders before spawning" step now attributes each placeholder to its actual source instead of implying all five come from the guard-values note/kill-switch probe (<hook-python>/<data-root> from the note or probe, <engine> from ${CLAUDE_PLUGIN_ROOT}, <run-dir> from the path the parent chose, <project-dir> from ${CLAUDE_PROJECT_DIR}). This is a doc-accuracy fix, not a control change — the underlying requirement (parent fills literal absolute values because a worker can't expand ${...} tokens) and the mutation-guard rules directly below it (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are all preserved verbatim.
  • fan-out-worker-brief.md#L20-L21: "checks any call that names the engine" (was "names hygiene.py") — previously verified against destructive_guard.py's hygiene.py marker check; <engine> resolves to that filename, so this remains accurate wording, not a weakened gate.
  • SKILL.md#L169-L171 and the --project-dir optionality in the scan templates: unchanged from prior passes on this PR, previously verified against hygiene.py's write_json()/load_policy — --project-dir is an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.
  • CHANGELOG.md/plugin.json: 0.32.1, correctly ordered above 0.32.0 and consistent with the diff described.
  • scripts/spoke-plugin-root-baseline.txt: fan-out-worker-brief.md count (3 → 1) matches the file's one remaining ${CLAUDE_PLUGIN_ROOT} occurrence.

Instruction-surface deletion lens (register, present in this checkout; Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim; this diff only re-attributes placeholder sources more precisely.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

kyle-sexton and others added 2 commits September 30, 2026 12:07
Renumber disk-hygiene to 0.32.2 above main's 0.32.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Renumber disk-hygiene to 0.33.1 above main's 0.33.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:code-review and follow its instructions
  • Post findings as inline PR comments
  • Post summary comment

Reviewed via gh pr diff 5571 (the local shallow checkout has no merge base with origin/main, so I used the GitHub-computed diff directly) at head f4992b7 — a merge of origin/main into this branch. The actual PR diff against main is small: plugin.json (0.33.0 → 0.33.1), CHANGELOG.md, SKILL.md (§1 run-directory wording), fan-out-worker-brief.md, and scripts/spoke-plugin-root-baseline.txt.

No new findings. This PR has had 8 prior review passes (code-review and security-review) across its commit history, and every finding raised along the way — Codex's P1 on the unverifiable hook-delivery claim, and this lane's finding that the "guard-values note or kill-switch probe" attribution overstated the source for <engine>/<run-dir>/<project-dir> — was fixed in earlier commits (3305b39, c443e87). The merge that produced the current head only pulled in an unrelated, already-reviewed upstream commit (adff838, PR #5508) that refined the same "guard-values note" wording in SKILL.md; the merge-resolved text in fan-out-worker-brief.md line 11 ("from the guard-values note (the probe in SKILL.md only when the note is absent)") matches SKILL.md's current wording exactly, so nothing new needs review there.

Independently re-verified against source for this pass:

  • SKILL.md#L166-L168: "the engine creates it (it creates the parent of --output)" — matches hygiene.py's write_json() (path.parent.mkdir(parents=True, exist_ok=True), line 355).
  • fan-out-worker-brief.md#L28-L30: --project-dir documented as optional — confirmed in engine_grammar.py:165 (Flag("--project-dir", ...) has no required=True, and Flag.required defaults to False).
  • fan-out-worker-brief.md#L19-L20: "checks any call that names the engine" — destructive_guard.py:512 still keys its gate off the literal hygiene.py marker, and <engine> resolves to that filename. Accurate.
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) matches the file's actual single remaining ${CLAUDE_PLUGIN_ROOT} occurrence.
  • CHANGELOG.md/plugin.json: 0.33.1 entry is correctly ordered above 0.33.0 and its wording matches the diff.

Out of scope for this lane: security angle already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions exactly
  • Check instruction-surface deletion lens (register consulted at docs/conventions/instruction-exception-register/README.md)
  • Diff this head against the last-reviewed content commit to scope what's new
  • Post findings

This is a docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill at head f4992b7 (plugin.json version bump 0.33.0 → 0.33.1, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt). No engine code (hygiene.py, destructive_guard.py, engine_grammar.py) is touched.

Scoping this run: gh pr diff 5571 confirms the PR's actual diff is unchanged in substance from the last-reviewed content commit (1516eeb) plus a version renumber to 0.33.1. git diff 1516eeb..HEAD for the two touched skill files shows the SKILL.md hunks are unrelated upstream content that arrived via the origin/main merges (not part of this PR's diff, per gh pr diff) — the only PR-relevant change since 1516eeb is in fan-out-worker-brief.md#L7-L14: "the guard-values note or the kill-switch probe in SKILL.md" narrowed to "the guard-values note (the probe in SKILL.md only when the note is absent)."

Content review:

  • fan-out-worker-brief.md#L7-L14: the "Parent: fill the placeholders before spawning" step has the parent substitute <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before a worker spawn, since a subagent can't expand ${...} shell tokens. This is a tightening, not a weakening — it stops a worker from silently mis-scanning on an unexpanded token. This is the resolved form of the finding raised on 1516eeb (all five placeholders had been attributed to a source that only carried two): it now attributes <hook-python>/<data-root> to the note (falling back to the probe only when the note is absent), and separately names ${CLAUDE_PLUGIN_ROOT} for <engine>, the chosen path for <run-dir>, and ${CLAUDE_PROJECT_DIR} for <project-dir>.
  • fan-out-worker-brief.md#L19-L20: "checks any call that names the engine" (was "names hygiene.py") — previously verified against destructive_guard.py's literal hygiene.py marker check; <engine> resolves to that filename, so this remains accurate wording, not a weakened gate.
  • The mutation-guard rules ("no apply/preview/handoff-verify/catalog/rm/del/moves", "no compound shells", "single invocation") are preserved verbatim, and every substituted value stays double-quoted in the three scan templates, so this diff introduces no new injection surface.
  • --project-dir documented as optional (SKILL.md and the scan templates): previously verified against engine_grammar.py's Flag("--project-dir", ...) (not required=True) and hygiene.py's load_policy/standing_policy_paths — it's an additive project-policy overlay, not part of the fail-closed VCS/checkout-evidence gating, so the doc matches actual engine behavior.

Instruction-surface deletion lens: consulted docs/conventions/instruction-exception-register/README.md directly (present in this checkout). None of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in the protected classes (irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority). The mutation-guard contract is carried forward unchanged; this diff only narrows an already-correct attribution and adds a new instruction (fill placeholders before spawning) rather than deleting an enforced rule.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

Renumber disk-hygiene to 0.33.2 above main's 0.33.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:code-review and follow its instructions
  • Post findings as inline PR comments
  • Post summary comment

Reviewed origin/main...HEAD at head b75d294 (docs-only change to the disk-hygiene plugin's /disk-hygiene:clean skill: plugin.json, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md, scripts/spoke-plugin-root-baseline.txt), scoped to changed files, against CLAUDE.md/AGENTS.md and .claude/rules/skill-bodies-state-current-rules.md (auto-loaded since this PR touches a skill reference body).

No new findings. b75d294 is a merge of origin/main into this branch. I diffed the two PR-authored content files directly against f4992b7 (the head the last code-review pass on this lane fully cleared, after 9 prior review rounds worked through Codex's and this lane's findings — the unverifiable hook-delivery claim, then the overstated "guard-values note or kill-switch probe" attribution):

git diff f4992b7 HEAD -- plugins/disk-hygiene/skills/clean/SKILL.md plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md

produces no output — both files are byte-identical to the already-cleared commit. The only change since is administrative: plugin.json (0.33.1 → 0.33.2) and a new CHANGELOG.md entry, picked up by merging in an unrelated disk-hygiene fix (e983c39, PowerShell string-data mentions) that landed on main in the interim and pushed this PR's version forward.

Verified for this pass:

  • plugin.json version (0.33.2) matches the CHANGELOG.md heading (## [0.33.2] - 2026-09-30) exactly.
  • The new changelog entry is correctly ordered above [0.33.1], is a single entry (no duplicate left over from the merge), and its wording matches the final diff (run-directory ownership in SKILL.md §1, the fan-out-brief placeholder-filling step, --project-dir optionality).
  • fan-out-worker-brief.md#L7-L18: placeholder attribution is precise per-field (<hook-python>/<data-root> from the guard-values note or probe, <engine> from ${CLAUDE_PLUGIN_ROOT}, <run-dir> from the chosen path, <project-dir> from ${CLAUDE_PROJECT_DIR}) — the fix from the last open review thread on this PR holds.
  • SKILL.md#L167-L169: "the engine creates it (it creates the parent of --output)" — previously verified against hygiene.py's write_json().
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) matches the file's single remaining ${CLAUDE_PLUGIN_ROOT} occurrence.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:security-review and follow its instructions exactly
  • Post findings

Skip-gate hit: this head already has a successful security review that still applies. Current head b75d294 is a merge of origin/main into this branch. I diffed it directly against f4992b7 — the commit this lane already reviewed and cleared twice (code-review and security-review, both "no issues found") — for every file this PR touches:

git diff f4992b7..HEAD -- plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md   # empty
git diff f4992b7..HEAD -- plugins/disk-hygiene/skills/clean/SKILL.md                             # empty
git diff f4992b7..HEAD -- scripts/spoke-plugin-root-baseline.txt                                 # empty

fan-out-worker-brief.md and SKILL.md — the two files carrying this PR's actual instruction-surface changes — are byte-identical to the already-reviewed commit. The only changes since are in plugin.json (0.33.1 → 0.33.2) and CHANGELOG.md (renumber + an unrelated disk-hygiene changelog entry, 0.33.1 "PowerShell lane allows engine names in string data," slotted in above this PR's entry). Both are administrative version/changelog churn from merging main, not new security-relevant surface. The destructive_guard.py PowerShell-lane change visible in a raw f4992b7..HEAD diff belongs to that unrelated main-branch commit (e983c39) pulled in by the merge — it is not part of this PR's diff (confirmed against gh pr diff 5571, which scopes to plugin.json, CHANGELOG.md, SKILL.md, fan-out-worker-brief.md).

Content already verified in prior passes on this PR (re-confirmed unchanged here):

  • fan-out-worker-brief.md#L7-L14: the parent now fills <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before spawning a worker, since a worker can't expand ${...} shell tokens — a tightening, not a weakening. Every substituted value stays double-quoted in the templates, so no new injection surface.
  • fan-out-worker-brief.md#L18-L20: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that literal filename and destructive_guard.py's marker check still keys off it; accurate wording, not a weakened gate.
  • The mutation-guard rules (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are preserved verbatim.
  • --project-dir documented as optional in fan-out-worker-brief.md and SKILL.md#L166-L169 (run directory described as engine-created): matches hygiene.py's actual argparse/load_policy/write_json behavior — --project-dir is an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.

Instruction-surface deletion lens (docs/conventions/instruction-exception-register/README.md, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions exactly
  • Post findings

Skip-gate hit: this head already has a successful security review that still applies. Current head a21ee6a is a merge of origin/main into this branch.

git diff b75d294..a21ee6a -- plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md \
  plugins/disk-hygiene/skills/clean/SKILL.md \
  plugins/disk-hygiene/.claude-plugin/plugin.json \
  plugins/disk-hygiene/CHANGELOG.md \
  scripts/spoke-plugin-root-baseline.txt

produces no output — all five files this PR actually touches (per the changed-files list) are byte-identical to b75d294, the commit this lane already reviewed and cleared. The 28 files that did change between those two commits (plugins/guardrails/hooks/block-hook-bypass.sh and others) are unrelated content pulled in by the origin/main merge — none of them are part of this PR's diff.

Content already verified in prior passes on this PR (unchanged at this head):

  • fan-out-worker-brief.md#L7-L14: the parent fills <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before spawning a worker, since a worker can't expand ${...} shell tokens — a tightening, not a weakening. Every substituted value stays double-quoted in the templates, so no new injection surface.
  • fan-out-worker-brief.md#L18-L20: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that literal filename and destructive_guard.py's marker check still keys off it; accurate wording, not a weakened gate.
  • The mutation-guard rules (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are preserved verbatim.
  • --project-dir documented as optional in fan-out-worker-brief.md and SKILL.md#L166-L169 (run directory described as engine-created): matches hygiene.py's actual argparse/load_policy/write_json behavior — --project-dir is an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.

Instruction-surface deletion lens (docs/conventions/instruction-exception-register/README.md, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:code-review and follow its instructions
  • Post findings as inline PR comments
  • Post summary comment

Skip-gate hit: this head already has a successful review from this lane that still applies. Current head a21ee6a is a merge of origin/main into this branch. I diffed it directly against b75d294 — the commit this lane already reviewed and cleared ("No new findings," after 9 prior review rounds worked through every finding Codex and this lane raised) — for every file this PR touches:

git diff b75d294..HEAD -- plugins/disk-hygiene/.claude-plugin/plugin.json plugins/disk-hygiene/CHANGELOG.md plugins/disk-hygiene/skills/clean/SKILL.md plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md scripts/spoke-plugin-root-baseline.txt

produces no output — all five files this PR touches (confirmed against gh pr diff 5571 --name-only) are byte-identical to the already-cleared commit. The only commit since is 2da4575 ("nudge on a surface note that ends mid-sentence," #5491), an unrelated main-branch change pulled in by the merge; it touches no file in this PR's diff.

Content already verified in prior passes on this PR (unchanged at this head):

  • fan-out-worker-brief.md#L7-L14: the "Parent: fill the placeholders before spawning" step attributes each of <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> to its actual source (the guard-values note/probe for the first two, ${CLAUDE_PLUGIN_ROOT} for <engine>, the chosen path for <run-dir>, ${CLAUDE_PROJECT_DIR} for <project-dir>) — the fix for both open review threads on this PR (Codex's unverifiable hook-delivery claim, and this lane's overstated "all five from the note/probe" attribution) holds.
  • fan-out-worker-brief.md#L19-L20: "checks any call that names the engine" — accurate per destructive_guard.py's literal hygiene.py marker check.
  • SKILL.md#L166-L169: "the engine creates it (it creates the parent of --output)" — matches hygiene.py's write_json().
  • --project-dir documented as optional: matches engine_grammar.py's Flag("--project-dir", ...) (not required=True) and hygiene.py's load_policy/standing_policy_paths (an additive project-policy overlay, not part of the fail-closed gating).
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) matches its single remaining ${CLAUDE_PLUGIN_ROOT} occurrence.
  • CHANGELOG.md/plugin.json: version and changelog entry consistent with each other and the diff.

No new findings.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

Renumber disk-hygiene to 0.34.1 above main's 0.34.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions exactly
  • Post findings

Skip-gate hit: this head already has a successful security review that still applies. Current head 2d8bf60 is a merge of origin/main into this branch.

git diff origin/main...HEAD -- plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md \
  plugins/disk-hygiene/skills/clean/SKILL.md \
  plugins/disk-hygiene/.claude-plugin/plugin.json \
  plugins/disk-hygiene/CHANGELOG.md \
  scripts/spoke-plugin-root-baseline.txt

The actual PR diff (origin/main...HEAD, the full set of files this PR touches) carries exactly the content this lane already reviewed and cleared multiple times (f4992b7, b75d294, a21ee6a — all "no issues found"): the SKILL.md §1 run-directory wording, the fan-out-worker-brief.md placeholder-filling step, the plugin version bump, the matching CHANGELOG.md entry, and the spoke-plugin-root-baseline.txt count. origin/main itself advanced since the last review (an unrelated disk-hygiene 0.34.0 entry — repeatable --path, mutation-prompt path listing — landed via #5523/#5546-adjacent main commits), which is why this PR's own diff now renders on top of 0.34.0 and bumps to 0.34.1; that upstream content is not part of this PR and was already reviewed on its own PR.

Content already verified in prior passes on this PR (unchanged at this head):

  • fan-out-worker-brief.md#L7-L18: the parent fills <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before spawning a worker, since a worker can't expand ${...} shell tokens — a tightening, not a weakening. Every substituted value stays double-quoted in the templates, so no new injection surface.
  • fan-out-worker-brief.md#L21-L22: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that literal filename and destructive_guard.py's marker check still keys off it; accurate wording, not a weakened gate.
  • The mutation-guard rules (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are preserved verbatim.
  • --project-dir documented as optional in fan-out-worker-brief.md and SKILL.md#L166-L169 (run directory described as engine-created): matches hygiene.py's actual argparse/load_policy/write_json behavior — --project-dir is an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.

Instruction-surface deletion lens (docs/conventions/instruction-exception-register/README.md, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim.

No CRITICAL, IMPORTANT, or SUGGESTION findings.

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:code-review and follow its instructions
  • Post findings as inline PR comments
  • Post summary comment

Skip-gate hit: this head already has a successful review from this lane that still applies. Current head 2d8bf60 is a merge of origin/main into this branch. origin/main had advanced to disk-hygiene 0.34.0 in the interim (an unrelated feature: repeatable handoff-verify --path, deletion-prompt path listing, and a new permissions.allow-can't-bypass-prompts gotcha) via f0575a7 — none of that is part of this PR's diff.

I confirmed via gh pr diff 5571 that the PR's actual diff against the new base is unchanged in substance from a21ee6a — the commit this lane already reviewed and cleared twice ("No new findings," after 9 prior review rounds resolved every finding Codex and this lane raised):

  • plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md and scripts/spoke-plugin-root-baseline.txt: git diff a21ee6a..HEAD for both is empty — byte-identical to the cleared commit.
  • plugins/disk-hygiene/skills/clean/SKILL.md: the PR-owned §1 wording ("the engine creates it (it creates the parent of --output)") is unchanged; the file's other diff hunks (unsupported-platform handoff, new gotcha) came from the origin/main merge, not this PR — confirmed against gh pr diff 5571, which scopes to only the §1 hunk for this file.
  • plugin.json / CHANGELOG.md: version renumbered 0.33.2 → 0.34.1 (to sit above main's 0.34.0), with this PR's ## [0.34.1] "Fixed" entry correctly ordered above ## [0.34.0]. No duplicate or lost entries, no merge-conflict markers in any of the five changed files (checked directly).
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) still matches the file's one actual remaining ${CLAUDE_PLUGIN_ROOT} occurrence.

No new findings. Every substantive issue raised across this PR's review history — Codex's P1 on the unverifiable hook-delivery claim, and this lane's finding that the "guard-values note or kill-switch probe" attribution overstated the source for <engine>/<run-dir>/<project-dir> — was fixed in earlier commits (3305b39, c443e87) and remains fixed here.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

Branch: docs/5520-clean-run-dir-brief-wording

kyle-sexton and others added 2 commits September 30, 2026 13:05
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Code review

  • Gather context (PR diff, changed files, prior review history)
  • Invoke /review:code-review and follow its instructions
  • Post findings as inline PR comments
  • Post summary comment

Skip-gate hit: this head already has a successful review from this lane that still applies. Current head 5a33aa1 is a merge of origin/main (renumbering disk-hygiene to 0.34.3 to sit above main's 0.34.2). I diffed the files this PR actually touches against 2d8bf60 — the commit this lane already reviewed and cleared ("No new findings," after 9 prior rounds worked through every finding Codex and this lane raised):

git diff 2d8bf60..HEAD -- plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md \
  plugins/disk-hygiene/skills/clean/SKILL.md \
  scripts/spoke-plugin-root-baseline.txt

fan-out-worker-brief.md and scripts/spoke-plugin-root-baseline.txt are byte-identical to the already-cleared commit. SKILL.md's only diff is this PR's own §1 wording (unchanged since the last pass) — the other SKILL.md hunks visible in a raw 2d8bf60..HEAD diff belong to unrelated main-branch commits (9aecb99 Windows device-name hints, b713f83 recycle-bin wording) pulled in by the merge, not this PR's diff (confirmed against gh pr diff 5571, which scopes only to the §1 hunk for this file). plugin.json/CHANGELOG.md changed only to renumber 0.34.1 → 0.34.3 and add/reorder this PR's changelog entry above the two unrelated ones that landed on main in the interim — administrative, not new content.

Content already verified in prior passes on this PR (unchanged at this head):

  • fan-out-worker-brief.md#L7-L14: the "Parent: fill the placeholders before spawning" step attributes each of <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> to its actual source — the fix for both open review threads on this PR (Codex's unverifiable hook-delivery claim, and this lane's overstated "all five from the note/probe" attribution) holds.
  • fan-out-worker-brief.md#L19-L20: "checks any call that names the engine" — accurate per destructive_guard.py's literal hygiene.py marker check.
  • SKILL.md#L167-L169: "the engine creates it (it creates the parent of --output)" — matches hygiene.py's write_json().
  • --project-dir documented as optional: matches engine_grammar.py's Flag("--project-dir", ...) (not required=True) and hygiene.py's load_policy/standing_policy_paths (an additive project-policy overlay, not part of the fail-closed gating).
  • scripts/spoke-plugin-root-baseline.txt: the fan-out-worker-brief.md count (1) still matches the file's one actual remaining ${CLAUDE_PLUGIN_ROOT} occurrence.
  • CHANGELOG.md/plugin.json: 0.34.3, correctly ordered above 0.34.2/0.34.1, no duplicate or lost entries, no merge-conflict markers in any of the five changed files.

No new findings. Every substantive issue raised across this PR's review history — Codex's P1 on the unverifiable hook-delivery claim, and this lane's finding that the "guard-values note or kill-switch probe" attribution overstated the source for <engine>/<run-dir>/<project-dir> — was fixed in earlier commits (3305b39, c443e87) and remains fixed here.

Out of scope for this lane: security angle of this diff already covered by the security-review lane on this PR (no issues found, run multiple times).

@claude

claude Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

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


Security review: no issues found

  • Gather context (PR diff, changed files)
  • Invoke /review:security-review and follow its instructions exactly
  • Post findings

Skip-gate hit: this head already has a successful security review that still applies. Current head 5a33aa1 is a merge of origin/main into this branch (renumbering disk-hygiene to 0.34.3).

git diff 2d8bf60..HEAD -- plugins/disk-hygiene/skills/clean/reference/fan-out-worker-brief.md \
  scripts/spoke-plugin-root-baseline.txt   # empty for both

fan-out-worker-brief.md and scripts/spoke-plugin-root-baseline.txt — the two files carrying this PR's non-administrative content — are byte-identical to 2d8bf60, the commit this lane already reviewed and cleared. I confirmed the PR's actual scoped diff via gh pr diff 5571: SKILL.md carries only the same run-directory wording hunk (§1, "Choose a unique run-directory path... the engine creates it") reviewed at every prior pass; plugin.json/CHANGELOG.md carry only the version bump (0.34.2 → 0.34.3) and matching changelog entry for issue #5520. The two other CHANGELOG.md entries visible in a raw 2d8bf60..HEAD diff (0.34.2: Windows device-name hints, null os_autoclean on Linux) belong to an unrelated main-branch commit (9aecb99, already on main and reviewed on its own PR) pulled in by the merge — not part of this PR's diff.

Content already verified in prior passes on this PR (unchanged at this head):

  • fan-out-worker-brief.md#L7-L18: the parent fills <hook-python>, <engine>, <data-root>, <run-dir>, and optional <project-dir> with literal absolute values before spawning a worker, since a worker can't expand ${...} shell tokens — a tightening, not a weakening. Every substituted value stays double-quoted in the templates, so no new injection surface.
  • fan-out-worker-brief.md#L21-L22: "checks any call that names the engine" (was "names hygiene.py") — <engine> resolves to that literal filename and destructive_guard.py's marker check still keys off it; accurate wording, not a weakened gate.
  • The mutation-guard rules (no apply/preview/handoff-verify/catalog/rm/del/moves, no compound shells, single invocation) are preserved verbatim.
  • --project-dir documented as optional in fan-out-worker-brief.md and SKILL.md#L167-L170 (run directory described as engine-created): matches hygiene.py's actual argparse/load_policy/write_json behavior — --project-dir is an additive policy overlay, not part of the fail-closed VCS/checkout-evidence gating.

Instruction-surface deletion lens (docs/conventions/instruction-exception-register/README.md, Gate 0 classes: irreversible-action, secret-handling, data-integrity, external-publication, legal-compliance, agent-authority): none of the reworded lines in SKILL.md/fan-out-worker-brief.md remove or soften a rule in those classes. The mutation-guard contract is carried forward verbatim.

No CRITICAL, IMPORTANT, or SUGGESTION findings.
· Branch: docs/5520-clean-run-dir-brief-wording

@kyle-sexton
kyle-sexton merged commit a96488c into main Sep 30, 2026
19 checks passed
@kyle-sexton
kyle-sexton deleted the docs/5520-clean-run-dir-brief-wording branch September 30, 2026 17:20
kyle-sexton added a commit that referenced this pull request Sep 30, 2026
…on and keep no per-path entries (#5587)

Closes #4009

## Summary

The owner decided on 2026-09-29 and 2026-09-30 that `scan --sizes-only`
keeps walking VCS and protected directories but goes through the same
large-scan confirmation gate as an ordinary unbounded walk, and sums
sizes without keeping one entry per path in memory. This PR implements
that decision.

## Fix

- `hygiene.py`: removed the `not sizes_only` exemption from both
large-scan confirmation checks (plain-target and `--root-children`
paths). VCS and protected-path walking under `sizes_only` is unchanged,
so totals stay exact.
- `scan_tree` adds sizes straight into the per-child rollup and target
total when `sizes_only` is set and appends no entries. Payload shape and
the `inventory_mode: sizes-only` / `rollup_precision` markers are
unchanged; ordinary scans and their entry cap are unchanged.
- Tests: gate test (both paths, with and without
`--confirmed-large-scan`), and a memory test (no per-path entries,
totals equal to an ordinary unbounded scan).
- Docs: SKILL.md, `scan-flags.md`, `safety-model.md`, README and the
fan-out worker brief (template carries `--confirmed-large-scan`) state
the gated behavior.
- disk-hygiene 0.30.0 to 0.30.1 with a CHANGELOG entry; released entries
are left as written and the new entry supersedes them.

## Verification

- `scripts/check-changelog-parity.sh --check`, `--check-order`,
`--check-bump origin/main`: pass.
- `scripts/validate-plugins.sh`: all manifests and the catalog
validated.
- `python3 test_hygiene.py` (549 tests), `test_engine_context.py` (8),
`test_guard_launch_monitor.py` (46), `test_kill_switch_probe.py` (20):
OK.
- `scripts/affected-tests.sh --run` reports failing suites outside
disk-hygiene's touched behavior (evals, session-flow, babysit-prs,
contract-clause coverage); these come from merged main content and are
not changed here. CI is the record.

## Related

Refs #4832 (introduced `--sizes-only`), #5336 (documented the earlier
behavior), #5571 (docs PR touching the same brief).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Sep 30, 2026
Refs: #5516

## Hold: do not merge

The `do-not-merge` label is applied. Owner condition 4 on #5516 says to
probe the guard `ask` on `apply --execute` under `bypassPermissions`
before the skill ships. Lane c was not run: the auto-mode classifier
denied the launch script and the denial was not worked around. Auto
mode, this machine's default, was not probed either. Release the hold
only after the owner runs lane c (`claude -p --permission-mode
bypassPermissions --tools Bash`, same scratch target and prompt as lanes
a and b) or accepts the gap in a comment here or on #5516. If lane c
fails open, condition 4 says fall back to A2 for that lane.

Second owner question: the argument-free kill-switch probe is not
matched by the engine-gate filter, so a delegated audit in default mode
stops at step 1 without a user allow rule for the probe. Accept that, or
add the allow rule.

Merge order: #5571 first, then this PR (see Related).

## Summary

Adds `/disk-hygiene:audit`, a model-invocable, read-only skill that runs
the kill-switch probe and one engine `scan` and reports the snapshot. It
runs no `preview` or `apply`; removal stays a separate
`/disk-hygiene:clean` run a person invokes. `clean` is unchanged. Ships
together with #5571 (#5520).

## Fix

- `skills/audit/SKILL.md` and `evals/evals.json` (three delegated-audit
cases and one negative case where "clean up my disk / delete these" must
route to `/disk-hygiene:clean`).
- The scan template takes a `<project-dir>` placeholder (a literal
absolute path, optional) in place of `${CLAUDE_PROJECT_DIR}`, and the
skill tells the parent to replace every `${...}` token and
`<placeholder>` in the fan-out worker brief with the probe's
`hook_python` and `data_root` before spawning, since a worker cannot
expand tokens.
- The inline `--plugin-dir` `data_root: null` gotcha carries a claim,
basis, as-of and recheck record. The null-`data_root` eval no longer
expects a guard denial to relay: no engine call is submitted in that
case.
- `audit` is registered in `scripts/skill-leaf-name-registry.txt` with
disk-hygiene as its 17th owner and a rationale paragraph.
- README lists the skill; plugin 0.30.0 to 0.35.0 (main took 0.31.0 to
0.34.1 for other disk-hygiene changes while this PR was open) with a
CHANGELOG entry linked to #5516; cheat sheet regenerated.
- Audit-only (toggle off) still runs the read-only scan and drops the
removal handoff, instead of stopping. The owner decision is silent on
this; the owner may overrule.

## Verification

Probe results (claude 2.1.285, worktree plugin loaded with
`--plugin-dir`, `permission-mode default`, fresh scratch target):

- Lane a, headless default: `apply --execute` denied by the guard
(`exact-engine-apply`, ask); `staging.tmp` survived.
- Lane b, `--bg` default: parked at a permission prompt on the apply;
`staging.tmp` survived.
- Lane c, `bypassPermissions`: not probed. Auto mode (this machine's
default) not probed.
- The argument-free probe is not matched by the engine-gate filter
(`Bash(*hygiene.py*)`), so a default-mode model-invoked session needs a
user approval or allow rule to run it. Under `--plugin-dir` the probe
reports `data_root` null.

Checks run locally on a9f61a8 (after merging origin/main and
renumbering 0.34.0 to 0.35.0), all exit 0: `check-skill-leaf-names.sh
--check` and its `.test.sh`; `check-adr-numbers.sh --check`;
`check-changelog-parity.sh --check`, `--check-order`, `--check-bump
origin/main`; `validate-plugins.sh`; `check-changed-skills.sh
origin/main`; `check-skill-count-claims.sh`; `check-spoke-plugin-root.sh
--check`; `check-docs-naming.sh --check`; `check-orphaned-fixtures.sh
--check`; `generate-cheatsheet.mjs --check`; `check-evals-quality.sh`
and `json.tool` on the audit evals; `hygiene.test.sh` (592 tests, 1
skipped) and `kill_switch_probe.test.sh`. The earlier "all pass" was
wrong: on 4c4faf7 CI `lint-2` failed `skill-leaf-names` (fixed by the
registry entry) and `adr-numbers` (a duplicate 0042 on main, fixed by
main's renumber, which this branch now includes).

The A2 fallback and the final call on closing #5516 stay with the owner,
so this PR uses `Refs`, not `Closes`.

## Related

#5516; #5520 / #5571 (ships together).

Merge order: #5571 lands first. This PR links its worker brief, which
still shows `${CLAUDE_PLUGIN_DATA}` and `${CLAUDE_PROJECT_DIR}` tokens
until #5571 lands. #5571 is stale: its base predates main's 0.29.2
through 0.31.0 changelog entries, so it needs a rebase and a renumber
above main's current version before it can merge. disk-hygiene versions
on main keep moving, so before this PR merges, merge main and re-run
`scripts/check-changelog-parity.sh --check-bump origin/main`,
renumbering above main's then-current version. The repo squash-merges
only, so the branch's `bump to 0.30.0` commit subject does not reach
main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

disk-hygiene: fix run-directory, fan-out brief and --project-dir wording

1 participant