Skip to content

Feature/stonecutter migration - #21

Merged
KP2048 merged 5 commits into
mainfrom
feature/stonecutter-migration
Aug 29, 2026
Merged

Feature/stonecutter migration#21
KP2048 merged 5 commits into
mainfrom
feature/stonecutter-migration

Conversation

@KP2048

@KP2048 KP2048 commented Aug 29, 2026

Copy link
Copy Markdown
Member

No description provided.

KP2048 and others added 5 commits August 28, 2026 16:06
Prerequisite for adding Stonecutter, which refuses to apply below
Gradle 9 (checked directly: 0.8.4, 0.9.1, and 0.9.7 all reject 8.x).
Verified clean on 9.7.1 first - full compile, unit tests, and the
whole task graph (Loom, Architectury, Dokka, ModFusioner, ModPublisher,
Shadow, the actualizer/archie plugins) all configure and run across
every module with no changes beyond the two below.

- Gradle 9 stopped bundling its own JUnit Platform launcher for
  useJUnitPlatform() - added junit-platform-launcher to the catalog
  and wired it once as testRuntimeOnly in the shared subprojects{}
  dependencies block.
- core/common's verifyGuiSpriteAssets task used the `by registering {}`
  delegate, deprecated in 9.6 and removed in 10 - switched to
  `register("...")`.

architectury-loom's pinned version also now reads 1.17.491 instead of
1.13.469 in gradle/libs.versions.toml. This wasn't a deliberate edit -
noticed the file already showed 1.17.491 when checked, with no edit
made by this work to explain it. Left as-is since it's what actually
resolved and ran successfully throughout verification, but flagging it
since its cause is unexplained.
Converts core/{common,fabric,neoforge} to a Stonecutter-managed tree/branch
structure (settings.gradle.kts: stonecutter { create("core") { branch(...) } }),
keeping datagen/gametest/test on the old includeModule() scheme until this
slice is proven out.

Root build.gradle.kts guards subprojects{}/allprojects{} plugin application
against Stonecutter's synthetic tree/branch container projects (:core,
:core:common, etc. - real leaf projects nest under them and must not get
build plugins applied directly).

Sibling-project references (fabric/neoforge -> common) go through Stonecutter's
node.sibling("common").project API rather than a hardcoded project path -
ProjectNode.project resolves straight to the sibling's Gradle Project.

The old namedElements/transformProductionX cross-project dependency (Loom's
own common() mechanism) produces a circular task dependency under Stonecutter's
nested per-version project paths, so fabric/neoforge instead depend directly
on common's own "jar" task output as a FileCollection. (A plain SourceSetOutput
FileCollection almost works the same way, but breaks shadowJar - Shadow's copy
action expects zip-safe entries, not raw class/resource directories.)

Also bumps the Shadow plugin from com.github.johnrengelman.shadow 8.1.1 to the
maintained com.gradleup.shadow 9.6.1 fork - the old one is incompatible with
Gradle 9.7.1 (MissingPropertyException: mode in ShadowCopyAction), independent
of the Stonecutter migration itself.

Disables the background-session worktree-isolation guard for this repo
(.claude/settings.json) at the user's request.

Verified: :core:{common,fabric,neoforge}:1.21.1:assemble all succeed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkTGULzd3V7X4ZGP3iw7P
Extends the core-only Stonecutter validation slice to datagen, gametest, and
test - all four module trees are now Stonecutter-managed. settings.gradle.kts
registers all four trees identically (branch("common")/branch("fabric")/
branch("neoforge"), single version "1.21.1" each); each tree gets its own
stonecutter.gradle.kts (mirroring core's).

Sibling-project references follow the pattern established for core:
- Same-tree (X:common <-> X:fabric/neoforge): node.sibling("common").project.
- Cross-tree (e.g. datagen -> core, test -> core/datagen/gametest): Stonecutter
  has no public cross-tree lookup API (node.sibling() only searches its own
  tree), so these resolve via rootProject.project(":tree:branch:$version").
- Every cross-project compiled-output dependency goes through the sibling's
  plain "jar" task output as a FileCollection, not project(path, configuration)
  or a bare project(path) - both trigger a circular compileJava<->compileKotlin
  task dependency under Stonecutter's nested per-version project paths,
  confirmed live across multiple project-pairings (common<->common,
  loader<->loader, common-mode<->loader). Deliberately not remapJar's output:
  that transforms named->intermediary for shipping and reintroduces the same
  class duplication one layer down (confirmed live: a Font/class_327
  duplicate-overload regression in already-working core code, traced to a
  poisoned shared .gradle/loom-cache/remapped_mods/ entry - cleared as part of
  this work).

files() dependencies carry no transitive module metadata, unlike the
project(path, "namedElements") dependencies they replace, so every affected
common-mode project (datagen/gametest/test's common modules) repeats
whatever api/modApi surface its own code actually needs from its sibling
(Compose, kotlinx.serialization, storage lib) - verified by removing each
speculatively-added line and confirming the build still needs it before
keeping it (e.g. libs.rei.common was not actually needed by datagen-common).

The actualizer merges each common module's own source directly into its
fabric/neoforge siblings' compilation (not just their compiled output), so
those loader projects need common's compile-time deps directly too - same
reasoning, same fix.

gametest-neoforge needed the loader-specific libs.storage.neoforge instead of
libs.storage.common - NeoForge's remap pipeline doesn't handle
earth.terrarium.common_storage_lib's common artifact correctly (same family
of gap as the documented Cloche NeoForge remapCommon limitation for this
library); using the common variant surfaced as an ambiguous ItemResource.of
overload resolving against raw Fabric intermediary-mapped parameter types.

Verified: `./gradlew assemble` succeeds for the whole repo (all 12
common/fabric/neoforge modules across core/datagen/gametest/test).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkTGULzd3V7X4ZGP3iw7P
…est/test loader modules

The files()-based cross-tree dependency on each core-{fabric,neoforge}
sibling (used to dodge the circular compileJava<->compileKotlin task
dependency documented in the previous commit) carries no runtime GAMELIBRARY
discovery either, same as it carries no compile-time transitive metadata.
core-fabric/core-neoforge each bundle the kotlinx.serialization format
add-ons (nbt/toml/json5) via bundleRuntimeLibrary - Archie's own Config
system needs all three at init - but that never propagated to any of
datagen/gametest/test's loader modules, which only had Compose repeated so
far.

Confirmed live via `./gradlew :test:fabric:1.21.1:runClient`:

  Caused by: java.lang.NoClassDefFoundError: io/github/xn32/json5k/ConfigBuilder
      at ...Json5ConfigSerializer.<clinit>
      at ...ConfigSpec.<init>
      at ...Archie.init

Same gap existed on datagen-fabric, datagen-neoforge, gametest-fabric,
gametest-neoforge, and test-neoforge (verified via each module's own
runtimeClasspath resolution, not just test-fabric where it was reported) -
fixed all six with the same runtimeLibrary(...) additions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XkTGULzd3V7X4ZGP3iw7P
…tonecutter

Stonecutter's nested per-version project layout broke several things that
keyed off the pre-migration flat project names:

- Maven publish's artifactId was "1.21.1" for every module (not just the
  intended -fabric/-datagen-common/etc. suffix missing) - the artifactId
  assignment ran before base.archivesName reached its final value. Moved it
  into afterEvaluate{}. Also fixed the archie-test exclusion, which checked
  project.name (now always "1.21.1") instead of project.path.
- modfusioner's fusejars task silently no-op'd ("No projects were found")
  since it resolves projects by bare Project.name, and every Stonecutter tree
  now has a leaf literally named "fabric"/"neoforge". Anchored it on the
  unique ":core" container project and override inputFile via
  gradle.projectsEvaluated once the real remapJar output paths are known.
- Dokka's per-module aggregation dependency block had been commented out
  during the migration (stale flat project paths) - rebuilt against
  Stonecutter's real :tree:branch:version paths.
- gameVersions in the publisher{} block now derives from
  libs.versions.minecraft instead of a separately hardcoded "1.21.1" literal.

Verified: generatePomFileForMavenPublication produces correct artifactIds,
test tree is excluded, fusejars produces a real merged jar (both
fabric.mod.json and neoforge.mods.toml present), dokka configuration
resolves all 9 module paths, and publishCurseforge/publishModrinth dry-run
(debug=true) cleanly against live CurseForge/Modrinth data.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WW8YqJDBH8AFaTFirpCQGZ
@KP2048
KP2048 merged commit c35a245 into main Aug 29, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant