Skip to content

fix(breakpoints): clear the provisional message once a breakpoint verifies - #476

Merged
debugmcpdev merged 4 commits into
debugmcp:mainfrom
MsfPablo:fix/clear-provisional-breakpoint-message
Aug 25, 2026
Merged

fix(breakpoints): clear the provisional message once a breakpoint verifies#476
debugmcpdev merged 4 commits into
debugmcp:mainfrom
MsfPablo:fix/clear-provisional-breakpoint-message

Conversation

@MsfPablo

Copy link
Copy Markdown
Contributor

Closes #471.

Both halves of the issue, fixed at the point where an adapter message is stamped onto a stored breakpoint.

1. Stale state. The provisional message was never cleared once the breakpoint verified, so list_breakpoints asserted verified: true + adapterId alongside a message meaning "Unbound breakpoint".

2. Raw l10n key. The string arrived as a bundle key rather than text, since L10N_FSPATH_TO_BUNDLE is unset in the adapter spawn and l10n.t(key, fallback) then returns the key verbatim.

normalizeBreakpointMessage(message, verified) in src/utils/breakpoint-message.ts drops a provisional note when verified is true, and otherwise resolves known js-debug keys to the English fallback declared at their own l10n.t call site. So the field either says something true or says nothing — and a leaked key never reaches the user either way.

Applied at both stamp sites, not just one. The issue points at the #439 reconciliation path, but that is only half of it: the comment at session-manager-core.ts:823 notes js-debug's worker path never emits breakpoints_synced, so for JavaScript the message actually lands via the breakpoint event handler. Fixing only the #439 path would have left the reported repro untouched. Both now go through the same helper.

Testtests/unit/utils/breakpoint-message.test.ts, including the assertion the issue suggests (a verified breakpoint must not carry a breakpoint. key):

$ npx vitest run tests/unit/utils/breakpoint-message.test.ts   # 5 passed
$ npx tsc --noEmit -p tsconfig.json                            # clean
$ npx vitest run tests/unit tests/core/unit                    # 3205 passed

Against main the same suites give 3200 passed with an identical 3 failures, all in the dotnet adapter and unrelated to this change — so this PR adds 5 passing tests and no failures.

Two environment notes, neither caused by this PR: pnpm install --frozen-lockfile fails on main with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH (overrides drift), and the postinstall CodeLLDB vendor step fails to fetch on this platform. I installed with --no-frozen-lockfile and deliberately reverted pnpm-lock.yaml so it is not part of the diff. Worth a look separately if you weren't aware.

I did not touch the vendored vsDebugServer.js — setting L10N_FSPATH_TO_BUNDLE at spawn time would fix the key at the source for all messages, but that is a larger change to adapter spawning and felt out of scope here. Happy to look at it if you'd prefer that direction.

…ifies

js-debug answers setBreakpoints from its pending-target stub with a
provisional message meaning 'Unbound breakpoint', and nothing cleared it
after the breakpoint bound. list_breakpoints then reported verified:true and
adapterId alongside a message asserting the opposite.

The message also arrived as a raw l10n bundle key, because
L10N_FSPATH_TO_BUNDLE is unset in the adapter spawn and l10n.t(key, fallback)
returns the key verbatim.

normalizeBreakpointMessage drops a provisional note when verified is true and
otherwise resolves known js-debug keys to the English fallback declared at
their call site, so no bundle key reaches the user. Applied at both places
that stamp an adapter message onto a stored breakpoint.

Closes debugmcp#471
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/session/session-manager-core.ts 80.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

…ries no message

Live verification of the repro showed the provisional message is stamped
while the breakpoint is still unverified (so it is stored in translated
form, "Unbound breakpoint"), and js-debug's later bind event flips
verified:true without a message field — leaving the stale note in place,
now in English instead of as a raw key.

Two amendments:
- Treat the translated fallback text as provisional too, since that is
  the form actually stored when stamping happens pre-verification.
- Re-normalize the stored message when an update carries none, at both
  stamp sites, so verification clears a stale provisional note while
  real messages (source-map notes, capability-drift warnings) pass
  through untouched.

Verified against the issue debugmcp#471 repro: list_breakpoints now reports
verified:true, adapterId set, and no message field at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@debugmcpdev

Copy link
Copy Markdown
Collaborator

Thank you — this is an outstanding first contribution. The analysis was exactly right on both counts: the two stamp sites (the #439 reconciliation path and the breakpoint-event path js-debug actually uses), and the l10n-key mechanism. The PR body alone saved a lot of review time.

Before merging I ran the literal #471 repro against your branch, and it surfaced one subtle gap I've fixed with a commit pushed to your branch (15af266 — hope you don't mind, we're bundling this for the 0.25.0 release):

  • The provisional message is stamped while the breakpoint is still unverified, so normalizeBreakpointMessage stores it in translated form ("Unbound breakpoint").
  • js-debug's later bind event flips verified: true without a message field, so the if (eventBp.message !== undefined) guard never revisited the stored text.
  • Net effect on your branch: the raw key was gone (good), but list_breakpoints still reported verified: true + message: "Unbound breakpoint".

The amendment keeps your helper and applies it slightly more aggressively: the translated fallback text counts as provisional too, and both stamp sites re-normalize the stored message when an update carries none. Re-verified against the repro: verified: true, adapterId set, and no message field at all. Your 5 tests still pass, plus 2 new ones for the translated form. Full unit suites: 3210 passed.

On your two environment notes — both appreciated:

  1. ERR_PNPM_LOCKFILE_CONFIG_MISMATCH — root cause is that the repo doesn't pin packageManager, so a different pnpm major computes the lockfile settings differently. A pin + CONTRIBUTING note is landing shortly. Reverting the lockfile out of your diff was exactly the right call.
  2. The CodeLLDB postinstall fetch failure — could you share your platform and the error output? Happy to file and fix that separately.

Will merge once CI is green. Thanks again — contributions at this level of care are very welcome here.

@debugmcpdev
debugmcpdev merged commit 27f9831 into debugmcp:main Aug 25, 2026
8 of 9 checks passed
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.

Verified JS breakpoints keep the raw provisional message 'breakpoint.provisionalBreakpoint' (untranslated key + contradicts verified:true)

3 participants