Skip to content

V5.5.0 beta - #205

Draft
mxriverlynn wants to merge 51 commits into
mainfrom
v5.5.0-beta
Draft

V5.5.0 beta#205
mxriverlynn wants to merge 51 commits into
mainfrom
v5.5.0-beta

Conversation

mattsnyder and others added 30 commits August 19, 2026 10:30
Introduces han-ddd as an opt-in plugin carrying the ddd-analysis skill
and seven specialist agents: domain-language-analyst,
business-capability-analyst, domain-ownership-analyst,
bounded-context-analyst, domain-map-synthesizer,
bounded-context-modeler, and bounded-context-critic.

The skill orchestrates a 12-step analysis flow: scope resolution,
repository inventory, parallel discovery across five agents
(domain-language-analyst, business-capability-analyst,
domain-ownership-analyst, han-core:structural-analyst,
han-core:behavioral-analyst), a bounded-context-modeler first pass,
a bounded-context-critic evaluation, exactly one revision pass, and
a synthesized report rendered from a references/ template into thirteen
sections (Executive Summary, Domain Landscape, Ubiquitous Language,
Business Capabilities, Current/Latent/Speculative contexts, Boundary
Problems, Context Map, Context Details, Rejected Candidates, Questions
for Domain Experts, Evidence Index).

Registers han-ddd in both marketplace manifests and updates the agents
and skills indexes. Depends on han-communication and han-core; not
bundled by the han meta-plugin.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…used agents

All seven agent role identities trimmed to under 50 tokens per
agent-domain-focus guidance. domain-map-synthesizer description tightened
to under 1024 characters.

bounded-context-analyst and domain-map-synthesizer removed: every dimension
of bounded-context-analyst is covered by the five specialized discovery
agents, and domain-map-synthesizer's synthesis and output are fully
covered by bounded-context-modeler, bounded-context-critic, and the skill's
report rendering. All references updated across agent definitions, long-form
docs, the agents index, the plugin README, and CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…analyst

"evaluate" implied structural-analyst determines whether directories
correspond to domain language boundaries — that inference belongs to
bounded-context-modeler. Changed to "surface" to accurately describe
what structural-analyst does: it surfaces S# structural findings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The "What you get back" section claimed completeness ("these named sections")
but listed 9 of 13 sections, omitting Executive Summary, Domain Landscape,
Ubiquitous Language, and Business Capabilities. Also corrects "Rejected or
Weak Candidates" to match the template name "Rejected or Weak Context
Candidates".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, restrict closing section

- Step 8.5 is now a hard gate: identifier-integrity and speculative-isolation
  errors stop the run before rendering; artifacts are preserved and validation
  failure is reported instead of "Analysis complete"
- Speculative isolation now covers Owns, Consumes, Does not own, Responsibilities,
  and Relationships fields — not only Relationships and Consumes
- DDD Strategic Relationship Overreach detection in the critic now scans every
  BCM# entry field (Purpose, Responsibilities, Capabilities, Owns, Consumes,
  Does not own, Relationships), not only Relationships fields
- Step 12 closing message is restricted to discovery-only next steps; asserting
  that a boundary violation can be fixed, prescribing a correction, or recommending
  extraction or refactoring is prohibited
- Report template Executive Summary and Boundary Problems sections carry matching
  prohibitions on remediation language and code-only strategic DDD assertions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds han-ddd:domain-visualizer, a presentation-only agent that translates
a completed DDD analysis into evidence-backed visual artifacts: domain
landscape, capability map, workflow swimlanes, state-machine diagrams,
ownership map, language collision matrix, boundary friction map, domain
question impact map, and scenario diagrams for competing interpretations.

The agent runs as the final step of /ddd-analysis after both hard gates
pass. It reads the eight persisted artifacts from the run folder and
writes Mermaid diagrams and Markdown tables to $run_folder/visuals/.
Visual generation failure is isolated — the DDD model and rendered
report remain valid regardless.

Step 12 (new) writes the rendered report to
$run_folder/synthesis/ddd-analysis.md and dispatches the visualizer.
The old Step 12 (present the report) becomes Step 13, with an Analysis
Visuals line added to its closing summary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bumps the dev-tooling group with 3 updates: [actions/checkout](https://github.com/actions/checkout), [actions/setup-node](https://github.com/actions/setup-node) and [actions/cache](https://github.com/actions/cache).


Updates `actions/checkout` from 6.0.3 to 7.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v6.0.3...v7.0.1)

Updates `actions/setup-node` from 6.4.0 to 7.0.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v6.4.0...v7.0.0)

Updates `actions/cache` from 5.0.5 to 6.1.0
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](actions/cache@v5.0.5...v6.1.0)
chore(deps-dev): bump the dev-tooling group with 2 updates

Bumps the dev-tooling group with 2 updates: [@j178/prek](https://github.com/j178/prek) and [prettier](https://github.com/prettier/prettier).


Updates `@j178/prek` from 0.4.9 to 0.4.11
- [Release notes](https://github.com/j178/prek/releases)
- [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md)
- [Commits](j178/prek@v0.4.9...v0.4.11)

Updates `prettier` from 3.9.5 to 3.9.6
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](prettier/prettier@3.9.5...3.9.6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dev-tooling
- dependency-name: actions/setup-node
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dev-tooling
- dependency-name: actions/cache
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dev-tooling
- dependency-name: "@j178/prek"
  dependency-version: 0.4.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-tooling
- dependency-name: prettier
  dependency-version: 3.9.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-tooling
...

Signed-off-by: dependabot[bot] <support@github.com>
Closes #107.

The planning chain had no checkpoint forcing an interface or data contract
into concrete, buildable form before implementation, so a "trusted" plan
could ship a shared contract as a to-be-authored deliverable and a builder
would invent it mid-build. Two additive gaps: plan-implementation never
required a contract in concrete form, and plan-work-items split one contract
across items with no rule against it.

Adds han-planning/references/contract-pinning-rule.md, owned by han-planning
and consumed by four skills. It defines what counts as a contract, what
counts as pinned, the phrases that never close one, and which stage owns
pinning it. The rule is binary: there is no deferred-with-reason state,
because an author who has one writes "TBD at build" and passes.

plan-implementation pins it: a new operating principle, a Decision-field
rule making the decision log treat a format grammar the way it already
treats a key name, a specialist-brief directive so the finding is generated
at all, and a binary aggregation check that raises an Open Question rather
than touching the spec-maturity gate's counted trip conditions.

plan-work-items keeps it whole: a shared contract is pinned in the item that
introduces it with consumers sequenced behind it, and the passive
"not draftable" flag gains an exception for a contract this breakdown itself
authors. Step 4 now reads the plan's Open Items, including the non-blocking
ones it previously never looked at.

iterative-plan-review backstops it: five keywords added to both force-up
lists and a Contract Check in the iteration checklist.

plan-a-feature records the delegation: routing rule 3 gains one carve-out so
a shared contract becomes an Open Item rather than vanishing.

check-contract-pinning.sh gives the rule a mechanical proxy, reporting four
failure classes separately and skipping fenced blocks so a worked example
never reads as a deferral. Two tests guard it beyond behavior: the two
per-skill copies stay byte-identical, and every phrase the script owns
appears in the canonical rule.
…guidance

Two conformance fixes plus one gap the contract-pinning work missed.

Script calls were fenced code blocks in five skills. The authoring guidance
(han-plugin-builder/skills/guidance/references/skill-building-guidance/script-execution-instructions.md)
requires prose with an action verb, because Claude may read a fenced block as
code to display rather than a command to run. Converted every remaining call
site: plan-a-feature, plan-a-phased-build, plan-work-items, and
han-reporting/html-summary.

plan-a-feature/SKILL.md was 501 lines, one past the 500-line ceiling. The
`T#` note lifecycle was split across Step 4 (capture) and Step 5 (flush),
which is how the two halves drift apart. Both now live in one owned
reference, references/t-note-protocol.md, carrying the qualifying tests, the
in-message accumulator form, the flush procedure, and the no-candidate case.
The file is 476 lines.

The contract-pinning change updated both force-up keyword lists in
iterative-plan-review but missed a third in plan-a-feature's
finding-resolution.md. A finding that leaves a shared contract un-pinned now
forces up to major there too, and the pure-implementation branch names the
Open Item carve-out that mechanic-routing.md added.
The CLAUDE.md repository layout named only references/ under the
han-planning skills directory, but every one of its five skills also
carries scripts/.

The plan-implementation long-form doc opened its "What you get back"
section with "Four cross-referenced files" and then listed three,
omitting artifacts/scope-boundary.md, and its summary bullet promised
"All three file paths". The section also never named the two executed
checks the skill runs before it summarizes, though the sibling planning
docs name theirs.
## Summary

- Adds a contract-pinning checkpoint to the planning chain so a shared
interface or data contract reaches concrete, buildable form before
implementation instead of being invented mid-build. Closes #107.
- One new owned rule
(`han-planning/references/contract-pinning-rule.md`) consumed by four
skills, plus one executable check with 15 Bats tests.
- Second commit is guidance conformance and is reviewable on its own:
script invocations converted from fenced blocks to prose across five
skills, and `plan-a-feature/SKILL.md` brought under the 500-line
ceiling.

## Why

The chain (`plan-a-feature` → `plan-implementation` → `plan-work-items`,
with `iterative-plan-review` as backstop) had no checkpoint forcing a
contract into concrete form, so a "trusted" implementation plan could
ship one as a to-be-authored deliverable. In the grounding incident the
ledger's entry types were named but its line grammar never was: the
schema doc shipped without it, a scanner invented a parsing regex
against the undefined format, and the real grammar was retrofitted a day
later. Zero of 17 review findings raised the gap.

Two additive gaps caused it. `plan-implementation` never required a
contract in concrete form, and `plan-work-items` split one contract
across items with no rule against it. Fixing either alone leaves the
other live.

## What reviewers should look at closely

**The rule is binary, with no deferred-with-reason state.** That was
deliberate: an author who has an escape hatch writes "the grammar
depends on the serialization library, TBD at build" and passes while
leaving the same hole.

**The new aggregation check stays out of the spec-maturity gate.** That
gate counts findings from distinct specialists, and a binary condition
bolted onto counted logic breaks it. An unpinned contract raises an
`OQ-N` instead, which the Step 6 loop already knows how to settle.

**`plan-work-items` now reads the plan's Open Items.** It previously
never looked at that section at all, so a non-blocking open item
vanished at the last stage that could see it. This came from a comment
on the issue and generalizes past contracts.

**The script is the only non-prose enforcement.** Nine of ten changes
are instructions followed by the same class of agent that missed the
gap. `check-contract-pinning.sh` reports four failure classes separately
and skips fenced blocks so a worked example never reads as a deferral.
Two tests guard it beyond behavior: the per-skill copies stay
byte-identical, and every phrase the script owns appears in the
canonical rule.

## How to verify

- [ ] `npm run lint`
- [ ] `npm test` (95 tests, 15 of them new)
- [ ] `bash
han-planning/skills/plan-implementation/scripts/check-contract-pinning.sh
<a plan file> <its folder>` against a real plan folder
- [ ] Read `han-planning/references/contract-pinning-rule.md` first;
every other change cites it

## Risk / rollback

Low. Nothing here changes an existing check's pass condition, and the
one new executable check is additive. The largest behavioral change is
that `plan-implementation` now treats an unpinned contract as reason to
keep iterating rather than to ship, which can add a round on a plan that
introduces a format. Revert with `git revert`.

## Not in this PR

- No version bump and no CHANGELOG entry; both belong to `/han-release`.
- `feature-implementation-plan-template.md` is 163 lines with no
Contents list. It is a document skeleton, so a Contents list would be
copied into every plan it generates. Left as-is deliberately.
Re-sync the vendored config, evidence, and YAGNI rule files with the
han-core canonical copies. Add the han-config-dir.sh symlink every
plugin carries and switch the ddd-analysis personal-config probe to it,
with the matching allowed-tools grant, instead of a hardcoded ~/.claude.
Trim the bounded-context-critic description under the 1024-character
target by moving the failure-mode catalog into the body where it
already lives, and align the Codex manifest capabilities with the other
plugins.
…the agent docs

Add han-ddd to the plugin table and opt-in lists in README, the plugin
index, concepts, CONTRIBUTING, and CLAUDE.md, naming domain-visualizer
where the other han-ddd agents are listed. Add a ddd-analysis chain to
the workflows map. Correct the agent long-form docs against their
sources: the critic's eighteen failure modes and legitimacy checks, the
modeler's IBN# and DC# outputs, the artifact-path briefing every
han-ddd agent receives, the visualizer's trigger conditions, and the
language analyst's structural-layout boundary. Add the Domain Concerns
report section to the ddd-analysis doc.
This PR adds `han-ddd`, an opt-in plugin that runs strategic
Domain-Driven Design analysis over an existing codebase and produces a
bounded-context and domain map, so that teams can discover where their
real domain boundaries live without hand-tracing the code themselves.

## Behavior changes

Running the new `ddd-analysis` skill dispatches five discovery agents in
parallel (domain-language, business-capability, domain-ownership,
structural, and behavioral analysts), then runs a modeling loop over
their findings: a first bounded-context pass, a critique pass, and a
revision pass. The result is rendered through a structured report
template. Every candidate context is classified as CURRENT (the boundary
is strongly expressed in the code today), LATENT (a real boundary that
implementation currently obscures), or SPECULATIVE (meaningful evidence,
but needs a domain expert to confirm), and each classification must pass
a legitimacy test before it appears.

The skill is deliberately conservative about speculation. A hard
validation gate (Step 8.5) stops the run and reports failure rather than
showing a report when it detects identifier-integrity errors or
speculative claims leaking outside their isolation, and that isolation
now covers the Owns, Consumes, Does not own, Responsibilities, and
Relationships fields rather than Relationships alone. Overreach
detection likewise scans every field of every modeled context. The
closing message is limited to discovery-oriented next steps and will not
prescribe fixes, recommend extraction or refactoring, or claim a
boundary problem can be resolved.

`han-ddd` is not bundled by the han meta-plugin, so it is installed on
its own. It depends on `han-communication` and `han-core`, and ships the
five domain agents the skill orchestrates.
#199)

Bumps the dev-tooling group with 3 updates:
[actions/checkout](https://github.com/actions/checkout),
[actions/setup-node](https://github.com/actions/setup-node) and
[actions/cache](https://github.com/actions/cache).

Updates `actions/checkout` from 6.0.3 to 7.0.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>skip running unsafe pr check if input is default by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2518">actions/checkout#2518</a></li>
<li>trim only ascii whitespace for branch by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2521">actions/checkout#2521</a></li>
<li>escape values passed to --unset by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2530">actions/checkout#2530</a></li>
<li>Various dependency updates</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v7...v7.0.1">https://github.com/actions/checkout/compare/v7...v7.0.1</a></p>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li><strong>[BREAKING]</strong> backport
<code>allow-unsafe-pr-checkout</code> to v6 by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2500">actions/checkout#2500</a></li>
<li>backport fixes to releases-v6 by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2527">actions/checkout#2527</a></li>
</ul>
<p><a
href="https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/">https://github.blog/changelog/2026-06-18-safer-pull_request_target-defaults-for-github-actions-checkout/</a>
for more details about this breaking change</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v6.1.0">https://github.com/actions/checkout/compare/v6.0.3...v6.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h2>v7.0.1</h2>
<ul>
<li>Skip running unsafe pr check if input is default by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2518">actions/checkout#2518</a></li>
<li>Trim only ascii whitespace for branch by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2521">actions/checkout#2521</a></li>
<li>Escape values passed to --unset by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2530">actions/checkout#2530</a></li>
<li>Various dependency updates</li>
</ul>
<h2>v7.0.0</h2>
<ul>
<li>Block checking out fork PR for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Various dependency updates</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/3d3c42e5aac5ba805825da76410c181273ba90b1"><code>3d3c42e</code></a>
prep v7.0.1 release (<a
href="https://redirect.github.com/actions/checkout/issues/2531">#2531</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/28802689a136bfcdb721715abd713740beecbe07"><code>2880268</code></a>
escape values passed to --unset (<a
href="https://redirect.github.com/actions/checkout/issues/2530">#2530</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/12cd2235efa0937479335606d7c3ac9f6c0973b1"><code>12cd223</code></a>
trim only ascii whitespace for branch (<a
href="https://redirect.github.com/actions/checkout/issues/2521">#2521</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/62661c4e71a304b2823ed026347b8d34c3eac541"><code>62661c4</code></a>
skip running unsafe pr check if input is default (<a
href="https://redirect.github.com/actions/checkout/issues/2518">#2518</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/e8d4307400f9427dba7cb98e488d6ab85f1cec5f"><code>e8d4307</code></a>
Bump the minor-actions-dependencies group with 2 updates (<a
href="https://redirect.github.com/actions/checkout/issues/2499">#2499</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/631c942040754b6e095e929c1677c07e10ed4f87"><code>631c942</code></a>
eslint 9 (<a
href="https://redirect.github.com/actions/checkout/issues/2474">#2474</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/4f1f4aec02e41874fa0262ea8ff5172d7978ad1e"><code>4f1f4ae</code></a>
Bump actions/upload-artifact from 4 to 7 (<a
href="https://redirect.github.com/actions/checkout/issues/2476">#2476</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/ba097532fb203f7e88c9c3c0b899b49469908a92"><code>ba09753</code></a>
Bump actions/checkout from 6 to 7 (<a
href="https://redirect.github.com/actions/checkout/issues/2488">#2488</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/b9e0990d219a03df7633c93f6f005a8fecbcab22"><code>b9e0990</code></a>
Bump docker/login-action from 3.3.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2479">#2479</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/e8cb398be4a550817e382abf69e4c12c76fce1f2"><code>e8cb398</code></a>
Bump docker/build-push-action from 6.5.0 to 7.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2478">#2478</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-node` from 6.4.0 to 7.0.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<h3>Enhancements:</h3>
<ul>
<li>Add cache-primary-key and cache-matched-key as outputs by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1577">actions/setup-node#1577</a></li>
<li>Migrate to ESM and upgrade dependencies by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1574">actions/setup-node#1574</a></li>
</ul>
<h3>Bug fixes:</h3>
<ul>
<li>Remove dummy NODE_AUTH_TOKEN export by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1558">actions/setup-node#1558</a></li>
<li>Only use <code>mirrorToken</code> in <code>getManifest</code> if
it's provided by <a
href="https://github.com/deiga"><code>@​deiga</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
</ul>
<h3>Documentation updates:</h3>
<ul>
<li>Add documentation for publishing to npm with Trusted Publisher
(OIDC) by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li>docs: Update restore-only cache documentation by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1550">actions/setup-node#1550</a></li>
<li>docs: Update caching recommendations to mitigate cache poisoning
risks by <a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1567">actions/setup-node#1567</a></li>
</ul>
<h3>Dependency update:</h3>
<ul>
<li>Upgrade <code>@​actions/cache</code> to 5.1.0, log cache write
denied by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/chiranjib-swain"><code>@​chiranjib-swain</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1536">actions/setup-node#1536</a></li>
<li><a href="https://github.com/deiga"><code>@​deiga</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1548">actions/setup-node#1548</a></li>
<li><a href="https://github.com/jasongin"><code>@​jasongin</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1569">actions/setup-node#1569</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6...v7.0.0">https://github.com/actions/setup-node/compare/v6...v7.0.0</a></p>
<h2>v6.5.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update <code>@​actions/cache</code> to 5.1.0 and add security
overrides for undici and fast-xml-parser by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1579">actions/setup-node#1579</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0">https://github.com/actions/setup-node/compare/v6.4.0...v6.5.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/820762786026740c76f36085b0efc47a31fe5020"><code>8207627</code></a>
Migrate to ESM and upgrade dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1574">#1574</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/04be95cf3511ea51ebf9f224ddfb99cc7ab87cd4"><code>04be95c</code></a>
Add cache-primary-key and cache-matched-key as outputs (<a
href="https://redirect.github.com/actions/setup-node/issues/1577">#1577</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/7c2c68d20d402ed6a201ada70a81341941093140"><code>7c2c68d</code></a>
docs: Update caching recommendations to mitigate cache poisoning risks
(<a
href="https://redirect.github.com/actions/setup-node/issues/1567">#1567</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/6a61c0375d66246de94630495909f12cf8dac84d"><code>6a61c03</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/setup-node/issues/1569">#1569</a>
from jasongin/update-actions-cache-5.1.0</li>
<li><a
href="https://github.com/actions/setup-node/commit/30eb73b41ded577900c1ebf968ef95cdf8f7434f"><code>30eb73b</code></a>
Resolve high-severity audit issues</li>
<li><a
href="https://github.com/actions/setup-node/commit/4e1a87a501d0302f99e30e2748568adcb388d09f"><code>4e1a87a</code></a>
Update dist</li>
<li><a
href="https://github.com/actions/setup-node/commit/360237f0c01778d0c17291f75c56d6feae4f7574"><code>360237f</code></a>
Strict equality</li>
<li><a
href="https://github.com/actions/setup-node/commit/4f8aac5beb2f0854bc79651567a18c67eb0b9de3"><code>4f8aac5</code></a>
Bump <code>@​actions/cache</code> to 5.1.0, log cache write denied</li>
<li><a
href="https://github.com/actions/setup-node/commit/f4a67bbeca970f103397d3d2b9462cf787cd2980"><code>f4a67bb</code></a>
Only use <code>mirrorToken</code> in <code>getManifest</code> if it's
provided (<a
href="https://redirect.github.com/actions/setup-node/issues/1548">#1548</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/0355742c943ddb13ca8a6b700f824231caa91e75"><code>0355742</code></a>
Remove dummy NODE_AUTH_TOKEN export (<a
href="https://redirect.github.com/actions/setup-node/issues/1558">#1558</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/v6.4.0...v7.0.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/cache` from 5.0.5 to 6.1.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v6.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v6.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1768">actions/cache#1768</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v6...v6.1.0">https://github.com/actions/cache/compare/v6...v6.1.0</a></p>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update packages, migrate to ESM by <a
href="https://github.com/Samirat"><code>@​Samirat</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v5.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h3>6.1.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a
href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435
Handle cache write error due to read-only token</a></li>
<li>Switch redundant &quot;Cache save failed&quot; warning to debug log
in save-only</li>
</ul>
<h3>6.0.0</h3>
<ul>
<li>Updated <code>@actions/cache</code> to ^6.0.1,
<code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to
^3.0.0, <code>@actions/io</code> to ^3.0.2</li>
<li>Migrated to ESM module system</li>
<li>Upgraded Jest to v30 and test infrastructure to be ESM
compatible</li>
</ul>
<h3>5.0.4</h3>
<ul>
<li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar
patterns)</li>
<li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb
protection, header validation fixes)</li>
<li>Bump <code>fast-xml-parser</code> to v5.5.6</li>
</ul>
<h3>5.0.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<h3>5.0.2</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.3 <a
href="https://redirect.github.com/actions/cache/pull/1692">#1692</a></li>
</ul>
<h3>5.0.1</h3>
<ul>
<li>Update <code>@azure/storage-blob</code> to <code>^12.29.1</code> via
<code>@actions/cache@5.0.1</code> <a
href="https://redirect.github.com/actions/cache/pull/1685">#1685</a></li>
</ul>
<h3>5.0.0</h3>
<blockquote>
<p>[!IMPORTANT]
<code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of <code>2.327.1</code>.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>4.3.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to <a
href="https://redirect.github.com/actions/toolkit/pull/2132">v4.1.0</a></li>
</ul>
<h3>4.2.4</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.5</li>
</ul>
<h3>4.2.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v4.0.3 (obfuscates SAS token in
debug logs for cache entries)</li>
</ul>
<h3>4.2.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/cache/commit/55cc8345863c7cc4c66a329aec7e433d2d1c52a9"><code>55cc834</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1768">#1768</a>
from jasongin/readonly-cache</li>
<li><a
href="https://github.com/actions/cache/commit/d8cd72f230726cdf4457ebb61ec1b593a8d12337"><code>d8cd72f</code></a>
Bump <code>@​actions/cache</code> to v6.1.0 - handle cache write error
due to RO token</li>
<li><a
href="https://github.com/actions/cache/commit/2c8a9bd7457de244a408f35966fab2fb45fda9c8"><code>2c8a9bd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1760">#1760</a>
from actions/samirat/esm_migration_and_package_update</li>
<li><a
href="https://github.com/actions/cache/commit/e9b91fdc3fea7d79165fceb79042ef45c2d51023"><code>e9b91fd</code></a>
Prettier fixes</li>
<li><a
href="https://github.com/actions/cache/commit/e4884b8ff7f92ef6b52c79eda480bbc86e685adb"><code>e4884b8</code></a>
Rebuild dist</li>
<li><a
href="https://github.com/actions/cache/commit/10baf0191a3c426ea0fa4a3253a5c04233b6e18f"><code>10baf01</code></a>
Fixed licenses</li>
<li><a
href="https://github.com/actions/cache/commit/e39b386c9004d72a15d864ade8c0b3a702d47a37"><code>e39b386</code></a>
Fix test mock return order</li>
<li><a
href="https://github.com/actions/cache/commit/b6928203372a8571ff984c0c883ef3a1adfb0c06"><code>b692820</code></a>
PR feedback</li>
<li><a
href="https://github.com/actions/cache/commit/60749128a44d25d3c520a489e576380cf00ff3f1"><code>6074912</code></a>
Rebuild dist bundles as ESM to match type:module</li>
<li><a
href="https://github.com/actions/cache/commit/5a912e8b4af820fa082a0e75cfd2c782f8fbfe0e"><code>5a912e8</code></a>
Fix lint and jest issues</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v5.0.5...v6.1.0">compare
view</a></li>
</ul>
</details>
<br />

Bumps the dev-tooling group with 2 updates:
[@j178/prek](https://github.com/j178/prek) and
[prettier](https://github.com/prettier/prettier).

Updates `@j178/prek` from 0.4.9 to 0.4.11
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/releases">@​j178/prek's
releases</a>.</em></p>
<blockquote>
<h2>0.4.11</h2>
<h2>Release Notes</h2>
<p>Released on 2026-07-25.</p>
<h3>Highlights</h3>
<ul>
<li>
<p>This release adds two new builtin hooks, <code>deny-pattern</code>
and <code>require-pattern</code>,
as native alternatives for <code>pygrep</code> use cases.
<code>deny-pattern</code> fails when a
configured pattern is found, while <code>require-pattern</code> ensures
every selected
file contains a match. By matching natively without spawning a Python
subprocess, they run over 4x faster than <code>pygrep</code> in
benchmarks. Note that
they use <a href="https://docs.rs/regex/latest/regex/#syntax">Rust
<code>regex</code> syntax</a>, which does
not support look-around features such as negative lookbehind.</p>
</li>
<li>
<p><code>prek run</code> now supports <code>--glob
&lt;PATTERN&gt;</code> to run hooks on tracked files
matching a glob. It can be repeated or combined with
<code>--files</code> and
<code>--directory</code>.</p>
</li>
<li>
<p>Hook priorities now support reusable aliases:</p>
<pre lang="toml"><code>[priorities]
checks = 10
<p>[[repos]]
repo = &quot;builtin&quot;
hooks = [
{ id = &quot;check-json&quot;, priority = &quot;checks&quot; },
{ id = &quot;check-yaml&quot;, priority = &quot;checks&quot; },
]
</code></pre></p>
<p>This makes parallel scheduling easier to read and maintain.</p>
</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>deny-pattern</code> and <code>require-pattern</code>
builtin hooks (<a
href="https://redirect.github.com/j178/prek/pull/2359">#2359</a>)</li>
<li>Support <code>--glob</code> patterns in <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/pull/2381">#2381</a>)</li>
<li>Support reusable aliases for hook priorities (<a
href="https://redirect.github.com/j178/prek/pull/2331">#2331</a>)</li>
<li>Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2390">#2390</a>)</li>
<li>Improve user-facing warnings and errors (<a
href="https://redirect.github.com/j178/prek/pull/2380">#2380</a>)</li>
<li>Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/pull/2394">#2394</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/pull/2384">#2384</a>)</li>
<li>Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/pull/2391">#2391</a>)</li>
</ul>
<h3>Bug fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/j178/prek/blob/master/CHANGELOG.md">@​j178/prek's
changelog</a>.</em></p>
<blockquote>
<h2>0.4.11</h2>
<p>Released on 2026-07-25.</p>
<h3>Highlights</h3>
<ul>
<li>
<p>This release adds two new builtin hooks, <code>deny-pattern</code>
and <code>require-pattern</code>,
as native alternatives for <code>pygrep</code> use cases.
<code>deny-pattern</code> fails when a
configured pattern is found, while <code>require-pattern</code> ensures
every selected
file contains a match. By matching natively without spawning a Python
subprocess, they run over 4x faster than <code>pygrep</code> in
benchmarks. Note that
they use
<a href="https://docs.rs/regex/latest/regex/#syntax">Rust
<code>regex</code> syntax</a>, which does
not support look-around features such as negative lookbehind.</p>
</li>
<li>
<p><code>prek run</code> now supports <code>--glob
&lt;PATTERN&gt;</code> to run hooks on tracked files
matching a glob. It can be repeated or combined with
<code>--files</code> and
<code>--directory</code>.</p>
</li>
<li>
<p>Hook priorities now support reusable aliases:</p>
<pre lang="toml"><code>[priorities]
checks = 10
<p>[[repos]]
repo = &quot;builtin&quot;
hooks = [
{ id = &quot;check-json&quot;, priority = &quot;checks&quot; },
{ id = &quot;check-yaml&quot;, priority = &quot;checks&quot; },
]
</code></pre></p>
<p>This makes parallel scheduling easier to read and maintain.</p>
</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>deny-pattern</code> and <code>require-pattern</code>
builtin hooks (<a
href="https://redirect.github.com/j178/prek/pull/2359">#2359</a>)</li>
<li>Support <code>--glob</code> patterns in <code>prek run</code> (<a
href="https://redirect.github.com/j178/prek/pull/2381">#2381</a>)</li>
<li>Support reusable aliases for hook priorities (<a
href="https://redirect.github.com/j178/prek/pull/2331">#2331</a>)</li>
<li>Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/pull/2390">#2390</a>)</li>
<li>Improve user-facing warnings and errors (<a
href="https://redirect.github.com/j178/prek/pull/2380">#2380</a>)</li>
<li>Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/pull/2394">#2394</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/pull/2384">#2384</a>)</li>
<li>Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/pull/2391">#2391</a>)</li>
</ul>
<h3>Bug fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/j178/prek/commit/92ba6c8c21e7acf5ce056b7c9b8dcba7325c3f5a"><code>92ba6c8</code></a>
Bump version to 0.4.11 (<a
href="https://redirect.github.com/j178/prek/issues/2402">#2402</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/f575e428961414bc079060061bc570b71e553942"><code>f575e42</code></a>
Bump quinn-proto from 0.11.14 to 0.11.16 (<a
href="https://redirect.github.com/j178/prek/issues/2401">#2401</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c0ed56d92af1530e0acc98da2a8544bcf1dd01e7"><code>c0ed56d</code></a>
Preserve system download policy when applying metadata (<a
href="https://redirect.github.com/j178/prek/issues/2395">#2395</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/3b8b5c53ea8ce674112e22f9f84addf3637ca9e0"><code>3b8b5c5</code></a>
Install Node hooks through git url (<a
href="https://redirect.github.com/j178/prek/issues/2394">#2394</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/ff11cbb2d30478d9b2607dd1886cf90e33979365"><code>ff11cbb</code></a>
Implement <code>requirements-txt-fixer</code> as a builtin hook (<a
href="https://redirect.github.com/j178/prek/issues/2390">#2390</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/c7dfc32c27f74ee04f9a4dc47b842fbb3e417631"><code>c7dfc32</code></a>
Match identify tags across filename parts (<a
href="https://redirect.github.com/j178/prek/issues/2399">#2399</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/928dc5cf3b7c7486664d6a7e34ce8d89a603d7f1"><code>928dc5c</code></a>
Speed up mixed-line-ending scans with memchr2 (<a
href="https://redirect.github.com/j178/prek/issues/2391">#2391</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/6c898499d8b7741f7e6b60cc42b195660e6d1afa"><code>6c89849</code></a>
Honor filenames in builtin hook entry and args (<a
href="https://redirect.github.com/j178/prek/issues/2389">#2389</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/28bc3f013e0c97c39834f2f02a708355ed642462"><code>28bc3f0</code></a>
Add description for no-commit-to-branch (<a
href="https://redirect.github.com/j178/prek/issues/2388">#2388</a>)</li>
<li><a
href="https://github.com/j178/prek/commit/1d9adddb83df05770ea2a5562f141171be174d77"><code>1d9addd</code></a>
Reduce blocking-pool overhead in file hooks (<a
href="https://redirect.github.com/j178/prek/issues/2384">#2384</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/j178/prek/compare/v0.4.9...v0.4.11">compare
view</a></li>
</ul>
</details>
<br />

Updates `prettier` from 3.9.5 to 3.9.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.9.6</h2>
<h2>What's Changed</h2>
<ul>
<li>Preserve quotes for methods named <code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19621">prettier/prettier#19621</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</li>
<li>Support <code>import defer</code> in <code>typescript</code> parser
(<a
href="https://redirect.github.com/prettier/prettier/pull/19624">prettier/prettier#19624</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19675">prettier/prettier#19675</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</li>
<li>Added a new official plugin <a
href="https://github.com/prettier/prettier/tree/3.9.6/packages/plugin-yuku"><code>@prettier/plugin-yuku</code>
🚀</a> (<a
href="https://redirect.github.com/prettier/prettier/pull/19628">prettier/prettier#19628</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19629">prettier/prettier#19629</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.6/CHANGELOG.md#396">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.9.6</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.9.5...3.9.6">diff</a></p>
<h4>TypeScript: Preserve quotes for methods named <code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19621">#19621</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="tsx"><code>// Input
interface Container {
  &quot;new&quot;(id: string): number;
}
<p>// Prettier 3.9.5<br />
interface Container {<br />
new(id: string): number;<br />
}</p>
<p>// Prettier 3.9.6<br />
interface Container {<br />
&quot;new&quot;(id: string): number;<br />
}<br />
</code></pre></p>
<h4>TypeScript: Support <code>import defer</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19624">#19624</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19675">#19675</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="tsx"><code>// Input
import defer * as foo from &quot;foo&quot;;
<p>// Prettier 3.9.5<br />
import * as foo from &quot;foo&quot;;</p>
<p>// Prettier 3.9.6<br />
import defer * as foo from &quot;foo&quot;;<br />
</code></pre></p>
<h4>JavaScript: Added a new official plugin
<code>@prettier/plugin-yuku</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19628">#19628</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19629">#19629</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<p><code>@prettier/plugin-yuku</code> is powered by <a
href="https://yuku.fyi/">Yuku</a> (A high-performance
JavaScript/TypeScript compiler toolchain written in Zig).</p>
<p>This plugin includes two new parsers: <code>yuku</code> (JavaScript
syntax) and <code>yuku-ts</code> (TypeScript syntax).</p>
<p><strong>To use this plugin:</strong></p>
<ol>
<li>
<p>Install the plugin:</p>
<pre lang="bash"><code>yarn add --dev prettier @prettier/plugin-yuku
</code></pre>
</li>
</ol>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/prettier/prettier/commit/8f0c95057cc91d5836409466cd9d9af3bb901e84"><code>8f0c950</code></a>
Release 3.9.6</li>
<li><a
href="https://github.com/prettier/prettier/commit/e9107647d0497d8ff1cacbb0f970d4543df77c1c"><code>e910764</code></a>
Update changelog</li>
<li><a
href="https://github.com/prettier/prettier/commit/ec3f1c7bd74495992bc6954323a1a7fc8368808e"><code>ec3f1c7</code></a>
Update typescript-eslint to v8.65.0 (<a
href="https://redirect.github.com/prettier/prettier/issues/19675">#19675</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/73d2efc2c6cba6f579585c88ef171132d90834ec"><code>73d2efc</code></a>
Update Yuku parser to v0.7.0 (<a
href="https://redirect.github.com/prettier/prettier/issues/19664">#19664</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/dd5e24eabeab1f75ad573c79781e5fd408bcfad3"><code>dd5e24e</code></a>
Preserve quotes for <code>TSMethodSignature</code> nodes named
<code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/issues/19621">#19621</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/c03ab4e71c23154d6b11537eee3c938f0d0f67d3"><code>c03ab4e</code></a>
Update dependency eslint-plugin-unicorn to v72 (<a
href="https://redirect.github.com/prettier/prettier/issues/19633">#19633</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/b74dd53076c7208291a6b2e585c310844b41d35f"><code>b74dd53</code></a>
Update Yuku parser to v0.6.5 (<a
href="https://redirect.github.com/prettier/prettier/issues/19654">#19654</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/f1b594ea1db1520c383d0e281d623551f671f824"><code>f1b594e</code></a>
Update dependency eslint-plugin-simple-import-sort to v14 (<a
href="https://redirect.github.com/prettier/prettier/issues/19655">#19655</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/0d9dfb61530986373000dd107ea58ceebb79e233"><code>0d9dfb6</code></a>
Update Yuku parser to v0.6.4 (<a
href="https://redirect.github.com/prettier/prettier/issues/19650">#19650</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/3bbb8159eb55575d4042653aa99f5f92a1416c19"><code>3bbb815</code></a>
Remove <code>typescript-only</code> directory (<a
href="https://redirect.github.com/prettier/prettier/issues/19636">#19636</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/3.9.5...3.9.6">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
Records the evidence, root cause, and correction plan for the three
findings in #148: automated-test-planning runs its full
pipeline regardless of question scope, the test analysis agents can only
argue a deferral from coverage location, and the readability editor does
not check its own insertions against the voice blocklist.

Carries 20 evidence items and 11 adversarial validation findings. Four of
those findings corrected the plan before implementation.
…sked

The skill classified nothing, so a narrow yes/no question ran the same
pipeline as a whole-branch analysis: up to seven agent dispatches, a
nine-section document, and two reviewers over it.

Adds a size band with the same shape code-review and iterative-plan-review
already use. Small defaults to focused mode: one agent, no conditional
specialists, no reviewers, and a prose answer instead of the template.
Medium and large are unchanged.

Classification reads the user's request before Step 1's file list, because
Step 1 falls back to the whole changed-files list when no scope is named,
and that describes the branch rather than the question. Step 3's
behavioral, prerequisite, and YAGNI sweeps run in both modes, so a focused
answer is shorter without being less filtered.

Registers the skill in docs/sizing.md alongside the other sizing-aware
skills.
test-engineer could justify skipping a proposed test only by pointing at
coverage elsewhere or at brittleness risk. Neither survives a reader who
grants the path is reachable and asks what the new assertion would add.
edge-case-explorer had the same gap, with "sufficient" left undefined.

test-engineer gains a fifth evaluation axis: name a specific weakening of
the code under test, predict which existing tests fail under it, and defer
only when an existing test already catches everything the candidate would.
Adds a Redundant Kill Set anti-pattern, a required Discriminating power
field on every deferred item, and a rule against deferring on coverage
location alone.

edge-case-explorer now defines sufficient: a test is sufficient for an edge
case only when it fails under a change that breaks that case.

Neither agent has a test runner, so both state that the answer is a
prediction from reading assertions and must name the test and assertion it
came from.

The canonical YAGNI rule is left untouched. It is written for committed
items generally and is vendored byte-identically into five plugins, while
this reasoning is test-specific.
The editor's only post-rewrite step confirmed facts survived. Its blocklist
criterion governed the draft it audited, never the sentences it wrote, so
the rewrite was the one place a fresh voice violation could originate and
the one place with no voice check.

Three planning skills tell the caller not to walk the self-check over the
editor's output, and one skill runs no independent check at all, so a
violation the editor introduces can reach the reader.

Adds a step 4 that re-reads only the sentences the editor rewrote or
inserted against the vocabulary blocklist and the em-dash positions, plus a
line in the returned report. The pass corrects named violations only and
leaves compliant wording alone, so a legal appositive em-dash survives it.
## Summary

- Gives `automated-test-planning` a size band so a narrow question runs
one agent and returns prose, instead of up to seven dispatches and a
nine-section document.
- Gives `test-engineer` and `edge-case-explorer` a discriminating-power
test, so a deferral is argued from what an assertion would catch rather
than from where coverage happens to sit.
- Makes `readability-editor` check the sentences it writes against the
voice blocklist it applies.
- Leaves the canonical YAGNI rule and `manual-test-planning` untouched
on purpose; both exclusions are argued in the investigation doc.

## Why

Closes #148, a Han feedback report. It scored the run 5/5 on output
accuracy and evidence discipline, and 2/5 on output length against
decision count. The analysis quality was never in question; the cost and
the durability of the reasoning were.

Each fix copies a mechanism the suite already runs. The size band is
`code-review`'s classifier plus `iterative-plan-review`'s lightweight
mode, and the suite's own agent-economics guidance already says not to
delegate work a skill can finish in a few tool calls, so that change is
a conformance repair rather than a new idea.

One part of the report is stale. The absolute em-dash ban it quotes was
replaced six days after filing by a rule legalizing two positions, so
two of its three flagged instances may no longer be violations. The
structural gap behind it is unaffected and is what this PR fixes.

Full evidence, root cause, and adversarial validation:
`docs/plans/test-planning-feedback-issue-148/feedback-investigation.md`
(20 evidence items, 11 validation findings).

## How to verify

- [ ] `npm run lint`
- [ ] Read `han-coding/skills/automated-test-planning/SKILL.md` Step 1.5
and confirm `arguments: size` is in the frontmatter. Without that key
there is no `$size` to bind, which validation caught in the first draft.
- [ ] Run `/automated-test-planning` with a narrow question on a branch
with many changed files. It should announce a small band and answer in
prose. Classification reads the request before the file list precisely
so this case works.
- [ ] Run `/automated-test-planning large` and confirm the full roster
and template still run.
- [ ] Dispatch `readability-editor` over a draft containing a legal
appositive em-dash and confirm the new pass leaves it alone.

## Risk / rollback

Low. Markdown instruction files only, no scripts and no behavior outside
a Claude Code session. Medium and large runs of
`automated-test-planning` are unchanged, so the blast radius is the
small band and the two agents' deferral rationale. Revert with `git
revert`; the four commits are independently revertable, one per
correction plus the investigation doc.

Three open risks are recorded in the investigation doc: the editor's new
pass is unvalidated against false positives, `manual-test-planning`
keeps an unconditional two-agent pipeline, and the discriminating-power
answer is a prediction rather than an executed mutation test.
…anges

Closes the gap issue #183 names between architectural-analysis, which
produces findings and stops, and plan-a-feature, which specifies behavior
a user observes and keeps symbol names out. Neither answers "these
responsibilities are wrong, plan the fix".

The skill takes whatever context is supplied, establishes the current
state, settles a target state, and produces a change plan that is
buildable directly by plan-work-items, tdd, or refactor.

Three properties answer the issue's three complaints:

- Code-level names are the subject rather than a leak. The plan names
  types, modules, and methods, because it plans a structure an engineer
  works in.
- The surface delta is a target-state record, not a migration table.
  Every element removed, added, moved, renamed, or re-scoped carries a
  statement that would still be correct if every other entry were
  deleted, so a removal always says where the responsibility went.
- Behavior preservation is a gate, not an assumption. Every delta entry
  is classified preserving, changing, or unknown, and the last two are
  escalated before they are committed.

The run reads a prior findings report when one exists and dispatches its
own structural, behavioral, and concurrency round when one does not. The
output folder resolves through the config-rule precedence chain.

Also adds reciprocal boundary clauses to architectural-analysis and
plan-a-feature, registers the skill across the docs surfaces, and adds it
to the four shared planning rules' consumer lists.
The branch added the plan-a-change skill and the han-ddd plugin but left
several cross-plugin documentation surfaces pointing only one way.

- Add /plan-a-change to the sizing-aware skill list, the per-skill table,
  and the per-skill Sizing links in docs/sizing.md.
- Add /plan-a-change to the sizing, YAGNI, evidence, readability, and
  han-planning enumerations in docs/concepts.md, and add the missing
  /automated-test-planning to the sizing list there.
- Add the missing Sizing section to the plan-a-change and ddd-analysis
  long-form docs, recording that ddd-analysis sizes analysis depth rather
  than team size and defaults to medium.
- Add reverse boundary and Related documentation pointers to
  plan-a-change from architectural-analysis, plan-a-feature,
  plan-work-items, and refactor, including refactor's frontmatter.
- Name /plan-a-change as a dispatcher in the fourteen agent long-form docs
  it dispatches.
- Document the discriminating-power criterion in the test-engineer and
  edge-case-explorer Key concepts, matching their definitions.
- Fix two wrong-depth docs/ links in the automated-test-planning doc.
- Correct han-planning's plugin.json description, which claimed a
  han-core-only dependency while declaring han-communication too.

Claude-Session: https://claude.ai/code/session_01UGo7ozwZcFKu2yVHtrGMMm
…anges (#207)

## Summary

- Adds `/plan-a-change` to `han-planning`: a skill that plans an
architecture-driven change to code that already exists, producing a plan
`plan-work-items`, `tdd`, or `refactor` can build from directly.
- Review the surface delta rule and the behavior-preservation gate
closely. Those two carry the design.
- No version bumps and no CHANGELOG entry. Adds reciprocal boundary
clauses to `architectural-analysis` and `plan-a-feature` so
disambiguation works in both directions.

## Why

Issue #183 names a gap between two existing skills.
`architectural-analysis` assesses an area and produces findings, then
stops. `plan-a-feature` specifies behavior a user observes, and its
content rule keeps symbol names out on purpose. Neither answers "these
responsibilities are wrong, plan the fix", so the author of that issue
hand-orchestrated `structural-analyst`, `behavioral-analyst`, and
`software-architect` and synthesised the result themselves.

The issue makes three asks. This PR answers all three in one skill:

**Code-level names are the subject, not a leak.** The plan names types,
modules, and methods, because it plans a structure an engineer works in
rather than behavior a user observes. The altitude limit is different in
kind: carry names, responsibilities, and contracts; never inline file
bodies or prescribe line-level edits.

**The surface delta is a target-state record, not a migration table.**
Five verbs, and every entry states what is true after the change in its
own right, written so it would still be correct if every other entry
were deleted. A removal always says where the responsibility went, or
that it went away and why. This is the fix for the issue's "one removal
had no target-state statement anywhere". A migration table is written
from the call site inward, so a responsibility moving between two
internal collaborators produces no row at all and vanishes from a
document built that way.

**Behavior preservation is a gate, not an assumption.** Every delta
entry is classified preserving, changing, or unknown. The last two are
escalated before commit. An entry that cannot be classified is escalated
rather than assumed safe.

Closes #183.

## What it does

Twelve steps: establish the reason, record the scope boundary, establish
the current state, select the team, propose the target state, settle the
delta, run the behavior gate, review, sweep for YAGNI and scope, write,
readability, present.

Two behaviors worth a reviewer's attention:

- **The reason is recorded and not assumed.** Step 1 classifies why a
change is being planned across six reason classes. A reported defect is
one of them; a prior findings report is another. Neither is presumed to
exist. A run with no recorded reason stops, because there is nothing for
the YAGNI evidence test to test against.
- **Discovery is conditional.** With a prior report, Step 2 reads it.
Without one, Step 2 dispatches structural and behavioral analysts (plus
concurrency on signal). That is the orchestration the issue describes
doing by hand.

The output folder resolves through the `config-rule` precedence chain,
so `output-directory` from either `.han/config.md` governs it.

## How to verify

- [ ] `npm run lint` and `npm test` (95 tests, all passing on this
branch).
- [ ] Read
`han-planning/skills/plan-a-change/references/surface-delta-rule.md`,
the file the issue's central complaint maps to.
- [ ] Check the boundary clauses in three descriptions read correctly
against each other: `plan-a-change`, `plan-a-feature`, and
`architectural-analysis`. All three stay under the 1024-character target
(765, 783, 843).
- [ ] Confirm the docs coverage rule holds: long-form doc at
`han-planning/docs/skills/plan-a-change.md`, scent line in the plugin
README, entry in `docs/skills/README.md`, chain entry in
`docs/workflows.md`.

## Risk / rollback

Low. The change is additive: one new skill plus registration across the
docs surfaces. The only edits to existing behavior are two description
clauses and four consumer-list lines in the shared planning rules, none
of which change what an existing skill does. `plan-a-change` uses the
boundary record from `planning-boundary-rule` but not its
visual-material convention, which is stated in the rule's consumer note.
Revert with `git revert`.
Issue #193 reported six problems from a real plan-implementation run. Four
are the same shape: a mechanic is written in one file and the file that must
honor it never reads it back.

One premise in the work item is wrong and it changed the fix. The issue says
the orchestrating thread has execution tools; all three planning skills grant
only find, git, mkdir, cp, and one config script. The measurement step works
inside that grant and records what the grant cannot reach.

Discovery ran structural and behavioral analysis over the area, then a review
round of three specialists over the draft. That round found a critical defect
in the plan itself: narrowing the editor's ledger while leaving four skills
testing for the removed sentence would have sent every clean run down the
degraded branch. Nine findings changed the plan.
Four of the six were the same shape: a mechanic written in one file that the
file which must honor it never read back. Each now has a named reader, and the
one whose failure is mechanical has a script.

Synthesis writes the plan first, so both companion files write backward into a
file that exists and a mid-run death leaves the primary artifact. A new
check-plan-cross-references.sh resolves the links in both directions, and a
shared synthesis-failure-rule.md stops either file-writing caller from running
the readability pass against a plan that was never written.

Specialists now cite a decision's field rather than the whole entry, and two
findings citing one identifier with different figures no longer merge, since a
genuine disagreement usually cites different evidence.

The readability editor reports what it inserted with the source span it drew
from, and its ledger stops asserting that everything survived. All four
consuming skills had their branches rewritten, not only extended: each tested
for the sentence the narrowed ledger removes, so leaving them would have sent
every clean run down the degraded path.

Discovery measures the figures its tools reach and records what they cannot,
rather than passing a spec assertion through as fact. The premise that the
orchestrator can run arbitrary commands was wrong; it holds find, git, glob and
grep, and the permission grant is unchanged.

Also repairs four in-area defects the discovery round found: two instruction
sentences split across a file boundary, ten link labels a directory too
shallow, a stale round cap, and a section missing from the write order that
required it. The rule that would have prevented the split sentences now sits
beside the ceiling that caused them.

Run against the fourteen existing plan folders, the new check found the
reported defect class in six of them.
Audit the entities this branch touched and fix five discrepancies between
documentation and its source of truth.

- CLAUDE.md: record synthesis-failure-rule.md, the new han-planning-owned
  reference file two skills cite, in both the repository layout and the
  shared planning conventions doc map.
- readability-editor long-form doc: document the Insertions ledger the agent
  now returns, and correct the fact-preservation bullet, which described a
  blanket survival claim the agent explicitly no longer makes.
- docs/sizing.md: add ddd-analysis, which binds $size and reads
  default-swarm-size but appeared in none of the three sizing-aware lists.
  Qualify the "default is small" claim, which ddd-analysis contradicts by
  defaulting to medium.
- architectural-analysis: add the missing reverse boundary to ddd-analysis,
  in both the frontmatter description and the long-form doc, plus the
  pairing link. ddd-analysis names architectural-analysis three times as
  its alternative and nothing pointed back.

Claude-Session: https://claude.ai/code/session_01HtgjM85z795Cd8oNC8J7do
)

Closes #193.

Feedback issue #193 reported six problems from a real
`plan-implementation` run. Four were the same shape: a mechanic
written in one file that the file which must honor it never read back.
Each now has a named reader, and the one whose
failure is mechanical has a script.

The plan behind this change is in
`docs/plans/plan-implementation-feedback-issue-193/`, with the discovery
findings and
the decision log beside it.

## One premise in the issue turned out to be wrong

The issue says the orchestrating thread "does have execution tools." It
does not. All three planning skills grant
`find`, `git`, `mkdir`, `cp`, and one config script, with no general
shell. So the measurement step works inside that
grant and records what the grant cannot reach, rather than passing a
specification's assertion through as fact. The
permission grant is unchanged, and widening it is deferred with a
trigger.

## What changed

**The synthesis boundary is guarded on both sides.** The plan is written
first, so both companion files write backward
into a file that exists and a mid-run termination leaves the primary
artifact rather than losing it. A new
`check-plan-cross-references.sh` resolves the links in both directions,
and a shared `synthesis-failure-rule.md` stops
either file-writing caller from running the readability pass against a
plan that was never written.

**A citation names the field, not the entry.** A decision entry carries
the committed option and the declined ones as
sibling fields, and a bare identifier does not say which one a figure
came from. Alongside it, two findings citing the
same identifier with different figures no longer merge, because a
genuine disagreement usually cites different
evidence.

**The readability editor reports what it wrote.** It names each sentence
it inserted with the source span it drew from,
and its ledger stops asserting that everything survived — an
unfalsifiable claim that had already reported a figure the
source never held.

**All four consuming skills had their branches rewritten, not only
extended.** Each tested for the exact sentence the
narrowed ledger removes, so adding a fourth branch and leaving the first
three would have sent every clean run down the
path meaning "no usable report came back." The review round caught this;
it is the defect the change exists to fix,
reproduced inside the fix.

**The deferral list got two readers**, one during the run and one at
build time, where the reported run's deferred flag
actually got built.

## Four in-area defects the discovery round found

Two instruction sentences split across a file boundary, ten link labels
a directory too shallow, a stale round cap
contradicting the two files that own it, and a section required by an
invariant but missing from the write order beside
it. Both split sentences came from commits that moved body text under
the 500-line ceiling, so the rule that would have
prevented them now sits beside that ceiling.

## Verification

- 23 new Bats tests for the script; 118 tests pass repo-wide; lint
clean.
- Run against the fourteen existing plan folders under `docs/plans/`,
the new check found the reported defect class in
six of them. Two were spot-verified as real: one plan cites `[D10]`
against a log that stops at `D-8`, and another
  references a "Phase 2" section that does not exist.
- All four `SKILL.md` files remain under the 500-line ceiling.

## Open, and deliberately not in this change

Five dispatch points still consume a returned report with no failure
branch. The Step 4 specialist fan-out is the one
worth attention: a dead agent's absence is indistinguishable from a
clean report with no findings, and a round that
silently lost one of three specialists produces a plan that reads
complete and is missing a domain.

Units 7 and 8 change a report shape across a plugin boundary and must
ship together, so the version bump is a release
decision rather than a code one.
…ew and research (#209)

Feedback issue #194 reported four runs where a Han skill confirmed a
reference existed without confirming it pointed at the right thing, or
produced a complete-looking report without saying what it had not done.
Three were in `code-review` and one in `research`. This change makes
both skills say what they did not do, and check that a reference
supports the thing it is attached to.

What changed:

- `code-review` gains a named **manual-only mode**, entered when the
dispatch mechanism fails (not when an agent returns nothing). The manual
review sweeps mapped checklist categories in the absent agents' place,
the report gains a `## Review Coverage` section that renders only when
coverage was absent, and the closing message names the cause and the
count. The independent validation pass skips in that mode because it
dispatches an agent.
- A `Packaging (when applicable)` checklist category fires on diffs that
change what gets packaged. It raises a Warning saying the review did not
open the built artifact and what to check by hand. Its summary row opens
with `Not checked —`.
- A finding whose location came from a region read of a file over 1000
lines names its enclosing unit and the lines read to confirm it. Guarded
twice: a fifth challenge axis in the validator brief, and a structural
verification item that runs in every mode.
- `research`'s traceability invariant is now two-part (resolvability and
support), defined once in Operating Principles and cited elsewhere. The
merge step records an old-to-new mapping across the renumbering,
rewrites every citation surface through it including the evidence-status
field, and labels a claim whose only source was dropped as no-evidence
rather than single-source. Both inline column enumerations now name the
one-line summary column.
- `post-code-review-to-pr` carries Review Coverage across to the pull
request and exempts it from the clarity pass's length-matching, so the
disclosure survives to the widest audience.
- Long-form docs for `code-review`, `research`, and
`post-code-review-to-pr` updated to match.

The plan and its artifacts are under
`docs/plans/code-review-research-feedback-issue-194/`. Two departures
from the issue are recorded there as the operator's decision: the
packaging finding discloses the gap rather than inspecting the artifact,
and the location rule fires on the region-read path rather than on
disassembler output the skill never reads.

Closes #194.
Three Han packages the README tells Codex users to install cannot be
installed. han-documentation and han-research are absent from
.agents/plugins/marketplace.json despite having valid Codex manifests;
han-linear is absent from the catalog and has never had a manifest at
all.

The root cause is structural rather than a one-off slip. Four
hand-maintained lists enumerate the Codex-installable packages (the
directory tree, the manifests, the catalog, the README) and nothing
checks that they agree. The drift entered on 2c09799, which scaffolded
both plugins and updated only the Claude marketplace; the comparison
case is 556b49e, which updated both marketplace files plus CLAUDE.md,
which is why han-ddd installs.

The plan names the directory tree as the authority and adds one Bats
check enforcing it, in three units that each leave the repo green:
register the two plugins that already have manifests; give han-linear a
manifest, a catalog entry, and a corrected CLAUDE.md line; then add the
check.

Planned with plan-a-change. Discovery ran structural and behavioral
analysts; the review round ran test-engineer, devops-engineer, and
junior-developer, which found nine defects in the draft, including a
verification step using git stash that cannot reach committed history
and a worked JSON example that would have introduced permanent
formatting drift.
han-plugin-builder's guidance is where every plugin-asset decision in
this repo is supposed to route, and it has no document describing the
Codex packaging surface. Its only Codex mentions are plugin-naming.md's
dot rule and that file's rename checklist, which acknowledges
.codex-plugin/plugin.json and a Codex marketplace exist as things to
keep in step. Nothing states a plugin needs both to ship.

Recorded as a deferral with a reopening trigger rather than pulled into
this change: the consistency check answers the question mechanically,
and a failing check is a stronger statement than a document nobody has
to read.
Both plugins have carried a valid .codex-plugin/plugin.json since they
were scaffolded in 2c09799, but that commit updated only the Claude
marketplace, so neither name was ever resolvable:

    $ codex plugin add han-documentation@han
    Error: plugin `han-documentation` was not found in marketplace `han`

A Codex install reads the catalog first and the per-plugin manifest
second, so the lookup failed before reaching manifests that were correct
all along. Adding the two entries is the whole fix for these two.

Both entries take the four-key form every existing entry uses, and sit
after han-core and before han-planning: the Codex catalog's order is the
Claude marketplace's order with its omissions removed, so restoring the
omitted names to their Claude positions is the placement consistent with
the file.

Unit 1 of 3 from docs/plans/codex-marketplace-catalog-consistency.
Closes two of the three symptoms in #198.
han-linear failed one layer deeper than han-documentation and
han-research: it was absent from the catalog and had never carried a
.codex-plugin/plugin.json on any commit, so a catalog entry alone would
have resolved to a directory with no manifest to read. Both land here.

The manifest copies the nine fields that are byte-identical across all
twelve siblings (author, homepage, repository, license, skills, and the
four constant interface keys) and supplies the eight package-specific
ones from han-linear's README and skill description.

It ships at 1.0.0 rather than mirroring the Claude manifest's 1.1.1. The
release skill's own rule is that a brand-new plugin is not bumped by the
release that introduces it, and a Codex manifest that has never existed
is that case. The two version fields are separate lineages: the release
skill bumps {source}/.claude-plugin/plugin.json and the Claude
marketplace, and never opens a .codex-plugin file. Eleven of twelve
pairs already differ, so seeding 1.1.1 would manufacture a parity the
next release destroys.

CLAUDE.md line 83 recorded the missing manifest as intentional. This
change makes that false, and it is the file every agent reads before
scaffolding, so it is corrected here rather than left to drift. Same
shape as 556b49e, which added han-ddd and updated the Codex catalog, the
Claude marketplace, and the map together.

Unit 2 of 3 from docs/plans/codex-marketplace-catalog-consistency.
Closes the third symptom in #198.
Nothing in the test, lint, or CI chain read a manifest or a marketplace
file, so the four data fixes above would not have stopped the next
plugin repeating 2c09799. This adds the check that would have caught
#198 when han-linear and han-ddd landed.

The directory tree is the authority: every han-* directory needs a Codex
manifest and a catalog entry. The han-* glob excludes the han/
meta-plugin structurally rather than by an exception list.

Three assertions, bash and grep only:

  1. the enumeration is non-empty, so the other two cannot pass over an
     empty set while looking identical to success
  2. every package has a .codex-plugin/plugin.json
  3. every package has a catalog entry whose name and path sit in the
     same entry, matched in a three-line window rather than tested for
     presence anywhere in the file

Deliberately not asserted: version parity (false for eleven of twelve
pairs) and description parity (false for all twelve). Both would fail
the build the day they landed, and neither is a latent goal, since the
release skill touches only the Claude side.

Verified against a worktree on the commit before the data fixes: the
check fails there and names han-documentation, han-research, and
han-linear, with han-linear failing both assertions. A consistency check
nobody has seen fail is a check nobody knows works.

sanity.bats stated that test/ keeps only harness-level checks, which
this file breaks. Widened to name the second category, keeping the
clause that still decides most cases: a test covering one script sits
beside that script.

Unit 3 of 3 from docs/plans/codex-marketplace-catalog-consistency.
#210)

Closes #198. Plans and implements the fix in five commits: two
documentation commits carrying the change plan, then the three change
units.

## What #198 reported

Three Han packages the README tells Codex users to install could not be
installed:

```
$ codex plugin add han-documentation@han
Error: plugin `han-documentation` was not found in marketplace `han`
```

`han-research` failed identically. `han-linear` failed one layer deeper:
absent from the catalog *and* never carrying a Codex manifest on any
commit.

## Why it happened

Four hand-maintained lists enumerate the Codex-installable packages —
the `han-*` directory tree, the per-plugin manifests,
`.agents/plugins/marketplace.json`, and the README — and nothing checked
that they agreed.

The drift is visible in the history. `2c09799` scaffolded
`han-documentation` and `han-research` and updated only the Claude
marketplace; its own message says "registered in the marketplace",
singular. The comparison case is `556b49e`, which added `han-ddd` and
updated both marketplace files plus `CLAUDE.md`, which is why `han-ddd`
installs today.

## The three units

| Unit | Commit | What it does |
| --- | --- | --- |
| 1 | `b83712f` | Two catalog entries for the plugins that already had
manifests |
| 2 | `1928de6` | `han-linear`'s manifest, its catalog entry, and the
`CLAUDE.md` line that recorded its absence as intentional |
| 3 | `f15663f` | The consistency check, plus the `sanity.bats` header
it makes stale |

Each unit leaves the repository green on its own.

## The check

The directory tree is the authority: every `han-*` directory needs both
files. The `han-*` glob excludes the `han` meta-plugin structurally
rather than by an exception list.

Three assertions, bash and grep only:

1. the enumeration is non-empty, so the other two cannot pass over an
empty set while looking identical to success
2. every package has a `.codex-plugin/plugin.json`
3. every package has a catalog entry whose `name` and `path` sit in the
**same** entry, matched in a three-line window rather than tested for
presence anywhere in the file

**Deliberately not asserted:** version parity (false for eleven of
twelve pairs) and description parity (false for all twelve). Both would
fail the build the day they landed, and neither is a latent goal — the
release skill touches only the Claude side.

### Verified to actually fail

Run against a worktree on the commit before Unit 1, with only the test
file copied in:

```
not ok 2 every han-* package carries a Codex manifest
# codex manifest missing: han-linear/.codex-plugin/plugin.json (copy han-ddd/... and edit the package-specific fields)
not ok 3 every han-* package has a catalog entry naming it and pointing at it
# catalog entry missing: add "name": "han-documentation" with "path": "./han-documentation" to .agents/plugins/marketplace.json
# catalog entry missing: add "name": "han-linear" with "path": "./han-linear" to .agents/plugins/marketplace.json
# catalog entry missing: add "name": "han-research" with "path": "./han-research" to .agents/plugins/marketplace.json
```

Exactly the three packages #198 names. On `HEAD`: 121 tests pass, 0
fail, every lint hook passes.

## Worth a reviewer's attention

- **`han-linear`'s Codex manifest ships at `1.0.0`**, not the Claude
manifest's `1.1.1`. The release skill's own rule is that a brand-new
plugin is not bumped by the release that introduces it. The two version
fields are separate lineages; seeding `1.1.1` would manufacture a parity
the next release destroys. **No version is bumped by this PR.**
- **The next release will classify `han-linear` as changed** on the
strength of the new manifest alone, and the level buckets have no entry
for "gained Codex installability." Worth deciding deliberately at
release time.
- **`CLAUDE.md` is edited**, and it was not in the area originally
scoped. Brought in because this change makes line 83 false, on the
`556b49e` precedent. Line 73 was cut for scope and is reinstatable.
- **Nothing was verified against a running Codex.** No CLI was
available. Every install-time claim traces to the repo's files and the
error text in #198; the fix copies the shape of the ten entries that
demonstrably work.
- **`docs/choosing-a-han-plugin.md` still gives Codex readers
Claude-only install commands.** Left alone as outside scope; recorded as
a follow-up.

## Planning artifacts

`docs/plans/codex-marketplace-catalog-consistency/` carries the change
plan, 11 decisions, 18 current-state findings, and the scope boundary.
Nine items are deferred with reopening triggers, including a reverse
check on the catalog and a Codex packaging document for the
`han-plugin-builder` guidance, which has none.

Produced with `/han-planning:plan-a-change`. The review round
(`test-engineer`, `devops-engineer`, `junior-developer`) found nine
defects in the draft plan, including a verification step using `git
stash` that cannot reach committed history, and a worked JSON example
whose formatting would have diverged permanently from every sibling
entry.
An outside reader reported that Han's docs contradict each other and the
skill definitions (#200). This plans the fix and records the evidence.

Verification widened the first of the three reported items. The quickstart
is missing four size-accepting skills, not the one reported: it lists 9,
the concepts page 12, and the skill frontmatter declares 14, of which 13
classify their own work. The cause is CONTRIBUTING.md step 6, which names
the sizing and concepts catalogs and not the quickstart, so four skill
additions between 2026-08-10 and 2026-09-09 updated the named pages and
left the quickstart behind.

The plan carries six delta entries in three units, each pinning the exact
replacement text: the two list syncs plus the checklist step, the two
han-reporting corrections, and the banner alt attribute. One entry is
behavior-changing, and the operator approved widening scope to cover it.

An automated catalog check is deferred under YAGNI with its reopening
trigger named. Nothing was cut for scope.
…aims

Closes #200.

The quickstart listed 9 sizing-aware skills and the concepts page 12,
where 13 skills classify their own work. Both now match docs/sizing.md,
which was already correct. CONTRIBUTING.md step 6 now names the quickstart
alongside the sizing and concepts catalogs, which is the reason it fell
four months behind: four skill additions since 2026-05-29 updated the two
pages the checklist named and left the third untouched.

Two pages stated the han-reporting dependency exception correctly and then
contradicted it a few lines later. On docs/choosing-a-han-plugin.md the
correct half sat in a trailing parenthetical while the bold sentence under
"The one thing that surprises people" erased it, so the exception now sits
in the bold sentence a skimming reader stops on. docs/concepts.md listed
reporting-only among installs that do not exist; it is the one layer plugin
you can install without han-core, so the page now says what it gives you.

The README banner gains alt text. It is the only image embed in the repo's
prose, and it carries the project name and tagline that a screen-reader
user previously got nothing of.

Plan, decisions, and evidence in docs/plans/gh-200-docs-consistency/.
Branch-scoped documentation audit over the 14 skills and 22 agents this
branch touched.

- research: add Write and Edit to allowed-tools. Step 8 writes the report
  and applies the editor's rewrite, but neither tool was declared.
- docs/readability.md: add /design-an-api, /plan-a-change, and
  /ddd-analysis to the per-skill table. All three dispatch
  readability-editor, and the table declares itself authoritative.
- plan-a-change: document the Step 9.5 readability rewrite in Cost and
  latency and in Related documentation.
- ddd-analysis: add the readability-editor bullet to Related
  documentation, matching the Step 10 dispatch its Cost section already
  described.
- readability-editor: add /ddd-analysis to the dispatcher list.
- risk-analyst: add /plan-a-change to the TL;DR dispatcher list and the
  Dispatch-when section; it was named in Related documentation only.
…aims (#211)

Closes #200.

An outside reader worked through the docs end to end and found pages
that disagree with each other and with the skill definitions. All three
of their findings were verified against the skill frontmatter and the
plugin manifests before anything was changed, and the first one turned
out larger than reported.

## The sizing-aware lists were three different lengths

`docs/quickstart.md` listed 9 skills and `docs/concepts.md` listed 12.
Thirteen skills classify their own work, which is what `docs/sizing.md`
already said. Both pages now match it.

The reporter found one missing skill. Four were missing, and the cause
is one line: `CONTRIBUTING.md` step 6 told contributors to update the
sizing and concepts catalogs and never mentioned the quickstart. Four
skill additions between 2026-08-10 and 2026-09-09 updated the two named
pages and left the third behind, so the quickstart's list had been stale
since 2026-05-29. Step 6 now names all three.

`plan-a-feature-to-confluence` declares `arguments: size` and stays out
of all three catalogs on purpose. It forwards the argument to
`plan-a-feature` rather than classifying anything, which step 6's own
opening condition already excludes.

## Two pages denied the `han-reporting` exception they document

`han-reporting` is the only layer plugin that does not declare
`han-core`, and both pages said so correctly before contradicting
themselves.

On `docs/choosing-a-han-plugin.md` the correct half sat in a trailing
parenthetical while the bold sentence two lines below it, under the
heading "The one thing that surprises people", generalized over it. A
skimming reader stops on the bold sentence, so the exception now lives
there.

`docs/concepts.md` listed reporting-only among installs that do not
exist. It is exactly the install that does exist, so the page now says
what it gives you: `/stakeholder-summary` and `/html-summary` plus
`han-communication`, without the `han-core` agent roster.

## The banner has alt text

`README.md` carries the only image embed in the repo's prose and had no
`alt` attribute, so the project name and tagline reached a screen-reader
user as the filename or as nothing.

## What is in this PR

Two commits. The first adds the change plan, the decisions behind it,
and the evidence, under `docs/plans/gh-200-docs-consistency/`. The
second applies the six edits.

Each edit was pinned to exact replacement text before being made, and
each of the plan's three verification checks passes: all three pages now
carry the same 13 names as `docs/sizing.md`, no page outside
`docs/plans/` claims that every layer install brings the shared agents,
and the banner announces the project rather than its filename. `npm run
lint` and `npm test` pass.

## Deliberately not in this PR

An automated check that a skill declaring `arguments: size` reaches
every catalog. It would have caught this drift on the day it started,
where the checklist edit only reminds a person. It is deferred with a
reopening trigger recorded in the plan: a second drift incident, or a
fourth page carrying the list.

Two things the review surfaced and this PR leaves alone, both noted in
the plan's Open Items. The plugin dependency graph is hand-copied across
four files with nothing enforcing agreement, which is the same failure
mode on a different fact. And `han-reporting/README.md` states no
dependencies at all.
Issue #201 reports a pairing session that tucked the piece-3 pre-build
ask under piece 2's stop, read "commit and next" as declining it, built
piece 3 without the person's read, and wrote "ask declined" into the
feedback record as the person's decision. The skill text permits it: the
rule says the ask comes before the build and pairing Step 5 says "ask
first", and neither forbids folding the ask into the previous stop.

`docs/plans/gh-201-pre-build-ask-timing/` holds the change plan, its
decision log, the current-state findings from a structural and
behavioral discovery round, and the scope boundary. The plan re-scopes
three sections of `collaborative-stop-rule.md` (and its two byte-identical
copies), pairing Steps 5 and 6, and the pairing long-form doc, and pins
every sentence the three files must agree on. Two behavior changes were
put to the operator and accepted: the ask is a turn of its own that a
stop never carries, and the record holds the person's words with the
run's reading labeled as the run's. A review round with the junior
developer, UX designer, and risk analyst extended the first change to a
marked first piece, gave the ask's reply a recorded path, and named the
run as the cause in the after-build message. Eight items sit under
Deferred (YAGNI) with their reopening triggers.
Closes #201.

The collaborative stop rule said the pre-build ask comes before the
build and pairing Step 5 said "ask first", and neither forbade folding
the ask into the tail of the previous piece's stop. A run did exactly
that, read "commit and next" as declining the ask it had tucked under
piece 2's stop, built piece 3 without the person's read, and wrote "ask
declined" into the feedback record as the person's decision.

`collaborative-stop-rule.md` now says a stop covers what just closed
and asks nothing about a later piece; the ask is a turn of its own,
opening the marked piece's turn after the person has replied to the
previous stop or to the plan; a reply to a stop or the plan answers
that alone and never counts as declining an ask the person has not
answered; a question about the ask holds it open; a bundled ask was
never posed and is presented on its own before building, and one found
after the build is named with the run as the cause rather than
re-asked. "Never require an answer before building" is gone, because
the build now waits for a reply to the ask, though a decline is a full
reply. The record's entry form is pinned: the person's words, the stop
or ask they answered, and any reading the run adds labeled as the run's,
with one worked example. The two vendored copies in `han-coding` and
`han-planning` are byte-identical to the canonical file.

Pairing Step 5 item 1 carries the same rule in the loop's terms and
names what happens to the reply: recorded against the ask, then the
build, with no pass through Step 6. Item 3 says naming the next concern
is a report, never a question. Step 6 writes the response in the
person's words against the stop or ask it answers. The long-form doc
promises each of these to the person in the same terms and adds one
turn per marked piece to its cost line.

The change plan, decision log, and findings behind every sentence are
under `docs/plans/gh-201-pre-build-ask-timing/`.
Closes #201.

A pairing session tucked the piece-3 pre-build ask under piece 2's stop,
read "commit and next" as declining it, built piece 3 without the
person's read, and wrote "ask declined" into the feedback record as the
person's decision. The skill text allowed it: the rule said the ask
comes before the build and pairing Step 5 said "ask first", and nothing
forbade folding the ask into the previous stop.

## The ask is a turn of its own, and a stop never carries it

`collaborative-stop-rule.md` now says a stop covers what just closed and
asks nothing about a later piece. The ask opens the marked piece's turn
after the person has replied to the previous stop, or to the plan when
the marked piece is the first, and it is the whole turn. A reply to a
stop or the plan answers that alone and never counts as declining an ask
the person has not answered. A question about the ask holds it open.

The line "never require an answer before building" is gone. Read
literally it licensed the build the issue reports. The build now waits
for a reply to the ask, and a decline is a full reply: "I don't know"
still advances the piece.

## A bundled ask is an unanswered ask

When an earlier turn put the ask under a stop or the plan and the reply
spoke only to that, the ask was never posed on its own, so the run
presents it now, on its own, before building. If the piece was already
built when that comes to light, the run says it put the ask under an
earlier turn so it went unanswered, and continues from the stop in hand.
It does not ask after the fact, because an ask after the build collects
the cost and none of the benefit.

## The record holds the person's words

The rule's "Recording what the person says" section pins the entry's
form: the person's words, the stop or ask they answered, and any reading
the run adds labeled as the run's, never written as what the person
decided. One worked example pins the shape. An ask with no entry is an
ask with no answer. This goes one step past the issue's suggested fix;
the issue names the wrong record entry as a second effect, and the
long-form doc already promised the record holds "which piece prompted
it" with nothing delivering it.

## What is in this PR

Two commits. The first adds the change plan, its decision log, the
current-state findings from a structural and behavioral discovery round,
and the scope boundary under `docs/plans/gh-201-pre-build-ask-timing/`.
The second applies the plan: five paragraphs in the canonical rule with
its two vendored copies kept byte-identical, three edits to
`pairing/SKILL.md` (Step 5 item 1 rewritten with what happens to the
ask's reply, one sentence on item 3, Step 6's opening sentence), and
five edits to `han-core/docs/skills/pairing.md` so the doc promises
exactly what the rule delivers, including one more turn per marked piece
in its cost line.

Every sentence the three files must agree on was pinned in the plan
before it was written, and copied rather than paraphrased. `md5 -q`
prints one hash for all three rule copies. `npm run lint` and `npm test`
pass. The five backing skills are untouched: the one new clause they can
act on sits in "What a stop presents", which they already read, and none
of them poses an ask.

## Deliberately not in this PR

Eight items sit under Deferred (YAGNI) in the plan with reopening
triggers, among them a three-state ask marker in the record, ask
behavior inside a "show me the next three" batch, a piece anchor on the
ask turn, and an acknowledgment on a re-presented ask. None is
implicated by the one incident on record.

No ADR links the rule to the pairing plan's decision D7, which named the
sentence this PR removes; the plan's decision D-3 records why it went.
No version bump and no changelog edit; both belong to `/han-release`.
On a Claude Code install backed by Amazon Bedrock the WebSearch tool does
not exist. The research-analyst agent declared it, the harness dropped
the unmatched entry silently, and the agent ran on WebFetch alone while
its report read as though a full survey had happened (#212).

The analyst now notices when WebSearch is not offered to it or a call is
refused, gathers by fetch alone, and opens its return with one fixed
"Web search:" line. The research skill copies that line into the top of
every report under Confidence, shields it from the readability rewrite,
passes it to the validator, and on any run where the value is not "used"
charters a completeness check and names the gap under Remaining Risks.
The agent's tools line, the skill's allowed-tools line, and the source
registry are unchanged. The long-form docs say what happens without
search and that the shipped agent cannot be given another search tool.

Closes #212
#214)

## Summary

- The research-analyst agent now notices when `WebSearch` is not offered
to it (or a call is refused), gathers by fetch alone, and opens its
return with one fixed `**Web search:**` line: `used`, or `not available.
…`.
- The `research` skill copies that line into every report's Summary
directly under Confidence, protects it from the readability rewrite,
passes it to the validator, and on any run where the value is not `used`
adds a completeness check to the validator's charter and a fixed
Remaining Risks entry. A missing line renders as `not reported. …` and
gets the same treatment.
- Nothing else moves: the agent's `tools:` line, the skill's
`allowed-tools:` line, the `A#` registry shape, and
`han-core/agents/adversarial-validator.md` are unchanged. The long-form
docs say what happens without search and that the shipped agent cannot
be given a different search tool (a plugin agent cannot carry its own
MCP server, and its `tools:` list cannot name a server the plugin does
not know).
- The plan behind this, with the decision log and current-state
findings, is in `docs/plans/gh-212-research-websearch-fallback/`. Three
things were deferred with reopening triggers: the GitHub/npm/PyPI fetch
fallback chain, named MCP search patterns in `tools:`, and a config
setting naming a search tool.

## Why

On a Claude Code install backed by Amazon Bedrock (confirmed by the
official docs; the reporter says Vertex too) the `WebSearch` tool does
not exist. A subagent's `tools:` list only narrows, so the unmatched
entry was dropped silently and the analyst ran on `WebFetch` alone while
its report read like a full survey. Nothing captured the fact at its
origin and no downstream rule keyed on it. Fixes #212.

## How to verify

- [ ] `npm run lint` passes.
- [ ] With this branch as the local marketplace source, dispatch
`han-research:research-analyst` directly on an Anthropic-backed install:
the first line of its return is `**Web search:** used`.
- [ ] Run `/research small` on the same install: the report's Summary
shows `- **Web search:** used` directly under Confidence, byte-identical
after the readability pass, and the closing chat message says nothing
about web search.
- [ ] Read Step 6 of `han-research/skills/research/SKILL.md` against an
imagined analyst return with no line: it yields the `not reported`
literal, and Step 7 then includes the completeness sentence.
- [ ] Open item, non-blocking: on a Bedrock install, `/research small`
should render the `not available` line. Nobody on this project has one;
the issue's reporter does, and asking them to paste a Summary is the
concrete check.

## Risk / rollback

Low risk; markdown-only, revert via `git revert`. The one thing to watch
for is a Bedrock report carrying `Web search: used`, which would mean
the analyst did not take the no-search branch there (the protocol names
both triggers, absent-from-list and refused-on-call, so it should hold
under either observation).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants