chore(main): release 2.0.0 - #46
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
TheMeinerLP
added a commit
that referenced
this pull request
Aug 4, 2026
…eplaceable services (#47) * docs: carry the extension-point spec and plan onto their own branch Stacked on feat/anvil-version-guard rather than main, because the plan moves the body of requireReadableVersion and that only exists on #45. Rebase onto main once #45 lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(anvil): resolve a service once, and refuse to guess between two * feat(anvil): make the version guard a service the caller can replace Moves the decision logic of requireReadableVersion into ChunkVersionPolicy / DefaultChunkVersionPolicy, unchanged, and resolves it through ServiceResolution.choose the way Task 1 built it. The loader keeps counting and logging a refusal itself; the policy only decides and throws. A builder that never touches versionPolicy()/discoverVersionPolicy() keeps discovering the default, so a plain constructor call refuses the same chunks it always did. versionPolicy(null) is the only way to skip the check entirely. * fix(anvil): let a foreign version policy win over the shipped default Review of the version-guard service extraction found the discovery path was unusable for any third party: falco-anvil registers its own DefaultChunkVersionPolicy, so a caller who registered a policy the documented way always hit "two providers" and got refused. Teaches ServiceResolution.discover/choose an optional shippedDefault class that steps aside for any single foreign provider; two foreign providers still refuse each other, so "no silent choice between undocumented opinions" still holds. Also: ServiceLoader.load now pins the service's own classloader instead of trusting the thread-context one, which is not reliable across a CloudNet/extension/plugin boundary; documents the new IllegalStateException on the three public entry points that can now throw it; adds the pass-through tests the two new builder setters were missing; and corrects a wrong test count in the task report. * docs(spec): the shipped default has to step aside, or the seam is decoration The resolution rules as written made discovery useless: falco-anvil registers its own provider, so a third party taking the documented route would always produce two and always get the refusal. Discovery could never return anything but the default. Found by the review of the first implementation, fixed there, and now corrected here so the document does not keep teaching the version that does not work. Two rules gained along the way. Only foreign providers are counted for the ambiguity check, so the default never appears in the error message. And discovery loads with the service's own class loader rather than the thread context one - under CloudNet or extension class loaders the context loader may not see the jar, and discovery would then silently find nothing and put the air chunk back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(anvil): let a caller decide what an unknown palette entry becomes * fix(anvil): address review findings on the unknown-entry policy - PaletteEntryResolver.toId's Javadoc now describes the contract this task's own change created: an implementation is allowed to fail, unchecked, instead of unconditionally promising a substitute. - Add the biome mirror of every UnknownEntryPolicyTest case (BiomePaletteResolver had none before this). - Narrow BiomePaletteResolver's three-argument constructor to package-private; it has no production caller and testability alone does not justify public API. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * docs(anvil): date the new members to the release they will actually land in #45 merged with a breaking-change marker, so release-please raised the next version to 2.0.0 (PR #46). Everything on this branch is additive on top of that, which makes it 2.1.0 - not the 1.2.0 the tags carried from when this branch was written against a 1.x line. Nineteen tags across ten files. @Version tags are untouched: those count a class's own revisions, not the artefact's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(anvil): record task 4 acceptance, including the archunit regression it found Six modules re-run with --rerun-tasks, both gate attacks re-executed and reverted, javadoc/japicmp re-verified. falco-anvil grew from 230 to 253 cases and every other module held; falco-archunit's ForeignCouplingTest now fails 4 cases because its allow-list regex was never extended for the new policy classes — reported here rather than fixed, per the acceptance's own instruction not to silently repair a defect found during acceptance. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * fix(anvil): let the unknown-entry policy name a substitute instead of resolving one DefaultUnknownEntryPolicy resolved Block.AIR and the biome registry itself, which archunit's ForeignCouplingTest rightly refuses (registry access belongs to exactly one adapter per kind). UnknownEntryPolicy now returns a palette name instead of an id; the resolver, which already holds the registry from the original lookup, resolves the substitute itself and fails the chunk - without asking the policy twice - if that name is unknown too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * test(archunit): widen byteLayerKnowsNoNbt for the anvil policy classes ChunkVersionPolicy, DefaultChunkVersionPolicy, UnknownEntryPolicy and DefaultUnknownEntryPolicy carry NBT in their contract by design, one layer above RegionFile's pure-byte guarantee that this rule actually protects. Add all four to ANVIL_NBT_LAYER and correct the rule's javadoc, which wrongly claimed the exemption was a self-maintaining complement rather than the hand-maintained name list it always was - the reason nobody extended it when these classes were added. * docs(anvil): note that the version guard and unknown-entry fallback are replaceable * docs(anvil): re-measure task 4 acceptance after the archunit fix closed the gap Three commits landed since the last measurement (fe569f5, 4985431, a7f7b57): UnknownEntryPolicy now names a substitute instead of resolving one, ANVIL_NBT_LAYER was widened and its Javadoc corrected, and README gained the replaceable-policy paragraph. Re-ran all six modules and the build/javadoc/japicmp check against the new tip: falco-archunit is back to 47/47, falco-anvil grew to 255 cases, no other module moved. Replaces the previous Result section rather than appending a second one, and keeps the archunit defect's discovery and actual fix in the history instead of quietly re-measuring it away. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * fix(anvil): refuse a custom resolver configured together with an UnknownEntryPolicy FalcoAnvilLoader.Builder.build(...) silently dropped the configured UnknownEntryPolicy whenever a caller also supplied their own blockResolver or biomeResolver: the resolver is used exactly as given, so the policy was never reached even though loader.unknownEntryPolicy() kept reporting it as active. A caller who set both, e.g. unknownEntryPolicy(strict).blockResolver(mine), got a loader that silently substituted air for an unknown block instead of enforcing the configured policy. The constructor now refuses that combination with an IllegalStateException naming the slot to use instead, applying the same standard ServiceResolution.choose already holds for explicit configuration versus discovery. A resolver configured without touching either unknownEntryPolicy slot is unaffected: a new unknownEntryPolicyConfigured flag on the builder tracks whether unknownEntryPolicy(...) or discoverUnknownEntryPolicy() was actually called, separate from the default value both already carry. Verified with a temporary mutation: disabling the new guard turned the two new tests red, confirming they actually exercise it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * docs(anvil): document that both policies are called concurrently and can be shared ChunkVersionPolicy and UnknownEntryPolicy are resolved once when a loader is built and then consulted by every parallel load afterward, since FalcoAnvilLoader.supportsParallelLoading() is true. Neither interface said so, leaving a foreign implementer to discover the requirement by reading the loader rather than the contract. Both javadocs now state the requirement explicitly and note that the shipped defaults are stateless. The two builder slots that accept an explicit instance (versionPolicy(...), unknownEntryPolicy(...)) now carry the same note the diagnostics slot already implies: an instance passed there is shared by every loader built from that builder afterward, so it has to tolerate exactly the concurrent, shared use the interface javadoc now documents. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * test(anvil): assert the legacy no-policy chunk actually decodes to air testWithoutAnyPolicyALegacyChunkIsNotChecked only asserted assertNotNull on the loaded chunk, even though its own javadoc claims "it loads ... as a chunk of air" -- nothing verified that. The test now reads a block back with the existing blockAt(...) helper and asserts it is Block.AIR, so the assertion matches what the test documents. Verified with a temporary mutation: changing the expected block to Block.STONE turned the test red, confirming the assertion is actually exercised. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * test(anvil): assert the shipped default's name is absent from the refusal message testTwoForeignProvidersAreStillRefusedEvenWithAShippedDefaultRegistered only checked that the two foreign provider names appear in the refusal message, never that the shipped default's name does not -- the other half of the rule the spec states: a default that stepped aside for a foreign provider is not one of the competing candidates and should not be named as one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR * docs(spec): pull the UnknownEntryPolicy signature in the design doc to what shipped The design section still declared int onUnknownBlock(...) / int onUnknownBiome(...) and said "returning an id substitutes it," but the interface that actually shipped returns String, not int. The registry lookup that turns a name into an id belongs in the one adapter that already owns it -- the resolver -- not duplicated into every UnknownEntryPolicy implementation, which is why the signature changed during implementation. The plan's Result section already documents this as superseded; only the design section still showed the old shape. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actions
Bot
force-pushed
the
release-please--branches--main--components--falco
branch
from
August 4, 2026 14:54
4755b59 to
9a1d9e1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 I have created a release beep boop
2.0.0 (2026-08-04)
⚠ BREAKING CHANGES
Features
Bug Fixes
This PR was generated with Release Please. See documentation.