You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e5b6d5c
Browse filesBrowse the repository at this point in the historyBrowse files
#378: waitForChildEventFlush paid an unconditional 150ms settle per
terminal signal on every adapter — the typeof guard was dead code because
MinimalDapClient defines flushChildEvents unconditionally, and terminal
slots chain, so a normal teardown paid 300-450ms of pure sleep on
python/ruby/go/java/dotnet/rust/cpp/mock. flushChildEvents now returns
undefined when no childSessionManager exists and the worker skips the
flush-and-settle entirely on an empty first round; the js-debug two-round
+ settle path is preserved byte-for-byte (#366 stays fixed).
#379: the #367 substring/comment-stripped relaxation of expectedContent
and statement anchors silently weakened the "cannot land on the wrong
line" guarantee — a substring pass was indistinguishable from an exact
match, and restart re-resolution (nearLine always supplied) could snap a
generic anchor among multiple matches without a trace. Matching behavior
is unchanged; the signal is restored:
- assertLineContent reports matchQuality (exact/substring/comment-stripped);
set_breakpoint warns on non-exact matches, quoting the actual line
- resolveStatement reports the candidate list when nearLine picked among
multiple matches; set_breakpoint and restart_debugging surface it
(anchorResolution.moved[].candidates + warning)
- statement+expectedContent compatibility gate aligned with the relaxed
predicate (trailing comments ignored, either side may be a substring)
- tool schema, skill content, and docs reworded to the true guarantee
("only lands on a line containing your text") and the stale whole-line
equality bullet in tool-reference fixed
Verified: 3647 unit tests green, e2e smoke 76/76, live python teardown
terminal chain ~1ms (was 300ms+), live js-debug run-to-completion output
capture intact, live substring warning confirmed.
Co-authored-by: JF <john.franklin@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/tool-reference.md
+6-6Lines changed: 6 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -141,10 +141,10 @@ Sets a breakpoint in a source file.
141
141
-`sessionId` (string, required): The ID of the debug session.
142
142
-`file` (string, required): Path to the source file (absolute or relative to project root).
143
143
-`line` (number, required): Line number where to set breakpoint (1-indexed).
144
-
-`statement` (string, optional): **Content addressing** — instead of `line`, pass the text of the target line, like an Edit-tool match — a distinctive substring is enough (leading/trailing whitespace and trailing `//`/`#` comments are ignored; an exact whole-line match always wins over substring matches). Cannot land on the wrong line; if the text appears on multiple lines the error lists every match; anchors re-resolve across `restart_debugging` after file edits. Provide `statement` OR `line`, not both. See [Statement anchors](#statement-anchors).
144
+
-`statement` (string, optional): **Content addressing** — instead of `line`, pass the text of the target line, like an Edit-tool match — a distinctive substring is enough (leading/trailing whitespace and trailing `//`/`#` comments are ignored; an exact whole-line match always wins over substring matches). Can only land on a line containing your stated text — an inexact or multi-candidate match still sets the breakpoint but adds a `warning` to the response; if the text appears on multiple lines the error lists every match; anchors re-resolve across `restart_debugging` after file edits. Provide `statement` OR `line`, not both. See [Statement anchors](#statement-anchors).
145
145
-`function` (string, optional): **Symbol addressing** — break on entry to a function/method by name (DAP function breakpoint). Session-global: no `file` or `line` at all, and names survive edits better than both. Composes with `condition` only. Supported by Python, Go, Rust, C/C++, .NET, Java, and JavaScript (JavaScript names are dotted runtime paths delivered over the CDP bridge — see [Function breakpoints](#function-breakpoints)); Ruby is accepted with a warning and validated at launch.
146
146
-`nearLine` (number, optional): With `statement` only — when the statement text appears on multiple lines, bind to the match closest to this line (ties go to the lower line).
147
-
-`expectedContent` (string, optional): With `line` only — assert the text of the target line before setting; a distinctive substring is enough (leading/trailing whitespace and trailing `//`/`#` comments are ignored). On a mismatch the breakpoint is **not** set and the error shows the actual content of that line and its neighbors — a fast, self-explanatory failure instead of a breakpoint that silently lands on the wrong line. See [Content assertions and loud snapping](#content-assertions-and-loud-snapping).
147
+
-`expectedContent` (string, optional): With `line` only — assert the text of the target line before setting; a distinctive substring is enough (leading/trailing whitespace and trailing `//`/`#` comments are ignored). On a mismatch the breakpoint is **not** set and the error shows the actual content of that line and its neighbors — a fast, self-explanatory failure instead of a breakpoint that silently lands on the wrong line. A relaxed match (substring, or one that only holds after ignoring text past a `//`/`#` marker) still sets the breakpoint but adds a `warning` quoting the actual line. See [Content assertions and loud snapping](#content-assertions-and-loud-snapping).
148
148
-`condition` (string, optional): Conditional expression — only break (or log) when it evaluates truthy.
149
149
-`logMessage` (string, optional): Create a **logpoint** instead of a pausing breakpoint — see [Logpoints](#logpoints) below.
150
150
-`suspendPolicy` (string, optional): Suspend policy when the breakpoint is hit — `"all"` suspends all threads (default), `"thread"` suspends only the event thread. Only supported by the Java/JDI adapter.
@@ -207,12 +207,12 @@ Relatedly, when a debug adapter *accepts* a breakpoint but binds it to a differe
-**Matching**: whole-line equality after trimming leading/trailing whitespace. Multi-line input is rejected — anchor on the first line of a multi-line construct.
211
-
-**Ambiguity is an error, and the error is the disambiguation UI**: every matching `line: content` pair is listed (capped at 20); add `nearLine` to bind to the closest match.
210
+
-**Matching**: whole-line equality after trimming leading/trailing whitespace; when no exact match exists anywhere, a substring match against comment-stripped lines is accepted (exact matches always win — the two populations never mix). Multi-line input is rejected — anchor on the first line of a multi-line construct.
211
+
-**Ambiguity is an error, and the error is the disambiguation UI**: every matching `line: content` pair is listed (capped at 20); add `nearLine` to bind to the closest match. A `nearLine` pick among multiple matches adds a `warning` naming every candidate line — proximity is a heuristic, not a guarantee.
212
212
-**Blank/comment anchors are rejected** (`#`, `//`, `/*` prefixes) — debuggers cannot break there reliably.
213
-
-**The anchor is stored on the breakpoint record** (visible in `list_breakpoints`) and **re-resolves on `restart_debugging`**: after you edit the file — the whole point of a debug session — the relaunch re-finds each anchored statement in the current file (the breakpoint's previous line breaks ties between duplicates). Moves are reported in the restart response's `data.anchorResolution.moved`; anchors that no longer match keep their previous line and warn (`data.anchorResolution.stale`) rather than failing the restart or dropping state.
213
+
-**The anchor is stored on the breakpoint record** (visible in `list_breakpoints`) and **re-resolves on `restart_debugging`**: after you edit the file — the whole point of a debug session — the relaunch re-finds each anchored statement in the current file (the breakpoint's previous line breaks ties between duplicates). Moves are reported in the restart response's `data.anchorResolution.moved` — a move picked among multiple matching lines carries a `candidates` list and a restart `warning`; anchors that no longer match keep their previous line and warn (`data.anchorResolution.stale`) rather than failing the restart or dropping state.
214
214
- Same readable-file requirement as `expectedContent` (no Java FQCNs, no attach sessions); composes with `condition`, `logMessage`, and `suspendPolicy` unchanged.
215
-
- A matching `expectedContent` alongside `statement` is accepted as redundant; a *different* one is an error (contradictory intent).
215
+
- A matching `expectedContent` alongside `statement` is accepted as redundant (matching under the same relaxed rules: trailing comments ignored, either value may be a substring of the other); a genuinely*different* one is an error (contradictory intent).
Copy file name to clipboardExpand all lines: skills/debugging/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -48,7 +48,7 @@ Rules that prevent 90% of failed sessions:
48
48
49
49
1. State a hypothesis about where reality diverges from expectation *before* setting breakpoints.
50
50
2. Set at most two breakpoints: last-known-good and first-known-bad. Run, inspect, halve the interval. Bisection beats stepping line-by-line from the top. Move the window mid-session with `remove_breakpoint` / `clear_breakpoints`; `list_breakpoints` shows what is currently set (with verified state and adapter ids).
51
-
- Prefer `statement: "<line text>"` over line numbers: it matches like an Edit-tool `old_string` (whole line or a distinctive substring — whitespace-trimmed, trailing comments ignored, exact matches win), cannot land on the wrong line, lists every occurrence on ambiguity (add `nearLine` to pick one), and re-resolves across `restart_debugging` after you edit the file. When you do address by line, pass `expectedContent: "<line text or distinctive substring>"` (trailing comments ignored) so a stale or off-by-one line number fails immediately with the actual nearby lines. A response saying `requested line N, bound to line M` means the adapter moved the breakpoint — trust the bound line.
51
+
- Prefer `statement: "<line text>"` over line numbers: it matches like an Edit-tool `old_string` (whole line or a distinctive substring — whitespace-trimmed, trailing comments ignored, exact matches win), only lands on a line containing your text (inexact or multi-candidate matches are flagged in the response `warning`), lists every occurrence on ambiguity (add `nearLine` to pick one), and re-resolves across `restart_debugging` after you edit the file. When you do address by line, pass `expectedContent: "<line text or distinctive substring>"` (trailing comments ignored) so a stale or off-by-one line number fails immediately with the actual nearby lines. A response saying `requested line N, bound to line M` means the adapter moved the breakpoint — trust the bound line.
52
52
-`function: "name"` breaks on entry to a symbol with no file or line at all — names survive edits best. Supported by Python/Go/Rust/.NET/Java/JavaScript (Java accepts bare `method`, `Class.method`, or fully-qualified names and binds every concrete overload; JavaScript names are dotted runtime paths like `obj.method` bound to the current function value — main-module function declarations bind at launch, functions in lazily-loaded modules bind at the next pause).
53
53
3. When pausing is too disruptive (hot loops, live or attached processes), use a **logpoint**: `set_breakpoint` with `logMessage: "x={x}"` streams interpolated values into `get_output` without stopping the program (Python/JS/Go/Rust; Java and .NET reject it with a clear error).
54
54
4. At each pause, record what you *learned* (variable values, actual control flow), not just where you are.
// A matching expectedContent alongside a statement anchor is redundant
702
698
// but harmless — agents combine them constantly (issue #280), so only
703
-
// genuinely contradictory intent is an error.
704
-
thrownewMcpError(
705
-
McpErrorCode.InvalidParams,
706
-
'statement and expectedContent disagree; a statement anchor is already content-addressed. Provide one or the other (a matching expectedContent is accepted as redundant).'
707
-
);
699
+
// genuinely contradictory intent is an error. "Matching" mirrors the
700
+
// relaxed assertLineContent predicate (issue #379): either value may be
701
+
// the more complete form of the other, and stale trailing comments on
'statement and expectedContent disagree; a statement anchor is already content-addressed. Provide one or the other (a matching expectedContent is accepted as redundant).'
// The breakpoint management tools below deliberately skip validateSession's
@@ -1016,7 +1053,7 @@ export class DebugMcpServer {
1016
1053
if(supportsStatementAnchors(bpMode)){
1017
1054
setBreakpointExtraProps.statement={
1018
1055
type: 'string',
1019
-
description: 'Address by content instead of line number: the text of the target line, like an Edit-tool match — a distinctive substring is enough (leading/trailing whitespace and trailing //- or #-comments are ignored; an exact whole-line match always wins over substring matches). Preferred over line — it cannot land on the wrong line and survives file edits across restart_debugging. If the text appears on multiple lines, the error lists every match; add nearLine to pick one. Provide statement OR line, not both'
1056
+
description: 'Address by content instead of line number: the text of the target line, like an Edit-tool match — a distinctive substring is enough (leading/trailing whitespace and trailing //- or #-comments are ignored; an exact whole-line match always wins over substring matches). Preferred over line — it can only land on a line containing your text (an inexact or multi-candidate match adds a warning to the response) and survives file edits across restart_debugging. If the text appears on multiple lines, the error lists every match; add nearLine to pick one. Provide statement OR line, not both'
0 commit comments