Skip to content

Add trusted grave helpers, navigation, reminders and item-rule inspection - #84

Open
BenCodez wants to merge 46 commits into
mainfrom
codex/trusted-graves-and-navigation
Open

BenCodez wants to merge 46 commits into
mainfrom
codex/trusted-graves-and-navigation

Conversation

@BenCodez

@BenCodez BenCodez commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Current capacity follow-up (dfe4b60)

Pending stored active graves now participate in logical grave-limit accounting while remaining unavailable for recovery. New death/admin creations reserve capacity before their existing two-second delayed callbacks; replacement selection and reservation are coordinated in the existing restoration owner. Cancellation releases only that admission. Unpublished creations do not enter marker restoration, navigation or claims. The same wrapper is transferred into normal creation. Queued/selected replacements do not consume a second logical slot. Limits still use the configured removal/drop policy and cancellable removal events. Duplicate pending intents keep the first admitted policy.

Focused checks: 162 passed, zero failures/errors/skips. Complete clean Maven package: 353 passed, zero failures/errors/skips. Fresh independent read-only delta review: No findings. Distributable SHA-256: 963d6c428010beacaf51505505f5f7878658005816d46a7ec8128293804c1e17 (9,060,128 bytes). The before-fix accepted-creation regression failed with expected count 1 / actual 0; it now passes.

Commands actually run through the serialized isolated Maven wrapper:

mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' '-Dtest=CreationCapacityTest,MarkerRestorationRegressionTest,GraveActionsTest,DeathPlayerOwnershipTest,AdminCreationAdmissionTest' test
mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' clean package
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-creation-capacity-native/run.py paper
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-creation-capacity-native/run.py folia
git diff --check

Exact-JAR native checks: Paper 26.2 build 133 and Folia 26.2 build 7, Java 25, each four passing protocol-driven cases (read-only item inspection, deliberately invalid reload rollback, real death capturing seven diamonds/seven XP, distant existing-menu removal with marker-region event ownership). Each log had the one expected invalid-reload error and zero unexpected runtime errors; servers/clients exited 0 and ports/process groups closed. This is not visual gameplay verification or a live test of repeated rapid death requests; reservation races are covered by automated tests. No schema/config migration. New creation identities/timestamps are captured at request admission, before the retained two-second delay; existing persisted timestamps are unchanged. Pending creation reservations are process-local and do not add a new crash-durability guarantee. Initial asynchronous MySQL inventory availability remains unverified.

Still not merge-ready: the new automated comments on the prior head concerning flat-file encoding fallback and rejected marker-cleanup scheduling are being investigated. This capacity commit does not claim to fix them or resolve their threads. Other previously documented limitations remain.

Adds per-grave trusted helpers, improvements to the existing grave menu/compass, opt-in protection and expiry reminders, and read-only held-item rule inspection. Existing default recovery permissions and timers remain unchanged. This PR remains not merge-ready because the limitations below are unresolved.

Implemented behavior

  • Separate finite TRACK and RECOVER grants use stable player UUIDs and canonical owner/death/world/block grave identities. Commands, menus and direct interaction reauthorize. Full RECOVER pays items and XP to the helper; tracking alone cannot recover. Owners can list and revoke grants.
  • The existing menu, compass and nearby claim command share accessible targets. Same-world distance/height and explicit cross-world labels avoid misleading distances. Claimed, removed and inaccessible targets are invalidated without loading distant chunks.
  • Distinct protection-ending and removal reminders are disabled by default, use actual deadlines, and offer one current login summary. Persistent recipient/grave/kind/deadline suppression avoids routine replay.
  • /gravestonesplus inspectitem uses the real ordered death-item evaluator without consuming randomness or modifying items. It identifies matching rules, their precedence, and limitations where death context is unavailable.

Commands: /gravestonesplus trust <online-name|uuid> <track|recover> <duration>, trustlist, revoketrust <online-name|uuid> <track|recover>, track, and inspectitem; existing graves, compass, and claimgrave are extended. Trust and inspection permissions default false. README includes opt-in configuration, permissions, and helper payout behavior. No partial recovery, parcel system, new recovery menu, or unrelated cosmetics are added.

Compatibility and persistence

Independent base: main at 251e7e25a85f6a5db7e3876180e9e6fbb5337618. No dependency on the VotingPlugin or MCPerks feature PRs. Java 21 and existing dependencies remain. Existing YAML records and SQL schemas remain readable without manual conversion. New local state files are selected-access.yml, selected-claims.yml, selected-claim-archive/, selected-marker-cleanup.yml, and grave-reminders.yml; back them up with normal grave data.

Full-claim reservations capture exact recipient/items/XP before delivery. Partial or unacknowledged payouts remain RESERVED for reconciliation rather than being automatically replayed. Completed identities archive before retirement. Items/XP and storage are not one transaction; this is conservative recovery, not a universal exactly-once guarantee across arbitrary failures.

Storage workers reuse item payloads prepared on a Bukkit owner. Restoration prepares Bukkit records on an owner and publishes marker changes on the saved location's region. Exact successor identities fence stale restoration, including successors found after unloaded publication. Expired startup records are not republished. Navigation pauses while helper or claim state is unavailable, preserving compass metadata. Default flat-file startup indexes cached positions before listener registration; MySQL still awaits its asynchronous backend read.

Legacy non-removing item-drop and main-thread removal behavior are preserved by separate paths. Recreation futures acknowledge checked persistence and marker-state transitions; legacy void recreation remains asynchronous (see unresolved API timing below). Invalid expiry replacements leave existing deadlines intact. Owner/death Java helper overloads resolve unique full identities; missing or ambiguous identities fail closed, and shortened experimental rows are not promoted into access.

Latest native-discovered Folia correction

A real native-player death on Folia 26.2 exposed Cannot read force-loaded chunk off global region in Grave.loadChunk. The latest commit uses region-owned loading plus a six-second location-scheduler task and its temporary region ticket on Folia; it does not read/change persistent force-loaded world flags from a region thread. Bukkit/Paper retain their existing force-load/release path. Regression tests exercise immediate/deferred loading, disabled callbacks, and unchanged Bukkit release behavior.

Latest head: 430bd581cc7e03b40ac4e95da3bea955866b69a7.

Staged reload and embedded calendar dependency

Reload captures bounded raw file contents on the I/O worker, prepares detached Config/Graves/NBT objects on the Bukkit owner, and publishes one configuration generation only after preparation succeeds. Late NBT/parse failure preserves the old objects. A core-hook exception restores the prior generation; arbitrary core runtime effects are not transactional. Files are not reread during publication. Reads are bounded to 16 MiB each plus Bukkit YAML limits. Migration runs in memory during preparation; a later normal save persists migrated keys. Existing backend selection and grave lists are not replaced by configuration reload; changing database settings still requires restart.

Successful native reload exposed an embedded AdvancedCore async-date event being dispatched inline from a server owner. AdvancedCore PR #360 now requests the check on its existing calendar worker. The tested consumer JAR includes exact AdvancedCore candidate bad9b56c5e3f006ca5de36629a95468346814d9f (library SHA 37a0476000b8d46b4f591962a231a39e3936b9e84c6aa3498ae7324a27200e18) staged only in an isolated local dependency cache. This is validation evidence, not remote snapshot availability. The POM coordinate remains 3.8.2-SNAPSHOT; consumers built against older same-version snapshots do not receive this fix. The producer must be reviewed and its library made available through the maintainer's normal workflow before relying on remote builds. No artifact was deployed.

Validation actually run

Through the serialized source-freezing wrapper:

mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-candidate/repository -DargLine=-Xmx512m -Dtest=RecoveryCompletionTest,NBTConfigManagerTest,SelectedCommandDispatchTest test
mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-calendar-consumer/repository -DargLine=-Xmx512m clean package
python3 evidence/gsp-native-features/prepare.py paper evidence/gsp-calendar-candidate-artifact.json
python3 evidence/gsp-native-features/prepare.py folia evidence/gsp-calendar-candidate-artifact.json
python3 evidence/gsp-native-features/run.py paper
python3 evidence/gsp-native-features/run.py folia
git diff --check
  • Focused: 32 passed before the extra core-hook rollback test. Final full build against the exact candidate library: 264 passed, zero failures/errors/skips. Fresh independent reload-delta source review: No findings; a retained-handler rebind allegation was retracted after verifying preexisting backend behavior. Independent calendar-worker review also returned No findings. These focused verdicts do not certify the whole PR.
  • Tested shaded JAR SHA e90cf7f1664ed1994aa87d0bde525afc055876110d17343f5defc161cf0b11f9; descriptor/config, Java21 base classes, absence of test libraries, and actual shaded core call to requestUpdate() verified. Frozen GSP source tree 446130d0d7520f5c6a697301c24ac89f4530c0c92a6a8920e7fd0ab781cbd41b.
  • Paper26.2 build133 and Folia26.2 build7 each10/10 native protocol cases passed with the same rebuilt JAR, Java25 and26.1clients via runtime-only Via bridge. No visual/manual gameplay claim. Original eight cases cover inspection, real death/respawn, deadline reminder, exact compass, untrusted denial, TRACK plus actual existing menu click, revocation and full RECOVER exact seven diamonds/seven XP once plus marker removal/repeat denial. Two new cases verify failed malformed-NBT reload preserves CHEST settings for a later actual death, and successful reload preserves selected-grave navigation.
  • Raw and sanitized logs audited. Each final fixture contains one expected error from deliberately malformed NBT reload; no other exception/scheduler/storage failure was found. The WEEK date event was observed and the prior async-dispatch warning was absent. Both server/client groups stopped normally, listeners closed, no termination fallback.
  • Earlier candidate b06a1242... passed gameplay assertions but failed the raw log audit on both products because of the async date warning; it is retained as failing evidence, not counted as a clean runtime pass. Prior chunk-ownership/setup failures remain recorded. Broad vendor/fixture warnings remain.
  • No live MySQL, Windows, or graphical test. Native coverage does not establish actual expiry/TTL, restart, overflow, cross-world/protection integrations or remote-before-creation behavior. Current hosted checks are separate and pending at publication. CodeRabbit skips automatic review here; status success is not a source-review verdict.

