Summary
The release-prep commit f298251e ("chore(release): 3.0.0 prep — Java<17 deprecation warning, docs/impl sync", 2026-07-11) was authored against a stale checkout and silently reverted merged fixes from at least three separate PRs. Three of those reverts are still live on develop.
The commit message documents none of the reverts — every one of them looks like an unintended overwrite. Its own message hints at the mechanism: "workflow stash-pop conflicts resolved keeping upstream action versions".
Found while reviewing #905, which is re-fixing one of these regressions without anyone realising it was a regression.
Regressions still present on develop
1. Remote clients share SharedSettings.GLOBAL again — HIGH
ef953ac0 gave each remote client its own settings copy. f298251e reverted it along with the comment explaining why:
Give each remote client its own settings copy, seeded from the agent baseline. Using the shared GLOBAL instance here let one client's SET_PARAMS (debug, dumpDir, outputFile, and notably trusted) leak into every other client and into the global transformer. The premain/local path already isolates settings the same way.
Current state — the asymmetry the fix removed is back:
btrace-agent/.../Main.java:1475 (local/premain) — new ClientContext(inst, transformer, argMap, clientSettings) — isolated copy
btrace-agent/.../Main.java:1514 (remote accept loop) — new ClientContext(inst, transformer, argMap, settings) — the shared global
settings there is the static field Main.java:180: private static final SharedSettings settings = SharedSettings.GLOBAL; — the same instance handed to BTraceTransformer via DebugSupport at Main.java:119.
Why this is worse than a tidiness issue:
RemoteClient.getClient (RemoteClient.java:151,163) does SharedSettings settings = ctx.getSettings(); then settings.from(((SetSettingsCommand) cmd).getParams()) on SET_PARAMS — mutating the context's instance in place, i.e. the global.
SharedSettings.from(Map) treats trusted as non-downgrading (SharedSettings.java:82,86: trusted |= b). So a single client that sets trusted flips it on for the agent globally, for every concurrent and subsequent client, permanently — there is no path back to false.
from() also copies grantedPermissions, deniedPermissions and grantAll.
- Authentication is only enforced in prepared mode (
ControlServer.isAuthenticationRequired() returns credentials != null, and credentials are created only when preparedMode is set), so on a normal attach the control port has no auth in front of this.
2. QUEUE_PROCESSOR_STACK_SIZE removed — JDK 26+ risk
Added by #843 (9f39a250, earlier 1317782c), removed by f298251e, never restored. The dropped code and its rationale:
ClassFile API's StackMapGenerator can exhaust the default stack depth when processing complex methods in JDK 26+ (class-file major >= 70). Use 4 MB on those JVMs only; on older JVMs keep the default (0 = JVM-chosen) to avoid any OS-level stack-allocation overhead that was intermittently delaying test startup on JDK 8/11/21 CI machines.
Main.java:191 is back to new Thread(r, "BTrace Command Queue Processor") with no explicit stack size, and QUEUE_PROCESSOR_STACK_SIZE has zero references. The CI matrix includes 27.ea.31-open.
3. ASM downgraded 9.10.1 → 9.9.1 in the Gradle plugin
btrace-gradle-plugin/build.gradle:30-31 — Renovate bumped ASM to 9.10.1 in #839 (aaed26ff); f298251e put it back to 9.9.1. Still 9.9.1 today, and the open Renovate PR #854 does not cover it, so it will not self-heal. This is the only ASM coordinate outside the version catalog, which is likely why nothing caught it.
(The same hunk also reverted junit-jupiter 6.1.1 → 5.11.4, but that has since moved to 5.14.4 independently and #902 settled the v6 question deliberately — not actionable.)
Already handled — do not double-fix
Audit scope and method
For all 50 files in f298251e, extracted every removed line and checked whether it is still absent from develop, then attributed each surviving removal with git log -S.
Reviewed and cleared as intentional (all stated in the commit message):
.github/workflows/* — these went floating-tag → pinned SHA digest. A hardening improvement, not a revert.
release.yml — io.btrace:btrace-client/-agent/-boot → the actually-published io.btrace:btrace.
btrace-dist/build.gradle, btrace-gradle-plugin/build.gradle POM blocks, docker/* — GPLv2+CE → Apache-2.0 relicensing.
messages.properties — removal of the unimplemented --grant/--deny/--grantAll client flags.
samples/AllMethods.java, ~30 docs files — org.openjdk.btrace → io.btrace rename, Java support policy, 3.0 version references.
Only btrace-agent/.../Main.java, btrace-client/.../Client.java and btrace-gradle-plugin/build.gradle carry unintended reverts.
Work
Prevention
Three merged fixes were reverted by one commit and nobody noticed for two weeks. Worth considering before 3.0.0:
- None of the reverted fixes had a test that would have failed. The settings-isolation one in particular is cheap to test and high-value.
- Large mixed-content commits (8 source files + ~42 docs/workflow files, 2084/379 lines) make review of the source portion effectively impossible. Splitting docs sync from behavioural change would have surfaced all three.
Summary
The release-prep commit
f298251e("chore(release): 3.0.0 prep — Java<17 deprecation warning, docs/impl sync", 2026-07-11) was authored against a stale checkout and silently reverted merged fixes from at least three separate PRs. Three of those reverts are still live ondevelop.The commit message documents none of the reverts — every one of them looks like an unintended overwrite. Its own message hints at the mechanism: "workflow stash-pop conflicts resolved keeping upstream action versions".
Found while reviewing #905, which is re-fixing one of these regressions without anyone realising it was a regression.
Regressions still present on
develop1. Remote clients share
SharedSettings.GLOBALagain — HIGHef953ac0gave each remote client its own settings copy.f298251ereverted it along with the comment explaining why:Current state — the asymmetry the fix removed is back:
btrace-agent/.../Main.java:1475(local/premain) —new ClientContext(inst, transformer, argMap, clientSettings)— isolated copybtrace-agent/.../Main.java:1514(remote accept loop) —new ClientContext(inst, transformer, argMap, settings)— the shared globalsettingsthere is the static fieldMain.java:180:private static final SharedSettings settings = SharedSettings.GLOBAL;— the same instance handed toBTraceTransformerviaDebugSupportatMain.java:119.Why this is worse than a tidiness issue:
RemoteClient.getClient(RemoteClient.java:151,163) doesSharedSettings settings = ctx.getSettings();thensettings.from(((SetSettingsCommand) cmd).getParams())onSET_PARAMS— mutating the context's instance in place, i.e. the global.SharedSettings.from(Map)treatstrustedas non-downgrading (SharedSettings.java:82,86:trusted |= b). So a single client that setstrustedflips it on for the agent globally, for every concurrent and subsequent client, permanently — there is no path back tofalse.from()also copiesgrantedPermissions,deniedPermissionsandgrantAll.ControlServer.isAuthenticationRequired()returnscredentials != null, and credentials are created only whenpreparedModeis set), so on a normal attach the control port has no auth in front of this.2.
QUEUE_PROCESSOR_STACK_SIZEremoved — JDK 26+ riskAdded by #843 (
9f39a250, earlier1317782c), removed byf298251e, never restored. The dropped code and its rationale:Main.java:191is back tonew Thread(r, "BTrace Command Queue Processor")with no explicit stack size, andQUEUE_PROCESSOR_STACK_SIZEhas zero references. The CI matrix includes27.ea.31-open.3. ASM downgraded 9.10.1 → 9.9.1 in the Gradle plugin
btrace-gradle-plugin/build.gradle:30-31— Renovate bumped ASM to 9.10.1 in #839 (aaed26ff);f298251eput it back to 9.9.1. Still 9.9.1 today, and the open Renovate PR #854 does not cover it, so it will not self-heal. This is the only ASM coordinate outside the version catalog, which is likely why nothing caught it.(The same hunk also reverted junit-jupiter 6.1.1 → 5.11.4, but that has since moved to 5.14.4 independently and #902 settled the v6 question deliberately — not actionable.)
Already handled — do not double-fix
Client.java:806malformedcmdQueueLimitagent arg. Fixed in Fix a batch of correctness, concurrency, and resource bugs across all modules #857 (ab2f4589), reverted byf298251e, currently being re-fixed by client: fix JAVA_HOME NPE at startup and malformed cmdQueueLimit token #905. Verified bygit log -L 804,807:btrace-client/src/main/java/io/btrace/client/Client.java.f298251eremoved Fix a batch of correctness, concurrency, and resource bugs across all modules #857'scloseQuietlyhelper, but feat(agent): authenticate prepared mode #895 later rewrote the accept loop with ahandedOffflag and afinallyblock that closes the socket. Functionally equivalent; no action needed.Audit scope and method
For all 50 files in
f298251e, extracted every removed line and checked whether it is still absent fromdevelop, then attributed each surviving removal withgit log -S.Reviewed and cleared as intentional (all stated in the commit message):
.github/workflows/*— these went floating-tag → pinned SHA digest. A hardening improvement, not a revert.release.yml—io.btrace:btrace-client/-agent/-boot→ the actually-publishedio.btrace:btrace.btrace-dist/build.gradle,btrace-gradle-plugin/build.gradlePOM blocks,docker/*— GPLv2+CE → Apache-2.0 relicensing.messages.properties— removal of the unimplemented--grant/--deny/--grantAllclient flags.samples/AllMethods.java, ~30 docs files —org.openjdk.btrace→io.btracerename, Java support policy, 3.0 version references.Only
btrace-agent/.../Main.java,btrace-client/.../Client.javaandbtrace-gradle-plugin/build.gradlecarry unintended reverts.Work
SharedSettingsisolation in the remote accept loop (Main.java:1514), matching the local path at:1475.SET_PARAMS{trusted=true}, assert the other client's context andSharedSettings.GLOBALare unaffected. This is the test whose absence let the revert through twice.QUEUE_PROCESSOR_STACK_SIZEand itsresolveQueueProcessorStackSize()helper.btrace-gradle-plugin/build.gradle, and consider moving the coordinate into the version catalog so Renovate tracks it with everything else.cmdQueueLimitline.Prevention
Three merged fixes were reverted by one commit and nobody noticed for two weeks. Worth considering before 3.0.0: