Skip to content

fix(scripts): lint the agent's checkout in the oracle lint hooks - #2282

Merged
KyleAMathews merged 1 commit into
mainfrom
fix/agent-lint-hook-worktree-root
Oct 28, 2026
Merged

KyleAMathews merged 1 commit into
mainfrom
fix/agent-lint-hook-worktree-root

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

🎯 Changes

The oracle lint hooks now lint the checkout that the agent works in. Fixes #2280.

Before this change, a session that started in the main checkout ran the main checkout's scripts/agent-lint-feedback.mjs. The script took its root from its own location, so the hooks linted the main checkout while the agent worked in .worktrees/<name>. Also, a plain directory under .worktrees/ has no .git entry, so git listed each of its files as new work on the main checkout's branch. The stop hook then returned thousands of reports for scratch copies and snapshots that no session changed.

This PR makes three changes:

  • The script resolves the checkout from the hook input's cwd with git rev-parse --show-toplevel. Without cwd, it uses the checkout that holds the script, as before.
  • When that checkout is another checkout with its own copy of the script, that copy runs. So a branch is linted by its own rule, as CI lints it. The run-budget report and mergeBase use the same checkout.
  • .gitignore lists /.worktrees/.

pnpm lint:changed and the pre-commit hook do not change: they run the script of the checkout they are in.

🔬 Oracle Coverage

Owner: scripts/lint-scope-oracle.property.test.js (scripts.lint-scope).

  • Law: the hooks select and lint the files of the checkout that the input's cwd names, with that checkout's own rule. A plain directory under .worktrees/ is never one of the launch checkout's changed files. Authority: the acceptance criteria in Agent stop hook lints other directories under .worktrees/ instead of the current worktree #2280, and AGENTS.md "Lint feedback while you work".
  • Reach: the grammar now draws a launch or a worktree session and a scratch directory. The driver adds a real worktree at .worktrees/wt and runs the stop hook as well as the edit hook, both from the launch checkout's script. It copies the repository's .gitignore into each temporary repository. When a branch edits the rule, the driver marks the rule's message in that copy only, so each report shows which checkout's rule made it. In 48 histories: worktree-session 25, worktree-own-rule 8, scratch-directory 13. The earlier 15 states are still reached.
  • RED: on unchanged main, the fixed-seed campaign failed for a launch session with a scratch directory (scratch-oracle.test.ts reported). The random-seed campaign failed for a worktree session (expected [case-0-oracle.test.js], observed []).
  • GREEN: vitest run --config scripts/oracle-scripts.vitest.config.mjs scripts/lint-scope-oracle.property.test.js passes both campaigns. pnpm test:lint-rules passes 231 rule tests and 10 script-oracle tests, and pnpm lint:oracles reports nothing.
  • Mutant: four mutants ran on copies, and each failed by assertion:
    • root from the script location only (the original defect): worktree selection empty
    • root from process.cwd(): worktree selection empty
    • no hand-off to the checkout's own script: reports came from the unmarked launch rule
    • .gitignore without /.worktrees/: scratch file reported
  • Limits: the grammar does not generate a hook input without cwd, a worktree outside the launch checkout, or a worktree branch with no copy of the script. In that last case the launch checkout's rule lints the worktree. The coverage map records these limits.

✅ Checklist

  • I have tested this code locally with pnpm test.

The tooling suites above pass. As a live check, this branch's stop hook with cwd set to another worktree ran that worktree's own script. It reported only that branch's budget notices, and no file under .worktrees/.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

This pull request and its description were written by Isaac.

Summary by CodeRabbit

  • Improvements
    • Lint hooks now select changed files and report results for the active checkout, including supported nested worktrees.
    • Worktree lint checks can use the launch checkout’s rules when the active checkout doesn’t contain them.
  • Documentation
    • Updated contributing guidance with checkout selection, worktree boundaries, and cases where hook checks are skipped.
  • Chores
    • Root-level .worktrees/ directories are now ignored by Git.

The agent hooks ran the script of the checkout where the session started and
linted that checkout, even when the agent worked in a worktree under
`.worktrees/`. Plain directories under `.worktrees/` also counted as new work
on the launch checkout's branch, so the stop hook returned thousands of
reports for files that no session changed.

The hooks now resolve the checkout from the hook input's `cwd`. When that
checkout has its own copy of the script, the copy runs, so a branch is linted
by its own rule. `.gitignore` lists `/.worktrees/`.

The lint-scope oracle now draws a launch or worktree session and a scratch
directory, runs the stop hook as well, and checks that every report comes from
the session checkout's own rule.

Fixes #2280.

