Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
dc706ba
test: cover polling listening sockets for read and write
fglock Aug 25, 2026
837b55a
fix: ignore invalid write interest on listening sockets
fglock Aug 25, 2026
6cc3f34
test: cover overloaded filehandle path coercion
fglock Aug 25, 2026
efbbb75
fix: stringify blessed open filenames
fglock Aug 25, 2026
e0f5c22
test: cover module_true do-file return values
fglock Aug 25, 2026
0415842
fix: preserve do-file values with module_true
fglock Aug 25, 2026
8be337b
test: cover split gzip response inflation
fglock Aug 25, 2026
a8d997f
test: cover weak state singleton lifecycle
fglock Aug 25, 2026
ad72b5e
test: cover malformed loaded-source diagnostics
fglock Aug 25, 2026
b2298d1
test: cover closure-retained discarded Promise clone
fglock Aug 25, 2026
cb9091f
test: call imported gzip constants explicitly
fglock Aug 25, 2026
9c23ad6
fix: decode streaming gzip responses
fglock Aug 25, 2026
f468075
fix: preserve missing-delimiter diagnostics for bareword blocks
fglock Aug 25, 2026
0e3d0c0
test: cover die after lexical filehandle cleanup
fglock Aug 25, 2026
108c4dd
test: cover loaded-source EOF line ownership
fglock Aug 25, 2026
75629e9
fix: preserve loaded-source EOF line ownership
fglock Aug 25, 2026
b37c80e
test: make lexical handle regression cwd independent
fglock Aug 25, 2026
72f0136
test: assert discarded Promise chain destruction
fglock Aug 25, 2026
a3cf3c2
fix: preserve Mojo Promise lifecycle roots
fglock Aug 25, 2026
73351f0
test: guard returned lexical filehandle lifetime
fglock Aug 25, 2026
0d5ed75
test: cover Promise warning cleanup timing
fglock Aug 25, 2026
cb553d7
fix: clear stale lexical readline diagnostics
fglock Aug 25, 2026
a356ea7
test: mirror Mojo Promise wait cleanup
fglock Aug 25, 2026
7ad8fb2
test: mirror paired Promise callback cleanup
fglock Aug 25, 2026
b9ff3a6
test: classify runtimes without real fork support
fglock Aug 25, 2026
f30831b
test: cover tempfile missing-parent diagnostics
fglock Aug 25, 2026
0e106ff
fix: classify PerlOnJava fork as non-real
fglock Aug 25, 2026
8fddc42
fix: report missing File::Temp parent directories
fglock Aug 25, 2026
23ebcd2
test: mirror Mojo Promise finally cleanup
fglock Aug 25, 2026
1fbf63f
test: cover File::Path option semantics
fglock Aug 25, 2026
190f70a
fix: honor File::Path option contracts
fglock Aug 25, 2026
192f2ea
test: cover wrapped File::Temp lifetime
fglock Aug 25, 2026
bd50e10
test: cover atomic sysopen with read-only permissions
fglock Aug 25, 2026
1307127
test: cover method-return scalar wrapper lifetime
fglock Aug 25, 2026
5ff2873
wip: snapshot lifetime candidates before test integration
fglock Aug 25, 2026
6299c01
wip: snapshot lifetime compiler work before Catalyst diagnosis
fglock Aug 25, 2026
bb183e3
fix: preserve lexical layers for atomic sysopen
fglock Aug 25, 2026
8c155f2
test: cover blessed glob destruction lifetime
fglock Aug 25, 2026
d2f9720
fix: retain blessed glob lexical owners
fglock Aug 25, 2026
cd3be7e
refactor: synchronize upstream File::Temp
fglock Aug 25, 2026
e1e54a7
test: cover supplementary code points in split
fglock Aug 25, 2026
1b168c3
fix: split strings by Unicode code point
fglock Aug 25, 2026
741df85
test: cover Mojolicious JSON runtime contracts
fglock Aug 25, 2026
6dda71c
fix(regex): share empty global retry state across patterns
fglock Aug 25, 2026
61c07a9
fix: honor Cpanel JSON encoder options
fglock Aug 25, 2026
fb1c56a
test: cover YAML::XS UTF-8 octet input
fglock Aug 25, 2026
15b021f
fix: decode YAML::XS UTF-8 octet input
fglock Aug 25, 2026
5257152
test: cover moved tempfile wrapper lifetime
fglock Aug 25, 2026
2aeff62
fix: snapshot file-test path operands
fglock Aug 25, 2026
554007a
test: cover nested array rvalue autovivification
fglock Aug 25, 2026
6253d17
fix: commit arrays on nested rvalue access
fglock Aug 25, 2026
96c6b11
test: cover Symbol delete_package semantics
fglock Aug 25, 2026
aeefdc5
fix: implement Symbol package teardown
fglock Aug 25, 2026
8023738
test: cover discarded callback capture lifetime
fglock Aug 25, 2026
3b8dfc9
fix: release discarded JVM closure captures
fglock Aug 25, 2026
944532a
test: cover socket close at lexical scope exit
fglock Aug 25, 2026
26e419e
test: cover deleted socket handle lifetime
fglock Aug 25, 2026
aeccfc3
test: cover transient socket argument lifetime
fglock Aug 25, 2026
e0f9bec
test: cover unstashed gensym socket lifetime
fglock Aug 25, 2026
7758baf
test: cover socket-owning container scope exit
fglock Aug 25, 2026
97abde2
test: cover durable scalar socket alias
fglock Aug 25, 2026
b5997db
test: cover closure-captured socket lifetime
fglock Aug 25, 2026
18761c9
test: cover blessed socket owner method cleanup
fglock Aug 25, 2026
c0909e8
test: cover stream callback socket cleanup
fglock Aug 25, 2026
331d465
test: cover explicitly returned socket lifetime
fglock Aug 25, 2026
533d504
test: cover aliases created before socket initialization
fglock Aug 25, 2026
4d630b1
test: cover socket ownership in returned lists
fglock Aug 25, 2026
763216b
test: preserve caller ownership across socket methods
fglock Aug 26, 2026
201f0f2
fix: close stream sockets at final Perl owner
fglock Aug 26, 2026
59618fc
test: cover repeated Mojolicious mount requests
fglock Aug 26, 2026
a91f766
fix: preserve live mounted routes during request cleanup
fglock Aug 26, 2026
eb6f185
test: cover skipped callback closure cleanup
fglock Aug 26, 2026
112da7a
fix: preserve captured lexicals across skip exits
fglock Aug 26, 2026
3b10373
test: cover gzip and zlib inflate auto-detection
fglock Aug 26, 2026
f34c936
fix: auto-detect gzip and zlib inflate wrappers
fglock Aug 26, 2026
4d5da70
test: cover shifted weak reference to deep cycle
fglock Aug 26, 2026
dc9db6d
test: cover recursive DBIC weak registry diagnostics
fglock Aug 26, 2026
c6f43fd
test: keep cycle weak checks observational
fglock Aug 26, 2026
712bf08
test: mirror DBIC inner leak registry call
fglock Aug 26, 2026
f66ab34
fix: preserve DBIC inner leak diagnostics
fglock Aug 26, 2026
7e67612
docs: summarize Mojolicious support
fglock Aug 26, 2026
3d9e2ec
test: cover DBIx quiet leak-registry handoff
fglock Aug 26, 2026
54fc20f
fix(runtime): clean quiet DBIx leak registries
fglock Aug 26, 2026
ebdfeff
docs: record final issue 1115 acceptance
fglock Aug 26, 2026
8032d14
fix(io): preserve inherited listener blocking mode
fglock Aug 26, 2026
edf3a13
docs: record Mojolicious acceptance follow-up
fglock Aug 26, 2026
1091c88
docs(examples): add Mojolicious task board UAT
fglock Aug 26, 2026
00766c8
fix: preserve stash aliases across source rebinds
fglock Aug 27, 2026
65e7c4d
fix: retain namespace metadata for moved nested stashes
fglock Aug 27, 2026
6d0fea4
fix: resolve aliases for packages ending in colon
fglock Aug 27, 2026
64165db
fix: delete colon-ended package namespaces
fglock Aug 27, 2026
37974f0
fix: treat shared stash aliases as isa-equivalent classes
fglock Aug 27, 2026
884a012
fix: recognize substr lvalues in UNIVERSAL isa
fglock Aug 27, 2026
3cc7e8c
fix: resolve IO invocants in UNIVERSAL can
fglock Aug 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions dev/design/destroy_weaken_plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ for `argsStack` indexing. JVM backend's `handlePackageOperator()` now emits runt

