Report swallowed failures

- Add art.arcane.iris.spi.CapabilityProbe so an absent optional API is recorded at debug with the failure class and message instead of a bare ignored catch
- Route runtime day-time reads, clock pushes and the noon time lock through IrisLogging.reportError with the world name and the full trace
- Report a level storage access that will not close, so a retained world session lock names its cause
- Report a failed iris.json rewrite with the file path instead of dropping the IOException
- Report Iris world registry and dimension read failures during Multiverse reconciliation instead of logging one debug line
- Report a failed pack compatibility summary and a failed vanilla-slot capture with their traces
- Report a superseded generation semantics shard that cannot be deleted, once, with its path
- Restore the interrupt flag when the global cache trimmer join is interrupted
- Replace ValueWithDiagnostics with CheckResult so a startup check carries the runtime lock reason it raises
- Give every startup check an explicit advisory or critical severity and lock the runtime on any Danger result, replacing the catch that recognised the injection check by id
- Lock the runtime when general.disableNMS holds a no-op binding or the NMS binding is unbound, instead of marking the runtime ready
- Match incompatible plugin names against every registered plugin without regard to case
- Name the JVM maximum heap in the memory check output
- Print the lock reason and what it blocks when Iris enables into a locked runtime
- Carry the per-check safeguard modes and diagnostic lines in /iris debugdump
This commit is contained in:
Brian Neumann-Fopiano committed 2026-09-08 04:44:31 -04:00
1 parent 45b9ff8e11
commit f83cf71b11
34 files changed
+1267 -306

No files matched your search

@@ -87,6 +87,7 @@ import art.arcane.iris.engine.framework.PreservationRegistry;
import art.arcane.iris.engine.framework.TreeBlockMaterial;
import art.arcane.iris.engine.object.IrisCompat;
import art.arcane.iris.core.safeguard.IrisSafeguard;
import art.arcane.iris.core.safeguard.RuntimeLockNotice;
import art.arcane.iris.engine.platform.PlatformChunkGenerator;
import art.arcane.iris.platform.bukkit.BukkitPlatform;
import art.arcane.iris.spi.IrisLogging;
@@ -305,10 +306,11 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
return;
}
StackWalker.StackFrame frame = null;
StackWalker.StackFrame frame;
try {
frame = DEBUG_STACK_WALKER.walk(stream -> stream.skip(1).findFirst().orElse(null));
} catch (Throwable ignored) {
} catch (Throwable unavailable) {
frame = null;
}
if (frame == null) {
@@ -444,7 +446,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
try {
IrisSettings currentSettings = IrisSettings.settings != null ? IrisSettings.settings : IrisSettings.get();
debug = currentSettings != null && currentSettings.getGeneral().isDebug();
} catch (Throwable ignored) {
} catch (Throwable unreadable) {
debug = false;
}
}
@@ -625,7 +627,9 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
MultiBurst.burst.reopen();
MultiBurst.ioBurst.reopen();
IrisLanguage.initialize();
debugDump = BukkitDebugDump.create(this);
debugDump = BukkitDebugDump.create(this, new BukkitDebugDump.Options(
() -> true,
() -> IrisSafeguard::debugReport));
languageSwitcher = BukkitLanguageSwitcher.register(this, IrisLanguage.selections(),
new BukkitLanguageSwitcher.Options("iris", "iris.all",
DirectorMiniMenu.Theme.irisGreen(), IrisLanguage.directorResolver(), IrisLanguage.editorOptions()));
@@ -866,6 +870,30 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
.orElse("Iris startup validation requires a restart.");
startupBoundaryRestart.set(true);
ServerConfigurator.restartAtStartupBoundary(restartReason);
return;
}
reportLockedRuntime();
}
/**
* refuseVanillaFallback only ever runs when enable itself failed. A boot that enabled into Danger Mode
* keeps every configured Iris world bound to a generator that throws, and until now said so nowhere
* after the banner.
*/
private static void reportLockedRuntime() {
String denial = IrisStartupValidation.denialReason().orElse(null);
if (denial == null) {
return;
}
boolean managedStorage;
try {
managedStorage = IrisWorldStorage.hasManagedWorldStorage(IrisWorldStorage.levelRoot());
} catch (Throwable unavailable) {
Iris.reportError("Could not inspect Iris world storage while reporting the locked runtime.", unavailable);
managedStorage = false;
}
for (String line : RuntimeLockNotice.compose(denial, managedStorage)) {
Iris.error(line);
}
}
@@ -1104,7 +1104,8 @@ public final class PendingWorldReplacementManager implements Listener {
Iris.instance.getServer().getAllowEnd()
);
} catch (Throwable failure) {
Iris.debug("Could not capture vanilla-slot availability yet: " + detail(failure));
Iris.reportError("Could not capture vanilla-slot availability at startup;"
+ " world replacement staging will resolve it on demand.", failure);
}
}