Co-authored-by: Isaac <no-reply@databricks.com>
@changeset-bot

changeset-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e405e29

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 126684fe-9cf9-4c1c-9b02-ca0b11d937bb
Commits

Reviewing files that changed from the base of the PR and between 45eeef8 and e405e29.

Files selected for processing: 5
  • .gitignore
  • docs/contributing/oracle-coverage.md
  • scripts/agent-lint-feedback.mjs
  • scripts/check-oracle-run-counts.mjs
  • scripts/lint-scope-oracle.property.test.js

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Walkthrough

The lint feedback script now selects the checkout from hook input, delegates to that checkout’s script when available, and calculates changed files and run budgets from its root. The repository ignores root-level .worktrees/ contents, and the property oracle covers launch-checkout and worktree sessions.

Changes: Worktree lint feedback

Layer / File(s) Summary
Checkout selection and lint execution
scripts/agent-lint-feedback.mjs, scripts/check-oracle-run-counts.mjs, .gitignore, docs/contributing/oracle-coverage.md
The script resolves the session checkout from hook input and delegates to its script when available. Changed-file and budget calculations use the selected checkout. Git ignores root-level .worktrees/ contents, and the documentation describes checkout selection and its boundaries.
Checkout and hook scope oracle
scripts/lint-scope-oracle.property.test.js
The property test models launch-checkout and worktree sessions. It checks changed, named, edit-hook, and stop-hook scopes, report marks, and coverage of worktree and scratch-directory cases.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant ClaudeHook
  participant LaunchScript as agent-lint-feedback.mjs
  participant Git
  participant SessionScript as Session checkout script
  ClaudeHook->>LaunchScript: Provide hook input with cwd
  LaunchScript->>Git: Resolve repository at cwd
  alt Session checkout has its own script
    LaunchScript->>SessionScript: Delegate with arguments and hook input
    SessionScript->>Git: Select changed files and merge base in session checkout
  else No distinct session script
    LaunchScript->>Git: Select files and merge base from selected root
  end
Loading

Possibly related issues

Possibly related PRs

  • TanStack/db#2236 — Adds the hook script and original changed-file selection that this pull request modifies.
  • TanStack/db#2233 — Adds createOracleReach, which the property test uses to require worktree and scratch-directory coverage.
  • TanStack/db#2237 — Changes shared oracle campaign and run-budget helpers used by the lint-scope oracle.

Suggested reviewers: tannerlinsley

Merge Risk: Minimal · up to e405e

The reviewed changes have no identified issue that needs resolution before merge. Normal checks remain appropriate.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: linting the agent's checkout in the oracle lint hooks.
Description check Passed The description includes all required template sections and provides detailed change motivation, oracle coverage, test evidence, checklist status, release impact, and known limits.
Linked Issues check Passed Issue #2280 is directly linked and active. The implementation resolves the checkout from hook input cwd with a script-location fallback in scripts/agent-lint-feedback.mjs. It delegates to the sele…
Out of Scope Changes check Passed The changes stay within Issue #2280. The updates to scripts/check-oracle-run-counts.mjs, the property test, coverage documentation, and .gitignore directly support checkout selection, rule selecti…
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Full details: Linked Issues check

Explanation

Issue #2280 is directly linked and active. The implementation resolves the checkout from hook input cwd with a script-location fallback in scripts/agent-lint-feedback.mjs. It delegates to the selected checkout's own script when that copy exists. Changed-file, oracle-file, run-budget, and mergeBase operations use the selected checkout. .gitignore excludes /.worktrees/, so plain scratch directories do not enter the launch checkout's untracked-file set. The property test exercises launch sessions, worktree sessions, scratch directories, edit hooks, and stop hooks. The documented acceptance case for pnpm lint:changed remains supported because the command uses the script in its current checkout.

Full details: Out of Scope Changes check

Explanation

The changes stay within Issue #2280. The updates to scripts/check-oracle-run-counts.mjs, the property test, coverage documentation, and .gitignore directly support checkout selection, rule selection, worktree isolation, and verification. No unrelated product or release changes are present.

Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 12 functions across 3 files. (2 skipped: 2 unsupported.)

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Oct 28, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/angular-db@2282

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/browser-db-sqlite-persistence@2282

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/capacitor-db-sqlite-persistence@2282

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@2282

@tanstack/convex-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/convex-db-collection@2282

@tanstack/db

npm i https://pkg.pr.new/TanStack/db/@tanstack/db@2282

@tanstack/db-ivm

npm i https://pkg.pr.new/TanStack/db/@tanstack/db-ivm@2282

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/TanStack/db/@tanstack/db-sqlite-persistence-core@2282