## 7. Progress Tracking

### Current Status: Moo 841/841; DBIx::Class 3000+ subtests passing across 60+ test files
### Current Status: Issue #1115 acceptance verification in progress

### Completed (this branch)
- [x] Phase 1-5: Full DESTROY/weaken implementation (2026-04-08–09)
Expand All @@ -373,6 +373,40 @@ for `argsStack` indexing. JVM backend's `handlePackageOperator()` now emits runt
- [x] Phase F3: STDERR close/dup detection (already fixed)
- [x] Phase F4: VerifyError interpreter fallback (already fixed)
- [x] Phase F5: @DB::args population in non-debug mode (2026-04-11)
- [x] Preserve weakly observed DESTROY objects proven reachable from live Perl
roots (2026-08-26)
- Prevents request-local `Mojolicious::Routes::Match` cleanup from destroying
a mounted route still owned by the `Mojolicious::Lite` application tree.
- Added `mojolicious_mount_lifecycle_regression.t`, validated on system Perl
and captured failing on the unfixed JVM backend before the runtime change.
- [x] Add a focused skipped-callback closure regression (2026-08-26)
- `mojolicious_skipped_closure_lifecycle_regression.t` passes on system Perl
and fails on the unfixed JVM backend after the skipped callback releases a
still-live outer `Test::Mojo` lexical.
- [x] Preserve enclosing closure captures across non-local callback exits
- `EmitStatement.emitLoopControlScopeExit()` now filters constructor-captured
slots just like ordinary scope exit. A `last SKIP` still cleans callback
locals, but no longer marks an enclosing captured lexical as exited.
- The focused JVM regression and upstream Mojolicious
`session_lite_app.t` now pass; interpreter coverage takes the documented
Test::Mojo skip. The second full build reached 845 passing tests before the
known intermittent `regex/re_debug_thread_region.t` failure, which passed
immediately in a focused rerun.
- [x] Support zlib wrapper auto-detection in the bundled raw inflater
(2026-08-26)
- Added `compress_raw_zlib_autodetect_regression.t`, validated on system Perl
and captured failing for both gzip and zlib wrappers on the unfixed JVM.
- `CompressRawZlib` now implements the `MAX_WBITS + 32` mode used by
`WANT_GZIP_OR_ZLIB`, selecting gzip framing or Java's zlib inflater from
the stream header.
- The focused regression passes all 6 tests and Catalyst Runtime's
`t/utf_incoming.t` passes all 151 tests, including its zlib charset path.
- [x] Complete Catalyst warning-test dependency environment (2026-08-26)
- Installed the unmodified `Class::Accessor` 0.51 distribution privately;
its 139 tests pass.
- Catalyst's undeclared compatibility-test dependency was the sole cause of
`t/plugin_new_method_backcompat.t` failing through an ignored `eval`; the
exact test now passes all 7 assertions without CPAN source changes.

### Known Remaining Failures
1. t/52leaks.t tests 12-20: Leak detection fails due to refcount overcounting (§3)
Expand All @@ -381,9 +415,11 @@ for `argsStack` indexing. JVM backend's `handlePackageOperator()` now emits runt
4. t/inflate/hri.t: Missing CDSubclass.pm module

### Next Steps
1. Performance optimization phases O1-O6 (blocking PR merge)
2. Investigate t/102load_classes.t failure
3. Investigate t/52leaks.t refcount overcounting if feasible
1. Rerun Catalyst Runtime acceptance excluding documented `fork`-only coverage.
2. Rerun DBIx::Class acceptance after the final runtime change.
3. Performance optimization phases O1-O6 (blocking PR merge)
4. Investigate t/102load_classes.t failure
5. Investigate t/52leaks.t refcount overcounting if feasible

### Test Commands
```bash
Expand Down
59 changes: 52 additions & 7 deletions dev/design/io_handle_lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This document explains how PerlOnJava manages the lifecycle of IO handles
(file descriptors), the fileno registry, and the tradeoffs made due to the
absence of Perl 5's reference counting and DESTROY mechanism.
differences between Perl 5 reference counting and JVM garbage collection.

## Background: How Perl 5 Does It

Expand All @@ -14,10 +14,10 @@ to the containing glob is dropped. The interpreter uses reference counting
calls `gp_free()` which closes the IO. The `DESTROY` method can also
participate in cleanup.

PerlOnJava has **none of these mechanisms**:
- No reference counting
- No DESTROY (object destructors never run)
- JVM garbage collection is non-deterministic
PerlOnJava implements selective reference counting for values whose lifetime
must be deterministic, including objects with `DESTROY`. JVM garbage
collection remains non-deterministic, so IO globs also need explicit runtime
ownership metadata where peer-visible close timing matters.

This creates a fundamental tension: we want to close file handles promptly
(to avoid fd leaks and flush data), but we can't safely determine when a
Expand Down Expand Up @@ -151,12 +151,33 @@ The failure chain:
| Reassigning `$fh = other` | Closes old IO (dangerous) | Old IO leaks until GC |
| Fd numbers | Recycled (unsafe) | Monotonic (safe, wastes numbers) |

## Stream Socket Ownership

Issue #1115 added selective ownership tracking for anonymous stream-socket
globs. Socket creation and `accept` establish an owner count, while lexical,
container, closure-capture, argument, and explicit-return cleanup transfer or
release ownership at the same deterministic boundaries Perl uses. The final
owner closes the socket so the peer observes EOF.

List assignment is significant for `IO::Socket::IP::accept`, which assigns
`($new, $peer)` from a returned temporary list. `RuntimeList.setFromList`
marks its materialized RHS as transient, allowing the sole socket ownership
token to move to the destination lexical. Values derived from active argument
aliases are excluded from that move so method-local aliases such as
`my $self = shift` cannot close a caller-owned socket.

The ownership close path is intentionally socket-specific. Ordinary anonymous
file handles retain the established unregister-only behavior because ecosystem
code such as Capture::Tiny relies on aliases that do not yet carry equivalent
ownership metadata.

### Future Improvements

If IO handle leaks become a practical problem, consider:

1. **Reference counting on RuntimeGlob**: Track how many RuntimeScalars
point to each glob. Only close IO when count reaches zero.
1. **Extend selective RuntimeGlob ownership beyond sockets**: Track enough
aliases for ordinary anonymous file handles to close only when their final
owner disappears.
- Pro: Correct, matches Perl 5 semantics
- Con: Adds overhead to every set() call involving GLOBREFERENCEs

Expand All @@ -178,3 +199,27 @@ If IO handle leaks become a practical problem, consider:
- `RuntimeIO.java` — fileno registry, `assignFileno()`, `unregisterFileno()`, `fileno()`, `close()`
- `IOOperator.java` — `duplicateFileHandle()`, `openFileHandleDup()`
- `RuntimeGlob.java` — `setIO()`, glob name and stash management

## Progress Tracking

### Current Status: Stream socket lifetime phase completed

### Completed Phases

- [x] Deterministic anonymous stream-socket ownership (2026-08-26)
- Added lexical, container, closure, argument, and return ownership transfer.
- Added JVM/interpreter regression coverage for scope exit, deletion,
captures, method aliases, pre-IO aliases, and returned list assignment.
- Verified Mojolicious long-polling, stream drain, and controller destruction.
- Related issue: #1115.

### Next Steps

1. Consider extending the ownership model to ordinary anonymous file handles.
2. Keep fd allocation monotonic until all alias forms have deterministic
ownership coverage.

### Open Questions

- Whether non-socket IO should share the socket counter or use cleaner-backed
fallback for aliases outside tracked Perl scopes.
47 changes: 47 additions & 0 deletions dev/design/refcount_alignment_52leaks_plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -708,3 +708,50 @@ first.
- PR: https://github.com/fglock/PerlOnJava/pull/508
- Key commits: `da301ca6f` (C), `ea39d29a8` (D), `87ed18e00` (E),
`ad7d32972` (F), `e8cec9a76` (G)

## Progress tracking: issue #1115 regression follow-up

### Current status: implementation and acceptance complete

### Completed phase (2026-08-26)

- Added `src/test/resources/unit/dbic_deep_cycle_weak_shift_regression.t`,
validated first with system Perl. It models the `t/52leaks.t` deep strong
cycle, the inline weakened shifted diagnostic, and DBIx's one-entry inner
`assert_empty_weakregistry` call.
- Made targeted statement-boundary release sweeps preserve referents held by
strong cycle islands.
- Restored the original DBIx leak-tracer boundary inside PerlOnJava rather
than patching DBIx: compatibility cleanup runs for the large outer registry
and quiet END registries, using the active call's live `@_` frame. The
one-entry non-quiet cycle diagnostic remains observational.
- Focused verification is green on JVM and interpreter (11/11 each). Upstream
DBIx `t/52leaks.t` completes with exit 0 and no real failures; its two
intentional prepared-statement-cycle diagnostics remain TODO results.
- Final acceptance exposed a separate branch regression in
`t/storage/savepoints.t`: a quiet one-entry registry retained the schema
handed off by `DBIx::Class::Schema::DESTROY`. Added
`dbic_quiet_registry_destroy_handoff_regression.t`; system Perl passes 5/5
while both unfixed backends failed 2/5. Quiet registry checks now trigger the
same cleanup regardless of registry size, without changing the non-quiet
one-entry cycle diagnostic. The backend-dependent argument-depth guard was
removed so JVM and interpreter both pass 5/5.
- Final `make` passes on integrated commit `54fc20fb7`. The full unchanged
DBIx::Class suite passes under `nice`: 325 files and 43,020 assertions,
including `t/52leaks.t`, `t/storage/savepoints.t`, and
`t/storage/txn_scope_guard.t`.

Files: `ScalarUtil.java`, `ReachabilityWalker.java`, `RuntimeCode.java`,
`dbic_deep_cycle_weak_shift_regression.t`, and
`dbic_quiet_registry_destroy_handoff_regression.t`.

### Next steps

1. Keep PR #1129 in draft for review.
2. Address review findings, if any, without weakening the Mojolicious,
Catalyst::Runtime, DBIx::Class, or project regression gates.

### Open questions and blockers

- No implementation blocker. Heavy gates must remain serial: concurrent
Gradle/CPAN workers reproduced timing-test failures and DBIx stalls.
4 changes: 1 addition & 3 deletions dev/import-perl5/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -901,11 +901,9 @@ imports:
- source: perl5/dist/Text-Abbrev/lib/Text/Abbrev.pm
target: src/main/perl/lib/Text/Abbrev.pm

# File::Temp - Temporary files (PerlOnJava custom implementation)
# Protected because we have a custom implementation
# File::Temp - Temporary files
- source: perl5/cpan/File-Temp/lib/File/Temp.pm
target: src/main/perl/lib/File/Temp.pm
protected: true

# IO::Dir - Directory operations (required by tests)
- source: perl5/dist/IO/lib/IO/Dir.pm
Expand Down
12 changes: 11 additions & 1 deletion dev/import-perl5/sync.pl
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,16 @@ sub file_sha256 {
return $digest->hexdigest;
}

# File::Copy copies bytes into an already-created staging file but does not
# preserve the source mode. Keep synchronized files reproducible instead of
# publishing tempfile's private 0600 mode.
sub copy_file_preserving_mode {
my ($source, $destination) = @_;
return 0 unless copy($source, $destination);
my $mode = (stat($source))[2] & 07777;
return chmod($mode, $destination) == 1;
}

sub record_snapshot_path {
my ($state, $project_root, $path) = @_;
my $relative = File::Spec->abs2rel($path, $project_root);
Expand Down Expand Up @@ -759,7 +769,7 @@ sub main {
print " Copying to: $import->{target}\n";
my ($temporary, $temporary_path) = tempfile('.import-XXXXXX', DIR => $target_dir, UNLINK => 0);
close $temporary;
unless (copy($source, $temporary_path)) {
unless (copy_file_preserving_mode($source, $temporary_path)) {
warn " ERROR: Copy failed: $!\n\n";
$error_count++;
next;
Expand Down
29 changes: 29 additions & 0 deletions dev/import-perl5/sync_file_mode.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use strict;
use warnings;
use Test::More tests => 3;
use File::Temp qw(tempdir);
use File::Spec;

require './dev/import-perl5/sync.pl';

my $directory = tempdir(CLEANUP => 1);
my $source = File::Spec->catfile($directory, 'source.pm');
my $destination = File::Spec->catfile($directory, 'staged.pm');

open my $source_fh, '>', $source or die "Cannot create $source: $!";
print {$source_fh} "package Imported; 1;\n";
close $source_fh or die "Cannot close $source: $!";
chmod 0644, $source or die "Cannot chmod $source: $!";

open my $destination_fh, '>', $destination
or die "Cannot create $destination: $!";
close $destination_fh or die "Cannot close $destination: $!";
chmod 0600, $destination or die "Cannot chmod $destination: $!";

ok(copy_file_preserving_mode($source, $destination),
'staging copy succeeds');
is((stat($destination))[2] & 07777, 0644,
'staging copy preserves the source mode');
open my $copied_fh, '<', $destination or die "Cannot read $destination: $!";
is(do { local $/; <$copied_fh> }, "package Imported; 1;\n",
'staging copy preserves the source contents');
99 changes: 97 additions & 2 deletions dev/modules/mojo_ioloop.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Mojo::IOLoop Support for PerlOnJava

## Status: Phase 4 IN PROGRESS -- RC1+RC5+RC6+Latin1+IndirectMethod fixed, RC2/RC3/RC4 remaining
## Status: Issue #1115 acceptance complete -- Mojolicious 9.49 runtime support

- **Module version**: Mojolicious 9.42 (SRI/Mojolicious-9.42.tar.gz)
- **Module version**: Mojolicious 9.49 (SRI/Mojolicious-9.49.tar.gz)
- **Date started**: 2026-04-09
- **Branch**: `docs/mojo-ioloop-plan`
- **PR**: https://github.com/fglock/PerlOnJava/pull/467
Expand Down Expand Up @@ -947,7 +947,102 @@ If Tier 1+2 fixes succeed:

**Estimated new total: 65/108 → ~75-80/108 test files passing**

## Issue #1115 Progress (2026-08-25)

### Current Status: Acceptance complete (2026-08-26)

Issue acceptance also requires bounded, fully passing Catalyst and DBIx::Class
suites after the Mojolicious runtime fixes are integrated.

### Completed Phases

- [x] Refresh Mojolicious 9.49 baseline and classify the timeout (2026-08-25)
- System Perl with loopback access: 109 files, 4,184 tests, PASS.
- PerlOnJava 5.44.1: bounded 900-second run timed out in `t/mojo/transactor.t`.
- Confirmed independent clusters in overloaded file paths, listening-socket polling,
Promise/IOLoop lifetime, gzip inflation, `module_true`, and parser diagnostics.
- Logs: `/tmp/issue1115-system-perl-loopback.log` and
`/tmp/issue1115-jcpan-loopback-baseline.log`.
- [x] Fix overloaded blessed filenames in three-argument `open` (2026-08-25)
- Added `mojolicious_filehandle_regressions.t` before the runtime fix.
- Fixed path mutation and bad-descriptor failures in asset, file, log, request,
response, and template paths without modifying Mojolicious.
- [x] Fix `IO::Poll` listener write-interest registration (2026-08-25)
- Added `mojolicious_socket_poll_regressions.t` before the runtime fix.
- `t/mojo/reactor_poll.t` passes 99/99 in the focused worker gate.
- [x] Preserve `do FILE` return values under `feature 'module_true'` (2026-08-25)
- Added `module_true_do_file_regression.t` before the runtime fix.
- Limited `module_true` substitution to `require`, preserving application objects
returned through Mojolicious script loading.
- [x] Decode streaming gzip responses (2026-08-25)
- Added `mojolicious_gzip_regressions.t` before the runtime fix.
- Implemented split-header gzip state, trailer validation, and byte counters in
`Compress::Raw::Zlib` compatibility code.
- Normal and chunked Mojolicious response subtests pass on JVM and interpreter
backends (20 assertions per backend).
- [x] Preserve malformed loaded-source delimiter diagnostics (2026-08-25)
- Added `mojolicious_loader_diagnostic_regressions.t` before the parser fix.
- Both backends now retain Perl's missing-right-curly message at EOF.
- [x] Preserve loaded-source EOF line ownership (2026-08-25)
- Extended the parser diagnostic regression before the second parser fix.
- Loaded files ending in a newline now attribute EOF to their final physical line,
while eval-string behavior remains unchanged.
- Mojolicious `t/mojo/loader.t` passes all 15 top-level subtests.
- [x] Preserve Mojo Promise lifecycle roots (2026-08-25)
- Added state-singleton, discarded-clone, and deterministic destruction
regressions before the runtime fix.
- `ReachabilityWalker` now follows persistent `state` storage and
`Scalar::Util::weaken` preserves its void return in list context.
- Focused lifecycle tests pass on both backends; upstream `t/mojo/promise.t`
passes all 40 subtests on JVM.
- The interpreter exposes a separate deferred warning-capture timing defect in
upstream subtests 34-35, now under a new test-first investigation.
- [x] Clear abandoned lexical readline diagnostic context (2026-08-25)
- Added stale-context and returned-filehandle lifetime regressions before the fix.
- The JVM explicit-return path now drops only the unaliased diagnostic pointer;
it does not close descriptors or alter IO holder counts.
- Full `make` passes and an isolated JAR containing the exact runtime source at
`cb553d756` passes all 226 assertions in Mojolicious `t/mojo/template.t`.
- The earlier post-assertion bad-descriptor report was reproduced only with an
older worker JAR; no additional runtime or Mojolicious change is required.
- [x] Classify non-real fork and preserve tempfile parent diagnostics (2026-08-25)
- Added `config_fork_capability.t` before advertising PerlOnJava's unsupported
process fork as the standard non-real fork classification.
- Added `file_temp_missing_parent.t` before restoring File::Temp's missing-parent
diagnostic in the bundled PerlOnJava implementation.
- Both regressions pass system Perl and both PerlOnJava backends; Mojolicious
`t/mojo/asset.t` passes all 22 subtests with its real-fork subtest skipped.
- [x] Honor bundled File::Path option contracts (2026-08-25)
- Added `file_path_options.t` before the bundled-runtime fix.
- `make_path` now initializes an empty error collector and `remove_tree` honors
`keep_root` while deleting descendants.
- The focused regression passes system Perl and both backends; two of the three
newly exposed Mojolicious `t/mojo/file.t` failures are resolved.
- [x] Preserve inherited listener non-blocking mode (2026-08-26)
- Added `mojolicious_inherited_listener_regression.t` before the runtime fix;
it passes system Perl and both PerlOnJava backends.
- `IO::Handle::_blocking` now follows transparent borrowed/dup/layered/shared
wrappers to the socket transport, so `new_from_fd` listeners do not block a
greedy Mojo accept loop after the first connection.
- [x] Run final bounded acceptance (2026-08-26)
- `nice -n 10 timeout 3600 ./jcpan -t Mojolicious`: 109 files, 4,194 tests,
PASS in 1,186 seconds; skips are upstream TEST_* developer/optional paths.
- Catalyst::Runtime: 199 supported files pass (real-fork-only `t/live_fork.t`
excluded); DBIx::Class: 325 files, 43,020 tests, PASS.

### Next Steps

1. Keep the WIP PR open for review and retain the focused regressions.
2. Track real-fork/prefork follow-up in issue #1144; it is intentionally outside
PerlOnJava's current process model.
3. Publish the Mojolicious `PASS` classification from the recorded acceptance log.

### Open Questions

- None for issue #1115; optional upstream facilities remain explicitly opt-in.

## Related Documents

- `dev/modules/smoke_test_investigation.md` -- Compress::Raw::Zlib tracked as P8
- `dev/modules/lwp_useragent.md` -- Related HTTP client support
- `dev/modules/poe.md` -- Related event loop support
Loading