Remaining findings and limits

  • Exact-position protection still awaits initial asynchronous MySQL reads; cached flat-file off-owner startup is addressed by the follow-up below; do not globally cancel ordinary blocks or infer ownership from stale tags.
  • Pending creation/restoration limit admission is not fully reconciled; cancellation or failed limit eviction must not permit unbounded new graves. This requires durable capture/admission work, not an active-list counter patch.
  • Legacy synchronous void recreation timing is not preserved by asynchronous durable revocation/persistence. A compatibility-safe completion decision remains needed.
  • Config/Graves/NBT staging addresses partial preparation publication. Remaining AdvancedCore reload file/reward reads still run in the owner callback and require further ownership work; this update does not claim the entire reload is free of gameplay-thread I/O. Producer PR #360 fixed inline preparation-callback admission and pending-hook watchdog finding 4239378339 at f840c4ada2438b070919fe7704be2f0639104003.
  • The death/respawn player callback follow-up below is now covered; broader remote creation and full optional-integration gameplay remain unverified. Passing the ten nearby-player cases is not universal Folia support proof.
  • Inventory/XP and disk are not atomic. Unwritable retained state cannot reliably survive termination; a reminder send followed by persistence failure may repeat. No unsafe automatic archive purge is introduced. Windows directory fsync is not universally guaranteed; no live Windows test is claimed.

No original checkout was modified. No merge, release, or deployment.

AI disclosure: This pull request was created with assistance from OpenAI Codex. Maintainer review by BenCodez is pending.

Current producer validation: AdvancedCore PR360, commit f840c4ada2438b070919fe7704be2f0639104003, library SHA256 6f5489f50dabf4aaa0f49d20522f4abb16313a0b3b17f12c58b81219cb14dafc. The watchdog now retains storage while consumer preparation/callback admission is pending; admitted retirement still has a bounded timeout. Producer focused61/full1,052 PASS, zero failures/errors/skips; fresh independent six-file follow-up review: No findings. Exact dependency staged only into a copied local cache, not installed/deployed; remote snapshot availability is unverified.

This unchanged consumer source 430bd581cc7e03b40ac4e95da3bea955866b69a7 was rebuilt against that exact candidate: 264 PASS, zero failures/errors/skips; distributable SHA256 5b9a67d4343aa2dc5a9e46db935d45a0d184cfcf5b8ed2ba95642deddd089236. Command actually run: mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m clean package, through the isolated source-freezing wrapper.

Native Paper26.2build133 and Folia26.2build7/Java25 each10/10 PASS: held-item inspection, death capture/items/XP, real owner/helper access, navigation, reload failure/success, reminders, full recovery and duplicate denial. Only one deliberate malformed-reload ERROR per run; no other runtime errors. These are automated native protocol checks, not graphical/manual gameplay. All owned servers/clients exited normally with closed listeners. Earlier sections record historical hashes/results; this section identifies the current dependency/artifact. Watchdog finding4239378339 is fixed, but other documented consumer feature/lifecycle limits remain and this is not an overall merge-readiness claim. No merge, release or deployment.

Death/respawn player ownership follow-up

Commit 7ca70ec223f7392f4d8a32a2369cb1c0753bb256 captures identity on death, dispatches delayed messages/restoration on the player entity scheduler, and fences stale or duplicate respawn callbacks. Every subsequent death rotates callback identity without discarding an undelivered kept-item snapshot. Offline/dead/disabled/rejected callbacks retain it for a later living respawn. Kept-item state remains session-local; legacy death capture is not made restart-durable or atomic by this patch.

Actual commands (JDK21, isolated frozen-source Maven wrapper, exact AdvancedCore f840c4a candidate above):

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m -Dtest=DeathPlayerOwnershipTest,RespawnSchedulingRegressionTest,CompassPermissionRegressionTest,ItemRuleEvaluatorTest test: 36 PASS, zero failures/errors/skips.
  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m clean package: 275 PASS, zero failures/errors/skips.
  • python3 evidence/gsp-native-features/run.py paper and python3 evidence/gsp-native-features/run.py folia from the isolated workspace: Paper26.2build133 and Folia26.2build7, Java25, each 10/10 PASS against final JAR SHA256 d06f35409381d1c58aa13df1840b790684a50a8244c029db06fd840e153986cf. Two protocol clients use test-only ViaVersion/ViaBackwards; no visual/manual gameplay claim. One intentional malformed-reload ERROR each, no other exception or ownership errors; server/client exits0, groups gone and listeners closed.

New listener tests cover actual death/respawn dispatch, duplicate and stale callbacks, rejected schedulers, offline/dead/disabled players, multiple player isolation, subsequent ineligible/no-kept-item deaths, snapshots and grave-region message handoff. Fresh independent source review: No findings. git diff --check passed. Kept-lore edge cases were automated mocked listener tests, not native gameplay cases. MySQL, remote-region creation, Windows, cross-world, actual TTL/expiry and overflow remain unverified. Earlier artifact/results above are historical; this section identifies the final consumer artifact. New hosted checks remain separate from local evidence; this is not an overall merge-readiness claim.

Cached flat-file startup protection

Commit 36d5a66643c66406c130ab8df24f69400d2ced35 indexes already-decoded flat-file positions before deferred Folia preparation. Exact pending-marker protection is available immediately, while item snapshot/serialization and chunk restoration admission remain owner-scheduled. No broad block cancellation, world scans, database joins or claim exposure are added. Initial MySQL reads are still required to discover exact stored positions.

Actual checks against exact copied AdvancedCore f840c4a artifact:

  • Before production fix, mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m -Dtest=MarkerRestorationRegressionTest#startupOffOwnerDefersCachedRecordPreparation test: 1 test, 1 expected failure (missing early pending index).
  • Focused mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m -Dtest=MarkerRestorationRegressionTest,MySQLRestorationOwnershipTest,DeathPlayerOwnershipTest test: 79 PASS. The startup case was then expanded to chest/head/barrier materials and protection listener paths.
  • Final mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine=-Xmx512m clean package: 277 PASS, zero failures/errors/skips. Commands use isolated source-freezing Maven wrapper and JDK21.
  • Final JAR SHA256 7f9e2747a56485f4bed8226823a4aee9c7b3cddb89223cbf4824277b39b93158, 9,044,822 bytes; class maximum65, Folia descriptor retained, no JUnit/Mockito packaged.
  • python3 evidence/gsp-native-features/run.py paper and python3 evidence/gsp-native-features/run.py folia: Paper26.2build133/Folia26.2build7 on Java25 each10/10 PASS against this final artifact. The ten cases cover the adjacent workflow described above, not a native reproduction of the delayed startup interval; that interval is verified by controlled scheduler regression tests. Native protocol clients/bridges are test-only; no visual/manual claim. Exactly one deliberate malformed-reload ERROR each, no other errors; all owned processes exited0, groups gone, listeners closed.
  • Fresh independent read-only focused review: No findings. Effective source remained unchanged; git diff --check passed.

Earlier artifact sections are historical. MySQL startup gap, durable death capture/admission/limit reconciliation, legacy void recreation timing and remaining owner-context I/O are still open; no overall merge-ready claim. Hosted checks for this head are separate and may still be pending. Original checkouts remain unchanged; no merge/release/deployment.

Successive death kept-item preservation

Successive deaths now preserve separate detached kept-item batches, including identical items in the same slot. Every death fences stale callbacks. The backlog is bounded to eight batches per player; exceeding it leaves the new death's drops and experience untouched. Inventory insertion leftovers become ordinary item drops at the player's location. This pending respawn state remains session-local.

Validation on commit c8ed7d65f65c5a3d21cf5fbe3d53684cfa931c51:

  • Focused DeathPlayerOwnershipTest,GraveActionsTest: 62 passing tests.
  • Complete Maven clean package: 279 passing tests, zero failures/errors/skips.
  • Fresh independent source review: No findings.
  • Candidate JAR SHA-256: 50ddf190f27954a722181a87d45c4c18c4d5a1c2ddcbe187d43c25135b7fc64d.
  • Automated native protocol gameplay: ten passing cases on Paper 26.2 build 133 and ten on Folia 26.2 build 7, Java 25, SQLite. Each run included one intentional invalid-reload error, otherwise clean audited logs and clean client/server shutdown. These cover held-item inspection, death/respawn, reminders, tracking, reload, helper authorization/revocation, and recovery.
  • Repeated kept-item death, stale callback, overflow, and backlog-limit cases were tested with mocks, not native gameplay. No visual client verification or MySQL test is claimed.

Remaining review/readiness work includes display identity repair persistence, login summaries during asynchronous startup, pending creation/limit ownership, and legacy void recreation API timing compatibility. This update does not declare the full PR ready to merge.

Latest restoration and login-readiness follow-up

Commit 61ae24472ca9945d4f7c67242052602690b55b71 persists replacement display identities before releasing the startup restoration record. Failed writes retry using the same repaired entity. SQL acknowledgement updates only the display/interaction columns on the exact active row; it does not recreate graves, change contents/XP, or overwrite removal flags. Login summaries remain pending until feature stores and record loading are ready and successful delivery completes; the existing bounded periodic player-owner pass handles retry, quit and shutdown.

Actual commands (offline isolated Maven cache):

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dtest=MarkerRestorationRegressionTest,GraveLoginReadinessTest,GraveActionsTest,GraveReviewRegressionTest,GraveReminderDeliveryTest,MySQLRestorationOwnershipTest test: 138 passing, zero failures/errors/skips.
  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package: 286 passing, zero failures/errors/skips; distributable JAR built.
  • git diff --check: passed. Fresh independent source-read-only review: No findings.
  • JAR SHA-256: d18205c94bd782be9e8a7469134e9323c41c322e9bffdede9eae654a99bff963; 9,047,664 bytes; 123 project classes target Java 21; packaged Folia declaration preserved.
  • Native automated protocol gameplay: ten checks passed on Paper 26.2 build 133 and ten on Folia 26.2 build 7, Java 25, SQLite. Full logs contained only the expected deliberate invalid-reload error. Clients and servers exited normally; process groups and listening ports were gone.

The delayed-startup/failed-write scenarios and SQL affected-row checks are mocked integration tests, not live MySQL or graphical gameplay. The native runs exercise the existing inspection, death/respawn, reminders, navigation, reload, helper access/revocation and recovery flows. Earlier focused attempts exposed fixture/compiler issues; only the final passing run supports this result.

The previous section's display-identity and login-readiness items are now addressed in source. Broader pending-creation/limit ownership, legacy recreation API timing compatibility and startup MySQL discovery still need assessment. This update does not claim overall merge readiness.

Latest death replacement preflight follow-up

Commit d9584d6543600f6e27c0d8407441a1edcd422fce resolves the replacement location, evaluates/copies items and reserves kept-item capacity before enforcing the existing grave limit. A missing location or full eight-batch kept-item backlog preserves the oldest grave and the new death's native drops/XP. Respawn cannot pay a staged batch before drops are consumed. Failed limit preflight removes only that death's batch, preserving older and successor batches. Successful replacements retain both configured limit-removal policies. Grave-bound items are cloned before deferred creation.

Actual validation (isolated offline Maven cache; no deployment profile):

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine='-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' -Dtest=DeathPlayerOwnershipTest,RespawnSchedulingRegressionTest,GraveActionsTest test: 78 passing, zero failures/errors/skips.
  • Same Maven/cache/JVM options with clean package: 295 passing, zero failures/errors/skips; full distributable JAR built.
  • git diff --check and staged diff check passed. Fresh independent read-only follow-up review of all three changed files and adjacent death/respawn, limit, scheduler and storage paths: No findings; effective source identity unchanged through build/review.
  • JAR SHA-256 81b2498db4e2c77cce6b011a08d1dd74fad1e1b1ef26c5dc34b0198ed4aacbc2, 9,049,537 bytes, 124 project classes target Java 21; test classes absent and packaged Folia declaration unchanged.
  • python3 evidence/gsp-death-limit-preflight-native/run.py paper and python3 evidence/gsp-death-limit-preflight-native/run.py folia: 10 existing automated protocol gameplay cases passed per platform, Paper 26.2 build133/Folia 26.2 build7, Java25, SQLite. Tests cover actual death/captured-item recovery, inspection, navigation, reminders, reload, helper isolation/revocation and duplicate-recovery rejection. Full log audits found exactly the intentional invalid-reload error per run; server/client exit0, groups gone, ports closed, no forced shutdown.

The old-code regression first reproduced four failures (both refusal conditions and both removal policies). An initial candidate test run had an uninitialized mock Bukkit registry fixture; it was corrected without weakening assertions. Initial artifact inspection accidentally included relocated dependency classes; final inspection identifies project classes from the unshaded artifact and separately checks every runtime base class's supported bytecode. The no-air/backlog/failed-limit/reentrant-successor paths are mocked regressions, not native gameplay. No graphical or live MySQL verification is claimed.

Remaining work: pending/unpublished/restoring grave limit accounting, durable creation ownership and shutdown/scheduler-failure recovery after death capture, legacy public void recreation timing compatibility, and initial MySQL discovery protection. This bounded preflight fix does not claim full PR merge readiness or solve those remaining lifecycle paths.

Death creation scheduler admission

Commit 4749375a326dc34838eb16c4fdf055e353b966da admits a cancellable location callback before oldest-grave removal or native drop/XP consumption. Early region callbacks wait for acceptance, execute once, and cancel. Failed scheduler/limit admission withdraws only this death's kept-item batch. Existing two-second location delay is explicit. No command, permission, configuration, public API or persistence-format changes.

Validation actually run (isolated serialized Maven, Java 21 project bytecode):

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' '-Dtest=DeathPlayerOwnershipTest,GraveActionsTest,MarkerRestorationRegressionTest' test: 140 passed.
  • Same Maven arguments with clean package: 301 passed, zero failures/errors/skips. Full suite includes final cancellation retry regression. Fresh JAR SHA-256 7058824b46ddfde9e745a8635ce7941119e3004d403d015b94d9027cecdb203b; 125 project classes Java 21, runtime base classes <= Java 21; tests absent; Folia metadata retained.
  • Original rejection regression before implementation: two cases failed with native drops cleared and XP zeroed; kept case also retained the rejected batch. After implementation all pass, including rejected/null/already-cancelled tasks, early callbacks, repeated execution, limit failure and cancellation retry.
  • python3 evidence/gsp-creation-admission-native/prepare.py paper evidence/gsp-creation-admission-artifact.json; python3 evidence/gsp-creation-admission-native/run.py paper; corresponding folia commands: exact-JAR native packet automation ten cases passed each on Paper 26.2 build 133 / Folia 26.2 build 7, Java 25, SQLite. Actual death capture and recovery of seven diamonds/seven XP once, helpers, navigation, reminders and reload. Full log audit: only the deliberately malformed reload error, no unexpected scheduler/storage exceptions. Clients/servers exit 0, process groups gone, ports closed. Test-only protocol bridges and permission probe are outside source/JAR.
  • git diff --check, complete three-file/staged diff and fresh independent source-read-only focused review passed (No findings), frozen identity 87425cad50795800cc73d771768146698c0f1db1805703c2427960d14e9268d1 unchanged.

Limits: scheduler rejection/early-callback cases are mocked production-entry tests, not forced failures on live servers. No visual gameplay or live MySQL verification. This fixes initial scheduler admission; accepted creation durability, nested marker callback failures/shutdown, pending/restoring grave limit accounting, and historical void-recreation timing compatibility remain unfinished. This does not establish crash-atomic death/disk ownership or overall merge readiness. Original checkouts unchanged. New-head hosted CI is pending until separately observed.

Administrative creation admission follow-up

At eadac739fd173e0338c545ac5d1c873016bb41f4, test-grave creation now obtains its cancellable location task before enforcing the oldest-grave limit. Death and administrative creation share the existing phase-fenced implementation: early callbacks wait for acceptance, failed preflight cancels creation, and accepted creation runs once. The existing two-second delay, limit-removal policy, public methods, configuration and persisted formats are preserved. No gameplay-thread I/O or dependency change was added.

Validation actually run in an isolated frozen checkout:

mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' -Dtest=AdminCreationAdmissionTest,DeathPlayerOwnershipTest,GraveActionsTest,MarkerRestorationRegressionTest test
mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' clean package
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-native-final/prepare.py paper /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-artifact-final.json
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-native-final/prepare.py folia /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-artifact-final.json
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-native-final/run.py paper
python3 /workspace/selected-plugin-features-workspace/evidence/gsp-admin-admission-native-final/run.py folia

Focused tests: 146 passed. Final clean package: 307 passed, zero failures/errors/skips; shaded JAR built. Six new mocked regression cases cover scheduler rejection and old-grave preservation, failed limit preflight with an early callback, and successful once-only administrative creation under both removal policies. The corrected before-fix regression run failed all four initial cases; an earlier incomplete fixture run is excluded from defect evidence. Final artifact SHA-256: 38cd617dd323a6d6d95105bb8b9dea7843dc88d2bf443ddd8a7c9c10b7c1d565 (9,051,718 bytes); Java 21 project classes, compatible base runtime bytecode, packaged defaults/descriptor checked, no test classes packaged. Both unstaged and staged diff checks passed. Fresh independent read-only follow-up review: No findings.

The exact final JAR passed 10 native gameplay/protocol checks on Paper 26.2 build 133 and 10 on Folia 26.2 build 7, using Java 25, SQLite, and test-only protocol/permissions fixtures. Checks included actual death capture and one recovery of seven diamonds/seven XP, helpers and revocation, navigation, reminders and reload. Log audit found only the deliberately malformed reload's expected error and classified environment/calendar warnings. Both owned servers/clients exited normally; process groups are gone and listeners closed. This is automated server/client evidence, not visually verified gameplay; live MySQL and forced live scheduler failures were not tested. New administrative admission failure and successful-creation cases are mocked tests.

Remaining creation work is explicit: unpublished/restoring grave limit accounting and durable accepted death-capture recovery are not implemented by this follow-up. Asynchronous/cancellable removal cannot be treated as already-freed capacity, and the public active-only grave count remains unchanged. This is not a claim of automatic exactly-once crash recovery.

Compass refresh failure isolation

Player-owned compass scheduling and refresh callbacks are best-effort per player. A disconnected player's rejected task no longer interrupts grave removal, helper revocation or another player's refresh. Identity invalidation remains immediate. This also protects claim/limit/conflict paths that use the same navigation invalidation method.

  • Two new production-entry regressions failed before the fix. Final coverage includes scheduler rejection and both inline/deferred callback failure, with continued helper revocation and active-list removal.
  • Focused command: mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' '-Dtest=NavigationLegacyCompassRegressionTest,RemovalRecoveryRegressionTest,GraveActionsTest' test: 62 passed. The subsequent deferred-callback parameter is covered by the full build below.
  • Final command: mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository '-DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp' clean package: 310 passed, zero failures/errors/skips.
  • Fresh independent read-only focused review: No findings. Staged diff check and artifact inspection passed; Java 21 class compatibility, Folia descriptor, default grave limit and absence of test classes retained.
  • JAR SHA-256: 529bee9423e53547bc42b3d49d5e7d32bc0acc06d9d1ef4030878a7d9a519dae.
  • No native server test ran on this new artifact. Earlier Paper/Folia gameplay evidence remains tied to its recorded older artifact. This change does not resolve the outstanding MySQL write-acknowledgement, player-removal region ownership, pending-limit or legacy recreation compatibility findings.

