Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
72 changes: 72 additions & 0 deletions .agents/skills/create-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: create-release
description: Create a PerlOnJava release, including the project-wide version bump, changelog promotion, validation, release PR, exact merged-commit tag, and GitHub release. Use for PerlOnJava version bumps, release preparation, release tags, or GitHub release publication.
---

# Create a PerlOnJava release

Follow `AGENTS.md`, especially its dirty-tree preflight, testing, branch, commit-attribution, and no-direct-push-to-master rules.

## Prepare

1. Fetch `origin` and create a clean `release/<version>` branch from current `origin/master` in a separate worktree.
2. Confirm the tag and GitHub release do not already exist.
3. Inspect the previous tag and GitHub release for naming, notes, and tag style.
4. Record the starting version from `src/main/java/org/perlonjava/core/Configuration.java.in`.

## Update the version

Run from the repository root:

```bash
perl Configure.pl -D version=<version>
```

Review every changed file. Search the entire tracked tree for both the old and new versions, including regex-escaped forms such as `5\\.44\\.0`. Update current product-version references, generated artifact names, launchers, packaging checks, examples, tests, and active documentation. Preserve references that are explicitly historical, such as prior changelog entries, upstream Perl history/delta documentation, and design discussions about older releases.

Do not commit the generated, ignored `Configuration.java`.

## Promote the changelog

In `docs/about/changelog.md`:

1. Leave a new, empty `## Work in progress` section at the top.
2. Promote the previous work-in-progress content to `## v<version>: <terse title>`.
3. Consolidate implementation history into short user-facing bullets. Keep important features, compatibility improvements, performance changes, and bug fixes; omit PR chronology, internal evidence mechanics, and superseded intermediate details.

Use the promoted changelog section as the source for GitHub release notes.

## Validate and integrate

1. Validate this skill when it changed:

```bash
python3 -m venv /tmp/perlonjava-release-skill-validator
/tmp/perlonjava-release-skill-validator/bin/pip install PyYAML
/tmp/perlonjava-release-skill-validator/bin/python /Users/fglock/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/create-release
```

Reuse an existing validation virtual environment when available. Do not
install PyYAML into an externally managed system Python.

2. Immediately before final validation, fetch `origin` and rebase the release
branch onto the latest `origin/master` so concurrent fixes are included.
Preserve and verify the release commits after the rebase. If `master`
advances again before publication, repeat the integration and required
validation rather than tagging a stale candidate.
3. Run `make`, capture its complete output, and stop if it fails.
4. Run `make test-bundled-modules`, capture its complete output, and require every bundled-module test to pass.
5. Audit the main claims in the promoted changelog and draft release notes. Map every headline feature and compatibility metric to recent evidence or a focused test; rerun representative tests for the release's primary advertised features. Stop when a main claim is stale, unverified, or failing.
6. Commit with the required AI attribution, push the release branch, and open a PR using `--body-file`.
7. Monitor all required CI checks. Merge only after local validation and CI pass.

## Tag and publish

1. Fetch `origin/master` after the release PR merges.
2. Verify the release changes are present and identify the exact merged `origin/master` commit.
3. Create `v<version>` using the same annotated/lightweight convention as the preceding release, targeting that exact commit. Verify the local tag target before pushing it.
4. Push only the release tag, then verify the remote tag resolves to the intended commit.
5. Create the GitHub release from a notes file, matching the previous release's title and concise Markdown style. Release notes are plain documentation and must not include AI attribution. Mark it latest unless this is explicitly a prerelease.
6. Verify the published release URL, title, tag, release status, and target commit.

