Skip to content

[FEATURE] Agent-native breakpoint addressing: expectedContent assertion, statement anchors, function breakpoints #271

Description

@debugmcpdev

Problem (an AX lesson)

Agents set breakpoints on the wrong lines because they don't have a gutter. A human points at a statement and the IDE resolves the line number; an agent reads a 1D token stream, keeps a running count (often from a snippet that started mid-file), and commits to an integer — predictably landing off-by-one-or-two on a blank line, a brace, or a comment. The result is confusing session behavior (breakpoint never hits, or hits somewhere unexpected).

Current mitigations all act after commitment or rely on the agent noticing warnings: the response echoes line content, adapters silently snap to the nearest valid line, and the schema description warns about non-executable lines. None of them move the anchor itself.

There is also a drift problem: line numbers go stale the moment the agent edits the file mid-session — which is the core fix-verify loop. restart_debugging (#238) re-applies breakpoints at their recorded lines, so after an edit the re-applied breakpoints can silently point at the wrong code.

Proposal: a progression of addressing modes

All modes return the same resolved contract — {breakpointId, line, content, verified, anchor?} — so list_breakpoints and the audit trail stay uniform. All compose with condition, logMessage, and suspendPolicy unchanged.

1. expectedContent assertion (cheap, ship first)

Keep line addressing, add optional expectedContent: string. Server hard-errors before setting anything if the trimmed line content doesn't match, and the error includes the actual content of that line plus a few neighbors. A checksum on intent: converts off-by-one from 'confusing session behavior' into an immediate, self-explanatory failure. Non-breaking, ~small diff (line content is already read for the response echo).

2. statement anchors (primary agent mode)

set_breakpoint {sessionId, file, statement: \"total = sum(prices)\", nearLine?: 80}

  • Exact-match after trimming leading/trailing whitespace; anchor at the first line of a multi-line match.
  • Ambiguity contract: multiple matches → error listing every match as line: content pairs (the error message is the disambiguation UI; agent picks in one follow-up). nearLine selects the closest match when provided.
  • Reject blank/comment-only anchors with a clear error.
  • Re-resolution: the anchor is stored on the breakpoint record; restart_debugging re-resolves anchors against the current file, so breakpoints survive the edit that was the whole point of the session.
  • Rationale: this recruits the single most-practiced agent skill — Edit-tool old_string matching — instead of demanding line arithmetic, a skill models are demonstrably bad at. Self-validating by construction: an anchor can't land on a blank line.

3. function breakpoints (symbol mode)

set_breakpoint {sessionId, function: \"build_cart\"} via DAP setFunctionBreakpoints, gated on supportsFunctionBreakpoints. Agents reason in symbols more reliably than in lines or statements, and names survive edits better than both.

Supporting: deliberate snapping

Where a line must be adjusted, use DAP breakpointLocations (where supported) to snap explicitly and report it loudly ('requested 12, bound to 13: total = ...') instead of relying on each adapter's silent adjustment.

Non-goals / alternatives considered

  • Fuzzy content matching as the primary mode — rejected: silent wrong-match is the exact failure class we're eliminating. Fuzzy is acceptable only as an explicit nearLine-guided fallback with a warning in the response.
  • AST-based addressing — per-language parser cost across seven adapters for marginal gain over statement + function modes.

Evaluation

This is an agent-experience change, so it should be validated like one: A/B the addressing modes against line-only in a controlled harness (same tasks, same model, feature-flagged server so conditions differ only in the tool contract). Metrics: wrong-breakpoint rate against annotated intended targets, correction re-sets within a few calls, rounds/tokens per task, and root-cause-identification success. Results will be posted here; the skill (skills/debugging/) gets updated with whichever contract wins.

Rollout

  1. expectedContent (non-breaking assertion) + loud snapping
  2. statement/nearLine + restart re-resolution + list_breakpoints anchor display
  3. function mode, capability-gated per adapter

Related: #236 (breakpoint management — record shape), #238 (restart re-apply — re-resolution hook), #235 (logpoints — anchors compose with logMessage).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions