Links
Tags
Creators
Details
0.6.0+26.1.2
Compatibility
Required content
Changes
The diagnostics work below was briefly numbered 0.5.4 and held back rather than published: on its own it added no capability, no coverage and no speed, and nobody should update a modpack for a release that only stops the mod misreporting itself. It ships as part of 0.6 instead.
Coverage
- Spiders path off-thread.
WallClimberNavigationoverridesmoveTo(Entity, double)without callingsuper, so the dispatch marker never ran for it and every spider chasing a player resolved its path on the server thread โ while/pathweaver mobscounted spiders as eligible. Third instance of one mixin mistake;NavigationOverrideCoverageTestnow derives the overriding navigation subclasses from Minecraft's own bytecode so a future one cannot silently opt out.
The default now explains itself
- The startup log says WHY
UNSAFEis the shipped default. It already warned that the denial had been ignored and that searches run alongside unaudited code. What it never said is the reason, which is what turns that from "this mod ships recklessly" into a trade an operator can evaluate: the checked tier denies every family on an ordinary modded pack โ measured at 0 of 187 eligible mob types on a 221-jar server pack โ so shipping it as the default would ship a mod that does nothing. It is now stated as a trade, explicitly not as a safety claim, and followed by what to actually do: run it on a copy of your world, keep the setting if nothing looks wrong after a few sessions, switch toAUDITEDand report it if something does.
Diagnostics that agree with the gates
A cumulative review of everything since 0.5.0 and an adversarial concurrency bug hunt. The bug hunt found no blocker and no high-severity defect, and said so explicitly rather than padding โ the epilogue pairing, the install-staleness checks, the evaluator clone, and the pool's generation isolation were all attacked and held.
Fixed
-
/pathweaver mobscalled every land family eligible while dispatch refused all five. Removing the command's early return so swim mobs stopped being under-reported had a cost nobody priced: the table is now printed in the one state where askingSafetyGate.isAllowedalone is wrong. Measured, not argued โisAllowed(Walk)=trueagainstcanDispatch(Walk)=false. The verdict consults the land registry, the command reads the live latch rather than a constant, and both halves are pinned by mutations that were compiled and observed to fail. -
deniedFamiliesmeant two different things in two places. On the same server in the same second, the startup log saiddeniedFamilies=0and/pathweaver statussaiddeniedFamilies=6. Both were right โ the log counts what is enforced, status counted what the scan found before the tier waived it โ and one label with two meanings is the class of defect this release exists to end. Status now printsdeniedByScan=andenforced=separately; the log keeps the name the README teaches. -
A mob held back by its
PathFinderwas blamed on a mod, including when it was vanilla's. The line named the class withgetSimpleName(), which is empty for an anonymous class, so a real pack producednavigates with , a mod-supplied PathFinder. Naming it properly showed what it was:Warden$1$1, aPathFindersubclass vanilla itself constructs. It now falls back to the full name and says "a PathFinder subclass" rather than accusing a mod. -
The command told operators that wall-climber chases stay synchronous โ in the release whose headline is that they no longer do.
-
The startup banner and
/pathweaver statusreported "ACTIVE, all six families" while five of the six were being refused every tick. Dispatch consults Fabric's land path-type registry latch in addition toSafetyGate; the two reporting sites did not. On a pack where that verification fails, the mod announced itself fully active,dispatchedrose only from squid and fish, and/pathweaver mobssaid the opposite โ the mod's own diagnostics contradicting each other on the first question an operator asks. All three reporting sites now answer through one predicate,SafetyGate.canDispatchโ four, in fact:/pathweaver mobswas open-coding the same rule a fourth time.Precisely what is shared, because an earlier draft of this entry overstated it: dispatch does not call
canDispatch. It evaluatesisAllowed, thenrequiresEmptyLandRegistry, then the latch, as three separate steps.canDispatchis a reconstruction of that sequence for the reporting sites, and an unpinned reconstruction is exactly how this bug became re-introducible twice โrequiresEmptyLandRegistrycould be replaced withreturn falseandcanDispatchreduced toisAllowed, each leaving all 289 tests green.SafetyGateDispatchParityTestnow asserts the reconstruction against the sequence over the whole input space rather than against itself, and the one-argument convenience wrapper that hid the call site is deleted rather than tested beside.The land-registry half covers all five land-derived families, not just the exact
Walkclass. This is the third time a diagnostic has been caught disagreeing with what the gates actually do. -
A setup failure before registration was swallowed entirely โ no outcome, no counter, no log. Everything from the attribute captures through the evaluator clone runs before the request reaches the sink, and the catch only recorded an outcome if it had. A deterministic failure there meant the mod did nothing, forever, while reporting itself as working. It is now counted whether or not registration happened โ as
SETUP_FAILEDwhen the request had already been counted as dispatched andSETUP_FAILED_PRE_DISPATCHwhen it had not. The split is atmarkDispatched, not at registration โ those are different events, and choosing on the wrong one left a single outcome that was simultaneously "wasted dispatched work" and "not part of dispatched". Logged once per server session. The reachable trigger is a third-party evaluator whose no-argument constructor throws when invoked outside its own construction path:canCloneproves a constructor resolves, never that it runs. -
The coverage contract treated an omitted
requireas safe. ASM only visits values that are present, sorequirearrived as null whenever it was left out โ and null was read as fine. What makes omission safe isinjectors.defaultRequire: 1in the shipped config, which the test read for the mixin list and never consulted for this. It now resolvesrequirethe way Mixin does. (That was verified by hand-mutating the config both ways during development; it is not pinned by a shipped test, and saying otherwise here would have been a claim the repo does not support.) -
That contract's declared side was gated on a literal
Mobreceiver. Every entity call in all six evaluators does have ownerMobon 26.1.2 โ verified โ but a version emitting the same call with aLivingEntitystatic type would have emptied the declared side and left every assertion in the class passing over a live attribute race. -
Both worker
ThreadLocalcaptures now happen inside thetry. Only anOutOfMemoryErrorcould have separated them, but the residue is the exact failure both javadocs warn about: a step height left published on a pooled thread and inherited by the next mob scheduled onto it. -
The banner blamed the compatibility tier for refusals it did not cause. A family failing only the clone check got the full "you opted into AUDITED" lecture and advice to edit
trustedMods, neither of which would have changed anything.
Documentation that was actively wrong
DESIGN.mdยง3 still said flying and amphibious evaluators were ineligible. They have been the default async path since 0.4.0. Anyone auditing the threading story from that file would have concluded axolotls, turtles, drowned, frogs and every flying mob were synchronous.- The recompute seam's javadoc claimed vanilla has two outcomes. It has four, and the whole table is now written out โ including the exit where a claim is still dropped, which is recorded as roadmap 2g rather than papered over. That is not a regression (0.5.0 dropped it on all three branches) and re-applying it there is precisely the 0.5.1 bug, so it needs the request to carry its origin rather than a widened condition.
- A javadoc describing
rollbackOptimisticTargetwas sitting aboveabortFailedInstall. Two more of the same: a javadoc inRequestOutcomeand one inPWNavigationeach sat directly above another javadoc, documenting nothing, and an@param dispatchCountednamed a parameter that had been replaced bystage. - The README's eligibility numbers were measured with the wrong instrument. It quoted 187 of 187
at the shipped default, from a harness that never inspects the
PathFindera mob actually holds./pathweaver mobsโ the thing a user can run โ says 184 of 187, holding back the two spiders and the warden. Nothing regressed; the old number was optimistic. Every figure in that section has been re-measured on 0.6.0 and the claim that 0.4.0 dispatched the first third-party evaluator is withdrawn: it never dispatched, and direct measurement now says so. - The release page claimed path equivalence for "all seven evaluator families". There are six, and
the seventh row in the harness output is a spider whose third-party
PathFindermeans it never dispatched โ so its "IDENTICAL" compared a synchronous path with itself. The claim also read as a proof where the README says, correctly, that this is one static scenario per family and that flying equivalence is not guaranteed by the design at all. Corrected in the README, the changelog and the Modrinth page. (The underlying result is real and is new: until 0.6.0 only Walk and Swim had an oracle comparison, and all six now have one.) - The
AUDITED+ all-nine-trusted row was quoted without the setting it was measured under.allowModdedMobAsyncdefaults to false, and at that tier the origin gate then refuses 98 of the pack's 187 mob types. The honest pair is 86 of 187 at stock settings and 184 with the bypass on. The old row said 185, then 184, and never said which. tools/scan_pack.pycounted mixin configs rather than mods in its totals line, and counted PathWeaver itself among the mods claiming a pathfinding target โ printing 22, then 21, where the README says 20. The documented figure was only reproducible on a directory with PathWeaver deleted from it, which is not a directory anyone has. It now counts distinct third-party mods.PLAN.mdwas a 0.2.3 artifact sitting in the repo root, whose "Future boundary" section stated no engine work remained after 0.2.2 โ beside a roadmap describing 0.6 through 1.0. Archived todocs/PLAN-0.2-archive.md.DESIGN.md's product decision still said "hold publication", reversed at 0.3.0 and four releases ago.
Added
- A worker-reachability analysis (
src/test/java/dev/pathweaver/reach/), the first step of the 0.6 plan to replace hand-written hazard lists with derivation. It is a discovery aid, not evidence. An earlier draft of this entry cited it as corroborating that no attribute hazard remains; a review showed it silently truncated in three places that contradicted its own stated guarantee. Those are fixed โ it now resolves interface defaults, records every truncation instead of swallowing it, and no longer maps a receiver onto a type that does not implement it. The numbers moved from 1,735 reachable / 0 unresolved / 12 hazards to 2,060 / 168 / 45, which is what an honest version of the same walk looks like. Details indocs/ROADMAP-0.6-archive.mdยง6. It found no unknown bug. What building it taught is recorded there too: the naive version is useless rather than imprecise, reporting 1,220 hazards including the client renderer. tools/scan_pack.py, which measured whyAUDITEDleaves nothing eligible: 20 mods in a real 221-jar server pack claim a watched target, any one of which denies everything, and 14 have no audit. Nine of those 14 touch onlyBlockBehaviour$BlockStateBaseand are not pathfinding mods at all. The tool over-approximates on purpose โ it reads mixin configs, not what the injected code reaches โ so it flags five that PathWeaver's own scanner clears. The scanner names nine blockers on this pack; the nine that touch onlyBlockStateBaseare a different nine, which is confusing enough to be worth saying out loud.- ASM is now an explicit test dependency instead of arriving through
fabric-loader.
318 unit tests (zero skipped), three game tests, four server harnesses, the client harness, a
benchmark showing no change against 0.5.3, and verification on a real 221-jar server pack in four
configurations: AUDITED with nothing trusted (0 of 187 eligible, nine mods named); AUDITED with
those nine trusted at stock settings (86 of 187 โ the origin gate refuses 98 mod-added mob classes);
the same with allowModdedMobAsync=true (184 of 187, nothing enforced, 732 searches installed); and
the shipped UNSAFE default (184 of 187, 755 dispatched / 749 installed / 6 discarded on the
shipping jar, with no PathWeaver exception in any run). With the world held still, all six evaluator families produced node-for-node
identical routes to a synchronous oracle โ one scenario each, which is evidence and not proof, and
which for flying mobs the design does not guarantee (README, What is unproven).
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:ZQJOU3vB:YzzP4acc"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:ZQJOU3vB:YzzP4acc"
}