MySQL incremental-write acknowledgement follow-up

Creation, updates, broken flags and deletion now propagate SQL/resource-cleanup failures through the plugin-managed backend, retaining the captured recovery snapshot for a confirmed retry. Direct public table methods preserve legacy logging-only behavior. Checked writes require auto-commit and accept idempotent zero affected rows; no schema migration is added.

Actually run with the isolated local dependency repository:

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -Dtest=MySQLRestorationOwnershipTest test: 41 passing, 0 failures/errors/skips.
  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository clean package: 332 passing, 0 failures/errors/skips; BUILD SUCCESS. Both commands used -DargLine=-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp under the existing Maven lock.
  • git diff --check: passed. Fresh independent read-only follow-up review: No findings.

Artifact SHA-256: ae5ca00faa943c6083ce1becf2869d669e275d9a28bba17b6ee5710f669075d6; 9,052,401 bytes. Java 21 base bytecode verified; no test libraries packaged.

The added SQL-failure/retry cases use mocked JDBC with real table/backend/manager methods. No live MySQL service or native server run was performed for this newest artifact; earlier native results belong to the older artifacts identified above. Memory-only recovery cannot survive termination while storage remains unwritable. This follow-up does not claim all remaining review concerns are resolved.

Interrupted startup persistence

If shutdown occurs before the initial grave index has finished preparing, newly captured graves are now atomically merged with the persisted flat-file records before storage closes. This preserves old records, legacy item representations and the new capture without decoding Bukkit objects on the storage worker. Death/keep-item behavior, configuration and storage schema are unchanged. Repeating the same merge replaces the matching stable grave identity; conflicting prepared identities fail closed. SQL recovery continues using acknowledged incremental writes.

Validation on commit 8cbb0d1: mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine="-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp" -Dtest=StartupGraveDocumentTest,MarkerRestorationRegressionTest test — 69 passing tests. Same options with clean package — 338 passing tests, zero failures/errors/skips. Real flat-file shutdown regression verifies both existing and newly captured records survive. Fresh independent read-only follow-up review: No findings. git diff --check passed. Shaded JAR SHA-256 e2f22015c7548109733d8b1751df5e4eb9ce994afd22f9ba01572bfd5402196c, 9,057,051 bytes; Java 21 base bytecode, plugin descriptor present and no test libraries.

This exact JAR has not been run on a native Paper/Folia test server. Older native results do not verify this change. Hosted checks for the new commit are pending. Other previously documented compatibility/review limitations remain.

Expiry replacement and native follow-up

Commit 8b81ac4058d64b3f0d6a4cdd7d1776a83459b929 preserves an existing expiry timer when a parsed duration fits in long but its addition to the death timestamp overflows. Disabled/empty lifetimes still cancel normally. Regression reproduced the previous zeroed deadline; focused GraveActionsTest,MarkerRestorationRegressionTest,GraveTimeLimitTest now passes 115 tests. Full clean package passes 338 tests, zero failures/errors/skips, using the Maven options recorded above. Fresh independent follow-up review: No findings. JAR SHA-256 034bf2ac6ff4b082e8da2c511d14d0562b4b0a890721e08811ef0e3e63eb3bbf, 9,057,084 bytes; base Java 21, plugin descriptor present, no test libraries.

The preceding persistence-fix commit 8cbb0d1efe3f8dd534a43518e9c058ae6ae6b6f8 / JAR e2f22015c7548109733d8b1751df5e4eb9ce994afd22f9ba01572bfd5402196c has now passed actual native protocol automation: Paper 26.2 build 133 and Folia 26.2 build 7, Java 25, 10 gameplay checks each before shutdown and 10 each after restart. Held-item inspection, real death capture, deadline reminder, selected compass/navigation, reload, tracking-only permissions, revocation, full helper recovery and duplicate-payout denial were observed. The helper's seven recovered diamonds persisted across restart; the second recovery added exactly seven. Each server/client exited zero, owned processes stopped, listeners closed, and no unexpected runtime errors appeared. Each run deliberately rejected one malformed reload, producing one expected error. Exact interrupted-initial-restoration timing remains covered by the real flat-backend automated regression, rather than a forced native timing race.

Commands actually run: python3 evidence/gsp-startup-merge-native/prepare.py paper evidence/gsp-startup-merge-native-candidate.json and the corresponding folia command; python3 evidence/gsp-startup-merge-native/run.py paper / folia; repeat runs on stopped, reused fixtures with unique run IDs and inventory-delta assertions. Test tooling lives outside the source PR. Initial restart harness attempts failed because the run ID was reused and because the test assumed a previously rewarded helper had zero diamonds; these were corrected and fresh fixtures verified before recording passes. Native results are protocol observations, not visually verified gameplay. The newer expiry-fix JAR has not had its own native run. Current hosted checks remain pending at this update. Other outstanding review/compatibility limitations remain.

Distant GUI removal follow-up

Player authority is checked on the actor scheduler immediately before scheduling removal. The cancellable grave-removal event, live-identity checks and marker transition run on the grave region; completion feedback returns to the player scheduler. Retired/replaced graves cannot be removed by stale callbacks. No command, configuration, storage-schema or reward changes.

Validation on commit 182b82a5c928c4588e0d9ca28d258f849ed648c1:

  • Focused command: mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine="-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp" -Dtest=GraveActionsTest,RecoveryCompletionTest,MarkerRestorationRegressionTest test: 132 passed, 0 failures/errors/skips.
  • Full command with the same Maven repository and JVM options: mvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package: 340 passed, 0 failures/errors/skips; distributable JAR built.
  • Exact JAR SHA-256 6cc4ba3edf368cef80b972720a77f2e5d0ec121164b3185ac1f02aa72470d2be; 9,057,288 bytes; Java 21 base bytecode, plugin descriptor present, no test libraries.
  • Actual server commands: python3 evidence/gsp-removal-region-native/run.py paper and python3 evidence/gsp-removal-region-native/run.py folia, using isolated native fixtures and the exact JAR: 4 checks each on Paper 26.2 build 133/Folia 26.2 build 7, Java 25. Real death capture, read-only inspection, deliberately invalid reload rollback, and distant existing-menu shift-right removal passed. A test-only listener verified the removal event's actual grave-region ownership. Marker removal, no item payout and subsequent claim denial were observed through native client packets. Both servers/clients exited normally and ports closed; one expected malformed-reload error per run, no unexpected runtime errors.
  • Fresh independent read-only review of this delta and adjacent lifecycle: No findings. git diff --check passed.

Native checks are protocol automation with a test-only compatibility bridge and ownership probe, not visually verified gameplay. Existing limitations elsewhere in this description remain applicable.

Legacy item fallback and rejected cleanup follow-up

Commit 59426bbe91004ad4e833b2638c92e5d1c34e523c preserves the flat-file Items fallback when binary inventory encoding throws IOException. Item/nested metadata are captured on the owner thread into plain YAML values, with the existing serialization aliases and slot identities. Normal save and interrupted-startup merge both round-trip the captured representation; subsequent item/metadata mutation cannot change the capture. MySQL continues to fail explicitly when the encoded inventory is unavailable. Cyclic, unsupported or excessively nested fallback data remains an acknowledged, retained failure rather than becoming an empty inventory. No file/database migration or default change.

After committed payout or synchronous Bukkit removal, location-scheduler rejection commits the already-admitted cleanup ticket without world/entity access on that caller. The existing bounded chunk/region cleanup retry removes owned markers without repeating payout or touching a successor.

Actual validation:

  • Focused mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -DargLine="-Xmx512m -Djava.io.tmpdir=/workspace/selected-plugin-features-workspace/build-tmp" -Dtest=MarkerRestorationRegressionTest,PreparedStorageSnapshotTest,LegacyPreparedItemsTest,GraveActionsTest,StartupGraveDocumentTest test: 136 passed, zero failures/errors/skips.
  • Full command with the same repository/JVM options and clean package: 357 passed, zero failures/errors/skips; distributable JAR built. SHA-256 98eb3ddd91b0fc669adf4cd0ddb8ac8a1daa201a41513998019cdf5b48419671, 9,063,368 bytes, Java 21 base bytecode, descriptor present, no test libraries.
  • Both scheduler-rejection regressions failed against the preceding implementation and pass now. Nested custom-item YAML save/reload, detached metadata/byte-array mutation, cycle rejection, SQL encoding failure and retained worker recovery are covered by automated tests.
  • python3 evidence/gsp-review-followup-native/run.py paper / folia: exact-JAR protocol automation on Paper 26.2 build 133/Folia 26.2 build 7, Java 25, four checks each: held-item inspection, malformed-reload rollback, real death capture and distant existing-menu removal. One expected malformed-reload error each, no unexpected runtime errors, all owned server/client processes stopped normally and ports closed. Existing fixture trees were reused.
  • Fresh independent source-read-only follow-up review: No findings. git diff --check passed.

The injected binary failure and scheduler rejection are deterministic automated tests, not forced live-server failures. Native results are protocol observations using test-only compatibility/ownership probes, not visually verified gameplay. Other previously stated limitations remain. New-head hosted CI/review is pending at publication; no review threads were manually resolved.

AI disclosure: This pull request was created with assistance from OpenAI Codex and reviewed by BenCodez.

