Skip to content

fix(stack): explain unresolvedSource frames in the adapter's own terms (#816) - #822

Merged
debugmcpdev merged 4 commits into
mainfrom
fix/816-unresolved-source-hint
Sep 29, 2026
Merged

debugmcpdev merged 4 commits into
mainfrom
fix/816-unresolved-source-hint

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Summary

Closes #816.

get_stack_trace appended js-debug's remedy to the note of every session whose frames carry unresolvedSource: true:

N frame(s) are source-mapped to files not present on this host (unresolvedSource: true) — their file is a label, not an openable path; attach with adapterConfig.sourceMaps: false to see the generated .js paths instead.

On a C/C++ attach that sentence sat under nine native frames (@NtWaitForSingleObject, @WaitForSingleObjectEx, @__tmainCRTStartup, @BaseThreadInitThunk, …). Nothing was source-mapped, there are no generated .js paths, and sourceMaps is a key the C/C++ adapter does not know. A Java session's kept JDK label (java/io/PrintStream.java) got the same sentence; a js-debug launch was told to "attach with adapterConfig…" too.

Measured

Windows 11, CodeLLDB 1.11.8, examples/cpp/pause_test.cpp attached by PID through a nested mcp-debugger with DAP_TRACE=1: the flagged frames arrive as source: { name: "@NtWaitForSingleObject", sourceReference: 1004 } (no path, most with presentationHint: "subtle"), so the resolver's rule (sourceReference != 0, not a <…> placeholder) is what flags them — the flag is right; the explanation was js-debug's.

Fix

  • The note's first sentence is adapter-neutral: N frame(s) have no source file on this host (unresolvedSource: true) — their file is a label, not an openable path; do not pass it to get_source_context.
  • New optional policy hook describeUnresolvedSource({ count, attachMode }) (next to describePendingStop, same try/catch consumption — a throwing hook costs only the sentence) supplies what such a frame is under the debugger:
    • js-debug: "They are source-mapped to files the package did not ship (a .js.map whose sources are not on disk); attach with adapterConfig.sourceMaps: false …" — spelled adapterLaunchConfig.sourceMaps: false for a launch session.
    • CodeLLDB (cpp, rust, cobol share describeLldbUnresolvedSource): "They are native frames without debug info (system libraries, CRT start-up) that CodeLLDB names by symbol; the program's own frames are the ones with a file path."
    • Policies with nothing to add (Java today) leave the neutral sentence alone.

Tests

  • server-inspection-tools.test.ts: the js get_stack_trace: includeInternals:false still returns ~50 node_modules frames, and source-mapped frames show unopenable relative '../src/…' paths #655 case is now an explicit js-debug attach fixture; new cases for a js launch (launch-side key), a cpp attach with the measured @symbol frames (LLDB sentence, no sourceMaps), a policy with nothing to add, and a throwing hook.
  • Policy units: js (attach/launch spelling), cpp, rust, cobol.
  • session-manager-dap.test.ts: the measured @symbol + sourceReference shape is flagged unresolvedSource, the program's frame is not.
  • e2e mcp-server-smoke-cpp-attach.test.ts (run locally on Windows): the note never carries sourceMaps/source-mapped and explains native frames when any are flagged.
  • npm run typecheck:all (0 errors), npm run lint, node scripts/check-docs.mjs clean.

Docs

docs/tool-reference.md (get_stack_trace notes), docs/stack-trace-filtering.md, docs/usage.md, docs/agent-debugging-guide.md, docs/cpp/README.md, docs/architecture/adapter-policy-pattern.md (the hook), changelog.d/816.fixed.md.

Note: this branch and #821 (#817) both touch tests/e2e/mcp-server-smoke-cpp-attach.test.ts in the same region; whichever merges second needs a trivial merge of the two assertion blocks.

🤖 Generated with Claude Code

#816)

get_stack_trace appended js-debug's remedy ("attach with
adapterConfig.sourceMaps: false to see the generated .js paths") to the
note of every session whose frames carry unresolvedSource: true. On a
C/C++ attach that was nine native frames CodeLLDB names by symbol
(@NtWaitForSingleObject, @BaseThreadInitThunk, …) because they have no
debug info — nothing was source-mapped and sourceMaps is a key the C/C++
adapter does not know. Java's kept JDK label got the same sentence.

- The note's first sentence is adapter-neutral ("N frame(s) have no
  source file on this host (unresolvedSource: true) — their file is a
  label, not an openable path; do not pass it to get_source_context").
- New optional policy hook describeUnresolvedSource({count, attachMode})
  supplies what such a frame IS under the debugger: js-debug names the
  unshipped source map and spells the switch for the session's mode
  (adapterConfig.sourceMaps on attach, adapterLaunchConfig.sourceMaps on
  launch — the old sentence said "attach" on launches too); the CodeLLDB
  policies (cpp/rust/cobol share describeLldbUnresolvedSource) say the
  frames are native code without debug info and that the program's own
  frames are the ones with a path. Policies with nothing to add leave
  the neutral sentence alone; a throwing hook costs only the sentence.

Measured (Windows cpp attach, CodeLLDB 1.11.8, DAP trace): the flagged
frames are `source: {name: '@symbol', sourceReference: N}` with no path,
so the resolver's rule (sourceReference != 0) is what flags them — the
flag is right, the explanation was js-debug's.

Closes #816

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

cynarlab and others added 3 commits September 28, 2026 22:51
…ow-ups (#816)

Review of #822:

- The neutral sentence said "no source file on this host", which overclaims
  for the JDI bridge's case (a class no breakpoint was set in is named by
  package path whether or not its source is here); it now says "no openable
  source path on this host … a label, not a path".
- describeUnresolvedSource receives the flagged frames' file labels
  (UnresolvedSourceContext.files), so a policy speaks from evidence: the
  CodeLLDB sentence says "native frames without debug info" only when every
  label is a `@symbol`, and otherwise names both cases (a symbol-only frame,
  or a runtime built elsewhere whose relative ../sysdeps/… path is not here —
  the kept paused frame of issue #672, which has debug info).
- The Java policy gains its own account: classes the bridge names by
  package path because it has no file path for them; a breakpoint set in a
  class's source file teaches the bridge its path.
- The unresolvedSource field doc and the resolver's rule-A comment name
  every adapter's case, not only js-debug's; the handler test asserts the
  flag reaches the payload again and types its fake policies; the COBOL
  guide points at the mechanism as #814 did for detach.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…urce in the cpp/rust policy tests (#816)

The follow-up commit widened the hook's context with the flagged frames'
file labels; these two suites were edited with it but left out of that
commit's add set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…urce-hint

# Conflicts:
#	tests/e2e/mcp-server-smoke-cpp-attach.test.ts
@debugmcpdev
debugmcpdev merged commit 9f9bd71 into main Sep 29, 2026
11 checks passed
@debugmcpdev
debugmcpdev deleted the fix/816-unresolved-source-hint branch September 29, 2026 03:17
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.

get_stack_trace gives the js-debug sourceMaps hint for native frames on a C/C++ (CodeLLDB) session

2 participants