@tanstack/electric-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/electric-db-collection@2282

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/electron-db-sqlite-persistence@2282

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/expo-db-sqlite-persistence@2282

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/node-db-sqlite-persistence@2282

@tanstack/offline-transactions

npm i https://pkg.pr.new/TanStack/db/@tanstack/offline-transactions@2282

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/powersync-db-collection@2282

@tanstack/preact-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/preact-db@2282

@tanstack/query-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/query-db-collection@2282

@tanstack/react-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/react-db@2282

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/react-native-db-sqlite-persistence@2282

@tanstack/react-router-with-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/react-router-with-db@2282

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/rxdb-db-collection@2282

@tanstack/solid-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/solid-db@2282

@tanstack/svelte-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/svelte-db@2282

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/TanStack/db/@tanstack/tauri-db-sqlite-persistence@2282

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/TanStack/db/@tanstack/trailbase-db-collection@2282

@tanstack/vue-db

npm i https://pkg.pr.new/TanStack/db/@tanstack/vue-db@2282

commit: e405e29

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 237 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/client.js 5.39 kB
packages/db/dist/esm/collection-options-brand.js 219 B
packages/db/dist/esm/collection-options.js 258 B
packages/db/dist/esm/collection/change-events.js 1.76 kB
packages/db/dist/esm/collection/changes.js 3.06 kB
packages/db/dist/esm/collection/cleanup-queue.js 828 B
packages/db/dist/esm/collection/config-errors.js 547 B
packages/db/dist/esm/collection/events.js 504 B
packages/db/dist/esm/collection/health-tree.js 698 B
packages/db/dist/esm/collection/index.js 6.32 kB
packages/db/dist/esm/collection/indexes.js 2.3 kB
packages/db/dist/esm/collection/lifecycle.js 5.59 kB
packages/db/dist/esm/collection/mutations.js 2.95 kB
packages/db/dist/esm/collection/state.js 7.69 kB
packages/db/dist/esm/collection/subscription.js 9.54 kB
packages/db/dist/esm/collection/sync.js 6.51 kB
packages/db/dist/esm/collection/validate-config.js 1.17 kB
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/error-message.js 642 B
packages/db/dist/esm/errors.js 7.27 kB
packages/db/dist/esm/event-emitter.js 1.06 kB
packages/db/dist/esm/index.js 4.79 kB
packages/db/dist/esm/indexed-db-wrapper.js 1.91 kB
packages/db/dist/esm/indexed-db.js 3.81 kB
packages/db/dist/esm/indexes/auto-index.js 924 B
packages/db/dist/esm/indexes/base-index.js 1.92 kB
packages/db/dist/esm/indexes/basic-index.js 1.93 kB
packages/db/dist/esm/indexes/btree-index.js 1.62 kB
packages/db/dist/esm/indexes/index-registry.js 916 B
packages/db/dist/esm/indexes/reverse-index.js 1.01 kB
packages/db/dist/esm/live-query-adapter.js 845 B
packages/db/dist/esm/live-query-observer-client.js 2.17 kB
packages/db/dist/esm/live-query-observer.js 3.3 kB
packages/db/dist/esm/live-query-options.js 2.02 kB
packages/db/dist/esm/live-query-primitives.js 406 B
packages/db/dist/esm/live-query-window-binding.js 1.56 kB
packages/db/dist/esm/live-query-window-controller.js 4.02 kB
packages/db/dist/esm/local-only.js 1.02 kB
packages/db/dist/esm/local-storage.js 4.58 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 1.11 kB
packages/db/dist/esm/proxy.js 3.51 kB
packages/db/dist/esm/query/builder/clone-query.js 854 B
packages/db/dist/esm/query/builder/functions.js 1.61 kB
packages/db/dist/esm/query/builder/group-keys.js 157 B
packages/db/dist/esm/query/builder/include-functions.js 229 B
packages/db/dist/esm/query/builder/index.js 7.72 kB
packages/db/dist/esm/query/builder/query-ir.js 312 B
packages/db/dist/esm/query/builder/ref-proxy-identity.js 292 B
packages/db/dist/esm/query/builder/ref-proxy.js 1.67 kB
packages/db/dist/esm/query/builder/wrapper-identity.js 221 B
packages/db/dist/esm/query/compiler/evaluators.js 2.51 kB
packages/db/dist/esm/query/compiler/expressions.js 603 B
packages/db/dist/esm/query/compiler/find-aggregate.js 328 B
packages/db/dist/esm/query/compiler/group-by.js 4.42 kB
packages/db/dist/esm/query/compiler/grouping.js 161 B
packages/db/dist/esm/query/compiler/index.js 10.4 kB
packages/db/dist/esm/query/compiler/joins.js 3.42 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 1.11 kB
packages/db/dist/esm/query/compiler/order-by.js 2.8 kB
packages/db/dist/esm/query/compiler/parent-routes.js 319 B
packages/db/dist/esm/query/compiler/query-equivalence.js 568 B
packages/db/dist/esm/query/compiler/route-metadata.js 1.24 kB
packages/db/dist/esm/query/compiler/select.js 1.5 kB
packages/db/dist/esm/query/effect.js 5.79 kB
packages/db/dist/esm/query/equality-conjunct.js 486 B
packages/db/dist/esm/query/equality-value-identity.js 736 B
packages/db/dist/esm/query/expression-helpers.js 1.61 kB
packages/db/dist/esm/query/ir-stable-identity.js 4.29 kB
packages/db/dist/esm/query/ir.js 2.26 kB
packages/db/dist/esm/query/join-conditions.js 257 B
packages/db/dist/esm/query/live-query-collection.js 391 B
packages/db/dist/esm/query/live/bucket-facade-adapter.js 3.17 kB
packages/db/dist/esm/query/live/collection-config-builder.js 8.24 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 2.64 kB
packages/db/dist/esm/query/live/graph-scheduler.js 305 B
packages/db/dist/esm/query/live/includes-runtime.js 212 B
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/materialized-pipeline.js 1.94 kB
packages/db/dist/esm/query/live/ordered-source-loader.js 6.47 kB
packages/db/dist/esm/query/live/public-key-reduction.js 970 B
packages/db/dist/esm/query/live/subset-demand-controller.js 2.44 kB
packages/db/dist/esm/query/live/utils.js 1.35 kB
packages/db/dist/esm/query/optimizer.js 2.95 kB
packages/db/dist/esm/query/pooled-live-query.js 5.14 kB
packages/db/dist/esm/query/pooled-source.js 219 B
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/runtime-reference-identity.js 630 B
packages/db/dist/esm/query/subset-dedupe.js 493 B
packages/db/dist/esm/scheduler.js 1.23 kB
packages/db/dist/esm/SortedMap.js 1.77 kB
packages/db/dist/esm/strategies/commit-completion.js 156 B
packages/db/dist/esm/strategies/debounceStrategy.js 658 B
packages/db/dist/esm/strategies/queueStrategy.js 523 B
packages/db/dist/esm/strategies/serial-pacer.js 486 B
packages/db/dist/esm/strategies/throttleStrategy.js 738 B
packages/db/dist/esm/sync-persistence.js 626 B
packages/db/dist/esm/sync-receipt.js 211 B
packages/db/dist/esm/transaction-commit-work.js 351 B
packages/db/dist/esm/transactions.js 4.57 kB
packages/db/dist/esm/utils.js 1.77 kB
packages/db/dist/esm/utils/array-utils.js 270 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 3.02 kB
packages/db/dist/esm/utils/callbacks.js 219 B
packages/db/dist/esm/utils/comparison.js 1.95 kB
packages/db/dist/esm/utils/cursor.js 753 B
packages/db/dist/esm/utils/error.js 262 B
packages/db/dist/esm/utils/get-or-create.js 155 B
packages/db/dist/esm/utils/index-optimization.js 2.58 kB
packages/db/dist/esm/utils/source-record.js 140 B
packages/db/dist/esm/utils/type-guards.js 230 B
packages/db/dist/esm/utils/uuid.js 530 B
packages/db/dist/esm/virtual-props.js 413 B
packages/react-db/dist/esm/DbProvider.js 317 B
packages/react-db/dist/esm/development.js 190 B
packages/react-db/dist/esm/HydrationBoundary.js 263 B
packages/react-db/dist/esm/index.js 330 B
packages/react-db/dist/esm/live-query-internals.js 282 B
packages/react-db/dist/esm/source-id-bindings.js 339 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.52 kB
packages/react-db/dist/esm/useLiveQuery.js 3.41 kB
packages/react-db/dist/esm/useLiveQueryEffect.js 504 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 1.37 kB
packages/react-db/dist/esm/usePacedMutations.js 429 B

compressed-size-action::db-and-react-package-size

@KyleAMathews
KyleAMathews merged commit b305fb2 into main Oct 28, 2026
25 checks passed
@KyleAMathews
KyleAMathews deleted the fix/agent-lint-hook-worktree-root branch October 28, 2026 17:23
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.

Agent stop hook lints other directories under .worktrees/ instead of the current worktree

1 participant