Bounded startup retention follow-up — 289ffbe

Inventory cloning and encoding now capture at most 128 combined active/broken records per owner callback for MySQL and cached flat-file startup. Readiness and the startup write fence remain closed until every batch finishes. Partial retirement retains the existing backend baseline; shutdown with pending owner snapshots uses the existing merge/upsert path, never an incomplete full-store replacement. The legacy retainRestoration API remains available.

Actual validation:

  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository clean package through the isolated serialized build wrapper: 360 tests passed; 0 failures/errors/skips.
  • Production-path regression reproduced the previous unbounded capture (260 encodes in one callback), then passed with 128/128/4 batches. Flat-file startup, duplicate retry admission, retirement, and interrupted-startup merge-on-shutdown are covered by mocked integration tests. An intermediate shutdown fixture expected a write without a pending write; the fixture now exercises an actual pending snapshot.
  • Fresh independent read-only focused review: No findings. git diff --check passed. Fresh distributable JAR: SHA-256 1654b8d01e63a6dfc0ba520d5590a3ad9cd2764c4753330a25e2ea3f4997b669, 9,065,182 bytes; Java 21 project bytecode and no JUnit/Mockito classes.

This follow-up has not been rerun on native Paper/Folia or live MySQL. Earlier native results above apply to their stated older artifact. A 128-record budget is not a fixed elapsed-time limit for unusually large/custom inventories. Remaining claim callback compatibility and distant-player Folia event-context concerns still require investigation; a green build alone is not a merge-readiness claim.

Claim callback ownership follow-up — c577b1b

Folia claims now perform initial actor checks on the claimant entity scheduler, cancellable grave callbacks and inventory/XP capture on the grave location scheduler, and authorization revalidation/reservation admission back on the actor. The existing async ledger and recipient-owned payout remain authoritative. Duplicate admissions are fenced on the grave; rejected region admission makes no reservation, and recipient retirement before reservation releases the unused admission. Public void claim APIs are preserved. Ordinary Bukkit primary-thread callers retain synchronous cancellable callbacks. GraveClaimEvent documents that Folia handlers must schedule mutable access to a distant player on their entity scheduler.

Actual verification:

  • The new production-entry regression first failed because callbacks ran on the player owner.
  • Focused mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -Dtest=GraveRegionOwnershipTest,GraveActionsTest,RecoveryCompletionTest test: 79 passed, 0 failures/errors/skips.
  • Full same-command clean package: 365 passed, 0 failures/errors/skips, distributable built.
  • Mocked integration covers separate actor/marker contexts, callback XP amendments, duplicate claims, cancellation, region rejection, recipient retirement, and synchronous Bukkit callback order. Existing recovery/overflow tests passed.
  • Fresh read-only review: No findings after dependency verification retracted an incorrect scheduler-overload concern. Packaged BukkitScheduler.runTask(..., Entity) was verified via javap to invoke runAtEntity. git diff --check passed.
  • Fresh JAR SHA-256 6e2e4e3fb170de0c3f3576800e7c9a8dc7b2f97f75a9df7631b776668baa9c73, 9,066,070 bytes; Java 21 project bytecode, Folia descriptor retained, no JUnit/Mockito classes.

Native Paper/Folia, live SQL, and external-plugin callback behavior have not been rerun against c577b1b. Earlier native results remain tied to their stated artifact. Legacy recreation timing remains a separate compatibility concern; this follow-up does not claim the entire PR is merge-ready.

Exact c577b1b native claim validation

Ran python3 /workspace/selected-plugin-features-workspace/evidence/gsp-claim-region-native/run.py paper and the corresponding folia invocation using the existing isolated test-server fixtures and the exact JAR SHA above. Four protocol-driven native checks passed on each server, Paper 26.2 build 133 and Folia 26.2 build 7, Java 25. Checks exercised read-only inspection, malformed-reload rollback, a real death with seven diamonds, and the public claim API from a distant actor. Paper paid seven captured XP; the reused Folia player had fourteen captured XP and received fourteen. Both paid exactly seven diamonds, cleared the grave marker, and denied another claim.

A test-only event probe observed one grave-owned claim callback. On Folia at 50,000 blocks away it explicitly reported graveOwned=true playerOwned=false; item/XP packet observations verified recipient payout. The first 512-block Folia attempt passed gameplay but reported both positions owned, so it was retained as an insufficient region-isolation attempt and rerun farther away. The probe initiates the real public claim API; this does not claim that the nearby-only player command permits remote claims. Each final log had exactly the intentional malformed-reload error and no unexpected scheduler/storage errors. All owned server/client processes exited 0, process groups were gone, and listeners were closed.

These are real server/protocol tests with a test-only setup/ownership plugin and ViaVersion/ViaBackwards for the 26.1 protocol client, not visually verified vanilla-client gameplay. Live MySQL and arbitrary external-plugin claim listeners remain unverified. Latest-head GitHub build also passed.

Reminder scheduling recovery — 0d731b8

Reminder/compass scheduling now uses a unique recipient admission token and the entity scheduler's retirement fallback. Thrown scheduling rejection, exceptional completion, and entity retirement release only that token. An older callback cannot run or release a newer admission after quit/rejoin or listener restart. The existing 128-recipient admission bound is serialized; no configuration, commands, persistence schema, or reminder deadline semantics changed.

Actually run:

  • Before the fix, ReminderSchedulingAdmissionTest#rejectedEntitySchedulingDoesNotPoisonLaterJoins reproduced 1 failure, 0 errors.
  • mvn -B -o -ntp -f GraveStonesPlus/pom.xml -Dmaven.repo.local=/workspace/selected-plugin-features-workspace/maven-pending-hook-consumer/repository -Dtest=ReminderSchedulingAdmissionTest,GraveReminderDeliveryTest,GraveLoginReadinessTest test: 14 passed, zero failures/errors/skips.
  • Same Maven options with clean package: 368 passed, zero failures/errors/skips; distributable built. Fresh JAR SHA-256 33da54d3aa3a80a7f87abf71cbbc1d4be597bb1439c8d4647776295864794306, 9,066,930 bytes, Java21 project bytecode, Folia descriptor retained, no test libraries.
  • Fresh independent focused read-only review: No findings, unchanged source identity. git diff --check passed.

Scheduling rejection/retirement and stale-callback cases are mocked integration tests; this new artifact has not been rerun natively. The native claim results above apply to c577b1b. Legacy reload completion and recreation timing concerns remain separate; no overall merge-ready claim.

Latest exact-artifact native helper/reminder validation

At unchanged head 0d731b81f035004133b94814ee9956ebae9f404e, distributable JAR SHA-256 33da54d3aa3a80a7f87abf71cbbc1d4be597bb1439c8d4647776295864794306:

  • Actually ran node --check /workspace/selected-plugin-features-workspace/evidence/gsp-helper-current-native/client.cjs, then python3 /workspace/selected-plugin-features-workspace/evidence/gsp-helper-current-native/run.py paper and the same command with folia (final -reload2 harness). Paper 26.2 build 133 / Folia 26.2 build 7, Java 25, two native protocol clients 26.1 with test-only ViaVersion/ViaBackwards. 11/11 checks passed per server; 22 total.
  • Actual packets verify held-item inspection without mutation; malformed reload rejection preserves CHEST behavior; real death captures seven diamonds and positive XP; actual expiry reminder; selected compass and navigation survive successful reload; untrusted helper denied; tracking-only grant opens existing grave menu and gives the correct compass but cannot claim; revocation invalidates tracking/compass; recovery grant pays the captured diamonds/XP once, clears marker, and repeat claim pays nothing.
  • A dedicated unchanged reload was acknowledged after recording one delivered expiry reminder; no duplicate appeared during the subsequent 6.5 seconds (the reminder scheduler runs every 5 seconds). This covers reload duplicate suppression, not reminder restart durability, which has separate automated coverage.
  • Both clients and servers exited 0, owned process groups were gone and listening ports closed. One deliberately induced malformed-reload error per server; no unexpected runtime errors. One actual claim event per server, on grave-owned context. This fixture does not establish distinct claimant/grave regions; the earlier distant-region native test remains the evidence for that.
  • Independent read-only evidence review: No findings. An initial review strengthened the test by requiring a new explicit reload inside the reminder assertion; both final runs were repeated after that correction. No plugin source changed, so the existing exact-source full Maven result (368 passing tests) and clean source review remain applicable.
  • These are native server/client packet checks, not visually verified gameplay. Existing public legacy reload/recreation completion-contract questions remain unresolved; this validation does not authorize a breaking API change.

Disk: reused existing stopped fixtures; archived 220 JAR copies by verified SHA-256, preserving worlds/logs/configuration and a restore manifest. All four original checkouts remain unchanged.

Latest follow-up at 7cfc970: close the grave table’s independently owned SQL pool after serial storage work drains; cleanup also runs when post-connect constructor initialization fails. Preserve the original setup failure and retire workers even if pool closure throws, using existing SimpleAPI APIs. No schema or configuration migration. Deferred legacy reload/recreation APIs are unchanged.

Validation: 41 focused tests passed; full clean Maven package passed all 372 tests with zero failures/errors/skips against exact corrected local AdvancedCore startup candidate d571f1ee (JAR SHA256 11e0beb93c74060216fc31fd22c9025802972741ad34ee0eeb80bbc233cd4db9). The new constructor test uses mocked connections/executors; no external database or new native Paper/Folia gameplay was run. Fresh independent focused review: No findings. Distributable ZIP, plugin metadata, Java 21 base compatibility, no embedded test libraries and git diff --check passed. Final JAR SHA256 7dafdab3b77d0d098b6dd78c6069d4487fe8d1e23acc06b42bf04d435bececac. Hosted checks for this commit are pending.

