fix(session-flow,discipline): drop the per-session subagent cap that no longer exists, and record the doc-currency audit - #2169
Conversation
…no longer exists, and record the doc-currency audit Pass (a) of the gate / check-skill doc-currency audit: do the claims this repo's gates and check skills make about how Claude Code behaves still match the docs? Method rule, because getting it wrong is worse than not looking: each page was asked to state its OWN current rule, never to confirm a sentence from this repo. A fetch summarizes through a small model, so "not mentioned" is a routine false negative, and a false negative read as drift means editing correct doctrine. No verbatim quote, no drift classification. VERIFIED CURRENT, by quote -- including the highest-blast-radius claim in the repo, the subagent-vs-fork context isolation the entire fresh-eyes checkpoint rule rests on: "Each subagent starts with a fresh, isolated context window... The exception is a fork, which inherits the parent conversation instead of starting fresh." Also confirmed: the agent `model`/`effort` value sets and their `inherit` defaults, frontmatter `name` optional and defaulting to the directory, the bare-alias registration, the v2.1.216 command-name history, and the `disable-model-invocation`/`user-invocable` defaults. DRIFTED, fixed here: three sites recorded "at most 200 subagents per session" (`CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION`, v2.1.212+) as a live constraint, read 2026-07-29. It was removed in v2.1.220-v2.1.224 -- "The 200-subagent-per-session cap is removed, so long-running sessions no longer refuse new subagents; the concurrency and depth limits still apply" -- and both cap and variable are gone from the sub-agents page. session-flow's orchestrate sources and SKILL, and discipline's sweep-all budget paragraph, were all planning against a ceiling that is not there. sources.md keeps it as an explicit Superseded note rather than deleting it, so a reader who remembers the cap learns what replaced it. Picked up on the same re-read: ultracode sessions are exempt from the concurrency limit, and a `/subtask` fork takes a slot but is never blocked by it. The larger finding is not drift at all, and is recorded in FINDINGS.md rather than acted on: the docs index lists 112 core pages and this repo cites 73. Among the uncited are cross-session-messaging, agent-teams, agents, feature-availability, sessions, and checkpointing -- a platform surface the doctrine has never evaluated under its own Native-first adoption gate. The Delegation-mechanics dispatch ladder is most affected: it runs generic subagent -> named agent -> cross-vendor advisor and does not know agent teams or background sessions exist. FINDINGS.md also records the week-32 changes that postdate most stamps and need their own decisions (zip-archive marketplace source, auto mode becoming the default on Aug 14, worktree isolation extending to Bash and git redirects, PreToolUse hooks no longer bypassing restrictions in internal side tasks), a usability defect in check-skill.sh's internal-ref extractor found by using it, and a method note about two local gate invocations that passed vacuously during #2161.
|
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 finished @kyle-sexton's task in 35s —— View job Security Review — PR #2169
Scope reviewed: Findings: none. This PR is a documentation-currency fix with no executable surface:
Nothing here warrants a CRITICAL/IMPORTANT/SUGGESTION finding. |
|
Claude finished @kyle-sexton's task in 3m 9s —— View job Review complete
SummaryThis is a doc-currency fix: it removes claims of a per-session subagent cap Independently verified (WebFetch against
Mechanical checks:
Not independently run: FindingsOne 🟡 nit posted inline: No other correctness, architecture, error-handling, or maintainability issues found. This is a |
|
Claude has reviewed this PR 5 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
…ntract-tier slice contract-slice-prune-gate was right to fail this: docs/topics/<slug>/ is Contract tier per the topic-docs convention -- committed on a task branch only, pruned before merge, with durable outcomes graduated to an ADR, spec, or tracker item first. FINDINGS.md was staged to merge as a permanent document, which is exactly the orphaned-artifact outcome the tier exists to prevent. Graduated to issues, then the slice deleted: - #2173 check-skill.sh resolves a cross-skill reference against the citing skill's own directory and the error names the wrong place. Found by using the gate; hit twice in #2161. - #2174 verification:measure description has no "Use when:" trigger phrasing. Pre-existing, carried as a footnote on two unrelated PRs; filed so it stops travelling. - #2175 Run the Native-first adoption gate against the six platform surfaces the doctrine has never evaluated (cross-session-messaging, agent-teams, agents, feature-availability, sessions, checkpointing). Not drift -- the question has simply never been asked, and Native-first already owns the procedure for asking it. - #2176 Decide the week-32 platform changes, with the Aug 14 auto-mode default as the time-sensitive one. The verified-current results and the method rule that produced them are preserved in this PR's own body and commit history rather than in a file that would outlive its task branch. Also takes the review nit on the discipline changelog: "the second constraint was fictional" implied the cap was never real. It was accurate when written (documented default 200, v2.1.212+) and went stale under the platform -- which is the failure mode a dated verification stamp exists to make findable, and worth saying precisely in a change whose whole subject is doc currency.
|
Claude finished @kyle-sexton's task in 57s —— View job Security Review — PR #2169
Scope reviewed: Findings: none. This PR is a pure documentation-currency fix with no executable or trust-boundary surface:
Nothing here rises to CRITICAL/IMPORTANT/SUGGENTION — this lane has nothing to flag on a docs-only change. |
|
Claude finished @kyle-sexton's task in 6m 10s —— View job Review complete
SummaryThis is the doc-currency fix removing a per-session subagent cap I also confirmed the earlier reviewer's nit ( Findings (posted inline)
Not independently run
No other correctness, architecture, or maintainability issues found. Security is out of scope for |
… what "the point" is Two review nits, one substantive. The citation swap in sweep-all replaced the env-vars link with whats-new/2026-w32, but env-vars was what sourced the paragraph's FIRST claim -- CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY, documented default 10 -- which the new link does not cover. A re-source for one claim silently unsourced another. Link restored. I could not re-verify that variable, and am saying so in place rather than letting it read as freshly checked. Two independent re-fetches of env-vars truncated before its alphabetical range, and the sub-agents page's concurrency section names only the concurrency and depth limits. That is NOT evidence of removal: the same truncated fetch returned ABSENT for CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS, which is quoted verbatim on the sub-agents page -- so ABSENT means "not in the excerpt", not "not in the docs". Calling it removed on that evidence is the false-negative-read-as-drift failure this audit's own method rule exists to prevent, and it would have edited a correct claim. The variable is marked carried-forward-and-unverified at the site, and tracked as an open item on #2176 rather than left to look current. The orchestrate nit: "which is itself the point this paragraph makes" had no clear antecedent. Named directly -- a third cap moved out from under that list after it was written, which is the reason to read current values rather than assume them.
|
Claude finished @kyle-sexton's task in 49s —— View job Security Review — PR #2169
Scope reviewed: Findings: none. This PR is a pure documentation-currency fix with no executable or trust-boundary surface:
Nothing here rises to CRITICAL/IMPORTANT/SUGGESTION — this lane has nothing to flag on a docs-only |
|
Claude finished @kyle-sexton's task in 2m 6s —— View job Code Review — PR #2169
SummaryThis review covers the state as of the latest commit (6c39519), which responds to the two nits
Both prior New findings (posted inline)
Mechanical checks
Not independently run
|
…the citation restore in the changelog Two review nits, both right. The orchestrate sentence stated the same removal twice -- once as "the per-session spawn total was removed" and again a clause later as "a third cap moved out from under this list" -- which reads as two events rather than one restated. The second clause was introduced fixing the previous round's ambiguous-antecedent nit and overshot. Dropped; the preceding sentence already carries the fact, and "read the current values rather than assuming them" is the point that needed to survive. The discipline 0.12.1 entry was silent on what the follow-up commit actually shipped. Since no second bump was taken, that entry is the only durable record of why the sweep-all citation reads the way it does -- the env-vars link restored, and CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY marked carried-forward-and-not-re-verified with its currency open rather than disproven. Now recorded there, so the changelog matches what shipped under that version.
|
Claude finished @kyle-sexton's task in 31s —— View job Security Review — PR #2169
Scope reviewed: Findings: none. This PR is a pure documentation-currency fix with no executable or trust-boundary surface:
Nothing here rises to CRITICAL/IMPORTANT/SUGGESTION — this lane has nothing to flag on a docs-only PR. Consistent with the four prior automated security-review passes on earlier commits of this PR, each independently reaching the same conclusion. |
|
Claude finished @kyle-sexton's task in 2m 58s —— View job Code Review — PR #2169
SummaryReviewed the current HEAD (
New finding (posted inline)
Mechanical checks
Not independently run
|
…aluated platform surfaces (#2177) Closes #2175 ## Summary The docs index lists 112 core `/docs/en/` pages; this repository cited 73. Six of the uncited ones are platform surfaces the doctrine had never evaluated, and its own Native-first adoption gate had never been run against any of them. Nothing in the repo was *wrong* about them — the doctrine simply predates them — but the **dispatch ladder** was handing an author a menu of delegation mechanisms that predated three of the platform's options, and the **cross-platform contract** never named its canonical availability input. This runs the gate against all six and records a verdict for each. ## Fix Verdicts, each recorded in `docs/PLUGIN-PHILOSOPHY.md` under Native-first → **Recorded gate runs**, in the [upstream-drift](https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/upstream-drift/README.md) four-part shape (claim, basis, as-of date, recheck trigger): | Surface | Verdict | Reason | Recheck trigger | |---|---|---|---| | [`agents`](https://code.claude.com/docs/en/agents) | **Adopt**, as a citation | The upstream comparison of every way Claude Code runs multiple agents. Becomes the dispatch ladder's canonical index — cited, never restated, so the menu cannot go stale inside this file. | The page adds or drops a parallelism surface. | | [`feature-availability`](https://code.claude.com/docs/en/feature-availability) | **Adopt**, as a citation | Named as the cross-platform contract's canonical input. Deliberately *not* copied: "Evidence and validation" bars restating a volatile provider matrix. | A plugin proposes narrowing its platform support. | | [`agent-teams`](https://code.claude.com/docs/en/agent-teams) | **Defer** | Fails gate 2 and stops there — "Agent teams are experimental and disabled by default", gated behind `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`, with limitations the page states outright ("No nested teams: teammates cannot spawn their own teammates"; `/resume` and `/rewind` do not restore in-process teammates). Defer rather than decline: the gap question stays open while the surface is opt-in and churning, and no plugin may depend on a team meanwhile. | The page drops the experimental warning or the env-var requirement. | | [`cross-session-messaging`](https://code.claude.com/docs/en/cross-session-messaging) | **Decline** | Fails gate 1 — the page directs it at "independent sessions that you start and steer yourself", not at skill dispatch. Could not be a portable rung either: "Claude Code doesn't offer cross-session messaging on native Windows" (this repo's primary dev machine), plus absent on Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform, and Microsoft Foundry. | The availability section stops excluding native Windows. | | [`sessions`](https://code.claude.com/docs/en/sessions) | **Decline** | Fails gate 1. Resume restores "the full history, including tool calls and results" — precisely the authoring story the inline-template conventions exist to withhold. It is the *opposite* of a fresh-eyes rung, not a missing one. | `sessions` grows a plugin-facing seam. | | [`checkpointing`](https://code.claude.com/docs/en/checkpointing) | **Decline** | Nothing to adopt, and the reason is the outcome: "Checkpointing does not track files modified by bash commands", and for any subagent other than a foreground forked skill, "rewinding doesn't restore the edits. Use git to revert them." The restored carve-out is narrow (a foreground `context: fork` skill), so a skill mutating through a shell script or a background worker states a git-based rollback and never leans on `/rewind`. | The limitations section drops either exclusion. | Two adopts land doctrine text, kept to a pointer each: - **Dispatch ladder** gains one paragraph naming `agents` as the canonical upstream comparison and pointing at the gate-run table for why the subagent rung is taken today. - **Cross-platform contract** gains one paragraph naming `feature-availability` as its canonical input, plus the ruling this run forced: a capability the platform does not ship on a supported OS is the *platform's* gap, never the "narrower, inherent platform boundary" a plugin may declare — the plugin still owes a portable path. No `docs/topics/<slug>/` directory was created; the durable outcome lives in the doctrine text, as the Contract-tier prune rule requires. Review rounds added three more edits, each closing a real gap a reviewer found (all four threads answered and resolved): - `docs/OFFICIAL-DOCS.md` gains all six pages in its **Authoring** table. They had become load-bearing citations while appearing nowhere in the index whose own warning says a needed page that is not listed must be added. - `docs/conventions/upstream-drift/README.md`'s **Adopters** registry gains a row for the gate-run table. It is the registry's first *recorded-decision* entry carrying per-row triggers rather than the divergence-at-fetch trigger its sibling tables share, so the row says so — otherwise a reader arriving from the component-stances row carries the wrong firing rule across. Recorded as **1.1.0** in that convention's own `CHANGELOG.md` (additive guidance under its stated SemVer rule). - The cross-session-messaging recheck trigger watched only the native-Windows premise, though the row also rests on the channel's stated purpose and on four provider exclusions. It now names all three, so the row cannot go stale with nothing firing. ## Verification Method: each of the six pages was fetched in full and asked to state its *own* rules — never asked to confirm or deny a sentence from this repo. Every upstream fact quoted above is verbatim from those fetches. **All six fetches returned complete pages; none truncated**, so no row rests on a "not mentioned" inference. The two *in-repo* claims a row leaned on were checked against the tree rather than asserted, and one was wrong (fixed in 4b3539a): - `grep -rn "context: fork" plugins/` — no shipped skill declares it in frontmatter, so the checkpointing carve-out is correctly described as narrow. The first draft also called the two documented exclusions "this fleet's two mutation paths"; that was false — `discipline`'s `sweep-all` applies its corrections on the main thread, which rewind *does* cover — so the row now states only the rule the page actually supports. - The first draft's agent-teams row claimed "no fleet skill needs inter-worker discussion". `session-flow`'s `orchestrate` already names agent teams as a surface the main session may reach (`SKILL.md:94`), so that census was wrong and would have contradicted a shipped skill. The row now rests on gate 2 alone, which is sufficient and verbatim. Gates run the CI way, against the committed tree, base-ref form: ``` bash scripts/check-contract-slice-prune.sh --check-diff origin/main # pass — leaves no path under docs/topics/ bash scripts/check-changed-skills.sh origin/main # pass — no changed skills bash scripts/check-changelog-parity.sh --check-bump origin/main # pass bash scripts/check-skill-portability.sh origin/main # pass — no skill files in scope npx --yes markdownlint-cli2 "docs/PLUGIN-PHILOSOPHY.md" # 0 errors ``` Docs-only diff, so no *plugin* version bump is owed. The one versioned surface touched — the `upstream-drift` convention — carries its own `CHANGELOG.md` entry (1.1.0). LF endings confirmed clean; `markdownlint-cli2` re-run clean over all four changed files. ## Related - Closes #2175 - Source: gate doc-currency audit, PR #2169 — graduated from that PR's findings slice per the topic-docs Contract-tier prune rule. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rent cap disappeared Review nit, and a real one. The paragraph opens by scoping "the platform ceiling" to DEPTH -- five layers, then nesting off, then a configurable default of three -- and its own heading is "needs a specific depth". Reusing "the ceiling moved again" for the per-session spawn total blurred two distinct caps into one, and read as "the depth default changed a fourth time", which is not what happened: depth is still where v2.1.219 left it. A paragraph whose whole job is "do not assume a fixed value" cannot afford its own transition sentence conflating which value moved. Now says a DIFFERENT cap disappeared entirely, states that depth is unchanged, and names what the removal actually changes -- how many caps there are, not where any of them sits. Pre-existing on HEAD rather than new in the last diff (introduced in 6c39519, untouched by 6c0ac20), flagged and fixed because it is live.
|
Claude finished @kyle-sexton's task in 1m 20s —— View job Code Review — PR #2169
SummaryReviewed the cumulative diff (
That was the last item still open across five prior review rounds on this PR. I re-checked the other
No new findings on this pass. Nothing left open from the prior rounds. Mechanical checks
Not independently run
|
|
Claude finished @kyle-sexton's task in 33s —— View job Security Review — PR #2169
Scope reviewed: Findings: none. This PR is a pure documentation-currency fix with no executable or trust-boundary surface:
Nothing here rises to CRITICAL/IMPORTANT/SUGGESTION — this lane has nothing to flag on a docs-only PR. Consistent with all five prior automated security-review passes on earlier commits of this PR, each independently reaching the same conclusion. |
…n misses (#2179) Closes #2173 ## Summary `check-skill.sh` check 5 resolves every bare `context/…`-shaped path against the **citing** skill's own directory. A skill citing a *sibling* skill's supporting file therefore failed as a broken internal ref — "no such file under the skill dir" — while the file plainly existed one directory over, and the message pointed at the citing skill. The author's natural next move was to look for the file where it could never be. That misdirection cost two round trips in a single PR (#2161), once in each direction. This implements issue options **(2) message** and **(1) docs**. Option (3) (narrowing extraction to link targets) is deliberately **not** implemented: prose and inline-code refs are presumed-intended coverage, and dropping them is a separate call. ## Fix - **Sibling-aware diagnosis (check 5).** When the unresolved path *also* resolves under a sibling skill of the same skills root, the finding names that sibling and the citation form that works. Still a **FAIL** — the bare form really does resolve against the citing skill, so it is wrong regardless of where the file lives; only the diagnosis gains detail. - **The sibling hit is evidence, not proof.** Because this check deliberately extracts prose and inline-code refs, a generic path (`scripts/run.sh`) can collide with an unrelated same-named sibling file. The original message — including its `hand-verify the line before fixing, may be an illustrative example` instruction — is kept **verbatim**, and the sibling evidence is appended conditionally, so both readings stay live: ```text FAIL: broken skill-internal ref: context/suppression.md (no such file under the skill dir; cited at SKILL.md:7 — hand-verify the line before fixing, may be an illustrative example). A file with that path DOES exist under sibling skill 'host': if that is the file meant, this is a cross-skill citation, and a bare path always resolves against the CITING skill's dir — write it as ${CLAUDE_PLUGIN_ROOT}/skills/host/context/suppression.md. If the names merely collide, the ref is unrelated to that sibling. ``` - **Layout-aware suggestion.** Which form is correct depends on the skills root, and the script's resolution ladder deliberately bakes no layout. A plugin-shaped root gets `${CLAUDE_PLUGIN_ROOT}/skills/<sibling>/<path>`; outside a plugin that variable is undefined, so the message names the layout-free `../<sibling>/<path>` instead of advertising a variable the consumer does not have. The plugin-shaped test itself is hoisted to a single `IS_PLUGIN_SKILL` computed once after the skill dir resolves — check 1's bare-alias branch and check 5's suggested form now read one boolean instead of restating the same layout convention twice. - **No false positives.** A path no sibling hosts keeps the original message unchanged. Sibling enumeration reuses check 3's `"$SKILLS_ROOT"/*/SKILL.md` glob (sorted, so a path present under more than one sibling names the first deterministically) and skips the citing skill. - **The two grep generators feeding the loop are untouched** — extraction behavior is unchanged. - **Docs (`docs/PLUGIN-PHILOSOPHY.md`).** Two sentences in the existing *Configuration ownership and scope* section, directly parallel to the `${CLAUDE_PROJECT_DIR}` project-path rule already there and to the section's own `Bundled plugin code and assets | ${CLAUDE_PLUGIN_ROOT}` row. No new section. `plugins/skill-quality/README.md`'s check-5 bullet and the script's own header list are updated to match. ## Verification - `plugins/skill-quality/scripts/check-skill.test.sh` — three new cases, all confirmed passing in CI (`plugin-gate` → `PASS: plugins/skill-quality/scripts/check-skill.test.sh`): - 36a: plugin-shaped root names the host sibling **and** the `${CLAUDE_PLUGIN_ROOT}` form, **and** still carries `hand-verify the line` — the caveat cannot be silently dropped again. - 36b: non-plugin root names the sibling-relative `../<sibling>/<path>` form and not the plugin-root one. - 36c: a ref no sibling hosts keeps the plain broken-internal-ref message with no `sibling skill` text (false-positive guard). - Manual reproduction against a throwaway plugin-shaped fixture reproduces the message quoted above, while a genuinely absent ref in the same `SKILL.md` still reports the unmodified `broken skill-internal ref: context/absent-file.md (…)`. - Repo gates, base-ref form against the committed tree: `check-shell-portability.sh`, `check-skill-portability.sh`, `check-changelog-parity.sh --check-bump`, `check-changed-skills.sh`, `check-contract-slice-prune.sh --check-diff` — all pass. `markdownlint-cli2` clean on the changed markdown. `shellcheck` clean and `shfmt -i 2` clean on both changed shell files. - Coverage note: the full suite was run to completion on Linux CI, not locally on Windows/Git Bash (where it is impractically slow); local Windows confirmation is limited to targeted smoke tests of the two new message branches. Nothing in the change is platform-sensitive — pure bash string ops and `-e`/`-f` tests, no `date`/`readlink`/GNU-only constructs — and `shell-portability-lint` passes. - `plugins/skill-quality` bumped to `0.15.1` with a matching `## [0.15.1]` CHANGELOG entry (patch is consistent with this plugin's history: `0.12.1` shipped a whole new check as a patch). ## Related - Closes #2173 - #2161 — the PR where the misfire was hit twice, once in each direction - #2169 — the gate doc-currency audit that recorded the finding --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Working #2176 (the week-32 sweep this PR's findings graduated into) reached the open verification item you flagged here —
The "different route to the same row" you asked for turned out to be a verbatim mirror of these docs,
Word for word what Two independent corroborations that the mirror is both faithful and post-2.1.224, rather than a stale copy agreeing with a stale claim:
The honest caveat: this is a same-day third-party mirror, not I touched nothing in |
…ges against doctrine and gate the archive source (#2180) Closes #2176 ## Summary Week 32 (v2.1.220–v2.1.224) landed after this repo's verification stamps, which cluster 2026-08-03/04/08. Every checklist item was worked against the source page's **own** current wording, all fetched 2026-08-10. Four items moved doctrine; five are checked-no-change; one was verified through a non-primary route and is flagged as such. Nothing is silently dropped. ## Fix **Auto mode becomes the default on 2026-08-14** (item 1, time-sensitive). Nothing in this repo assumed `default` permission mode — the permission-rule-hygiene convention and `claude-config`'s `audit-permission-grants` already treat auto mode as live. What was stale is the *framing*: the convention described auto mode as a state a session **enters**, which makes its anti-patterns read as latent. They are not. `docs/conventions/permission-rule-hygiene/README.md` gains a dated section recording three things — a dropped grant is now the **first** run's outcome, not a later one; "run it outside auto mode" is a downgrade rather than a remedy (kept only for the `Agent`-rule case, which has no bare-command analog); and neither the drop list nor the project/local `defaultMode: "auto"` self-grant block changes. The claim is bounded to the plans the docs bound it to: the same page still says provider-routed sessions (Bedrock, Google Cloud's Agent Platform, Microsoft Foundry, gateway) "start in your `defaultMode`, which is Manual unless you change it." **The `archive` marketplace source gets a decision and a gate** (item 2). Its platform floor is transport-level only — HTTPS, no loopback/link-local/cloud-metadata hosts, enforced on every redirect hop — and the `sha256` that pins the bytes is documented as **"Optional"**. Unpinned, one URL can serve different content on every install with nothing to detect it: the mutable-remote-artifact surface the plugin-acceptance security review denies by default. So the review now **requires** the pin (`docs/MIGRATION-PLAYBOOK.md`, criterion 6), and `scripts/validate-plugin-contracts.mjs` enforces it over `.claude-plugin/marketplace.json` rather than leaving it to a reviewer's eye. Recorded with it: the digest doubles as the version when none is declared, so a repinned archive still needs a `version` bump; and org distribution via claude.ai admin settings doesn't accept the source at all. No entry uses `archive` today — the rule governs the first that does. **Two edits replace an incident with a rule.** `source-control`'s worktree skill justified moving git calls out of pre-compute with one observed refusal from #1619, which invites a future author to retest and fold them back. v2.1.224 documented the enforcement, so the constraint now cites it — including that a command Claude Code "can't verify stays inside the worktree" is blocked on the same footing as one that would really reach the main checkout, which is why narrowing the commands cannot make the block safe again. And `claude-ops`' plugin-sync skill: an in-session `/plugin` install can now activate itself, which reads like the skill's closing reload guidance went stale. It did not — `sync` installs with the `claude plugin install` **shell** command, which "doesn't run in a session". Recording why beats leaving the next reader to relax it. ## Verification | # | Item | Disposition | |---|---|---| | 1 | Auto mode default 2026-08-14 | **Fixed** — `permission-rule-hygiene` reframed from opt-in to default; scope bounded to Pro/Max/Team. No hook, guardrail, or skill assumed `default` mode (searched for prompt-guaranteed phrasings; zero hits). | | 2 | Zip-archive `archive` source | **Fixed** — security-review clause requiring the `sha256` pin, plus a machine gate in `validate-plugin-contracts.mjs`. Gate tested both directions locally (unpinned entry fails, pinned passes, catalog restored). | | 3 | Worktree isolation extended | **Fixed (docs) + checked-no-change (guardrails)** — `guardrails` ships no worktree-boundary guard, so nothing is redundant and nothing assumed the narrower behavior; its hooks gate dangerous git verbs, hook bypass, commit convention, hardcoded paths, and secrets. The `source-control` worktree skill's constraint is now grounded in the documented three checks. | | 4 | PreToolUse auto-allow narrowed | **Checked, no change** — no hook in this repo emits `permissionDecision: "allow"`. The only `permissionDecision` producer is `context-guard/hooks/zone-gate.sh`, which emits `"deny"`. Nothing relied on the old bypass. | | 5 | `/fork` uses its own worktree | **Checked, no change** — every `fork` reference in this repo is the Agent-tool **subagent** fork (`session-flow:orchestrate`, `discipline:sweep-all`, `session-flow:handoff`), not the `/fork` slash command. No doc states or assumes that `/fork` shares the original checkout. | | 6 | Plugin activation on install | **Fixed** — no plugin README tells users to restart (all use `/plugin marketplace add` + `/plugin install`), so nothing was stale there. The substantive point is the opposite of the obvious one and is now recorded in `claude-ops` `context/scope-semantics.md`: the new in-session activation does **not** apply to `claude plugin install`, so `sync`'s reload guidance stands. | | 7 | `/review` aliases `/code-review` | **Fixed** — `plugins/review/README.md`. The plugin's own commands are unaffected (0.18.0 already made the namespaced form the only one it registers); the README now names `/review` as a fourth spelling of the bundled reviewer so the plugin isn't abbreviated onto it. | | 8 | Ultraplan removed | **Checked, left as-is (deliberate)** — the one reference, `docs/topics/context-engineering-claude-5/design/official-corroboration.md:355`, is a topic-design doc: a record of what the corroboration sweep found when written, not a live instruction. Editing it would falsify the record rather than correct doctrine, and `docs/topics/` is Contract tier where an edit invites the prune gate. Left intact. | | 9 | `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | **Verified current — but not from the primary page.** See the caveat below. | | — | 200-subagent cap removal | **Out of scope, owned by #2169** (still OPEN). It edits the same `sweep-all` region; deliberately untouched here to avoid a conflict. Corroborated independently: the `sub-agents` page's concurrency section names only the concurrency and depth limits. | ### Item 9: what could not be verified from the primary source `env-vars` truncated for a **third** time. The fetch reached `CLAUDE_CODE_DISABLE_1M_CONTEXT` and stopped — alphabetically well before the `MAX` range — and the summarizer duly reported that "no table rows exist whose variable name begins with `CLAUDE_CODE_MAX`". That is the exact false negative the method rule exists to catch, and it reproduces the earlier failure rather than resolving it. A different route reached the row. `ericbuess/claude-code-docs` is a verbatim mirror of these docs whose `docs/env-vars.md` was last synced **2026-08-10T21:32:29Z — the same day** (commit message `Update Claude Code docs - 2026-08-10 | Updated: … env-vars.md …`). It carries the row unchanged: > `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | Maximum number of read-only tools and subagents that can > execute in parallel (default: 10). Higher values increase parallelism but consume more resources That matches `plugins/discipline/skills/sweep-all/SKILL.md` word for word, so the citation is **current, not drifted**. Two corroborations that the mirror is both faithful and fresh: the same file carries `CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION` as "Removed in v2.1.224 and now a no-op" — the week-32 change #2169 is landing, which could only appear in a post-2.1.224 sync — and its `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS` row agrees with the `sub-agents` page fetched directly here. **Stated plainly: this is a same-day third-party mirror, not `code.claude.com`.** Strong evidence, one rung below a primary read. No file changes on this item — the `sweep-all` text on `main` carries no unverified marker (that marker lives in #2169's branch), so there is nothing here to correct. The finding is posted to #2169 so its author can drop the marker. ### Gates run (committed tree, base-ref form) - `check-contract-slice-prune.sh --check-diff origin/main` — pass ("leaves no path under `docs/topics/`") - `check-changelog-parity.sh --check-bump origin/main` — pass - `check-skill-portability.sh origin/main` — pass (2 skill files) - `check-shell-portability.sh origin/main` — pass (no shell files in scope) - `check-contract-clause-coverage.py` — pass - `validate-plugin-contracts.mjs`, `generate-catalog.mjs --check`, `generate-cheatsheet.mjs --check` — pass - `markdownlint-cli2` over all 8 changed markdown files — 0 errors - `check-changed-skills.sh origin/main` — still running locally when this PR opened; CI is the authority Version bumps: `claude-ops` 0.28.3→0.28.4, `review` 0.18.0→0.18.1, `source-control` 0.51.5→0.51.6. The `docs/` and `scripts/` changes need none. ## Related - #2169 — the doc-currency audit this graduated from; owns the 200-cap fix and the `sweep-all` file - Source: [`whats-new/2026-w32`](https://code.claude.com/docs/en/whats-new/2026-w32) - Pages fetched 2026-08-10: [permission-modes](https://code.claude.com/docs/en/permission-modes), [plugin-marketplaces](https://code.claude.com/docs/en/plugin-marketplaces), [worktrees](https://code.claude.com/docs/en/worktrees), [discover-plugins](https://code.claude.com/docs/en/discover-plugins), [code-review](https://code.claude.com/docs/en/code-review), [sub-agents](https://code.claude.com/docs/en/sub-agents) --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n in sweep-all (#2182) Closes #2176 Follow-on to #2180. #2176 is already closed; this lands the one edit that only became possible after #2169 merged. ## Summary #2169 landed the v2.1.224 subagent-cap removal with an honest in-place marker beside it: `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` was "carried forward from the 2026-07-29 read and NOT re-verified … its currency is open, tracked as its own item". #2176 was that item, and #2180 verified it — but the marker was not on `main` when #2180 opened (it lived on #2169's branch), and #2169 merged minutes ahead of it. So `main` now carries a settled claim that advertises itself as open and points at a closed issue. This closes that gap. ## Fix The citation is **current, not drifted**. The row reads exactly as `sweep-all` cites it: > `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY` | Maximum number of read-only tools and subagents that can execute in parallel (default: 10). Higher values increase parallelism but consume more resources The marker is **replaced, not deleted**, because the route is the load-bearing part. `env-vars` truncated before the `MAX` range for a **third** time — the fetch reached `CLAUDE_CODE_DISABLE_1M_CONTEXT` and the summarizer duly reported no rows beginning `CLAUDE_CODE_MAX`, the exact false negative this repo's method rule exists to catch. The row was read verbatim from a same-day verbatim mirror of these docs (`ericbuess/claude-code-docs`, `docs/env-vars.md`, synced 2026-08-10T21:32:29Z), whose freshness is corroborated by its carrying the v2.1.224 cap removal that #2169 just landed — a fact that cannot appear in a pre-2.1.224 sync. So the new note says what is true and no more: re-verified 2026-08-10, unchanged, **but not from the primary page** — treat it as one rung below a primary read. That neither overclaims a fetch that did not happen nor leaves a closed question looking open. ## Verification - `validate-plugin-contracts.mjs`, `generate-catalog.mjs --check`, `generate-cheatsheet.mjs --check` — pass - `markdownlint-cli2` over both changed files — 0 errors - `discipline` 0.12.1 → 0.12.2 with a matching `## [0.12.2]` CHANGELOG entry - Remaining gates: CI is the authority ## Related - #2180 — the week-32 sweep; item 9's full write-up and both verbatim quotes - #2169 — landed the marker this removes, and the cap removal that corroborates the mirror's freshness - [`env-vars`](https://code.claude.com/docs/en/env-vars) — the primary page, which has now truncated before this range on three independent fetches --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rasing (#2181) Closes #2174 ## Summary A skill `description` is the text Claude matches against to decide whether to **load** the skill, so a description shaped like a summary of what the skill *is* makes the skill under-fire. The skill-quality gate reported this on `verification:measure`: ```text WARN: description has no 'Use when:' trigger phrasing — a description is a trigger spec, not a summary ``` This fixes `measure` and sweeps the rest of the corpus, which the issue explicitly asks for. **All 196 skills were checked** — not a base-ref diff. 29 carried a check-12 warning; 25 are fixed here and 4 are deliberately left as-is with the reasoning below. ## Fix Check 12 in `plugins/skill-quality/scripts/check-skill.sh` has two branches, and the sweep found both in the wild: | Warning | Found | Fixed | Left | | --- | --- | --- | --- | | `description has no 'Use when:' trigger phrasing` | 22 | 18 | 4 | | `'Use when:' triggers are not single-quoted` | 7 | 7 | 0 | **No `Use when:` phrasing (22).** Most already had good routing phrases, but behind a lowercase `use for` the gate does not recognize (`planning:*`, `testing:*`, `toolchain:check`, `review:fanout`, `implementation:implement`, `verification:confirm`, `verification:measure`). A few named only a topic or a state and no phrase a user types (`context7:lookup`, `toolchain:lint`). **Unquoted triggers (7).** The gate's trigger-drop protection tracks only `'single-quoted'` text, so phrases written with escaped double quotes (`debugging:debug`, `docs-hygiene:compress`, `kindle-dedrm:manage`) or as a bare comma list (`repo-hygiene:clean`) had **no regression cover at all** — a later rewrite could have dropped any of them silently. Those are quoting changes; the wording is unchanged. Across the 25, **108 typed trigger phrases were added and zero existing phrases were dropped** — the gate's keyword-preservation check sees a superset, not a rewrite. This matters most on `measure`, whose base-ref trigger set includes `'cannot quantify'`: that is *prose*, not a trigger, but the extractor tracks any single-quoted span, so the natural "clean this up" rewrite would have dropped it and **failed** check 3. It is preserved verbatim. ### Deliberately left as-is (4) All four are `disable-model-invocation: true` **and** carried no pre-existing quoted phrase. A skill that cannot be model-invoked is never matched against its description, so triggers would buy no auto-invocation there — and inventing user-typed phrases for them would invite exactly the misfire this issue is about. The review round below sharpened this: dmi-true alone is not sufficient grounds, because a phrase that lives *only* on a dmi-true skill is unreachable (that is the `kindle-dedrm` finding). So for each of the four, the additional question is whether some phrase a user would type is left with no model-invocable home. It isn't: - `discipline:wait-what` — its description *is* the instruction ("Type `/discipline:wait-what` the moment you notice you are skimming; only you know when you stopped following"). Self-observation is the trigger; by construction the model cannot detect it. - `firecrawl:update`, `playbooks:update` — maintainer-only drift checks whose descriptions say "Not for consumers — consumers update via `/plugin marketplace update`". There is no user phrase that *should* route here, so nothing is stranded. Their model-invocable siblings (`firecrawl:firecrawl`, `playbooks:boris`) are both fixed in this PR and carry the consumer-facing phrases. - `github:setup` — `SKILL.md` states "User-invoked only", the plugin README lists it as "user-invoked only", and the only references to it are documentation. It is a deliberate slash command, not an orphan and not a routing target. Where a `disable-model-invocation: true` skill *already* had quoted phrases (`planning:questionnaire`), the connector is normalized to `Use when:` and nothing is invented — it is the only dmi-true skill among the 25 changed here. ### One deliberate cross-skill duplicate `kindle-dedrm:manage` carries a byte-identical copy of `'set up Kindle DRM removal'`, a trigger on its sibling `kindle-dedrm:setup`. It was invisible while double-quoted, and quoting it for tracking makes two siblings claim the same typed phrase. It is kept anyway: `setup` is `disable-model-invocation: true`, so its description is never matched against user text, and `manage` — model-invocable, with an action router that delegates to `/kindle-dedrm:setup` — is the only skill that can receive the phrase by model invocation. Dropping the duplicate would leave the phrase reachable only by an explicit slash command. A collision check over the whole corpus confirms this is the *only* overlap: the other 107 added phrases collide with nothing. ### Versioning 13 plugins touched, each with a patch bump and a matching `## [x.y.z]` CHANGELOG entry: `context7` 0.5.1, `debugging` 0.6.1, `docs-hygiene` 0.10.1, `firecrawl` 0.5.1, `implementation` 0.13.1, `kindle-dedrm` 0.7.1, `planning` 0.30.1, `playbooks` 0.8.2, `repo-hygiene` 0.9.1, `review` 0.18.1, `testing` 0.5.2, `toolchain` 0.12.1, `verification` 0.5.2. ## Verification How the sweep covered all 196 skills: the gate ships no `--all` mode — `check-changed-skills.sh` maps a base-ref diff to skill dirs — so check 12 was reimplemented against the checker's **own** `plugins/skill-quality/scripts/skill-frontmatter.sh` semantics (`extract` / `field` / `strip_quotes` / `extract_triggers`, including the intra-word-apostrophe normalization) and run over every `plugins/*/skills/*/SKILL.md`. Two fidelity controls: - Spot-checked against the real `check-skill.sh` on one skill from each warning class (`verification:measure`, `docs-hygiene:compress`) — same classification both times. - The only place the reimplementation could diverge from the awk is block-scalar / trailing-comment handling. **No SKILL.md in the corpus uses a block-scalar `description:` or `when_to_use:`** (`grep -c '^description: *[|>]'` over all 196 = 0), so both take the plain-scalar path. - The authoritative confirmation is CI: `check-changed-skills.sh origin/main` runs the *real* checker over exactly the 25 changed skills. Gates run locally on the committed tree, base-ref form: | Gate | Result | | --- | --- | | `scripts/check-changelog-parity.sh --check-bump origin/main` | pass | | `scripts/check-changelog-parity.sh --check` | pass | | `scripts/check-skill-portability.sh origin/main` | pass — no unexcused coupling tokens in 25 skill files | | `scripts/check-contract-slice-prune.sh --check-diff origin/main` | pass | | `markdownlint-cli2` over all 38 changed `.md` | pass — 0 errors | | Trigger preservation + listing cap, all 25 | pass — 0 dropped, max listing 951/1536 | | Cross-skill trigger collision, whole corpus | pass — 0 collisions | | Line endings | all changed files `i/lf w/lf` | `scripts/check-changed-skills.sh origin/main` — the gate that reported the original warning — runs green in CI as `skill-quality-gate` over all 25 changed skills. It was also run to completion locally on `measure` alone, before the sweep was layered on: `PASS — 0 errors, 0 warning(s)`, `all 4 base-ref trigger phrase(s) preserved`. Post-change sweep: **192 of 196 skills clean**, the remaining 4 being the documented exemptions. ## Related - Closes #2174 - Surfaced during #2161 (touched `measure/context/metrics.md`, not the frontmatter) and carried again as a noted follow-up on #2169 - Gate: `scripts/check-changed-skills.sh`, `plugins/skill-quality/scripts/check-skill.sh` check 12 - Trigger-drop protection this relies on: `check-skill.sh` check 3 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rt claims, record upstream corroboration (#2184) No linked issue ## Summary Doc-currency **pass (b)**, never run before. Pass (a) (#2169) asked whether the repo's claims about how Claude Code *behaves* were still factually current. This pass asks the harder question: **is the doctrine these gates enforce still the right rule**, given current authoritative guidance? Scope was doctrine a gate, check skill, or CI script actually enforces. Every source was asked to state its own position; no supersession is claimed without a verbatim quote from the page itself. Two things had quietly diverged, both in `### Model tiers` / `### Effort tiers`. The rest held, and several items are now backed by upstream text that did not exist — or was not cited — when they were written. ### Per-item verdicts | Item | Verdict | Basis | |---|---|---| | Fresh-eyes checkpoints — bias classes, mandatory fresh-context non-fork delegation | **Still sound, now upstream-stated** | `sub-agents`: "Each subagent starts with a fresh, isolated context window… The exception is a fork, which inherits the parent conversation instead of starting fresh." `best-practices` now states the *doctrine* too: a fresh context "improves code review since Claude won't be biased toward code it just wrote"; a verification subagent exists "so the agent doing the work isn't the one grading it" | | Fresh-eyes — inline-template conventions | **Sound but incomplete → one bullet added** | `best-practices` "Add an adversarial review step" names a failure the doc did not carry: "A reviewer prompted to find gaps will usually report some, even when the work is sound", and chasing all of them "leads to over-engineering" | | Fresh-eyes — deterministic-gate exemption | **Still sound** | `best-practices` ranks a Stop hook and a verification subagent as distinct rungs of the same "give Claude a way to verify its work" ladder; nothing contradicts the narrow reach | | Naming — imperative grammar vs upstream gerunds | **Still sound; justification re-grounded** | The doc *characterized* the upstream position; it now quotes it. Gerunds are what that page says to "consider using", `process-pdfs` sits under "Acceptable alternatives", and "inconsistent patterns within your skill collection" is under Avoid | | Naming — fixed verb table, exceptions list, leaf-name registry | **House convention, no upstream position** | Upstream takes no position beyond charset limits and collection consistency. Stands on its own stated rationale; does not masquerade as backed | | Setup contract — required-iff criteria, `check`+`apply`, closed verb set | **House doctrine, no upstream position** — now labeled | No official page takes a position on a consumer-facing `setup` skill. `disable-model-invocation: true` *is* backed: upstream's own rule is "for workflows with side effects that you want to trigger manually" | | Setup — native init idioms (`Setup` hook event, `SessionStart`) | **Still sound** | `Setup` event and its `--init-only` / `--init` / `--maintenance` framing unchanged on the hooks reference | | Instruction economy — line budgets, progressive disclosure | **Still sound** | "Keep SKILL.md body under 500 lines for optimal performance" verbatim, twice on the page (`check-skill.sh` check 4). The 200-line soft target is house convention, correctly labeled advisory. "Avoid deeply nested references" is carried, correctly attributed | | Instruction economy — the two quoted rules | **Still sound** | Both verbatim on `best-practices` today, unchanged | | Delegation mechanics — dispatch ladder, named-agent bar | **Still sound** | Subagent isolation and `tools` frontmatter unchanged; the Agent tool still exposes `model` and no effort counterpart (live schema, 2026-08-10) | | **Model tiers — `availableModels` blocked pin** | **Superseded → fixed** | Doc recorded the branch as "unresolved upstream, and stated here as such". Upstream now resolves it per surface: a subagent override "falls back to the subagent's inherited model", except a family alias on the Anthropic API substituting to "the newest permitted version of its family" (v2.1.222); a skill or command override is *ignored* and "runs on the session model" | | **Effort tiers — `low` at the bulk rung** | **Incoherent against current upstream → fixed** | The model ladder's bulk row is Haiku 4.5; the effort rules told that lane to pin `low`. "Models not listed here do not support effort" and no Haiku is in that table — corroborated independently by the roster's adaptive-thinking column reading No for Claude Haiku 4.5 | | Model tiers — table rows and recheck trigger | **Still sound, trigger re-tested negative** | Opus 5 / Sonnet 5 / Haiku 4.5 current; Opus 4.8 confirmed legacy. A further family, Claude Mythos 5, appears upstream but "is not generally available" — invitation-only under Project Glasswing — so the trigger has not fired | | Model tiers — interleaved thinking | **Still sound** | "Claude Haiku 4.5 does not support interleaved thinking" and the consecutive-tool-calls carve-out are both verbatim as cited | | Model tiers — `CLAUDE_CODE_SUBAGENT_MODEL` | **Narrowed** | Still overrides both, but upstream adds an off position: "Set to `inherit` to use normal model resolution instead" (v2.1.196) | | Effort tiers — lane rules, cache caveat, the two-dials rule | **Still sound** | `sub-agents` frontmatter `effort` confirmed with all five levels; the unsupported-level fallback sentence confirmed verbatim | | Design boundary — plugins vs standalone appeal | **Sound but uncited → citation added** | `plugins` draws exactly this line: standalone for "project-specific customizations", plugins for "versioned releases, reusable across projects" | | Design boundary — horizontal decoupling, "a bare unguarded cross-plugin reference is a defect" | **House doctrine, no upstream position** | Upstream documents `dependencies` and namespacing but takes no stance on optional cross-plugin coupling. Stands on its own reasoning | | Two-lane convention posture | **House doctrine, no upstream position** | Attributed to `melodic-software/standards`, not to upstream. No masquerade | | Evidence and validation | **Still sound** | `best-practices` independently asks for evidence over assertion: "Have Claude show evidence rather than asserting success" | ## Fix Two corrections and four recorded corroborations, all in `docs/PLUGIN-PHILOSOPHY.md`. No plugin touched, so no version bump or CHANGELOG entry is owed. **Corrections** 1. **Effort tiers.** The bulk-sweep bullet now states that the two ladders do not compose at their bottom rung: effort is a per-model capability and Haiku has none, so the pin is inert rather than downgraded — and silently, since this is *not* the documented unsupported-level fallback (there is no supported level to fall back to). A lane wanting the cheapest tier takes it by model and omits the pin. Nothing in the fleet pins `haiku` today, so the defect was doctrinal, not live. 2. **`availableModels` blocked pin.** The "unresolved upstream" framing and the `enforceAvailableModels`-ordering derivation are replaced by the now-documented per-surface rule, split into its subagent and skill/command branches, which the old paragraph lumped together. The conclusion survives intact — a blocked subagent alias can still land below the session, and a blocked *cheap* pin lands on the session's own model — but the recheck trigger was pointing at a sentence that no longer carries the ambiguity, so it is rewritten too. **Corroboration recorded** - Fresh-eyes checkpoints gains the upstream statement of the doctrine (not just the mechanism), plus a fourth inline-template bullet bounding what counts as a finding. - Naming replaces a characterization of the upstream guidance with its actual words. - The setup contract cites upstream for `disable-model-invocation` and says plainly that the rest has no upstream position. - The design boundary's vague appeal gains its citation. **Stamps** refreshed only on pages actually fetched this session: `sub-agents`, `model-config`, `code.claude.com` `best-practices`, `plugins`, `hooks`, `agent-skills/best-practices`, platform `thinking`, `models/overview`. ## Verification ```text bash scripts/check-contract-slice-prune.sh --check-diff origin/main # pass bash scripts/check-changed-skills.sh origin/main # pass (no skills changed) bash scripts/check-changelog-parity.sh --check-bump origin/main # pass bash scripts/check-skill-portability.sh origin/main # pass (no skills in scope) npx --yes markdownlint-cli2 "docs/PLUGIN-PHILOSOPHY.md" # 0 errors ``` Fleet grep confirms the effort finding is doctrinal only: `git grep -n '^model:' -- 'plugins/*/agents/*.md'` returns no `haiku` pin, and every `effort:` pin sits on an `opus`, `sonnet`, or `inherit` lane. **Could not verify.** Stamps left untouched on pages not fetched: `plugins-reference`, `code.claude.com` `skills`, `feature-availability`, `agents`, `agent-teams`, `cross-session-messaging`, `sessions`, `checkpointing`, `prompt-caching`, `settings`, and the platform `effort` / `thinking-steering-and-cost` pages. The **Recorded gate runs** and **Component stances** tables therefore keep their existing dates. The `SessionStart`-plus-`${CLAUDE_PLUGIN_DATA}` half of the native-init stamp was not re-verified against `plugins-reference`, so that 2026-07-17 stamp stands even though the `Setup` half was confirmed. One upstream rule this repo does not carry, deliberately left alone as out of scope for a currency pass: `agent-skills/best-practices` asks for a table of contents in reference files longer than 100 lines. Adding it would be new doctrine, not a currency correction. ## Related - #2169 — doc-currency pass (a), the behavior-currency pass this one follows 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eferred gate calls (#2186) No linked issue ## Summary Three deferred judgment calls, all made here. **The uncited doc pages were never dispositioned, and the set is larger than recorded.** PR #2177 worked from an index of 112 core `/docs/en/` pages with ~33 uncited. Re-derived today, the index lists **135** core pages and this repo cites **78**, leaving **57** unevaluated. #2177 also demonstrated the miss rate of dismissing by eye: it took six pages that had been written off as irrelevant and found every one load-bearing enough to warrant a verdict. So all 57 get a recorded disposition here rather than a second eyeball pass. The finding that mattered is in the **cross-platform contract**. It reads one axis — the operating system — and names `feature-availability` as its canonical input. That page carries two axes, model provider and subscription plan, and scopes itself to what runs locally: "The Claude Code CLI and everything that runs locally work on every provider." The **host surface** a consumer runs in was therefore never read at all, by either the contract or its input. It has to be, because a host can withhold the plugin system itself rather than one capability, and where no plugin loads there is no portable path for one to owe. **`check-skill.sh` check 5** and **check 12's 4-skill warning floor** were both left open as "a separate call". Both are decided, at their own sites, with the reasoning recorded so neither is re-litigated from a false premise. ## Fix ### 1. Uncited-page disposition (57 pages) One stated relevance test, applied to all 57 so the dismissals are auditable rather than tacit: > **Relevant** if the page describes a surface a plugin author can **declare, invoke, or must > accommodate.** Otherwise **not relevant.** **Split: 1 adopt / 0 defer / 3 decline / 4 relevant-as-evidence / 49 not relevant.** Verdicts land in `docs/PLUGIN-PHILOSOPHY.md` under Native-first → **Recorded gate runs**, in the [upstream-drift](https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/upstream-drift/README.md) four-part shape (claim, basis, as-of date, recheck trigger), following #2177's form. | Page | Disposition | |---|---| | `platforms` | **Relevant → ADOPT, as a citation.** The canonical host-surface index; the axis `feature-availability` does not carry. Lands doctrine. | | `github-enterprise-server` | **Relevant → DECLINE.** A real plugin-distribution surface ("Plugin marketplaces \| ✅ Supported") — declines on need, not subject: nothing here documents a GHES-hosted mirror or fork. | | `ultrareview` | **Relevant → DECLINE.** Fails gate 1: every run is human-confirmed and metered, so no skill can reach it. | | `chrome` | **Relevant → DECLINE.** Ships as the built-in `claude-in-chrome` skill; nothing to declare. Recorded because it only *looked* cited — see the dead-link note below. | | `desktop`, `vs-code`, `mobile`, `desktop-wsl` | **Relevant → read in full as the evidence base for the `platforms` row**; no separate verdict, because they are one finding seen from four pages rather than four surfaces. Quoted verbatim in that row. | | `jetbrains` | Not relevant — false friend: "plugin" there is the JetBrains IDE plugin, a different sense. Ranked 2nd by `plugin`-keyword density and is the one page where that signal is pure noise. | | `desktop-quickstart`, `desktop-linux`, `desktop-ios-simulator`, `web-quickstart`, `troubleshoot-install` | Not relevant — install and first-run recipes; nothing declarable. | | `slack`, `claude-tag` | Not relevant on their own — delegation front ends indexed by `platforms`, which is the adopted citation; `slack` is additionally being retired for Team/Enterprise. | | `devcontainer` | Not relevant — container recipe; its only `marketplace` hit is a VS Code extension link. | | `gitlab-ci-cd`, `github-actions-cloud-providers` | Not relevant — CI recipes and provider IAM routing; zero plugin or skill surface (`gitlab-ci-cd`: 0 keyword hits). | | `amazon-bedrock`, `google-vertex-ai`, `microsoft-foundry`, `claude-platform-on-aws` | Not relevant — provider auth/IAM config; the plugin-facing consequence is the availability matrix, already adopted as `feature-availability`. | | `gateways`, `llm-gateway`, `llm-gateway-connect`, `llm-gateway-protocol`, `llm-gateway-rollout` | Not relevant — org request-routing plane between the client and a provider; no plugin declares or observes it. | | `claude-apps-gateway`, `claude-apps-gateway-config`, `claude-apps-gateway-deploy`, `claude-apps-gateway-on-aws`, `claude-apps-gateway-on-gcp`, `claude-apps-gateway-spend-limits` | Not relevant — deploying and operating Anthropic's gateway product; `gateway.yaml`, Kubernetes, spend caps. | | `self-hosted-environments`, `self-hosted-environments-quickstart`, `self-hosted-environments-configuration`, `self-hosted-environments-deploy`, `self-hosted-environments-identity`, `self-hosted-environments-reference`, `self-hosted-environments-testing` | Not relevant — standing up and operating cloud-session runners on org infrastructure. | | `admin-setup`, `authentication`, `legal-and-compliance`, `third-party-integrations` | Not relevant — enterprise deployment, identity, and policy plane; no surface a plugin declares or observes. | | `analytics` | Not relevant — but **fetched, not assumed**, because per-skill or per-plugin cost attribution would have bound instruction economy. It has none: attribution is PR-level only. (The per-skill/per-plugin usage breakdown is a consumer-side `/usage` dialog, not an authoring input.) | | `network-config` | Not relevant, and the third clause of the test is why rather than the family label: proxy, custom CA, and mTLS are **transport configured on the client**, so a skill making a network call either succeeds or sees an ordinary failure — there is nothing to declare or degrade. Its two plugin-adjacent lines are egress allowlist entries a network admin sets, not a plugin (`downloads.claude.ai` for "Plugin executable downloads"; `storage.googleapis.com` for "plugin metadata shown in `/plugin`"). | | `corporate-launcher` | Not relevant, checked against the page rather than dismissed as admin tooling: `CLAUDE_CODE_PROCESS_WRAPPER` wraps "every process Claude Code launches **from its own binary** — the background service, every session it hosts in agent view, and Claude Code's relaunches after an update". A plugin's `${CLAUDE_PLUGIN_ROOT}/bin/` invocation is a Bash-tool subprocess, not a Claude Code self-spawn, so the `bin/` stance is unaffected and owes no change. | | `champion-kit`, `communications-kit` | Not relevant — internal-advocacy and rollout-comms collateral. | | `accessibility`, `keybindings`, `terminal-config`, `voice-dictation`, `fullscreen`, `fast-mode` | Not relevant — consumer client settings; no plugin declares or must accommodate them. | | `prompt-library` | Not relevant — copy-paste prompts for users, not an authoring surface. | **Doctrine added — one paragraph, plus four table rows.** The cross-platform contract gains the host axis, citing `platforms` and restating none of its facts. The three verbatim host facts (Desktop-in-WSL sessions lack "connectors and plugins"; `/plugin` "[doesn't] work from the app" on mobile; Desktop's Cowork tab sources plugins "not from the CLI's `~/.claude` directory") live in the gate-run row, where they carry a recheck trigger — not in the contract, which states only the rule they establish. **A dead citation, deliberately not fixed.** Every doc URL this repo cites was checked live — all 81 slugs plus the 4 subpath citations (`agent-sdk/overview`, `agent-sdk/agent-loop`, `agent-sdk/plugins`, `whats-new/2026-w32`). **84 of 85 return 200.** One does not: `code.claude.com/docs/en/browser` now 404s (`chrome` is the live page). Its sole occurrence is `plugins/playbooks/skills/boris/vendor/SKILL.md:938` — a **verbatim upstream baseline kept for drift detection**, which the plugin README says to treat as untrusted and which `/playbooks:update` owns. Hand-editing it would corrupt the vendor SHA it exists to compare. Recorded in the `chrome` row with that path as its recheck trigger instead. ### 2. `check-skill.sh` check 5 — KEEP the extractor as-is (decided, recorded at the site) Two premises are usually offered for narrowing to markdown-link targets. Both are false, and the comment now says so, because the premise is what keeps the question alive: 1. **"It matches bare paths in prose."** It does not, and never did. Both generators are delimited — backtick-wrapped, or a `](…)` link target — and both are scoped to the `INTERNAL_DIRS` allowlist. Naked prose cannot match. (#2179's own summary and CHANGELOG entry describe it as extracting "prose and inline-code refs"; the in-script wording is corrected here to match what the greps do.) 2. **"The backtick branch is redundant."** Measured over the 196-skill corpus rather than argued: | Measure | Count | |---|---| | Backtick-form refs, all SKILL.md | 282 | | Link-form refs, all SKILL.md | 475 | | **Unique backtick-form refs with no link form anywhere in the same file** | **122** | | …spread across | **39 skills** | | …of those 122, resolving to a real file today | **122 (100%)** | Narrowing would drop 122 real, currently-resolving supporting-file references across 39 skills. The link branch being the larger share is not the question; the overlap is, and 122 refs sit outside it. The false-positive risk that motivated the proposal is real but **latent, not observed** — zero on the current corpus. It is handled by message wording (every failure carries `hand-verify the line before fixing, may be an illustrative example`) rather than by deleting coverage of 39 skills. Reopen only if a false positive is actually observed. ### 3. Check 12's 4-skill warning floor — INTENTIONAL, no dmi carve-out (all 4 confirmed) #2181's reasoning holds, and upstream states the premise more strongly than #2181 did. The skills doc's frontmatter-behavior table gives, for `disable-model-invocation: true`: **"Description not in context, full skill loads when you invoke"** — so trigger phrasing on such a skill cannot route anything, at all. `user-invocable` defaults to `true` (confirmed on the same page, not assumed), so `github:setup` omitting it is slash-command-only, exactly its declared contract. The load-bearing half of #2181's argument is the *stranded-phrase* test, which is an empirical claim about the current tree, so each was re-checked against the tree rather than against #2181's prose: | Skill | Verdict | Confirmed against the tree | |---|---|---| | `discipline:wait-what` | **Right to leave** | Its description *is* the instruction; the trigger is noticing you have stopped following. No sibling needed — by construction the model cannot detect it. | | `firecrawl:update` | **Right to leave** | Maintainer-only. Sibling `firecrawl:firecrawl` **verified** to carry the consumer phrases (`'scrape this page'`, `'crawl this site'`, `'WebFetch is blocked'`, …). Nothing stranded. | | `playbooks:update` | **Right to leave** | Maintainer-only. Sibling `playbooks:boris` **verified** to carry `'how does Boris use Claude Code'`, `'Claude Code workflow tips'`, `'optimize my CLAUDE.md'`, … Nothing stranded. | | `github:setup` | **Right to leave** — the weakest of the four as originally argued, and it holds | #2181 argued from intent ("user-invoked only"). Checked instead for a stranded phrase: model-invocable siblings `github:advise` and `github:audit` carry the plugin's consumer-facing routing, including `'help me set up Y'`. `setup` covers plugin *prerequisites* (gh auth, writing `.claude/github/`), which is a deliberate slash command, not a routing target. | **No carve-out is added**, and that is the recorded call. Exempting dmi-true from check 12 would suppress a warning that is doing no harm while hiding the `kindle-dedrm` failure mode #2181 itself surfaced — a phrase reachable only from a skill the model can never match. The floor stays; the exemptions stay documented at the check-12 site. ## Verification **Method.** Every page was fetched with `curl -sL …/<slug>.md` — the raw markdown, not WebFetch. That removes the summarizer and the truncation window from the loop entirely, so the METHOD RULE holds trivially: every upstream sentence quoted in this PR and in the doctrine is verbatim from a complete page, and a genuine "the page never states X" is a checkable claim rather than a routine false negative. Byte counts confirm no truncation (e.g. `desktop.md` 96,288 bytes, `vs-code.md` 49,764). No page was asked to confirm a sentence from this repo. **The uncited set was re-derived, not inherited.** The grep was also re-run with **no `--include` filters** to be sure no citation lives in a file type the filter misses — identical result, 81 slugs, so 57 uncited is the real number. **Every cited URL was checked live**: 84 of 85 (81 slugs + 4 subpath citations) return 200; the single 404 is the vendored `browser` link described above. **The gate-1 check that decided the headline adopt** was run against the page rather than assumed: `feature-availability`'s section headings are *Availability by model provider*, *Availability by subscription plan*, and *Model availability* — no host-surface axis — and its only feature table header row is `| Feature | Pro | Max | Team | Enterprise |`. Had it carried a host axis, `platforms` would have been a redundant second index and this would be a decline instead. Gates run the CI way, against the **committed** tree, base-ref form: | Gate | Result | |---|---| | `bash scripts/check-contract-slice-prune.sh --check-diff origin/main` | pass — leaves no path under `docs/topics/` | | `bash scripts/check-changelog-parity.sh --check-bump origin/main` | pass | | `bash scripts/check-changed-skills.sh origin/main` | pass — no changed skills | | `bash scripts/check-skill-portability.sh origin/main` | pass — no skill files in scope | | `bash scripts/check-shell-portability.sh origin/main` | pass — no unexcused GNU-only constructs | | `npx --yes markdownlint-cli2` over all 3 changed `.md` | **0 errors** | | `shellcheck` + `shfmt -i 2 -d` on `check-skill.sh` | clean | | `bash -n check-skill.sh` | clean | | Line endings | all 5 changed files `i/lf w/lf` | Because the change to `check-skill.sh` is comments only, `check-changed-skills.sh` exercises nothing — so the script was run directly to prove it still parses and behaves: - `check-skill.sh measure` → `PASS — 0 errors, 0 warning(s)`, `all 10 base-ref trigger phrase(s) preserved`. - `check-skill.sh wait-what` → `PASS — 0 errors, 2 warning(s)`, one of which is verbatim `description has no 'Use when:' trigger phrasing` — confirming the documented floor still fires as described rather than being silently suppressed. - `check-skill.test.sh` runs to completion in CI (`plugin-gate`); locally on Windows/Git Bash it is impractically slow, per the coverage note #2179 recorded. Nothing here is behavioral. `plugins/skill-quality` → **0.15.2** with a matching `## [0.15.2]` entry. The `docs/` changes are docs-only and owe no plugin bump; the `upstream-drift` **Adopters** registry already carries a row for the gate-run table (added in #2177), and these rows join that table rather than create a new adopter, so that convention needs no version change. `docs/OFFICIAL-DOCS.md` gains the four newly load-bearing pages, per the rule its own warning states and the precedent #2177's review set: a needed page that is not listed must be added. No `docs/topics/<slug>/` directory was created — the durable outcome is doctrine text, as the Contract-tier prune rule requires. ## Review rounds Three threads, all real, all answered and resolved. Each found a defect in the *basis* of a row rather than in its verdict, which is the failure mode a decision record most needs caught: a verdict outlives the reasoning nobody re-reads. - **The GHES row's premise was overstated and its trigger fired on arrival** (`chatgpt-codex-connector`). It claimed "every plugin README ships the github.com shorthand". Re-derived from the tree: 54 of 65 carry the literal string, 9 carry no install block, `dometrain` points at another github.com marketplace, and `plugins/github/README.md` — deliberately marketplace-agnostic — uses the `<marketplace-owner>/<marketplace-repo>` placeholder. All are still `owner/repo` shorthand, so the trigger now names the form that actually signals a non-github.com host, a **full git URL**, of which the tree has none. The verdict stays Decline, but the review surfaced a real finding that had been waved through and is now recorded in the row: a consumer redistributing the `github` plugin from a GHES-hosted marketplace would follow that README and have the shorthand silently resolve to github.com instead of their own instance. - **"Platform" was doing two jobs** (`chatgpt-codex-connector`). The existing `feature-availability` row and `docs/OFFICIAL-DOCS.md` both described that page as covering "platform, provider, and plan", while this change rests on the host axis being absent from it. Both senses of the word in one table would let a future audit read the host axis as already covered and retire the new row as redundant. The page's own sense is the **provider** platform — its axis headings are *Availability by model provider* and *Availability by subscription plan* — and both sites now say so explicitly. - **The `platforms` row claimed four evidence pages and quoted three** (`claude`). Correctly diagnosed as a missing fact rather than an overstated page: `vs-code` does carry a host-axis fact, and the most directly plugin-relevant of the four — its CLI-vs-extension table gives `Commands and skills` as `All` for the CLI against `Subset (type / to see available)` for the extension, so a skill this fleet ships may not be reachable there. It is now quoted in the row. All gates and `markdownlint-cli2` re-run clean over the changed files after these edits. CI is green, including `plugin-gate` — which runs `check-skill.test.sh`, the only executable proof that the check-5 comment insertions changed no behavior. ## Related - #2177 — established the Recorded-gate-runs table and its four-part row form; this run extends it and corrects its page census (112 → 135 core pages, ~33 → 57 uncited) - #2179 — deferred the check-5 extractor question as "a separate call"; decided here - #2181 — swept 196 skills for `Use when:` phrasing and left 4 with stated reasoning; all 4 re-reviewed and confirmed here - #2169 — the gate doc-currency audit these findings trace back to --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The repo carries ~291 dated verification stamps (`verified`/`fetched`/`as of` 2026-MM-DD) spanning 2026-07-15 to 2026-08-08. PR #2169 re-verified only the ~8 claims a gate or check skill directly enforces; the rest had gone unchecked for up to four weeks, which is exactly the drift a dated stamp exists to surface. A stamp nobody re-reads is worse than no stamp: it advertises a currency the claim does not have. WHY THE VERIFICATION IS TRUSTWORTHY THIS TIME. Previous passes fetched pages through WebFetch, which summarizes through a small model and truncates long pages, so "the page does not say that" was a routine false negative and no negative claim could be settled. This pass reads `https://code.claude.com/docs/en/<page>.md`, which returns the complete raw markdown source (hooks alone is 249 KB), and greps it. Every CONFIRMED claim here is backed by a verbatim string match against the full page, and the two negatives asserted below are sound because the whole page was in hand. WHAT MOVED. 50 stamps on claims re-confirmed by verbatim quote had their dates refreshed to 2026-08-10. Two claims are corrected: - `scripts/check-silent-skips.sh` said exit-0 hook stderr is "discarded entirely". The hooks reference says it "goes to the debug log only, never the transcript, and Claude never sees it". The gate's conclusion is untouched — a debug-only sink is not a visibility surface — but the comment now states what upstream states. - `context-guard`'s reader contract quoted a statusline sentence, "Before v2.1.132 these were cumulative session totals", that upstream has since removed. The dead quote is replaced with an explicit sourcing-status note. The 2.1.132 floor itself is deliberately kept: it is conservative, dropping it could only widen which payloads the token shape trusts, and the misfire it prevents is silent. WHAT WAS NOT CHECKED, AND WHY. CHANGELOG entries and `docs/topics/**` records describe what was true when written — re-dating them would falsify the record, so they were read only to confirm that character and left alone. `env-vars` claims were skipped by assignment. Claims sourced to platform.claude.com, github.com, or this repo's own gate runs are outside a Claude Code docs pass. Full coverage table in the PR body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m
The repo carries ~291 dated verification stamps (`verified`/`fetched`/`as of` 2026-MM-DD) spanning 2026-07-15 to 2026-08-08. PR #2169 re-verified only the ~8 claims a gate or check skill directly enforces; the rest had gone unchecked for up to four weeks, which is exactly the drift a dated stamp exists to surface. A stamp nobody re-reads is worse than no stamp: it advertises a currency the claim does not have. WHY THE VERIFICATION IS TRUSTWORTHY THIS TIME. Previous passes fetched pages through WebFetch, which summarizes through a small model and truncates long pages, so "the page does not say that" was a routine false negative and no negative claim could be settled. This pass reads `https://code.claude.com/docs/en/<page>.md`, which returns the complete raw markdown source (hooks alone is 249 KB), and greps it. Every CONFIRMED claim here is backed by a verbatim string match against the full page, and the two negatives asserted below are sound because the whole page was in hand. WHAT MOVED. 50 stamps on claims re-confirmed by verbatim quote had their dates refreshed to 2026-08-10. Two claims are corrected: - `scripts/check-silent-skips.sh` said exit-0 hook stderr is "discarded entirely". The hooks reference says it "goes to the debug log only, never the transcript, and Claude never sees it". The gate's conclusion is untouched — a debug-only sink is not a visibility surface — but the comment now states what upstream states. - `context-guard`'s reader contract quoted a statusline sentence, "Before v2.1.132 these were cumulative session totals", that upstream has since removed. The dead quote is replaced with an explicit sourcing-status note. The 2.1.132 floor itself is deliberately kept: it is conservative, dropping it could only widen which payloads the token shape trusts, and the misfire it prevents is silent. WHAT WAS NOT CHECKED, AND WHY. CHANGELOG entries and `docs/topics/**` records describe what was true when written — re-dating them would falsify the record, so they were read only to confirm that character and left alone. `env-vars` claims were skipped by assignment. Claims sourced to platform.claude.com, github.com, or this repo's own gate runs are outside a Claude Code docs pass. Full coverage table in the PR body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m
#2187) No linked issue ## Summary The repo carries **327 dated verification stamps** (`verified` / `fetched` / `as of` 2026-MM-DD), spanning 2026-07-15 → 2026-08-08. PR #2169 re-verified only the ~8 claims a gate or check skill directly enforces. The rest had gone unread for up to four weeks — which is exactly the drift a dated stamp exists to surface. A stamp nobody re-reads is worse than no stamp: it advertises a currency the claim does not have. This PR re-verifies **72 stamps** against the live upstream pages and reports honestly on the 49 upstream claims it did not reach. ### The method change that makes this pass different Earlier passes fetched docs through `WebFetch`, which summarizes through a small model and **truncates long pages**. Under that route "the page doesn't say that" is a routine false negative, so no negative claim can be settled and no drift classification is safe. This pass reads **`https://code.claude.com/docs/en/<page>.md`**, which returns the complete raw markdown source (`content-type: text/markdown`), and greps it: | page | raw bytes | | :-- | --: | | `hooks.md` | 249,026 | | `settings.md` | 290,489 | | `changelog.md` | 525,429 | | `sub-agents.md` | 96,094 | | `plugins-reference.md` | 90,982 | Every CONFIRMED claim below is backed by a verbatim `grep -F` match against the full page. Two **negative** claims are now assertable for the first time, because the whole page was in hand rather than a truncated slice: - `docs/conventions/hook-observability/README.md` — no native "verbose hooks" toggle exists. - `plugins/claude-memory/skills/stateless/reference/official-guidance.md` — no settings-precedence exception bullet names `autoMemoryEnabled`, `CLAUDE_CODE_DISABLE_AUTO_MEMORY`, or auto memory. One caution for the next person: markdown **link flattening** causes false misses. Four `sub-agents` quotes appeared to have vanished until inspection showed the only difference was `[fork](#fork-the-current-conversation)` becoming `a fork`. All four were verbatim-intact. Grep on a link-free fragment. ## Fix ### Drift found and corrected (3) **1. `scripts/check-silent-skips.sh` — exit-0 stderr is not "discarded entirely".** The gate comment claimed exit-0 hook stderr is "discarded entirely". The hooks reference says: > Stderr from a hook that exits 0 goes to the debug log only, never the transcript, and Claude never sees it. The debug log is the one place it survives. **The gate's conclusion is untouched** — a debug-only sink is not a visibility surface, so a `>&2`-only notice on an exit-0 skip path is still invisible to both user and agent. The comment now states what upstream states, and records the correction so the next reader does not re-derive it. **2. `context-guard` — the 2.1.132 token-semantics floor lost its upstream source.** `reference/reader-contract.md` quoted the statusline page as saying *"Before v2.1.132 these were cumulative session totals"*. That sentence **is no longer on the page**, and the version number went with it. What the page still states is only the present-tense semantics the floor depends on — "Token counts currently in the context window, from the most recent API response". The dead quote is replaced with an explicit sourcing-status note; `scripts/statusline-tee.sh` carries the same note at its `cli_version` comment. **The floor itself is deliberately unchanged.** `TOKEN_SEMANTICS_MIN_VERSION` still gates the token shape at `>= 2.1.132`; no behaviour, test, or zone result moves. Dropping it could only *widen* which payloads the token shape trusts, and the misfire it guards against is silent — a pre-2.1.132 cumulative 170k in a 200k window reads as a perfectly plausible current occupancy and resolves `dumb` while the live context may be smart-zone. It stays as a conservative lower bound, now labelled as retained-not-doc-backed. Re-source before any change that relaxes it. **3. Both `statusline-shim.sh` copies cited a plugins-reference section that no longer exists.** The 14-day orphaned-cache grace period was attributed to a section titled *"Plugin cache and file access"*. Upstream renamed it to **"Plugin caching and file resolution"** (cache root `~/.claude/plugins/cache`). The behaviour cited is unchanged and still stated verbatim — but a citation whose section title has vanished cannot be followed, which is precisely the rot a dated stamp exists to expose. Both comments now name the current title and record the former one. ### Scope correction (1) `docs/PLUGIN-PHILOSOPHY.md` — the "Pages load-bearing for this document" stamp covered seven bullets, one of which is a `melodic-software/standards` file, not a Claude Code page. The refreshed stamp now says so explicitly instead of implying the whole list was re-checked. The six Claude Code pages were each re-fetched and confirmed to still carry the topics named beside them (`Plugin manifest schema`, `Version management`, `Plugin caching and file resolution`, `Persistent data directory`, `Hooks in skills and agents`, `Tag plugin releases for version resolution`, `pluginConfigs` read scopes). ### Confirmed and re-dated (no claim changed) `docs/PLUGIN-PHILOSOPHY.md` · `docs/conventions/hook-observability/README.md` · gate/hook/script comments in `check-silent-skips.sh`, `post-compact-mark.sh`, `record-rate-limit-stop.sh`, `packet-seal.sh`, `destructive_guard.py`, `skill-reference-verify.sh`, `markdown-format.sh`, `typos-format.sh`, `check-structure.sh`, both `statusline-shim.sh` · and skill bodies/references across `claude-config`, `claude-memory`, `claude-ops`, `context-guard`, `discipline`, `disk-hygiene`, `guardrails`, `implementation`, `plugin-quality`, `rate-limit-guard`, `session-flow`, `work-items`. The densest single block, `session-flow/skills/orchestrate/context/sources.md` (13 stamps), was re-checked quote by quote against `sub-agents`, `workflows`, `changelog`, and `whats-new/2026-w32`. All still match. Its 0.22.2 finding is independently re-confirmed: the sub-agents page now states outright *"There's no limit on the total number of subagents Claude can spawn over a session"*, and `CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION` appears nowhere on it. ## Verification ### Coverage — all 327 stamps accounted for **The first version of this table was wrong, and review caught it.** It was built from a single-line regex, `(verified|fetched|as of) 2026-[0-9]{2}-[0-9]{2}`. This repo hard-wraps prose, so a stamp whose keyword ends one line and whose date begins the next is invisible to it — **30 stamps were hidden that way**, and the denominator I published (291) was itself understated. The wrap-aware pattern is: ``` (verified|fetched|as of)\s*(?: \s*(?:[#>*-]\s*)?)?(2026-\d{2}-\d{2}) ``` Buckets below are disjoint and sum to the total; nothing is hidden in a residual. | Bucket | Count | Treatment | | :-- | --: | :-- | | **Dated 2026-08-10 (current)** | **104** | 72 refreshed by this PR after verbatim confirmation; 32 already current from PR #2169, #2184 and other in-flight work | | CHANGELOG entries | 69 | **Left alone.** A CHANGELOG entry describes what was true when written — re-dating it would falsify the record | | Upstream Claude Code doc — **not re-checked** | **49** | Honest gap. See below | | Repo-internal claims (no external page) | 47 | Out of scope for a docs-currency pass — recorded gate runs, this repo's own probes | | Non-upstream sources | 25 | `platform.claude.com`, `claude.com/blog`, `github.com`, `git-scm.com` — different corpus | | `docs/topics/**` | 29 | **Left alone.** Records of what was true when written; Contract tier, gated | | `env-vars`-cited | 4 | Skipped by assignment — a parallel agent owns that route | | **TOTAL** | **327** | | The brief estimated ~260; the wrap-aware regex above is the number. ### The line I drew, stated before the work started Verify, in order: (1) every `docs/PLUGIN-PHILOSOPHY.md` claim; (2) every code-comment claim inside a gate, hook, or script, since those are load-bearing for behaviour; (3) skill-body and reference claims on pages obtained in full. Deprioritize READMEs and CHANGELOGs as historical record, and leave `docs/topics/**` alone. **What that leaves unchecked: 49 upstream claims**, thinly spread — `docs/conventions/loop-lane/README.md` (8), `docs/MIGRATION-PLAYBOOK.md` (4), `docs/PLUGIN-PHILOSOPHY.md` (3, each a stamp spanning a `platform.claude.com` page alongside Claude Code pages — see below), and `playbooks/**` (9, mostly `platform.claude.com`-adjacent model-calibration notes). No other file has more than 2. These are reachable by the same method and are the natural next slice; they were cut for depth over breadth, not because they are lower risk. Three `PLUGIN-PHILOSOPHY` stamps cover several pages at once, at least one of them outside this corpus. Where I verified the Claude Code pages but not the `platform.claude.com` one under the same stamp, I left the date alone rather than refresh a stamp that also vouches for a page I did not open. The same rule produced the scope correction above. **No stamp was re-dated without a verbatim quote retrieved this session.** Every one of the 12 stamps added in the review round was already backed by a quote pulled in the original sweep; none was newly assumed. **Every stamp in a file this PR claims to have verified now carries the new date.** That was not true in the first push — review caught CHANGELOG entries asserting more than the diff delivered — and the wrap-aware regex above is what makes the claim checkable rather than assertable. Bumping a date on a claim I could not locate would launder an unverified claim into a fresh stamp — strictly worse than leaving it stale, and invisible to review. Where a claim could not be confirmed it kept its old date and sits in the 46. ### Gates (CI form, committed tree) - `bash scripts/check-contract-slice-prune.sh --check-diff origin/main` — pass - `bash scripts/check-changelog-parity.sh --check-bump origin/main` — pass - `bash scripts/check-skill-portability.sh origin/main` — pass - `npx markdownlint-cli2 <43 changed md files>` — 0 errors - `bash scripts/check-changed-skills.sh origin/main` — pass (10 skills checked, 0 failed) 14 plugins touched, each patch-bumped with a `## [x.y.z]` CHANGELOG entry. Pure-`docs/` changes carry none. No `docs/topics/<slug>/` created. ## Related - PR #2184 — landed on `docs/PLUGIN-PHILOSOPHY.md` while this was in flight; rebased onto it, and its richer model/effort corrections were kept over this PR's date-only edits at every conflict - PR #2169 — the prior audit whose ~8 gate-enforced claims are treated here as fixed points and not redone - The `.md`-endpoint route was shared with the parallel `env-vars` effort, whose truncation problem it also solves --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
No linked issue
Summary
Pass (a) of a doc-currency audit on this repo's gates and check skills: do the claims they make about
how Claude Code behaves still match
code.claude.com/docs? One real drift found and fixed at threesites; every other outcome graduated to a tracked issue (see Related) rather than to a document that
would outlive its task branch.
Pass (b) — whether the enforced doctrine is still best practice — is deliberately not attempted.
Fix
The per-session subagent cap no longer exists, and three sites planned around it.
plugins/session-flow/skills/orchestrate/context/sources.md,.../orchestrate/SKILL.md, andplugins/discipline/skills/sweep-all/SKILL.mdall recorded "at most 200 subagents per session"(
CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION, v2.1.212+), read from the sub-agents page on 2026-07-29.Current: "The 200-subagent-per-session cap is removed, so long-running sessions no longer refuse new
subagents; the concurrency and depth limits still apply" (2026-w32,
v2.1.220–v2.1.224). Both the cap and its variable are gone from the reference page, which now carries
only the concurrency limit and the depth limit.
sources.mdkeeps the old claim as an explicit Superseded note rather than deleting it, so areader who remembers the cap finds out what replaced it instead of finding silence. Two riders picked
up on the same re-read:
ultracodesessions are exempt from the concurrency limit, and an in-session/subtaskfork takes a slot while it runs but is never blocked by it.session-flow0.22.1 → 0.22.2,discipline0.12.0 → 0.12.1.Verification
Method rule, because getting this wrong is worse than not looking. Each page was asked to state
its own current rule, never to confirm or deny a sentence from this repo. A fetch summarizes
through a small model, so "the page doesn't mention X" is a routine false negative — and a false
negative read as drift means editing correct doctrine on the strength of a lossy read. No verbatim
quote, no drift classification; anything without one is recorded
unverifiable.Verified current, by quote:
PLUGIN-PHILOSOPHY.md:565, :613)model:sonnet/opus/haiku/fable/full ID/inherit, "Defaults toinherit"effort:low…max, "Default: inherits from session"nameoptional, "Defaults to the directory name"check-skill-leaf-names.shderives every leaf from the directory/fancyalso invokes the skill unless another command already uses that name."disable-model-invocationdefaultfalse;user-invocabledefaulttruesetupcontract invalidate-plugin-contracts.mjsGates run in CI form against the committed tree:
check-skill-portability.sh origin/mainclean(3 skill files),
markdownlint-cli20 errors across 57 files.Claim inventory: ~260 dated stamps spanning 2026-07-15 → 2026-08-08, citing 73 distinct doc pages.
Related
The audit's other outcomes were graduated to tracked issues and the topic slice pruned, per the
topic-docs Contract-tier rule that
contract-slice-prune-gateenforces — a findings document mergedinto
docs/topics/would have been exactly the orphaned artifact that tier exists to prevent:check-skill.shresolves a cross-skill reference against the citing skill's owndirectory, and the error names the wrong place. Found by using the gate; hit twice in feat(mutation-testing): add the mutation-testing plugin and wire the measurement into tdd and verification #2161.
verification:measuredescription has no "Use when:" trigger phrasing. Pre-existing,carried as a footnote on two unrelated PRs; filed so it stops travelling.
never evaluated:
cross-session-messaging,agent-teams,agents,feature-availability,sessions,checkpointing. The docs index lists 112 core pages; this repo cites 73. Not drift —the question has simply never been asked, and Native-first already owns the procedure for asking
it. The dispatch ladder is most affected: generic subagent → named agent → cross-vendor advisor,
with no rung for agent teams or background sessions.
archive+SHA-256 pin, a
marketplace.jsonsource typevalidate-plugins.shhas never seen), worktreeisolation extending to Bash and git redirects, PreToolUse hooks no longer bypassing restrictions in
internal side tasks, and the auto-mode default landing Aug 14 as the time-sensitive one.
Method note carried into #2176 rather than lost: two local gate runs passed vacuously during #2161
(
--pathsover a hand-filtered list;--check-bumpbefore anything was committed). Run gates the wayCI runs them — base-ref form, against a committed tree.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FdBsorqGjCU4Mg5nrmgz4m