Repository navigation
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
There was a problem hiding this comment.
💡 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".
| if (!recordsLoaded) plugin.getFeatureIO().submit(() -> { | ||
| List<GravesConfig> active = storage.loadGraves(), broken = storage.loadBrokenGraves(); |
There was a problem hiding this comment.
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 👍 / 👎.
| public void recreateBrokenGrave(Grave grave) { | ||
| recreateBrokenGrave(grave, null); | ||
| } |
There was a problem hiding this comment.
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 👍 / 👎.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
💡 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(); |
There was a problem hiding this comment.
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 👍 / 👎.
| featureIO.submit(() -> { | ||
| configFile.reloadData(); gravesConfig.reloadData(); nbtConfigManager.reloadConfig(); return true; |
There was a problem hiding this comment.
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 👍 / 👎.
| if (!(backend instanceof MySQLGraveStorageBackend sql)) | ||
| return java.util.concurrent.CompletableFuture.failedFuture(new IllegalStateException("MySQL backend unavailable")); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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; |
There was a problem hiding this comment.
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 👍 / 👎.
| if (folia.isFolia()) folia.getImpl().runAtEntityLater(player, deliverCompass, () -> {}, 100L); | ||
| else folia.getImpl().runLater(deliverCompass, 5L, TimeUnit.SECONDS); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| featureIO.submit(() -> { | ||
| configFile.reloadData(); gravesConfig.reloadData(); nbtConfigManager.reloadConfig(); return true; | ||
| }).whenComplete((loaded, failure) -> { |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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; |
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| admitted.submit(() -> { | ||
| started.set(true); | ||
| try { write.run(); return true; } | ||
| catch (RuntimeException failure) { | ||
| synchronized (this) { if (retained == null) retained = recoverySnapshot(); } |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| Grave grave = identity == null ? legacyTarget(player, meta, legacy) : resolve(identity); | ||
| if (grave == null && pending(identity)) continue; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| storageManager.saveBrokenGravesFromObjects(brokenGraves); | ||
| storageManager.saveGravesFromObjects(graves); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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(); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| public void removeGrave(final GraveRemoveReason reason) { | ||
| plugin.getBukkitScheduler().runTask(plugin, () -> removeOwned(reason), gravesConfig.getLocation()); | ||
| } |
There was a problem hiding this comment.
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 👍 / 👎.
| plugin.getGraveClaimLedger().queueLimit(identity, gravesConfig.getUuid(), evidence).whenComplete((saved, failure) -> { | ||
| if (failure == null && Boolean.TRUE.equals(saved)) { | ||
| limitPayoutPending = true; | ||
| plugin.getGraveRestoration().retainLimit(this); |
There was a problem hiding this comment.
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 👍 / 👎.
| graveRestoration = new com.bencodez.gravestonesplus.graves.GraveRestoration(this, storageManager); | ||
| graveRestoration.start(); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| plugin.getBukkitScheduler().runTask(plugin, () -> { | ||
| if (removeState(reason, () -> player.isOnline() && plugin.isLiveGrave(this) |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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(); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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)); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| if (loading) { | ||
| // Shutdown during restoration must not publish an incomplete grave index. | ||
| closeBackendIfRequested(true); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| if (expireTime > 0 && expireTime <= System.currentTimeMillis()) { | ||
| removeGrave(GraveRemoveReason.EXPIRED); | ||
| } else { | ||
| schedule(timeLimit); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| public void claim(final Player player) { | ||
| if (player == null) return; | ||
| plugin.getBukkitScheduler().runTask(plugin, () -> beginClaim(player, null, false), player); |
There was a problem hiding this comment.
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 👍 / 👎.
| 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); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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); } |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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()); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| public void recreateBrokenGrave(Grave grave) { | ||
| recreateBrokenGrave(grave, null); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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, () -> { |
There was a problem hiding this comment.
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 👍 / 👎.
| public void reload() { | ||
| reloadAsync(); |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
💡 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".
| event.setDroppedExp(0); | ||
| event.getDrops().clear(); | ||
| if (admitted[0] != null) admitted[0].newest().accepted = true; | ||
| handoff.accept(); |
There was a problem hiding this comment.
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 👍 / 👎.
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:
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
/gravestonesplus inspectitemuses 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, andinspectitem; existinggraves,compass, andclaimgraveare 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:
mainat251e7e25a85f6a5db7e3876180e9e6fbb5337618. 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 areselected-access.yml,selected-claims.yml,selected-claim-archive/,selected-marker-cleanup.yml, andgrave-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 regioninGrave.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 SHA37a0476000b8d46b4f591962a231a39e3936b9e84c6aa3498ae7324a27200e18) staged only in an isolated local dependency cache. This is validation evidence, not remote snapshot availability. The POM coordinate remains3.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 --checke90cf7f1664ed1994aa87d0bde525afc055876110d17343f5defc161cf0b11f9; descriptor/config, Java21 base classes, absence of test libraries, and actual shaded core call torequestUpdate()verified. Frozen GSP source tree446130d0d7520f5c6a697301c24ac89f4530c0c92a6a8920e7fd0ab781cbd41b.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.Remaining findings and limits
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 SHA2566f5489f50dabf4aaa0f49d20522f4abb16313a0b3b17f12c58b81219cb14dafc. 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
430bd581cc7e03b40ac4e95da3bea955866b69a7was rebuilt against that exact candidate: 264 PASS, zero failures/errors/skips; distributable SHA2565b9a67d4343aa2dc5a9e46db935d45a0d184cfcf5b8ed2ba95642deddd089236. 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
7ca70ec223f7392f4d8a32a2369cb1c0753bb256captures 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 paperandpython3 evidence/gsp-native-features/run.py foliafrom the isolated workspace: Paper26.2build133 and Folia26.2build7, Java25, each 10/10 PASS against final JAR SHA256d06f35409381d1c58aa13df1840b790684a50a8244c029db06fd840e153986cf. 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 --checkpassed. 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
36d5a66643c66406c130ab8df24f69400d2ced35indexes 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:
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).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.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.7f9e2747a56485f4bed8226823a4aee9c7b3cddb89223cbf4824277b39b93158, 9,044,822 bytes; class maximum65, Folia descriptor retained, no JUnit/Mockito packaged.python3 evidence/gsp-native-features/run.py paperandpython3 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.git diff --checkpassed.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:DeathPlayerOwnershipTest,GraveActionsTest: 62 passing tests.clean package: 279 passing tests, zero failures/errors/skips.50ddf190f27954a722181a87d45c4c18c4d5a1c2ddcbe187d43c25135b7fc64d.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
61ae24472ca9945d4f7c67242052602690b55b71persists 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.d18205c94bd782be9e8a7469134e9323c41c322e9bffdede9eae654a99bff963; 9,047,664 bytes; 123 project classes target Java 21; packaged Folia declaration preserved.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
d9584d6543600f6e27c0d8407441a1edcd422fceresolves 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.clean package: 295 passing, zero failures/errors/skips; full distributable JAR built.git diff --checkand 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.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 paperandpython3 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
4749375a326dc34838eb16c4fdf055e353b966daadmits 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.clean package: 301 passed, zero failures/errors/skips. Full suite includes final cancellation retry regression. Fresh JAR SHA-2567058824b46ddfde9e745a8635ce7941119e3004d403d015b94d9027cecdb203b; 125 project classes Java 21, runtime base classes <= Java 21; tests absent; Folia metadata retained.python3 evidence/gsp-creation-admission-native/prepare.py paper evidence/gsp-creation-admission-artifact.json;python3 evidence/gsp-creation-admission-native/run.py paper; correspondingfoliacommands: 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 identity87425cad50795800cc73d771768146698c0f1db1805703c2427960d14e9268d1unchanged.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:
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.
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.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.529bee9423e53547bc42b3d49d5e7d32bc0acc06d9d1ef4030878a7d9a519dae.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-tmpunder 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 withclean 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 --checkpassed. Shaded JAR SHA-256e2f22015c7548109733d8b1751df5e4eb9ce994afd22f9ba01572bfd5402196c, 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
8b81ac4058d64b3f0d6a4cdd7d1776a83459b929preserves an existing expiry timer when a parsed duration fits inlongbut its addition to the death timestamp overflows. Disabled/empty lifetimes still cancel normally. Regression reproduced the previous zeroed deadline; focusedGraveActionsTest,MarkerRestorationRegressionTest,GraveTimeLimitTestnow passes 115 tests. Fullclean packagepasses 338 tests, zero failures/errors/skips, using the Maven options recorded above. Fresh independent follow-up review: No findings. JAR SHA-256034bf2ac6ff4b082e8da2c511d14d0562b4b0a890721e08811ef0e3e63eb3bbf, 9,057,084 bytes; base Java 21, plugin descriptor present, no test libraries.The preceding persistence-fix commit
8cbb0d1efe3f8dd534a43518e9c058ae6ae6b6f8/ JARe2f22015c7548109733d8b1751df5e4eb9ce994afd22f9ba01572bfd5402196chas 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.jsonand the correspondingfoliacommand;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: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.mvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package: 340 passed, 0 failures/errors/skips; distributable JAR built.6cc4ba3edf368cef80b972720a77f2e5d0ec121164b3185ac1f02aa72470d2be; 9,057,288 bytes; Java 21 base bytecode, plugin descriptor present, no test libraries.python3 evidence/gsp-removal-region-native/run.py paperandpython3 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.git diff --checkpassed.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
59426bbe91004ad4e833b2638c92e5d1c34e523cpreserves the flat-fileItemsfallback 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:
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.clean package: 357 passed, zero failures/errors/skips; distributable JAR built. SHA-25698eb3ddd91b0fc669adf4cd0ddb8ac8a1daa201a41513998019cdf5b48419671, 9,063,368 bytes, Java 21 base bytecode, descriptor present, no test libraries.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.git diff --checkpassed.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
retainRestorationAPI 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 packagethrough the isolated serialized build wrapper: 360 tests passed; 0 failures/errors/skips.git diff --checkpassed. Fresh distributable JAR: SHA-2561654b8d01e63a6dfc0ba520d5590a3ad9cd2764c4753330a25e2ea3f4997b669, 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.
GraveClaimEventdocuments that Folia handlers must schedule mutable access to a distant player on their entity scheduler.Actual verification:
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.clean package: 365 passed, 0 failures/errors/skips, distributable built.BukkitScheduler.runTask(..., Entity)was verified viajavapto invokerunAtEntity.git diff --checkpassed.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 paperand the correspondingfoliainvocation 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:
ReminderSchedulingAdmissionTest#rejectedEntitySchedulingDoesNotPoisonLaterJoinsreproduced 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.clean package: 368 passed, zero failures/errors/skips; distributable built. Fresh JAR SHA-25633da54d3aa3a80a7f87abf71cbbc1d4be597bb1439c8d4647776295864794306, 9,066,930 bytes, Java21 project bytecode, Folia descriptor retained, no test libraries.git diff --checkpassed.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-25633da54d3aa3a80a7f87abf71cbbc1d4be597bb1439c8d4647776295864794306:node --check /workspace/selected-plugin-features-workspace/evidence/gsp-helper-current-native/client.cjs, thenpython3 /workspace/selected-plugin-features-workspace/evidence/gsp-helper-current-native/run.py paperand the same command withfolia(final-reload2harness). 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.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:
cd3f650and AdvancedCore #361d571f1e, built/installed locally in dependency order.git diff --checkpassed.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
b768553makes 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,NavigationLegacyCompassRegressionTest20 passed, fullmvn -B -o -ntp -f GraveStonesPlus/pom.xml clean package377 passed, zero failures/errors/skips. Build used corrected local AdvancedCored09f0d891and published SimpleAPI40. Fresh independent read-only delta review: No findings.git -c core.whitespace=cr-at-eol diff --checkpassed. Fresh distributable SHA-256a50a34682a47143b60be00ecd1140b6f646b246e43760c373e881974d6bef3e6(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 —
2c6a594Death/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 package381 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. Plaingit diff --checkpassed. Fresh JAR SHA-256fd9e7214269fcae7fd563f111e6ca882e69facc62f3b668f0502ea814f9435c1(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 packagepassed 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 andgit diff --checkpassed. 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, andgit diff --checkpassed. Distributable SHA-256:88f3cfbb9bc7097a1892613242d9a6049ceb80dddbc9fd7853cf0a03fa180eba(9,066,735 bytes). Local dependencies matched the previously validated AdvancedCore/SimpleAPI artifact identities. The exact1564cf9/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.