Skip to content

chore(lint): cover tools/ in the lint gate; attach cause in dev-proxy rebuild() (#718) - #745

Merged
debugmcpdev merged 3 commits into
mainfrom
fix/718-lint-covers-tools
Sep 16, 2026
Merged

debugmcpdev merged 3 commits into
mainfrom
fix/718-lint-covers-tools

Conversation

@debugmcpdev

@debugmcpdev debugmcpdev commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Closes #718.

What

pnpm lint — and so .husky/pre-push and all three CI jobs that run it — linted src/, packages/*/src/ and scripts/ but not tools/. The dev-proxy supervisor under tools/dev-proxy/ starts, stops and proxies the backend; it sat outside the gate with two preserve-caught-error errors in BackendManager.rebuild() (lines 366 and 375 on current main — the issue's 355/364 are from an older revision) that nothing reported.

  • package.jsonlint gains "tools/**/*.{js,mjs,cjs}". A superset of the issue's tools/dev-proxy/**: tools/ contains only the dev-proxy today, so the findings are identical, and a future tools/ directory is covered by default. Experimental probes belong in scripts/experiments/, which eslint.config.js already ignores. No ESLint config change: the **/*.{js,mjs,cjs} block already configures .mjs with node globals, and preserve-caught-error comes from js.configs.recommended.
  • lint:fix now runs the same four globs with --fix instead of src/**/*.ts alone, so the hook's "run pnpm run lint:fix for auto-fixes" hint is true for everything lint reports. (Running it over the widened globs on this tree changes nothing.)
  • tools/dev-proxy/dev-proxy.mjs — both rebuild() rethrows attach the caught execSync error as cause. Safe with respect to dev-proxy forwards backend stderr verbatim with naive chunk splitting #154's sanitization: every consumer of that error serializes err.message alone (handleDevTool's two catches, the fatal handler), so the raw build output on cause never reaches a tool response or a log line.
  • tests/integration/dev-proxy-startup.test.tsrebuild() and its catch blocks had no coverage. A new case sets DEV_PROXY_BUILD_CMD to a failing command and calls dev_rebuild_and_restart: the payload is exactly { success: false, error: "Build failed: …boom…" } with no cause, and the old backend keeps serving because the build failed before the restart.
  • DocsCONTRIBUTING.md (Dev-Loop Gate + Setup), AGENTS.md, and the adapter guide's checklist (which already omitted scripts/**) state the new glob set and drop the lint/lint:fix asymmetry note.

Verification

  • pnpm exec eslint "tools/**/*.{js,mjs,cjs}": 2 errors before, 0 after.
  • pnpm run lint (now covering tools/) clean; typecheck:all, changelog:check, check:docs clean.
  • tests/integration/dev-proxy-startup.test.ts: 6/6 (the new case 1.2 s).
  • Pre-push gate passed.

🤖 Generated with Claude Code

Review round (4aa0f41)

The /code-review on the first commit looked at what the newly-covered catch blocks actually said, and three of its findings were real defects in those lines:

  • A buffer overflow was reported as a timeout. err.killed || err.signal === 'SIGTERM' was the timeout test, but execSync never sets killed, and an output-buffer overflow (ENOBUFS, 1 MiB default) arrives with the same SIGTERM — probed on this box: timeout → code: 'ETIMEDOUT', overflow → code: 'ENOBUFS', both signal: 'SIGTERM'. The timeout branch now keys on ETIMEDOUT, and maxBuffer is 64 MiB so an over-chatty build is not killed at all.
  • A timed-out build discarded the output it had produced. The timeout message now carries the same sanitized tail the failure message does, so "where was it when it hung" is answered.
  • A failed build sent a spurious tools/list_changed. The build fails before restart() runs, so the backend — and its tool inventory — is untouched, yet both handlers announced a change. Build and restart are now sequenced by one helper (rebuildThenRestart) that notifies only for a restart failure; BackendManager.rebuildAndRestart() is gone, and a rejected env update no longer notifies either.
  • lint:fix is pnpm run lint --fix — one glob list instead of a second copy that could drift again (the drift class this issue is about).
  • The integration case is renamed to what it can observe (it cannot see cause), asserts that no notification is added past the initial start's own, and a second case drives a hanging build through DEV_PROXY_BUILD_TIMEOUT_MS=1000. Both fail on the previous dev-proxy.mjs.

Declined here: making rebuild() async (execSync blocks the supervisor for the length of the build) is a concurrency-model change rather than a lint-gate fix — filed as #748. Attaching a slimmed cause instead of the raw execSync error would defeat preserve-caught-error's purpose; the message-only contract is documented at the throw site and locked by the tests.

Verification after the round: tests/integration/dev-proxy-startup.test.ts 7/7; lint (tools/ included), typecheck:all, changelog:check, check:docs clean; pre-push gate passed.

… rebuild() (#718)

`pnpm lint` (pre-push and CI) linted src/, packages/*/src/ and scripts/
but not tools/, so the dev-proxy supervisor sat outside the gate with two
preserve-caught-error findings in BackendManager.rebuild() that nothing
reported.

- package.json: add "tools/**/*.{js,mjs,cjs}" to `lint`; `lint:fix` now
  runs the same globs with --fix instead of src/**/*.ts alone, so the
  hook's "run lint:fix" hint holds for every finding lint reports.
  tools/ contains only the dev-proxy; experimental probes live in
  scripts/experiments/, already ignored by eslint.config.js.
- dev-proxy.mjs: both rebuild() rethrows attach the caught execSync error
  as `cause`. The tool handlers serialize err.message alone, so the raw
  build output never reaches a response (issue #154's invariant).
- tests/integration/dev-proxy-startup.test.ts: drive dev_rebuild_and_restart
  through a failing DEV_PROXY_BUILD_CMD — the payload is { success, error }
  with a "Build failed:" message, no cause, and the old backend keeps
  serving. rebuild() had no coverage before.
- CONTRIBUTING, AGENTS.md and the adapter guide's checklist state the
  new glob set (the guide's line already omitted scripts/).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…al output, and never announce an inventory change for a failed build (#718)

Review of #745 on the catch blocks the lint gate now covers:

- `err.killed || err.signal === 'SIGTERM'` misclassified an execSync
  ENOBUFS kill (1 MiB default buffer) as a timeout — both arrive with
  signal SIGTERM and execSync never sets `killed` (probed: timeout →
  code ETIMEDOUT, overflow → code ENOBUFS). Discriminate on ETIMEDOUT and
  raise maxBuffer to 64 MiB so an over-chatty build is not killed at all.
- The timeout message now carries the sanitized output produced before
  the kill, the way the failure message already did.
- A failed build never reaches restart(), so the running backend's tool
  inventory is unchanged; the handlers used to send tools/list_changed
  for it anyway. Build and restart are now sequenced by one helper that
  notifies only for a restart failure (rebuildAndRestart() is gone; a
  rejected env update no longer notifies either).
- lint:fix is `pnpm run lint --fix`: one glob list, no second copy to
  drift (the drift this issue is about).
- Integration tests: the failed-build case asserts no notification is
  added past the initial start's own; a new hanging-build case asserts
  the timeout message and its partial output. Both fail on the previous
  dev-proxy.mjs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@debugmcpdev
debugmcpdev merged commit 5712c40 into main Sep 16, 2026
10 checks passed
@debugmcpdev
debugmcpdev deleted the fix/718-lint-covers-tools branch September 16, 2026 22:45
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.

Dev-loop lint gate omits tools/dev-proxy, leaving runtime supervisor code unchecked

2 participants