---
title: "Doctor: Version Compatibility: Feature Matrix (part 2)"
description: "Part 3 of 4 of Version Compatibility for the Doctor skill."
canonical: "https://orchestkit.yonyon.ai/docs/reference/skills/doctor/references/version-compatibility/02-feature-matrix-part-2"
---

# Doctor: Version Compatibility: Feature Matrix (part 2)

Part 3 of 4 of Version Compatibility for the Doctor skill.

> Part of the [Doctor](/docs/reference/skills/doctor) skill reference. The main page carries the skill itself; this page holds material that used to sit at the bottom of it.

### Version Compatibility

| Feature | Min CC Version | OrchestKit Usage | Degradation if Missing |
|---------|---------------|-----------------|----------------------|
| 200-subagent-per-session cap removed | 2.1.224 | The per-session spawn cap is gone; long-running sessions no longer refuse new agents. Concurrency and depth limits still apply. **Retires ork's standing "capped at 6-12, below the new 200 ceiling" immunity claim** (recorded in `shared/cc-support.json` on 2026-07-18). The ceiling it referenced no longer exists, and depth is now the only structural limit (#3324) | Docs assert immunity from a cap that no longer exists |
| `archive` plugin source | 2.1.224 | Plugins can install from a zip over HTTPS with optional SHA-256 pinning, without git or npm. ork's marketplace entry uses a local path source (`.claude-plugin/marketplace.json`); `archive` is an additional distribution channel with supply-chain pinning, not a defect to fix | Plugin distribution requires git or npm |
| long project paths no longer collide | 2.1.224 | Project paths over 200 chars could resolve to another project's session directory under a shared sanitized prefix. **Verified no-op for ork: the longest sanitized project dir on this machine is 93 chars**, and the worktree convention (`.worktrees/&lt;task&gt;` inside the repo) adds ~15 | Session list/rename/fork/delete could cross projects |
| headless cross-session messages expire | 2.1.225 | Cross-session messages no longer stay parked without a notice or expiry in headless sessions and during startup. Matters for ork's `-p` surfaces (`bare-eval`, `ci-sentinel`): a held message in a `-p` worker cannot show an approval dialog, so without expiry it parked forever | A headless worker accumulated invisible held messages |
| auto mode: safety-filter refusal isn't a block | 2.1.225 | Auto mode no longer counts a safety-filter refusal of its own permission check toward the consecutive-block limit; the action is still denied, but the model is told to move on instead of retrying. Changes the denial dynamics ork's auto-mode guards operate inside (#3331) | A refused permission check burned the consecutive-block budget |
| `SendMessage` reaches other machines by name | 2.1.225 | `SendMessage` can now **start** a conversation with a Remote Control session on another machine by name (`ListAgents` shows them as `name [ref]`), instead of only replying. **Escalates #3316**: a background ork agent that guesses a name is no longer confined to this machine, and a confirmed remote recipient is never silently swapped for a same-named local session | Cross-machine sends were reply-only, bounding the blast radius |
| plugin `settings.json` honours only 2 keys | 2.1.226 (verified-at, not introduced-at) | **A plugin's bundled `settings.json` is NOT a settings scope.** `plugins-reference.md:858` verbatim: "Default configuration applied when the plugin is enabled. Only the `agent` and `subagentStatusLine` keys are currently supported". The scope list (`settings.md:15-24`) is Managed / User / Project / Local — a plugin bundle is none of them. Everything else a plugin declares there is silently discarded: no error, no warning, no log line. ork shipped 10 top-level keys and 14 env vars in `src/settings/ork.settings.json` for months and **not one ever took effect** (measured: of the 14 env vars, every one was unset in a live session except `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`, which came from the operator's shell profile, not from ork). Three independent live proofs of the discard: `plansDirectory: ".claude/plans"` never created that directory while the default `~/.claude/plans` exists; `sandbox.enabled` + `failIfUnavailable: true` never sandboxed a Bash call nor hard-failed startup; `CLAUDE_CODE_NO_FLICKER: "1"` never overrode the operator's explicit `tui: "default"`. The inert keys were deleted in this change. **The `permissions` block is deliberately retained even though it is equally inert**, because inertness and coverage are independent arguments: deleting it loses no enforcement, but it would delete the only written record that someone intended those paths denied, and "the key was inert" must not quietly become "the risk was reviewed". Its `Read(~/.ssh/**)` / `Read(~/.aws/credentials)` / `Read(~/.netrc)` denies have never been enforced by anything — not by this discarded file, and not by a hook, because **ork registers no PreToolUse hook for the `Read` tool at all** (measured: 19 `pretool/bash/*` + 1 `pretool/write-edit/*`, no `pretool/read/*` category exists). The block stays until a real hook covers it. For plugin-private config the sanctioned path is `userConfig` -> `pluginConfigs[&lt;plugin-id&gt;].options` (`plugins-reference.md:581`), surfaced as `$\{user_config.KEY\}` and `CLAUDE_PLUGIN_OPTION_&lt;KEY&gt;`; for anything else, guide the operator to user settings or their shell profile | A plugin author believes shipped defaults are in effect when CC discarded every one of them |
| 2.1.227 changelog bullets reviewed | 2.1.227 | Closes the deliberate limit recorded in `shared/cc-support.json` on 2026-08-11, which triaged 2.1.227 from the **shipped binaries** (contract surface only) and left the changelog unreviewed. All five bullets are CC-internal with no ork surface: feature-flag tier evaluation on an expired login token, `claude-code-action` `allowed_non_write_users` on GitHub-hosted runners, `/tui` restoring a rewound conversation, slash-menu rendering, event-loop stalls | A release was recorded as triaged on one axis only |
| project memory folder no longer deleted | 2.1.228 | Session cleanup was **deleting contents inside a project's memory folder**. That is exactly where the operator memory store lives (`~/.claude/projects/&lt;slug&gt;/memory/`), so on CC &lt; 2.1.228 a cleanup pass could destroy accumulated memory files. This is a **floor argument, not an adoption**: no ork change makes it safe, only running &gt;= 2.1.228 does | Session cleanup could silently delete the memory store |
| plugin-cache cleanup spares symlinked dev checkouts | 2.1.228 | Background plugin-cache cleanup deleted a plugin's cache when its only version was a **symlinked development checkout**, ork's own dev loop, where `CLAUDE_PLUGIN_ROOT` points into the cache. Also a floor argument | A dev-checkout plugin could be garbage-collected mid-session |
| Write tool no longer requires a prior Read | 2.1.228 | Newer models may overwrite an existing file they have not read this session, matching the Edit tool's rules; older models still require the read. **Verified no-op for ork**: no hook or doc encodes a read-before-write assumption (measured: `src/hooks/src/pretool/write/` holds `architecture-change-detector.ts` + `security-pattern-validator.ts`, neither gates on a prior read) | Write hard-failed on an unread existing file for every model |
| marketplace entries merge whole | 2.1.228 | A marketplace entry redefined in a higher-precedence settings tier could inherit **another tier's custom headers**; entries now merge as whole entries. ork's `.claude-plugin/marketplace.json` declares no custom headers, so no-op, but a consumer who redefines the ork entry in user settings is now safe from header bleed | A redefined entry silently inherited foreign auth headers |
| cross-session inbox present on first run | 2.1.228 | Cross-session messaging sometimes started **without an inbox** in the first session after install or upgrade, so peer sends had nowhere to land. Relevant to #3316's delivery assumptions; no ork code change | A first-run session could drop inbound peer messages |
| `ListAgents` marks `offline` / `cloud` | 2.1.229 | Disconnected Remote Control sessions are marked `offline` and your cloud sessions labeled `cloud`. **This is the liveness primitive #3316 was missing**: a sender can now scope to live peers instead of messaging a dead name. **ork gets this for free**, because all 19 agents that grant `SendMessage` also grant `ListAgents` (see the corrected 2.1.224 row above). The "4-agent gap" first claimed here was a measurement artifact and is retracted; no ork agent can send without also being able to check liveness | A roster entry gave no signal whether the peer was alive |
| sandbox domain lists fail closed | 2.1.229 | IPv6 literals in `sandbox.network` domain lists are now bracketed (`[::1]:443`), and **ambiguous spellings are enforced fail-closed and flagged by `/doctor`**. ork's recommended starter config in `doctor/references/sandbox-posture.md` is unaffected (4 plain hostnames, no IPv6 literal, no port), but the file's "no detection API" honest-limit was partly stale, because `/doctor` now reports at least the ambiguous-spelling class. Strengthens #3322 | An ambiguous domain spelling could fail open, unflagged |
| `CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS` | 2.1.229 | Workflow fan-outs stagger same-prefix sibling agents so later siblings read the **cached prompt prefix** instead of re-paying it; set to `0` to disable. A direct token win for ork's fan-out skills (`audit-full-mapreduce`, `skill-fitness`), documented in `chain-patterns/references/dynamic-workflow-patterns.md`, which carried no concurrency or cost content before this | Every sibling in a fan-out re-paid the shared prefix |
| workflows honour container CPU limits | 2.1.229 | Dynamic workflows inside CPU-limited containers used the **host machine's** core count instead of the container's limit, over-parallelizing ork workflows in CI runners and Docker | Workflow concurrency ignored the cgroup CPU limit |
| marketplace `command` sources | 2.1.229 | A local command (for example an IDE) prints the plugin directory; it is **re-resolved each session and applied without a restart**, and `mode: "link"` uses it in place. ork ships two `git-subdir` entries today; a `command` source would give contributors a local-build channel with no reinstall. **Opportunity, not a defect** | Local plugin development required a reinstall per build |
| subagent fork on by default, `subagent_type: "fork"` first-class | 2.1.232 | Forking is on by default and fork is an explicit `subagent_type` whose subagent inherits the full conversation and prompt cache. The 2.1.212 and 2.1.221 rows above say ork's `Agent()`-based fork pattern is unaffected by `/fork` changes; this is the first release where the pattern docs needed a note (`chain-patterns/references/fork-pattern.md`, `brainstorm/SKILL.md`). Hooks match the bare `Agent` tool name and `agent-registry-validator` leaves an unknown bare word alone, so no false prompt on a fork spawn | Fork docs described implicit detection as the only route |
| Task tools removed for newest models | 2.1.233 | `TaskCreate`/`TaskUpdate`/`TaskGet`/`TaskList` are removed for the newest models unless `CLAUDE_CODE_ENABLE_TODO_TOOLS=1`. The flag is honoured only from user or managed settings, so ork cannot ship it; 34 of 37 ork agents grant the tools in frontmatter and the `TaskCreated` hook event stays registered, all of which is inert until the operator sets the flag. Documented in `agents-validation.md` and `task-dependency-patterns/SKILL.md` | Agents granted Task tools that were silently absent |
| `/commit-push-pr` stops auto-approving dangerous flags | 2.1.229 | git/gh commands carrying `--force`, `--amend`, `--no-verify` and similar are no longer auto-approved by that command. **Converges with ork's guards but does not replace them**: ork's guards key off the Bash command string across every command, not one slash command, so nothing is subtracted here | A dangerous flag rode along on an auto-approved commit flow |
| `2.1.264` never published | 2.1.264 | **Status: not applicable.** No such release exists. Verified on two independent surfaces: the upstream [CHANGELOG](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md) jumps `## 2.1.263` straight to `## 2.1.265`, and the npm registry lists `2.1.261, 2.1.263, 2.1.265, 2.1.266, 2.1.267, 2.1.268` with no `2.1.264` (`npm view @anthropic-ai/claude-code versions --json`, measured 2026-09-11). Fourth instance of a pattern already recorded here for 2.1.192, 2.1.253 to 2.1.256 and 2.1.262. Filed with an explicit verdict rather than left as a hole in the series, because a missing row and a triaged-empty result are indistinguishable to a later reader | A gap in the version series reads as an untriaged release |
| `2.1.265` release | 2.1.265 | **Status: one doc adoption (`--plugin-dir` folders), the rest free upside. No ork code change.** [CHANGELOG 2.1.265](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21265). **Introduced:** `--plugin-dir` now accepts a folder *of* plugins, where every child folder carrying a manifest loads and children added or removed while running are picked up, extending the 2.1.74 precedence row and the 2.1.128 `.zip` row documented in `configure/references/cc-version-settings.md`; a 1 GB cap on tool results saved to disk, with the in-conversation preview saying when a saved file was truncated; `user.email` and `user.groups` in Claude apps gateway telemetry. **Breaking:** `forceLoginGatewayUrl` in managed settings now makes a machine a gateway session from startup and ignores a leftover claude.ai login or API key; gateway sessions export OpenTelemetry straight to the collector named in `OTEL_EXPORTER_OTLP_ENDPOINT` instead of through the gateway relay; plugin display metadata now prefers the marketplace entry over `plugin.json` on the Installed tab and in `claude plugin details`. The gateway pair is **not applicable to ork** (zero gateway keys across `src/`, `manifests/` and `shared/`); the metadata change is benign because ork's marketplace entry and `plugin.json` agree. **Real ork surface, all of it fixes:** (1) resuming a foreground-spawned subagent rewrote its tool list and system prompt prefix, and agent teammates plus resumed subagents moved **SubagentStart hook context and preloaded skills out of the prompt prefix on later turns**, both breaking prompt-cache reuse. ork registers 3 SubagentStart hooks and preloads skills, so every delegated resume re-paid the prefix; (2) non-interactive sessions (`-p` with stream-json input, Agent SDK, cloud sessions) no longer reset the shell working directory at each new user message, so a `cd` persists across turns, the exact shape ork's headless harnesses (`bare-eval`, `ci-sentinel`) run in; (3) forked skills (`context: fork`) now stream their kickoff prompt, and with `--forward-subagent-text` their text turns, as stream-json progress events. **73 of the 107 `src/skills/*/SKILL.md` declare `context: fork`** (measured by a `^context:\s*fork$` match inside the `---` fence, source tree only, not the `plugins/` copies), so this was silent for the majority of the catalog in any stream-json consumer. An earlier draft of this row said 74, taken from `grep -l 'context: fork'`, which also counts the prose mention in `chain-patterns/SKILL.md`. Same body-grep failure the 2.1.224 row above documents; (4) `--worktree` startup checks out in parallel on git 2.32+, a free speedup for the 25 `isolation: worktree` agents; (5) a plugin path containing a backslash could bypass the symlink containment check on macOS and Linux, and plugin directories whose name begins with two dots were wrongly refused; (6) a plugin default component folder the OS cannot check is now reported in `/plugin` with its error code instead of being silently skipped; (7) resuming a workflow run whose run journal is missing now fails with a clear error instead of rerunning every agent, which covers ork's 3 workflow scripts; (8) MCP servers configured as `http` that speak only the legacy HTTP+SSE transport now fall back to SSE instead of never connecting | Subagent resumes and teammate turns re-pay the prompt prefix; `cd` does not persist across headless turns; fork-context skills emit no stream-json progress; a backslash plugin path escapes symlink containment |
| `2.1.266` gateway env revert | 2.1.266 | **Status: not applicable.** [CHANGELOG 2.1.266](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21266). A single bullet reverting a 2.1.265 regression: the undocumented `CLAUDE_CODE_USE_GATEWAY` environment variable, previously ignored unless `ANTHROPIC_BASE_URL` and `ANTHROPIC_AUTH_TOKEN` were both set, began forcing Cloud gateway sign-in on its own in 2.1.265, so setups pairing it with an API key, `apiKeyHelper` or custom auth headers failed every request with "Not signed in to the Cloud gateway". The variable on its own is ignored again and no configuration change is needed. **Verified no-op for ork: zero matches for `CLAUDE_CODE_USE_GATEWAY` across `src/`, `manifests/` and `shared/` outside this matrix row itself, which now names the variable.** Nothing introduced, nothing broken | On 2.1.265 exactly, a config setting that variable alongside an API key fails every request |
| `2.1.267` release | 2.1.267 | **Status: one adoption candidate (`maxEffortLevel`), one major free upgrade (`effort:` now honoured). No ork code change yet.** [CHANGELOG 2.1.267](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21267). **Introduced:** `maxEffortLevel`, a settings key set top-level or per model under `modelSettings`, capping the effort level on every provider including Bedrock, Vertex and Foundry while still letting a user pick lower. ork references it zero times (measured across `src/`, `manifests/`, `shared/`) and could not ship it from a plugin bundle anyway (see the 2.1.226 row), so it belongs in `configure` and `doctor` as a documented operator setting, not a shipped default. Also `--system-prompt-snapshot off`, rendering the system prompt fresh on every request for prompt iteration. **Breaking:** managed `allowedHttpHookUrls`, `httpHookAllowedEnvVars` and `allowedChannelPlugins` now admit **nothing** rather than everything when unreadable, a fail-closed flip that sits under ork's HTTP-hook surface (`src/hooks/README.md`, the 2.1.63 and 2.1.69 rows above); self-hosted-runner `--use-anthropic-git-proxy` is reported at registration and warns per session; gateway `forward_user_identity` upstreams return a 429 as-is instead of failing over, so per-user limits hold. The last two are not applicable to ork. **Highest-signal fix of the whole wave:** `effort:` frontmatter on custom commands, skills and subagents was being **ignored** on models whose default effort is still pinned (Opus 4.7, Opus 4.8, Fable 5). **All 36 ork agents and 42 ork skills declare `effort:`** (measured inside the frontmatter fence), so on those models every one of those declarations did nothing. This is the exact sibling of the 2.1.259 fix that made the `model:` pin in 39 skills take effect, and it lands the same way: a declaration ork already ships simply starts working, with no repo change. Note it also refines the 2.1.222 row above, which said a subagent's spinner shows its own `effort:`; the label was right while the value was inert. **Other ork surface:** Workflow `agent()` calls carrying large output schemas were refused outright in auto mode instead of being checked by the safety classifier, and ork's 3 workflow scripts pass schemas; resuming a transcript over 5 MB dropped parallel tool calls **and their hook output** from the reloaded conversation; `-p --resume` after `/compact` no longer inserts a spurious "Continue from where you left off." turn; and a large prompt-cache batch (byte-stable tool lists, mid-session MCP and plugin tools delivered as deferred definitions, `/model` switches no longer re-sending every tool definition, `--system-prompt` and `--append-system-prompt` subagents recording once, a print-mode conversation resumed interactively keeping its prefix) removes several of the cache-miss classes behind the #3876 measurement | `effort:` silently ignored on Opus 4.7, Opus 4.8 and Fable 5; no way to cap effort across providers; large-schema workflow agents refused in auto mode; hook output dropped when resuming a big transcript |
| `2.1.268` release | 2.1.268 | **Status: two adoption candidates, one matrix row superseded, the rest upside or not applicable. No ork code change yet.** [CHANGELOG 2.1.268](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md#21268). **Introduced:** `--json` on `claude plugin install`, `uninstall`, `update`, `enable` and `disable`, plus `errorDetails` and `noteDetails` on each row of `claude plugin list --json`. ork already parses `claude plugin list --json` in `dream/SKILL.md` and `doctor/rules/mcp-status-checks.md`, so the per-row fields are a direct doctor upgrade rather than a new dependency. Also `CLAUDE_CODE_WEBFETCH_DEADLINE_MS`, since WebFetch now fails after 300 seconds instead of hanging on a server that never finishes the response (`0` turns the deadline off); `configDirectory` in `claude auth status --json`; `gatewayInternalNetworks`, gateway `pricing:` in `gateway.yaml` and gateway CIDR startup warnings; and `claude self-hosted-runner --remove-session-state`. The gateway and self-hosted-runner items are **not applicable to ork**. **Breaking, and it supersedes the 2.1.233 row above:** the task-tracking tools (`TaskCreate`, `TaskGet`, `TaskUpdate`, `TaskList` and **now `TodoWrite`**) are offered only on Claude 3.x, Opus 4.0 to 4.7, Sonnet 4.0 to 4.6 and Haiku 4.5; anywhere else still needs `CLAUDE_CODE_ENABLE_TODO_TOOLS=1`, which a plugin cannot ship. 2.1.233 said "removed for the newest models"; 2.1.268 replaces that vague edge with a named allowlist and pulls `TodoWrite` into the same rule. **34 of ork's 36 agents grant `TaskCreate` in frontmatter** (measured inside the `---` fence, never by body grep, per the 2.1.224 correction; the two that do not are `genui-architect` and `emulate-engineer`), and the `TaskCreated` and `TaskCompleted` hook events stay registered, so the caveat in `agents-validation.md` and `task-dependency-patterns/SKILL.md` needs the allowlist wording, not just "newest models". **Second breaking change:** plain `WebFetch` deny and ask rules no longer apply to Artifact tool reads and updates; blocking or gating those now needs an `Artifact` rule or `WebFetch(domain:claude.ai)`. **Verified no-op for ork: zero `WebFetch(` rules across `src/settings/` and `manifests/`**, but a consumer who gated artifact reads behind a WebFetch deny now has an open path. **Real ork surface, all fixes:** (1) `PermissionRequest` hooks were **not firing in `--print` mode**. ork registers 4 of them, the `permission/unified-dispatcher` gate matching `Bash(git push*)`, `Bash(rm -rf*)`, `Bash(gh pr *)`, `Bash(npm publish*)` and similar, plus a Write and Edit matcher, so every headless `-p` run (`bare-eval`, `ci-sentinel`) executed with those gates silently absent. The same release also fixes policy-helper warnings not printing on headless runs; (2) `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` did not extend SessionEnd hooks carrying **no** per-hook `timeout`, which were still cancelled after 1.5 seconds, which amends the two 2.1.74 rows above. **Verified no-op for ork's own hooks: all 7 registered SessionEnd hooks declare an explicit `timeout`** (30 s, 5 s, 8 s, 15 s and so on), so only a consumer's timeout-less hook was ever affected; (3) deny and ask permission rules on symlinked directories (`/etc`, `/tmp`, `/var` on macOS, `/bin` on Linux) did not apply when a path was given by its real location, and Bash commands ignored deny rules written on a symlinked path spelling. That is the `/tmp` versus `/private/tmp` reality every macOS ork session runs in, and it hardens the recommendations in `doctor/references/sandbox-posture.md`; (4) a Read or Edit deny rule did not apply when an `env -C`, `eval` or similar command the permission checker cannot analyze sat on the same line, the same hidden-command class ork's own normalizer closed in #3288 and #3289; (5) plugin and marketplace errors printed a token or password taken from a git source URL, and `/mcp`, `/plugin`, `claude mcp list`, `claude mcp get` and MCP login errors printed secrets resolved from `$\{VAR\}` placeholders, a leak class adjacent to ork's MCP redaction hook; (6) a respawned in-process teammate could pick up tools or a system prompt from a same-named agent file in a folder that was never trusted; (7) `claude plugin validate` rejected plugin paths whose directory name begins with two dots, which the loader accepts, and plugins silently skipped a default monitors file or root `SKILL.md` that could not be checked, both of which now surface; (8) `/plugin` install, enable and disable take effect when the menu closes, so `/reload-plugins` is no longer needed afterwards, continuing the 2.1.221 install-loop row; (9) Remote Control sessions served by `claude remote-control` now show their session title instead of a generated name in `ListAgents`, which the peer and worktree-collision checks read. **Startup:** projects holding `.claude/workflows/` scripts no longer parse each script when listing them. ork ships its 3 workflow scripts under `plugins/ork/workflows/` and has no `.claude/workflows/` directory, so that one is a consumer-side win | PermissionRequest hooks and policy-helper warnings silently absent under `-p`; symlink-spelled and `env -C`-adjacent deny rules do not apply; secrets printed in plugin, marketplace and MCP output; the SessionEnd timeout env var ignored for timeout-less hooks; Task tools absent with no named model allowlist to check against |
| Function Hooks `classic.PreToolUse` rename (2.1.265 to 2.1.270) | 2.1.266 | **Status: fixture updated, no ork runtime change (ork ships no `modules` key).** In a Function Hooks module, bare `on("PreToolUse", ...)` was the one bare event name `claude plugin validate` accepted through 2.1.263. From 2.1.266 it fails with `"PreToolUse" is not an event`, and the legacy shell-hook bridge is addressed as `classic.PreToolUse`. **No CHANGELOG bullet for 2.1.265 to 2.1.270 mentions it** (the feature is still gated by `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS`), so only the #3917 canary in `cc-contract-probe.yml` saw it. **Measured on 2026-09-14:** the same one-line module is rejected by the local 2.1.268, 2.1.269 and 2.1.270 binaries, and `classic.PreToolUse` validates on all three. Because the validator checks shape and not membership (`banana.PreToolUse` also validates), the membership evidence is the binary: 2.1.270 defines a `classic.PreToolUse` dispatch site and `executePreToolHooks` routes shell PreToolUse hooks through it (8 string hits, against 0 on 2.1.263 per #3917). **Bracket:** the probe passed 2026-09-08 07:08Z on @latest 2.1.263 and first failed 2026-09-09 07:08Z on @latest 2.1.266 (npm publish times 2.1.265 at 09-08 19:05Z, 2.1.266 at 09-08 23:32Z). 2.1.265 was never probed, so the canary floor is the first measured rejection. **2.1.269 and 2.1.270 moved nothing further:** `tool.call\{tool=Bash\}`, `session.start`, `engine.create`, `prompt.submit` and `$.ui.log` are unchanged. The fixture now registers `classic.PreToolUse` and the script also asserts the bare-name rejection, so a revert is caught as well as a further rename | A module registering bare `PreToolUse` fails `claude plugin validate` on 2.1.266 and later; the CC Contract Probe read DRIFT daily from 2026-09-09 until the fixture moved |