SQL bootstrap compatibility follow-up (11f35da): constructor-time logging on older compatible SimpleAPI no longer depends on an unassigned plugin field, and a closed/uninitialized pool is rejected before grave table setup. Failed setup retires owned resources, and the legacy cleanup guard avoids retiring an already stopped worker again with corrected SimpleAPI. No new dependency API, schema, configuration migration, or changes to the deferred legacy reload/recreate paths.

Verification:

  • 43 focused SQL ownership/bootstrap/snapshot tests passed.
  • Full clean distributable build: 374 tests passed; zero failures, errors or skips.
  • Candidate dependencies: SimpleAPI #111 cd3f650 and AdvancedCore #361 d571f1e, built/installed locally in dependency order.
  • Fresh independent read-only focused review: No findings. git diff --check passed.
  • Fresh JAR SHA-256: 3133ad2a459d22be8c8cadd8e4f1d5b375d63d146b2f158129af1e3639b8bb5b; metadata, class compatibility and absence of test libraries inspected.

The older-library callback and failed-pool states are mocked regression tests backed by inspection of the previous SimpleAPI APIs/source; this follow-up was not run against an older live server or real external MySQL instance. Earlier native gameplay evidence applies to the previously documented feature snapshot, not to this new SQL follow-up. No release/deployment performed.

Unavailable-world rendering follow-up

Commit b768553 makes current, navigation and historical grave menus, location command messages and deadline reminders render retained graves whose world is unavailable. They show the stored world UUID and coordinates without resolving/loading a world. Available-world output remains compatible; authorization, recovery, deadline and the deferred reload/recreate APIs are unchanged.

Actual validation: focused UnavailableWorldRenderingTest,GraveReminderDeliveryTest,HistoricalMenuOwnershipTest,NavigationLegacyCompassRegressionTest 20 passed, full mvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package 377 passed, zero failures/errors/skips. Build used corrected local AdvancedCore d09f0d891 and published SimpleAPI40. Fresh independent read-only delta review: No findings. git -c core.whitespace=cr-at-eol diff --check passed. Fresh distributable SHA-256 a50a34682a47143b60be00ecd1140b6f646b246e43760c373e881974d6bef3e6 (9,065,879 bytes); ZIP/plugin metadata/Java21/no test-library checks passed. Tests use mocked Bukkit services and real feature persistence; no new native Paper/Folia or external MySQL acceptance is claimed. New hosted checks are pending.

Grave-limit admission follow-up — 2c6a594

Death/admin creation now reserves asynchronous ledger-worker capacity for an old grave's limit payout before consuming replacement contents. Immediate rejection leaves native death drops/XP intact or declines admin creation. Additional replacements are declined while a replacement is unpublished or failed/cancelled eviction leaves the owner above the limit. Admission remains distinct from durable acknowledgement; uncertain persistence retains the records. Existing public limit-removal APIs and deferred legacy reload/recreate timing remain unchanged.

Actually run on this exact candidate: focused creation/admin/death/restoration tests 119 passed, full mvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package 381 passed, zero failures/errors/skips. Corrected local AdvancedCore #361 and published SimpleAPI40 dependencies. Fresh independent source-only delta review: No findings; an initial reviewer report confused nullable Player target with the persisted owner UUID and was withdrawn after tracing both arguments. Plain git diff --check passed. Fresh JAR SHA-256 fd9e7214269fcae7fd563f111e6ca882e69facc62f3b668f0502ea814f9435c1 (9,066,688 bytes); ZIP integrity, Folia descriptor/plugin metadata, Java21 maximum base target and absence of test libraries passed. New tests exercise real feature persistence with deterministic worker saturation/failure and mocked Bukkit events. No new live MySQL/Paper/Folia gameplay claim. Hosted checks for this commit are pending.

Pending startup marker protection

While asynchronous MySQL records are loading, event-owner callbacks protect only loaded, exactly tagged grave markers without admitting claims or scanning/loading distant chunks. Partial record batches do not leave an unindexed successor marker unprotected. Deferred physics repair restores the captured identity tag as well as the material, and stale callbacks cannot resurrect graves already claimed or removed. Live grave metadata and known removed/destroyed records stay outside the fallback; untagged legacy markers retain the documented conservative reconciliation limitation.

Validation for this four-file follow-up: 86 focused tests and all 391 tests in mvn -B -f GraveStonesPlus/pom.xml clean package passed with zero failures/errors/skips. Regressions cover fresh head/chest tile state after AIR repair, partial record admission, identity changes, and actual claim/manual-removal paths while cleanup is withheld during startup. Fresh independent read-only GPT-6.1 Sol Extra High review returned “No findings.” JAR ZIP/metadata, Java 21 base bytecode, test-library exclusion and git diff --check passed. Artifact SHA-256: 0cf32630962a353e3a37f079b76bafc1cdc74b0711f550b9e91a474667206eca. No new external MySQL, native Paper/Folia or visual gameplay run is claimed for this follow-up. The deferred legacy reload/recreation API timing work remains untouched.

Bounded navigation refresh follow-up (1564cf9)

Grave removal invalidates the selected identity immediately. Compass inventory cleanup uses the existing player-owner maintenance loop (up to 16 players per five-second pass, capped at 128 outstanding tasks, plus login refresh), preventing grave × player task fan-out. Navigation retains its own grave/access/restoration readiness checks and continues to clear stale compasses when reminder suppression storage has failed. Action-time authorization remains authoritative; compass appearance never grants access. The deferred legacy reload/recreation API timing changes remain untouched.