Stop rather than overwrite an existing tag/release, publish from an unmerged branch, tag an unexpected commit, or continue after a failed required check.
25 changes: 0 additions & 25 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,31 +190,6 @@
╚══════════════════════════════════════════════════════════════════════════════╝
```

## Incident Log (do not delete — this is why the rules above exist)

| Date | What was lost | Root cause |
|------------|------------------------------------------------|---------------------------------------------------|
| 2026-04-28 | ~600 cpan-tester module results (4736 → 4139) | Agent ran `git checkout dev/cpan-reports/` on an unstaged refresh; concurrent `cpan_random_tester.pl` instances also race on `.dat` files (separate bug). |
| 2026-04-29 | cpan-reports refresh commit (briefly, on a feature branch — recovered from reflog) | Agent resolved a rebase conflict with `git checkout --ours` thinking it would keep the branch's version. During rebase, `--ours` means UPSTREAM, so the upstream files were taken, the replayed commit became empty, and rebase silently dropped it. Recovery: `git reset --hard <sha>` from `git reflog`, then re-rebase using `--theirs`. |
| 2026-04-30 | (no work lost — recovered) Working tree on `fix/class-trait-tests` was overwritten with master content | Agent ran `git checkout master -- .` to A/B test failures vs master without first snapshotting and without switching branches. Recovery only worked because the changes had already been committed to HEAD: `git restore .` (also a forbidden command on a dirty tree, but safe here because "dirty" was master content, not user work) brought the tree back from HEAD. Correct workflow would have been: stash via `git diff > /tmp/wip.patch`, or use `git worktree add` for the master comparison instead of mutating the current tree. |
| 2026-04-30 | A full afternoon chasing a phantom "DBIx::Class regression" in `t/76joins.t` / `t/96_is_deteministic_value.t` | Investigative agent launched the test repeatedly under `/usr/bin/time -p ./jperl …` (no `timeout` wrapper). Each hung JVM survived past the agent's lifetime, accumulated as ~14 orphans at 100% CPU each, and starved the active `jcpan` harness — which then SIGKILLed innocent tests after 300 s of no TAP output. Symptom looked exactly like a real perf regression. Fix: always `timeout N ./jperl …` for any potentially-hanging run. |
| 2026-08-06 | (no source work lost — build recovered) A process cleanup killed the active Gradle test workers, producing exit 137 failures in two shards. | Agent selected Java PIDs from a broad CPU list without first constraining them to stale processes. Recovery: rerun `make` without killing workers; subsequent build completed successfully. Fix: never kill by CPU list alone; identify the exact command and build ownership first. |
| 2026-08-17 | (no source work lost — stale workers removed) Failed `make` runs were interrupted after their known Joni failures, but their Gradle unit-shard workers survived and competed with later builds. | Agent sent Ctrl-C to the parent build session before all parallel workers had exited. Recovery: identified stale workers by PID, start time, and shard work directory, terminated only those exact PIDs, and left the current build and sibling repositories untouched. Fix: let failed parallel `make` runs finish naturally, or verify and clean up their exact child PIDs before starting another build. |
| 2026-08-17 | (no source work lost — CPAN run rerun) A concurrent `make` replaced the development shadow JAR while an active `jcpan` process was spawning a child JVM, causing a transient `ClassNotFoundException`. | Agent waited for another worktree's build but did not wait for the same worktree's bounded CPAN runs before rebuilding `target/perlonjava-5.44.0.jar`. Recovery: let `make` finish and rerun the affected CPAN target. Fix: never rebuild a worktree's development JAR while that worktree has active `jperl` or `jcpan` processes. |
| 2026-08-18 | (no source work lost — wrong local WIP ref recovered) A test-snapshot cherry-pick landed in the original checkout instead of its newly created continuation worktree. | Agent chained `git worktree add` and `git cherry-pick` while the shell remained in the original working directory. Recovery: preserved the mistaken commit on a recovery branch, restored the original WIP ref to its exact prior commit without reset, then cherry-picked in the intended worktree. Fix: run post-creation Git commands with the new worktree as the explicit working directory and verify `git branch --show-current` before committing. |
| 2026-08-20 | (no source work lost — green build evidence discarded) A coordinator cherry-picked an integrated worker commit into a checkout while `make` was still validating an earlier supposedly immutable commit. | Integration and validation shared one worktree, and the coordinator continued integration before the build session drained. Recovery: let the exact build processes finish untouched, mark the result invalid regardless of exit status, and rerun from an immutable barrier. Fix: never mutate, cherry-pick, rebase, or regenerate a checkout with an active build/test gate; integrate in a separate worktree or wait for the gate to finish. |
| 2026-08-22 | (no source work lost — focused tests rerun) Two A165 focused JVMs opened an incomplete shadow JAR and exited immediately with `ClassNotFoundException`. | Agent treated Gradle's `> Task :shadowJar` console line as task completion and started `jperl` while the same worktree's build was still writing the JAR. Recovery: waited for the build process itself to exit, verified the stable JAR hash, and reran the bounded tests. Fix: a task-start line is not a completion fence; never launch `jperl` until the owning build process has exited successfully. |
| 2026-08-22 | (no source work lost — focused result discarded) An agent edited a direct-Joni test while its focused `make test-joni` gate was active. | The running build compiled a mutable source identity, so its failure could not distinguish the old test from the corrected test. Recovery: discarded the result and reran from a frozen diff. Fix: do not edit any file in a worktree from build launch until that gate drains, even when implementation can otherwise continue in parallel. |
| 2026-08-22 | (no source work lost — four valid builds drained naturally) Two workers each launched what appeared to be the third permitted regex implementation build. | The first worker released the atomic launch mutex when its `timeout` wrapper was visible but before the owned `make` executable appeared; the second worker could not yet count it and launched concurrently. Recovery: preserved both valid runs, launched no fifth job, and let them drain. Fix: under the mutex, count accepted launch intents and active owner roots, then release only after the exact payload executable is visible with its intended cwd; a shell or timeout ancestor is not a visibility fence. |
| 2026-08-22 | (no source work lost — String::Random evidence discarded) Two CPAN gates used a JAR in the integration checkout's `target/` directory while the coordinator rebuilt that same path. | Workers treated a matching embedded source SHA and an initial file hash as immutable identity, but did not copy the artifact out of the shared build tree. Recovery: stopped only the exact affected process, retained its log as invalid evidence, and reran from a private copy after the build drained. Fix: acceptance gates must use hashed task-owned copies of JARs and launchers; any overlap with a writer invalidates the result. |
| 2026-08-24 | (no source work lost — focused probes rerun) A Text::CSV `jperl` probe twice observed a transient missing `Main.class` while another agent's focused bundled-module build replaced the same worktree's development JAR. | The coordinator allowed readers and writers of the shared development JAR to run concurrently despite the existing 2026-08-17 warning. Recovery: stopped new launches, let the active Net::SSLeay build finish naturally, verified no build or `jperl` process remained, and reopened a single-writer/readers-after-build fence. Fix: coordinate one explicit shared-JAR build fence per worktree; no `jperl`/`jcpan` reader may start while a build can replace the JAR, and no build may start until all readers finish. |
| 2026-08-24 | (no source work lost — core regex evidence discarded and rerun) A core `pat.t`/`pat_thr.t`/`anyof.t` reader was launched beside `make test-bundled-modules` on the same candidate JAR. | The coordinator incorrectly classified the bundled-module target as read-only, but it runs `shadowJar` before its module tests and can replace the development JAR. Recovery: let both bounded processes drain naturally, retained the bundled result, discarded the overlapped core result, and reran the core files after the writer exited. Fix: classify every Make target by its full dependency graph; `make test-bundled-modules` is a shared-JAR writer and must never overlap `jperl` or `jcpan` readers of that worktree. |

When you cause a new incident, append a row here in the same commit
that fixes it. Future agents need to see that these warnings are real.

---

## Project Rules

### Progress Tracking for Multi-Phase Work
Expand Down
10 changes: 5 additions & 5 deletions Configure.pl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# USAGE:
#
# ./Configure.pl # Show current configuration
# ./Configure.pl -D version=5.44.0 # Update version everywhere
# ./Configure.pl -D version=5.44.1 # Update version everywhere
# ./Configure.pl --upgrade # Upgrade dependencies to latest versions
#
# VERSION UPDATE BEHAVIOR:
Expand Down Expand Up @@ -88,7 +88,7 @@ sub show_help {
-D key=value Set configuration value

Supported configuration keys:
version - PerlOnJava version (e.g., 5.44.0)
version - PerlOnJava version (e.g., 5.44.1)
Updates Configuration.java.in, build files, and all JAR references

Read-only keys (managed by build system):
Expand All @@ -103,7 +103,7 @@ sub show_help {

Examples:
./Configure.pl # Show current configuration
./Configure.pl -D version=5.44.0 # Update version everywhere
./Configure.pl -D version=5.44.1 # Update version everywhere
./Configure.pl --search org.h2.Driver # Search for JDBC driver
./Configure.pl --direct com.h2database:h2:2.2.224
./Configure.pl --upgrade # Upgrade all dependencies
Expand Down Expand Up @@ -285,8 +285,8 @@ sub update_version_everywhere {

# Update version in README.md (feature support line)
if ($file =~ /README\.md$/) {
(my $old_feature_version = $old_version) =~ s/\.0$//;
(my $new_feature_version = $new_version) =~ s/\.0$//;
my ($old_feature_version) = $old_version =~ /^(\d+\.\d+)/;
my ($new_feature_version) = $new_version =~ /^(\d+\.\d+)/;
if ($file_content =~ s/(Perl )\Q$old_feature_version\E( language compatibility)/$1$new_feature_version$2/g) {
$updated = 1;
print "Updated version in $file\n";
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ FROM eclipse-temurin:24-jdk
WORKDIR /app

# Copy the built JAR file from the Maven container
COPY --from=build /app/target/perlonjava-5.44.0.jar /app/perlonjava-5.44.0.jar
COPY --from=build /app/target/perlonjava-5.44.1.jar /app/perlonjava-5.44.1.jar

# Copy the wrapper scripts
COPY --from=build /app/jperl /app/jperl
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ tasks.buildDeb {

// Project metadata
group = 'org.perlonjava'
version = '5.44.0'
version = '5.44.1'

// CycloneDX SBOM generation configuration
cyclonedxBom {
Expand Down
2 changes: 1 addition & 1 deletion dev/design/bytecode_debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,5 @@ Fix strategy:

## Notes

- `jperl` runs `target/perlonjava-5.44.0.jar`. Rebuild after changes, otherwise you may be debugging stale code.
- `jperl` runs `target/perlonjava-5.44.1.jar`. Rebuild after changes, otherwise you may be debugging stale code.
- `JPERL_ASM_DEBUG_CLASS` is useful to avoid massive logs during large tests.
2 changes: 1 addition & 1 deletion dev/design/debugger.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This client would use JPDA to communicate with the JVM, but would present the de
## Run PerlOnJava with Debug Flags

```bash
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -jar target/perlonjava-5.44.0.jar myscript.pl
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -jar target/perlonjava-5.44.1.jar myscript.pl
```

## Start Debugging
Expand Down
12 changes: 6 additions & 6 deletions dev/design/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ This guide helps you start using PerlOnJava to run Perl code on the Java Virtual

1. Download the JAR file:
```bash
java -jar target/perlonjava-5.44.0.jar
java -jar target/perlonjava-5.44.1.jar
```

2. Run your first Perl script:
```bash
java -jar target/perlonjava-5.44.0.jar -E 'print "Hello from Perl on JVM!\n"'
java -jar target/perlonjava-5.44.1.jar -E 'print "Hello from Perl on JVM!\n"'
```

## Basic Usage Examples
Expand All @@ -28,12 +28,12 @@ java -jar target/perlonjava-5.44.0.jar -E 'print "Hello from Perl on JVM!\n"'

Run a Perl file:
```bash
java -jar target/perlonjava-5.44.0.jar script.pl
java -jar target/perlonjava-5.44.1.jar script.pl
```

Run Perl code directly:
```bash
java -jar target/perlonjava-5.44.0.jar -E 'for (1..3) { print "$_\n" }'
java -jar target/perlonjava-5.44.1.jar -E 'for (1..3) { print "$_\n" }'
```

### 2. Using Modules
Expand Down Expand Up @@ -96,12 +96,12 @@ Common switches:

Enable debugging output:
```bash
java -jar target/perlonjava-5.44.0.jar --debug script.pl
java -jar target/perlonjava-5.44.1.jar --debug script.pl
```

View generated bytecode:
```bash
java -jar target/perlonjava-5.44.0.jar --disassemble script.pl
java -jar target/perlonjava-5.44.1.jar --disassemble script.pl
```

## Next Steps
Expand Down
2 changes: 1 addition & 1 deletion dev/design/graalvm.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Added GraalVM support to pom.xml in a dedicated profile:
Used GraalVM tracing agent to capture required runtime methods:

```bash
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/perlonjava-5.44.0.jar examples/life.pl
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image -jar target/perlonjava-5.44.1.jar examples/life.pl
```

## Results
Expand Down
Loading
Loading