Repository navigation
fix: 2.11.0 test-flight findings — probe hits read at exit, probes wait for their class, clearer replies, hint-free flights - #52
Merged
Conversation
…itself up (#51) The hook built the server JAR with ./mvnw only. Where ~/.m2 is read-only (a sandboxed Claude Code) the wrapper cannot install Maven, the build failed silently, and the plugin's MCP server started without a JAR. - hooks/ensure-server-jar.sh replaces the one-line hook: ./mvnw, then mvn -o, then mvn, with the old JAR moved aside so a failed or killed build never leaves a partial one, and a lock against parallel sessions. - A failed build is visible: a systemMessage names the build log and the exact command to build by hand; Claude gets the same as context. - The MCP server entry moves from the root .mcp.json into .claude-plugin/plugin.json: a checkout of this repository no longer gets a broken project-level jdwp-inspector next to the plugin's. - README and docs describe the hook, the fallback and the reconnect.
- #5 The Field That Lies: field watchpoints never see a write through Field.set or Unsafe, which the hint, the debug path and the sandbox house rules claimed they do. The flight keeps the reflective write and now teaches the blind spot: the hint describes the tell (a watchpoint that fires for the constructor and then stays silent while the value flips), the debug path bisects before/after the suspect call; par 5. - #8 The Magic Patch: the confirming resume counts, par 4. - #10 The Oversold House: solved when one specific double sale is named (seat, first and second window), which a count after the fact cannot give. The debug path uses the probes waiting for BoxOffice to load and the hits read at the target's exit; par 4 stays. It no longer promises every double sale and says the probe sits inside the race window. The class Javadoc no longer points at check-then-act. - The scoring rule is written into both READMEs and the house rules: every jdwp_* call from the first after attaching until the root cause is evident; attach and clean-up are free. - Sandbox nits: package-info and test Javadocs carry the README's flight numbers and names and no longer state the bug; the spoiler comment in TransferService is gone.
…t, probes wait for their class, clearer stops and replies (#48, #50, #47) #48 - B2: while fast probes exist, a SUSPEND_ALL VMDeathRequest holds the target at its exit until the listener has drained every probe ring and resumed it; FAST_*_READ_AT_EXIT says what was read. Hits nobody read before a test JVM exited were lost. - B1: jdwp_set_fast_logpoint / jdwp_set_fast_breakpoint wait for a class that is not loaded yet (own ClassPrepareRequest, same ID, FAST_*_CLASS_LOADED or _ARM_FAILED) instead of refusing; forceLoad cannot load anything at VM start, and a failed force-load says so and waits too. - B3: jdwp_reset counts the jdwp_suspend_thread holds it releases. #50 - Exception stops name type and message (Throwable.detailMessage, read as a field); jdwp_set_exception_breakpoint takes suspendPolicy ('thread' default, 'all'). - [VM_DEATH] lists what the run recorded and every field breakpoint with its hit count (a silent one points at the reflection/Unsafe blind spot); jdwp_reset and jdwp_disconnect after the exit say the target exited and what went with it; reset warns that released threads run on. - Field events carry the access site and values; a field-breakpoint stop is field_breakpoint=N; a stop names the logpoint hits recorded since the last jdwp_get_events; get_events marks events of earlier attachments. - Evaluation: generated methods declare throws Throwable (checked exceptions in blocks), unqualified calls of this's methods are rewritten, compile errors are listed once with the offending line instead of the temp path, long expressions are echoed shortened, jdwp_evaluate_expression defaults threadId to the current stop. - JDK frames inside the test harness collapse with it and gaps are named; a thread blocked entering synchronized shows the monitorenter's line (HotSpot reports the next bytecode); jdwp_dump_locks lists Object.wait() threads apart from the lock graph; no class suggestion from JDK classes at VM start; 'Released before waiting:' instead of 'Resumed: VM start'. - A deferred class restore names the stop's own thread, and jdwp_overview lists pending restores. #47 - § 1: a fast breakpoint stop keeps its own reason. - § 2: the watchdog ages each invocation from when its thread is seen running (suspended between invocations = host work) and needs two blocked samples on the same monitor. - § 3: the probe recorder counts its writers and re-checks the kill switch; a clear waits for them before the final drain, so no entry is missed or written after it. - § 4: live cases for jdwp_reset during an invocation, co-delivered arming hits on one line, and disconnect during an invocation; live tests for B1 and B2. The java-debug skill, README and docs follow.
…le .mcp.json mentions (#48, #49, #51) - Live test: hits nobody read are read when the target ends with System.exit, as surefire's forked JVM does (flight #10's path), not only when main returns. Both exit tests wait until the probe has written before the target exits: a field watch set after arming could slow the workers enough that no hit came in the two seconds, which made the test flaky. - README's feature list and docs/breakpoints.md no longer claim that field watchpoints see writes through reflection or Unsafe; the sandbox house rules no longer list the bugs of two flights; docs/testing.md drops a stale line number. - jdwp_connect's description, a Javadoc and application.properties no longer point at the removed root .mcp.json. - JdiEventListener: the new helpers sat between formatLogpointResult and its Javadoc.
The failing tests are the players' problem statement, yet their comments named each root cause; the production Javadocs did too. Both now state only what a reader of real code would see. The READMEs drop the Hint lines, several of which were the root cause, and flight #10's symptom no longer points at the check-then-sell gap. Flight #5 takes three calls: a field watch that fires once in the constructor and never again, while the value still flips, shows the write bypasses field stores. The sandbox zip needs the plugin release after 2.11.0, which reads probe and watch hits at the target's exit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes what the 2.11.0 test-flight run and the PR #46 review found.
Closes #48
Closes #49
Closes #50
Closes #51
Part of #47: § 1–3 are fixed; § 4 has three of its live cases (see "Not in this PR").
Server (#48, #50, #47)
jdwp_set_fast_logpoint/jdwp_set_fast_breakpointon a class that is not loaded yet register a waiting probe instead of refusing. It arms on the class'sClassPrepareEvent, keeps its ID, and shows asWAITING_FOR_CLASSin the overview.SUSPEND_ALLVMDeathRequestholds the target at VM death until each ring buffer is drained (bounded at 5 s). This also works underSystem.exit, which is how surefire's forked JVM ends. The[VM_DEATH]reply lists what the run recorded and each field watchpoint's hit count, with a note when a watch saw nothing.jdwp_resetreports thejdwp_suspend_threadholds it released.jdwp_resetandjdwp_disconnectsay when the target has already exited.jdwp_get_events.jdwp_set_exception_breakpointtakessuspendPolicy(thread|all).throws Throwable).synchronizedline: HotSpot reports the line after it.jdwp_dump_lockslistsObject.wait()threads separately from the lock graph.Plugin install (#51)
hooks/ensure-server-jar.shbuilds the server JAR at session start. It tries./mvnw, thenmvn -o, thenmvn, and says when all three fail. Thejdwp-inspectorentry moved into.claude-plugin/plugin.json, and the root.mcp.jsonis gone. After a hook-triggered build, the server needs a reconnect in/mcp, and the hook says so.Test flights (#49)
{ block }mode #8 and fix: emit eval wrapper into target's package when this is non-public (#7) #10 match what the tools do.Field.settrips no watchpoint. Its par is now 3.{ block }mode #8 is par 4, and fix: emit eval wrapper into target's package when this is non-public (#7) #10 has a 4-call par path.Hint:lines are gone.Tests
taskset -c 0).FastProbeLifecycleLiveTest: waiting probes, and hits read at exit aftermainreturns and underSystem.exit; it passed 6 runs in a row;SuspensionOwnershipLiveTestcases: reset during an evaluation, co-delivered arming, and disconnect during an evaluation that never returns.Not in this PR
suspendPolicy=all: no end-to-end test yet. They take the same route throughSuspensionSessionas breakpoint stops.