Actual checks: 16 focused tests passed; full offline clean Maven package passed all 392 tests with zero failures/errors/skips. A real failed reminder-state fixture reproduced the cleanup failure before the fix. Fresh independent local Codex review used GPT-6.1 Sol Extra High and returned No findings. Final ZIP, plugin metadata, Java 21 base-class compatibility, absence of embedded test libraries, and git diff --check passed. Distributable SHA-256: 88f3cfbb9bc7097a1892613242d9a6049ceb80dddbc9fd7853cf0a03fa180eba (9,066,735 bytes). Local dependencies matched the previously validated AdvancedCore/SimpleAPI artifact identities. The exact 1564cf9 / 88f3cfbb… JAR also passed eight packet/gameplay checks each on Paper 26.2 build 133 and Folia 26.2 build 7 (Java 25). An independent evidence audit verified the source/JAR binding, actual packet observations, clean runtime logs, graceful shutdown, absent process groups and closed listeners. These checks establish initial expiry-reminder delivery, owner/helper tracking, existing-menu compass selection, revocation, and serial recovery of seven diamonds/seven XP with duplicate denial. They do not establish changed deadlines, restart/crash durability, concurrent claims, cross-region Folia behavior, visual rendering, or MySQL. The two user-deferred legacy reload/recreation cases were intentionally omitted. The exact-head hosted Maven build passed.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T20:20:18.073232Z 1564cf9 New commits
🔒 Security Review ✅ Completed 2026-10-09T23:34:19.384924Z 44633bb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 73992da0-7535-432f-8323-dce34ef7c6fd

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44633bb276

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +47 to +48
if (!recordsLoaded) plugin.getFeatureIO().submit(() -> {
List<GravesConfig> active = storage.loadGraves(), broken = storage.loadBrokenGraves();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Materialize MySQL graves on a Bukkit-safe context

For MySQL installations, this moves GravesMySQLTable.loadAll() onto the gsp-feature-io thread, but that method calls Bukkit.getWorld(...) and decodes serialized Bukkit ItemStacks. The previous startup path loaded records from a Bukkit task; on Paper/Folia the new path can race or fail during restoration because Bukkit/world materialization is occurring on an arbitrary I/O thread. Keep the JDBC work here, but transfer the raw records to an appropriate server context before resolving worlds and items.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

Comment on lines 143 to +145
public void recreateBrokenGrave(Grave grave) {
recreateBrokenGrave(grave, null);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the legacy recreation method's synchronous contract

Existing integrations calling recreateBrokenGrave(grave) now return immediately while the grave is still destroyed and absent from the active list because this wrapper discards the asynchronous result. Previously the same public method completed those state/list mutations before returning, so callers that immediately inspect, persist, or interact with the recreated grave now observe stale state with no way to await completion through this signature. Preserve the old entry point's behavior or provide a compatibility-safe completion mechanism.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58e1cd07a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
}
if (!loaded) return;
grave.loadBlockMeta(loc.getBlock()); grave.removeHologramsAround(); grave.checkBlockDisplayAndFixIfMissing(); grave.createHologram();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject successor marker identities before adoption

When a stale active backend record shares coordinates and material with a newer grave—possible after a failed removal write followed by reuse of the location—isValid() accepts the successor solely by material, and this call then replaces its metadata and chunk/tile identity with the stale record. Both records are published as live while interaction targets whichever restored last, orphaning or exposing the other grave; check GraveMarkerCleanup.hasConflictingIdentity(...) before publishing or tagging the restored record.

AGENTS.md reference: AGENTS.md:L41-L44

Useful? React with 👍 / 👎.

Comment on lines +362 to +363
featureIO.submit(() -> {
configFile.reloadData(); gravesConfig.reloadData(); nbtConfigManager.reloadConfig(); return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Materialize grave records on a Bukkit-safe context

Fresh evidence after the MySQL startup fix is this reload path: with entries in Graves.yml, gravesConfig.reloadData() invokes GravesConfig.deserialize, which calls Bukkit.getWorld(...) and decodes serialized Bukkit ItemStacks on the gsp-feature-io thread. A normal /gravestonesplus reload can therefore race or fail on Paper/Folia and abort the remainder of reload; keep file reading on this worker but move grave-record materialization to the appropriate server context, as the MySQL restoration path now does.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

Comment on lines +100 to +101
if (!(backend instanceof MySQLGraveStorageBackend sql))
return java.util.concurrent.CompletableFuture.failedFuture(new IllegalStateException("MySQL backend unavailable"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve flat-file restoration after MySQL fallback

When DataStorage is MYSQL but the Database section is absent, init() explicitly installs FlatFileGraveStorageBackend while leaving type as MYSQL. Restoration consequently selects loadMySQLForRestoration(), reaches this failed future, and retries forever instead of loading Graves.yml, so all existing graves remain withheld despite the logged flat-file fallback. Update the effective storage type during fallback or select restoration from the actual backend.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 57b687109a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (retired || block == null || !plugin.isEnabled()) return null;
PositionKey position = new PositionKey(block.getWorld().getUID(), block.getX(), block.getY(), block.getZ());
Set<String> candidates = positions.get(position);
if (candidates == null || !block.getWorld().isChunkLoaded(position.x() >> 4, position.z() >> 4)) return null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Protect markers until the restoration index is populated

While the initial YAML/MySQL read and claim-ledger work is still queued, positions is empty, so this branch makes every persisted marker appear unprotected even though isLoading() is true. A player, explosion, fluid, or piston acting during that startup window can destroy the marker; restoration then observes an invalid grave and moves it to broken history instead of restoring the live grave. Add a startup protection path rather than treating an absent candidate set as proof that the block is unrelated.

AGENTS.md reference: AGENTS.md:L41-L44

Useful? React with 👍 / 👎.

Comment on lines +264 to +265
if (folia.isFolia()) folia.getImpl().runAtEntityLater(player, deliverCompass, () -> {}, 100L);
else folia.getImpl().runLater(deliverCompass, 5L, TimeUnit.SECONDS);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the five-tick respawn compass delay

When GiveCompassOnRespawn is enabled on Paper/Spigot, the previous runTaskLaterAsynchronously(..., 5L) delay was five server ticks, but this now explicitly waits five seconds (and the Folia branch likewise waits 100 ticks). This makes compass delivery roughly twenty times slower after every respawn; keep the entity-safe scheduling while using the prior five-tick delay.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 748e8d4073

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +362 to +364
featureIO.submit(() -> {
configFile.reloadData(); gravesConfig.reloadData(); nbtConfigManager.reloadConfig(); return true;
}).whenComplete((loaded, failure) -> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve reload's synchronous completion contract

reload() now returns immediately after queuing the file reads, while the CommandLoader reload handler still sends “GraveStonesPlus reloaded” as soon as this method returns. Consequently, callers that inspect configuration immediately after a normal reload still see the old state, and a failed asynchronous read is reported to the user as a successful reload. Preserve the previous completion semantics or expose/await a completion stage before acknowledging the command.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da47b39e5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}, grave.getGravesConfig().getLocation());
plugin.recreateBrokenGrave(grave);
clickEvent.getWhoClicked().sendMessage(MessageAPI.colorize("&cGrave readded"));
if (!canAdministerHistorical(clickEvent.getPlayer())) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Dispatch historical authorization to the player owner

When a staff member clicks a broken-grave inventory on Folia, BInventory invokes this callback asynchronously, but this line immediately calls Player.hasPermission through canAdministerHistorical before scheduling onto the player's entity owner. Unlike the live-grave callback above, this can race or fail the authorization check and prevent recreation, viewing, or teleporting; capture the click intent and perform this check inside an actor-owned task.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

public synchronized void close() {
if (backend != null) {
backend.close();
enqueue(() -> backend.close());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Close the backend only after retained writes drain

When a backend write has populated retained (or the queue has no admission capacity), routing backend.close() through enqueue drops the close action because enqueue substitutes another recovery snapshot. Conversely, if a queued write fails ahead of an already-enqueued close, the close runs first and the drain listener then attempts the retained recovery against the closed MySQL backend. During disable/reload this can either leak the connection manager or lose the intended shutdown recovery pass, so the terminal close needs to run after retained writes have drained rather than use the ordinary coalescing path.

AGENTS.md reference: AGENTS.md:L63-L65

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a499aae8a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +259 to +263
admitted.submit(() -> {
started.set(true);
try { write.run(); return true; }
catch (RuntimeException failure) {
synchronized (this) { if (retained == null) retained = recoverySnapshot(); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Serialize item stacks before entering the I/O worker

Every queued flat-file or MySQL write executes this backend callback on gsp-feature-io, where GravesConfig.serialize() and GravesMySQLTable.encodeItemsSafe() ultimately pass Bukkit ItemStacks through BukkitObjectOutputStream; additionally, the failure branch rebuilds snapshots and clones live stacks on this same worker. On Paper/Folia, saves after grave creation, claim, or removal can therefore perform Bukkit item operations outside their owning context and fail or produce incomplete persistence. Materialize the serialized item payload on the appropriate server owner before enqueueing only filesystem/JDBC work.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd2710a653

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +59 to +60
Grave grave = identity == null ? legacyTarget(player, meta, legacy) : resolve(identity);
if (grave == null && pending(identity)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve legacy compasses during pending restoration

After the backend read completes, loading() becomes false even while individual graves are still pending archive or region admission. For pre-upgrade compasses that only carry gravecompass, identity is null and legacyTarget() searches only the published active list, so pending(identity) cannot recognize the withheld grave and the next login/periodic refresh permanently strips the compass metadata and lodestone. Match legacy time/location data against pending records, or defer legacy-compass invalidation until restoration has finished.

AGENTS.md reference: AGENTS.md:L48-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8c13f51a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 165 to 166
storageManager.saveBrokenGravesFromObjects(brokenGraves);
storageManager.saveGravesFromObjects(graves);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Persist flat-file recreation as one state transition

For a FLATFILE installation, these calls are queued as two independent rewrites of the same Graves.yml: the first removes the grave from brokengraves while the old active list still lacks it, and only the second adds it to graves. A process or host crash after the first save therefore leaves the successfully recreated marker in the world but permanently drops its item/XP record from both lists. Update both keys and publish them with one durable save before completing recreation.

AGENTS.md reference: AGENTS.md:L33-L36

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce9c0b3d5d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (retired || !plugin.isEnabled()) { running.set(false); return; }
if (!Boolean.TRUE.equals(saved) || failure != null) { process(batch); return; }
record.setDestroyed(true); if (record.getDestroyedTime() == 0) record.setDestroyedTime(System.currentTimeMillis());
long lifetime = com.bencodez.simpleapi.time.ParsedDuration.parse(plugin.getConfigFile().getBrokenGraveTimeLimit(), TimeUnit.HOURS).getMillis();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Catch invalid broken-grave lifetime during restoration

When an existing configuration contains a malformed BrokenGraveTimeLimit, this parse throws inside an unobserved whenComplete callback. For records whose world is already resolved, neither process(batch) nor running.set(false) then executes, so the restoration timer permanently skips future retries and all remaining persisted graves stay withheld until restart, where the same value stalls restoration again. Validate or safely parse the duration and always release/continue the restoration cycle on failure.

AGENTS.md reference: AGENTS.md:L65-L67

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c065528deb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +518 to +520
public void removeGrave(final GraveRemoveReason reason) {
plugin.getBukkitScheduler().runTask(plugin, () -> removeOwned(reason), gravesConfig.getLocation());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve removeGrave's synchronous main-thread contract

Preserve the existing synchronous behavior when removeGrave(reason) is invoked on the normal Spigot/Paper server thread. This implementation always queues another task, whereas previously a main-thread caller observed the cancellation event, destroyed flag, and active/broken-list transition before the method returned; integrations that immediately inspect or persist the grave now see stale live state. Keep the legacy entry point synchronous when already on the correct owner, or provide a compatibility-safe completion mechanism.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

Comment on lines +1121 to +1124
plugin.getGraveClaimLedger().queueLimit(identity, gravesConfig.getUuid(), evidence).whenComplete((saved, failure) -> {
if (failure == null && Boolean.TRUE.equals(saved)) {
limitPayoutPending = true;
plugin.getGraveRestoration().retainLimit(this);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve dropItemsOnGround's non-removing contract

Keep the public dropItemsOnGround method from implicitly becoming a grave-removal operation. Existing callers used this method to select and schedule item drops only, but routing it into queueLimit now eventually pays experience, marks the grave destroyed, moves it to broken storage, and removes its marker; integrations that separately manage removal or XP under the previous contract can therefore perform unexpected payouts or lose the live grave. Move the new limit workflow behind a separate internal entry point while retaining this de-facto API behavior.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

Comment on lines +250 to +251
graveRestoration = new com.bencodez.gravestonesplus.graves.GraveRestoration(this, storageManager);
graveRestoration.start();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce grave limits while restoration is loading

Do not expose death handling before the asynchronous restoration has populated the active-grave index, or include retained restoration records in limit calculations. With a slow YAML/MySQL read, players can die after this call while graves is still empty, so numberOfGraves does not see their persisted graves and creates another without scheduling the configured oldest-grave removal; once restoration publishes the old records, the player remains above GraveLimit.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 948c0e9f43

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

*/
public void checkTimeLimit(String timeLimitRaw) {
if (timeLimitRaw == null || timeLimitRaw.trim().isEmpty()) {
removeTimer(); expiryDeadline = 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the existing expiry timer until the new value parses

When a reload supplies a syntactically valid YAML file but an invalid GraveTimeLimit such as tomorrow or an overflowing numeric value, this clears every live grave's existing timer and deadline before parsing fails. reloadAsync() still completes successfully, so those graves silently become non-expiring until another valid reload or restart; parse and validate the replacement first, then cancel the old schedule only when the new value is valid or explicitly empty.

AGENTS.md reference: AGENTS.md:L65-L67

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9584d6543

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +549 to +550
plugin.getBukkitScheduler().runTask(plugin, () -> {
if (removeState(reason, () -> player.isOnline() && plugin.isLiveGrave(this)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Dispatch removal events to the grave's region owner

On Folia, when an owner or administrator removes a grave from a GUI while located in another region, this schedules removeState on the player's entity owner, where it fires GraveRemoveEvent; listeners that inspect or modify the grave marker then access a block owned by a different region and can fail the removal with a thread-ownership error. Keep the permission check on the actor owner, but dispatch the event and grave-state transition to gravesConfig.getLocation() afterward.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4749375a32

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
private boolean loading() {
return plugin.getGraveRestoration() != null && plugin.getGraveRestoration().isLoading()
|| !plugin.getTrustedGraveAccessStore().isReady() || !plugin.getGraveClaimLedger().isReady();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Catch rejected compass-refresh scheduling before removal aborts

When Folia rejects a refresh task for any online player—for example, because that player's entity scheduler retires during disconnect—this uncaught exception propagates through Grave.removeState(). That method has already marked the grave removed and destroyed, but has not yet revoked access, moved the grave to broken storage, cancelled its timer, or committed marker cleanup, leaving an inaccessible grave in the active list until restart. Treat each inventory refresh as best-effort and prevent its rejection from aborting the grave transition.

AGENTS.md reference: AGENTS.md:L63-L65

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eadac739fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (backend != null && isMySQL()) {
backend.upsertGrave(grave, broken);
GravesConfig snapshot = snapshot(grave);
enqueue(() -> backend.upsertGrave(snapshot, broken));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Propagate MySQL write failures into recovery

When MySQL is unavailable during a grave creation or transition, GravesMySQLTable.upsertGrave and updateExistingGrave catch SQLException, log it, and return normally, so this queued action is reported as successful and latestPrepared is never retained. A newly captured grave can therefore remain only in memory and disappear after restart, while a failed removal can remain active in the database; make backend writes propagate failure so the recovery snapshot is preserved.

AGENTS.md reference: AGENTS.md:L65-L65

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e141b29087

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +353 to +355
if (loading) {
// Shutdown during restoration must not publish an incomplete grave index.
closeBackendIfRequested(true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Flush retained graves before closing during restoration

Fresh evidence after the terminal-close fix is this restorationLoading branch: on a flat-file Folia server, a death can create a grave while owner-side restoration is still pending, and saveGravesFromObjects then stores the new grave only in retained; if the plugin is disabled before restoration completes, this branch closes the backend without publishing that snapshot. Because the death event's items and XP were already consumed, the next restart loads the old Graves.yml and permanently loses the new grave's contents; either gate death handling until restoration completes or merge and durably flush retained new records before closing.

AGENTS.md reference: AGENTS.md:L31-L36

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 21db06043c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +724 to 727
if (expireTime > 0 && expireTime <= System.currentTimeMillis()) {
removeGrave(GraveRemoveReason.EXPIRED);
} else {
schedule(timeLimit);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject deadlines that overflow the death timestamp

Fresh evidence after the earlier parsing fix is a duration whose millisecond value itself fits in a long, but whose addition to the grave's epoch timestamp overflows: GraveDeadlines.deadline(...) returns 0, this branch falls through to schedule(...), and that method cancels the existing timer before returning for the zero deadline, silently making the grave non-expiring. Validate the computed deadline before replacing the current schedule.

AGENTS.md reference: AGENTS.md:L65-L67

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8cbb0d1efe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1335 to +1337
public void claim(final Player player) {
if (player == null) return;
plugin.getBukkitScheduler().runTask(plugin, () -> beginClaim(player, null, false), player);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve claim's synchronous callback boundary

When a Paper/Spigot integration calls the public claim(Player) method on the main thread, this unconditional scheduler hop now returns before GraveClaimEvent, its cancellation result, and the XP mutation occur; previously those effects were observable before the call returned. Existing integrations that inspect state or perform follow-up persistence immediately after claim can therefore race the queued claim, so retain synchronous execution when already on the supported owner or provide a compatibility-safe completion mechanism.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

Comment on lines +1367 to +1371
GraveClaimEvent claimEvent = new GraveClaimEvent(this, player, isOwner(player));
GraveRemoveEvent removeEvent = new GraveRemoveEvent(this, GraveRemoveReason.CLAIMED);
try {
Bukkit.getPluginManager().callEvent(claimEvent);
if (!claimEvent.isCancelled()) Bukkit.getPluginManager().callEvent(removeEvent);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Dispatch claim events on the grave region owner

On Folia, if an integration calls claim for a player outside the grave's region, beginClaim runs on the player's entity owner and these custom grave events are fired there. A listener that inspects or modifies the marker through event.getGrave() then performs world access from the wrong region and can throw, causing the catch below to abort an otherwise valid claim; dispatch the grave-event boundary to the stored grave location before returning to the player owner for inventory payout.

AGENTS.md reference: AGENTS.md:L38-L38

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b81ac4058

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


void prepareItemsForStorage() {
try { preparedItems = InventorySerializer.encode(items); }
catch (IOException failure) { preparationFailure = new java.io.UncheckedIOException("Could not prepare grave items", failure); }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the flat-file item fallback when encoding fails

When InventorySerializer.encode rejects a custom or otherwise unsupported item, this now stores an exception on the snapshot; serialize() subsequently throws that exception before reaching its existing Items fallback. Flat-file creation and recovery writes then fail repeatedly—including the shutdown flush—so a newly captured grave can exist only in memory and lose its items after restart, whereas the previous fallback preserved them in legacy YAML form. Prepare an owner-safe legacy representation rather than disabling that fallback.

AGENTS.md reference: AGENTS.md:L31-L36

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 182b82a5c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

plugin.removeGrave(this);
plugin.getTrustedGraveAccessStore().revokeForGraveAsync(identity);
plugin.getGraveNavigation().invalidate(identity); removeTimer();
plugin.getBukkitScheduler().runTask(plugin, this::cleanupMarker, gravesConfig.getLocation());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain cleanup when grave-region scheduling is rejected

When the grave-region task is rejected after a payout—for example, while a Folia region or the plugin is retiring—this call throws after the items/XP were delivered and the grave was marked destroyed and moved to broken storage. cleanupMarker() therefore never commits the prepared cleanup ticket, and shutdown subsequently closes that unused ticket, leaving the world marker and metadata behind until a later restart can reconstruct the intent. Catch the rejection and durably retain or commit cleanup before finishing the claim transition.

AGENTS.md reference: AGENTS.md:L36-L36

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfe4b60093

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
private void acceptRecords(GraveStorageManager.RestorationRecords records) {
List<GravesConfig> active = records.active(), broken = records.broken();
storage.retainRestoration(active, broken);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Batch restoration retention work

On MySQL installations with many graves, the decoder intentionally materializes only 128 records per tick, but this call immediately passes the complete result to retainRestoration, which clones and serializes every grave and item stack synchronously on one Bukkit owner task. Thousands of persisted graves can therefore produce a single long server tick or watchdog timeout after the supposedly batched decode finishes; retain these snapshots incrementally under the same bounded budget.

AGENTS.md reference: AGENTS.md:L63-L65

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 59426bbe91

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 157 to +158
public void recreateBrokenGrave(Grave grave) {
recreateBrokenGrave(grave, null);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve synchronous recreation in the legacy overload

When an existing integration calls recreateBrokenGrave(grave) on the normal Bukkit main thread and immediately inspects the grave, this delegation returns as soon as the asynchronous ledger check starts; the destroyed flag and active/broken-list transition now occur later in thenCompose. Previously those mutations were complete before the method returned, so follow-up API calls can still observe the grave as historical. Keep the legacy overload synchronous on the supported thread or otherwise preserve its observable completion boundary.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c577b1b673

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
private void schedule(Player player, long expected) {
if (scheduled.size() >= 128 || !scheduled.add(player.getUniqueId())) return;
plugin.getBukkitScheduler().runTask(plugin, () -> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Release reminder admission when entity scheduling is rejected

On Folia, a player can disconnect after the global reminder timer snapshots them but before this entity-owner task is submitted; if runTask rejects after onQuit has already removed the UUID, the newly added scheduled entry is never cleared. Future joins and periodic passes then always fail scheduled.add(...), permanently disabling reminders and compass refresh for that UUID until plugin restart. Catch scheduling rejection and remove the admission in that path as well.

AGENTS.md reference: AGENTS.md:L65-L65

Useful? React with 👍 / 👎.

Comment on lines +390 to +391
public void reload() {
reloadAsync();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the synchronous reload API completion boundary

When an existing integration calls the public reload() method and then immediately reads configuration or performs a configuration-dependent action, this now returns before any file has been read or the replacement configuration published; prior behavior completed those mutations before returning. Adding reloadAsync() is useful, but silently making the legacy entry point fire-and-forget breaks its observable de-facto API contract, so retain synchronous behavior for that entry point or provide a compatibility-safe completion bridge.

AGENTS.md reference: AGENTS.md:L55-L55

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11f35da274

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +248 to +251
event.setDroppedExp(0);
event.getDrops().clear();
if (admitted[0] != null) admitted[0].newest().accepted = true;
handoff.accept();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require successful limit eviction before accepting creation

When DropItemsOnGraveRemoval is enabled and queueLimit cannot persist the eviction—such as while the claim ledger is unavailable or its bounded worker is full—dropAndRemoveForLimit returns without removing the selected grave, but this still accepts the replacement and consumes the death drops. Fresh evidence after the capacity-reservation change is that GraveRestoration.completeCreation unconditionally removes the temporary creationReplacements exclusion, so the failed eviction becomes visible as an extra grave and repeated deaths can exceed GraveLimit; propagate eviction admission success and only accept the creation under an explicit failure policy.

AGENTS.md reference: AGENTS.md:L63-L65

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant