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
ponder-lab/ML's merge queue is configured to squash-merge, and the merge queue silently reverts submodule pointers when two PRs touch master in sequence and the second PR was branched from a pre-first-PR base. This isn't a hypothetical—it just happened on 2026-05-27.
#343 didn't intentionally touch the submodule, but the squash made it look like it did.
Why CI Didn't Catch This
#341 also dropped the local <exclude>ProxyDeserialization.class</exclude> shade-filter on the assumption that the upstream jython3 build no longer ships the class. With the submodule reverted, the upstream ant build does ship it again, but the fat-JAR build doesn't fail—shade just packages the class at the default-package level. CI only smoke-tests the fat JAR's existence and Main-Class manifest entry; it doesn't validate slim-JAR consumability. So both #341 and #343 passed CI cleanly.
The downstream symptom: Hybridize via Tycho 5+'s bnd auto-wrap hits the same The default package '.' is not permitted by the Import-Package syntax failure that #557 was supposed to close.
ponder-lab#346 repairs the regression with a one-line submodule SHA bump, but the underlying foot-gun remains.
Mitigation Options
Each has a cost; this issue tracks the discussion, not a chosen path.
Require rebase-before-merge. Force every PR to be at master HEAD before the merge queue admits it. Eliminates the squash-replay issue entirely. Costs a rebase per PR; on a busy week with concurrent PRs this is meaningful friction.
Switch from squash-merge to merge-commit. Merge commits preserve the actual file states from each parent rather than replaying a diff. Submodule pointer survives the merge correctly. Costs a noisier commit graph and breaks the "one PR = one commit" pattern many automation hooks rely on.
CI check: reject PRs whose submodule diff would revert master. Cheap to add (a small shell snippet in continuous-integration.yml). Catches the regression at PR time before it reaches the queue. Doesn't prevent the squash-replay mechanism, just guards against its visible effect.
Summary
ponder-lab/ML's merge queue is configured to squash-merge, and the merge queue silently reverts submodule pointers when two PRs touch master in sequence and the second PR was branched from a pre-first-PR base. This isn't a hypothetical—it just happened on 2026-05-27.
Concrete incident
jython3to0.0.2-SNAPSHOT; drop redundantProxyDeserializationshade-exclude ponder-lab/ML#341 (closing Slim-jar consumption blocked byjython3default-package class (ProxyDeserialization.class) #557) merged at commitbaeddd93, bumping thejython3submodule pointer tob81600db(the post-Slim-jar consumption blocked byjython3default-package class (ProxyDeserialization.class) #557 build that stripsProxyDeserialization.classfromjython-dev.jar).PythonInvokeInstructiononiIndex()for consistency with inheritedequalsponder-lab/ML#343 was branched from PRE-Bump jep from 4.2.2 to 4.3.0 #341 master, where the submodule pointer was still at580ea6ba. The PR didn't intentionally touch the submodule.64f60021, GitHub replayed the entire PR diff against the post-Bump jep from 4.2.2 to 4.3.0 #341 tree. The replay included the (now-divergent) submodule pointer, silently reverting Bump jep from 4.2.2 to 4.3.0 #341's bump.git show 64f60021 -- jython3confirms:#343 didn't intentionally touch the submodule, but the squash made it look like it did.
Why CI Didn't Catch This
#341 also dropped the local
<exclude>ProxyDeserialization.class</exclude>shade-filter on the assumption that the upstreamjython3build no longer ships the class. With the submodule reverted, the upstreamantbuild does ship it again, but the fat-JAR build doesn't fail—shade just packages the class at the default-package level. CI only smoke-tests the fat JAR's existence andMain-Classmanifest entry; it doesn't validate slim-JAR consumability. So both #341 and #343 passed CI cleanly.The downstream symptom: Hybridize via Tycho 5+'s bnd auto-wrap hits the same
The default package '.' is not permitted by the Import-Package syntaxfailure that #557 was supposed to close.ponder-lab#346 repairs the regression with a one-line submodule SHA bump, but the underlying foot-gun remains.
Mitigation Options
Each has a cost; this issue tracks the discussion, not a chosen path.
Require rebase-before-merge. Force every PR to be at master HEAD before the merge queue admits it. Eliminates the squash-replay issue entirely. Costs a rebase per PR; on a busy week with concurrent PRs this is meaningful friction.
Switch from squash-merge to merge-commit. Merge commits preserve the actual file states from each parent rather than replaying a diff. Submodule pointer survives the merge correctly. Costs a noisier commit graph and breaks the "one PR = one commit" pattern many automation hooks rely on.
CI check: reject PRs whose submodule diff would revert master. Cheap to add (a small shell snippet in
continuous-integration.yml). Catches the regression at PR time before it reaches the queue. Doesn't prevent the squash-replay mechanism, just guards against its visible effect.Slim-JAR smoke test in CI. Independent of (3): exercising the slim-consumption path (e.g., via a minimal Tycho target build that pulls the published slim JAR) would catch Slim-jar consumption blocked by
jython3default-package class (ProxyDeserialization.class) #557-class regressions regardless of cause. Larger lift than (3).I'd lean (3) as the lowest-cost mitigation worth adopting; (4) as a longer-term hardening; (1)/(2) as policy decisions if the foot-gun recurs.
Related
jython3to0.0.2-SNAPSHOT; drop redundantProxyDeserializationshade-exclude ponder-lab/ML#341, Bump black from 25.9.0 to 25.11.0 #343, Bump commons-cli:commons-cli from 1.10.0 to 1.11.0 #346.jython3default-package class (ProxyDeserialization.class) #557 (the issue whose closure was effectively undone by the regression).