Commits
Tarun Sukhani authored f9f76974061
fix: fourth audit pass — interrupts, ThreadLocal hygiene, doc/spec sync P2 fixes: - Mail.java: switch the back-pressure gate from acquireUninterruptibly() to acquire() so Future.cancel(true) and resetExecutor() can unblock waiters cleanly. Previously a saturated gate would let shutdown leak still-pending sends; now cancellation propagates and the task returns false with the interrupt status restored. - PlayHandler.java: clear CachedBoundActionMethodArgs and ControllersEnhancer.currentAction in the request-cleanup block. ActionInvoker.initActionContext sets both ThreadLocals; without the cleanup, pooled platform threads leaked the previous request's bound method args and controller-call stack across requests. VT mode masked this because each request got a fresh thread that died after. - ServletWrapper.java: parity fix — also clear ControllersEnhancer.currentAction (CachedBoundActionMethodArgs was already cleared here). Both paths now have the same cleanup contract. - VirtualThreadScheduledExecutor.java: SelfReschedulingFuture transitions to terminal state via handle.cancel(false) when the scheduler is shut down between runs or RejectedExecutionException is thrown during the reschedule submit. Previously the periodic future could remain non-terminal forever — isDone() returned false, get() blocked indefinitely — diverging from STPE's "shutdown cancels periodic tasks" contract. - openspec/specs/java-25-compilation/spec.md: rewrite to describe "Java 25 only" reality. Previous spec required compatibleJavaVersions to retain entries 17–23 and described default java.source as "17", both contradicting the current code (which accepts only "25" and defaults to "25"). - documentation/manual/releases/release1.12.x/releasenotes-1.12.0.textile: correct two passages that still claimed Java 17–25 acceptance with the current "25 only / pre-25 JDKs rejected at startup" behavior. P3 fixes: - resources/module-skel/build.xml: bump build-release from 17 → 25 so new-module skeletons match the framework's Java 25 emission. - GroovyTemplate.java: wrap tagTemplate.internalRender(args) in try/finally so TagContext.exitTag() runs even when render throws. Without this, the TagContext ThreadLocal stack accumulated stale entries on pooled threads when render threw. Deferred: - StreamChunkAggregator upload-spooling on the Netty EventLoop thread (P2): legitimate concern but requires structural refactor — either AsynchronousFileChannel, a dedicated I/O executor with bounded queue, or migration to Netty's HttpPostRequestDecoder. Out of scope here; worth a separate ticket. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>