Skip to content

compat: add Create Crafts & Additions deterministic recipe integration - #74

Merged
swear01 merged 10 commits into
mainfrom
compat/issue-66-createaddition
Aug 3, 2026
Merged

compat: add Create Crafts & Additions deterministic recipe integration#74
swear01 merged 10 commits into
mainfrom
compat/issue-66-createaddition

Conversation

@swear01

@swear01 swear01 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #66.

Evidence-backed Outcome B for Create Crafts & Additions 1.6.0: accept deterministic Rolling and Charging via the public modular SDK; explicitly reject Liquid Burning. Scanner-format-17 recovery on current main isolation; Codex review recovery closes shape fail-closed, live config cost tokens, real remainder/multi-output evidence, JEI family Processing labels, reloadable-rate-independent eligibility, and complete checked-overflow atomic assertions.

Recovered onto Immersive Engineering main d8314fc after PR #62 merge (additive docs/overview.md + static regressions). Addresses Codex review 4843430670 four actionable findings:

  1. P1 stale holder — fixture selects real IRON_ROD, replaceRecipes removes it, then asserts complete atomic no-op on STORAGE commit.
  2. P1 non-positive rate refresh — dynamic RecipeFamily pending uses Cost.free(); resolveVariants/match turn cost/plan IllegalArgumentException into no usable variant without aborting menu/server tick.
  3. P2 ingredient dedupe — canonical StorageResourceKey putIfAbsent before TypedRecipeInput construction.
  4. P2 docs — reloadable rate is cost/plan fail-closed, not eligibility membership.

Head 341c647. Local gates: createaddition static 8/8, createaddition GameTests 9/9, Compat Kit verify 12/12 across 5 commands, quiet exclusive matrix 3/3 (21,162 recipes; Craftable prepare 30.682 ms; first/shared p95/warm switch 0.925 / 0.360 / 0.277 ms; storage interaction p95 13.128 ms; shared index 4,113,648 bytes ≈ 3.922 MiB; per-menu 116,952 bytes), Python 610/610, build, runData written 0, git diff --check clean. 9 MiB/50 ms/128 KiB gates unchanged. No bot review triggered; not merging.

Test plan

  • Focused createaddition static regressions RED→GREEN
  • ./gradlew runCreateadditionGameTestServer → 9/9
  • Compat Kit bundled verify → 12/12 across 5 commands
  • Full python3 -m unittest discover scripts → 610/610
  • ./gradlew build + runData (written 0)
  • Exclusive quiet runCompatibilityMatrixGameTestServer → 3/3 under 50 ms / 9 MiB / 128 KiB
  • git diff --check clean
  • CI green on latest head

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces compatibility support for the Create Crafts & Additions mod, enabling integration with its Rolling Mill and Tesla Coil charging recipes while explicitly excluding Liquid Burning. It adds a dedicated GameTest fixture with eight integration tests, updates the overall compatibility matrix to include fourteen mods (raising the benchmark to 11,779 recipes), and refactors the Compat Kit tool to bundle runtime dependencies into the compile classpath. Feedback on the implementation highlights two critical robustness issues in CreateadditionCompat.java: a potential IndexOutOfBoundsException in itemKeys caused by redundant deduplication, and a potential division-by-zero ArithmeticException in chargingWork if the charge rate evaluates to zero.

Comment on lines +222 to +230
private static List<StorageResourceKey> itemKeys(
List<ItemStack> representatives,
HolderLookup.Provider registries
) {
return representatives.stream()
.map(stack -> StorageResourceKey.item(stack, registries))
.distinct()
.toList();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using .distinct() on the StorageResourceKey stream in itemKeys is redundant because representatives is already distinct. More importantly, if any normalization in StorageResourceKey.item causes two distinct ItemStacks to map to the same key, the size of alternatives will be smaller than representatives. This will result in an IndexOutOfBoundsException when accessing alternatives.get(index) in consumedWithRemainder. Removing .distinct() ensures the list sizes always match and prevents potential runtime crashes.

    private static List<StorageResourceKey> itemKeys(
            List<ItemStack> representatives,
            HolderLookup.Provider registries
    ) {
        return representatives.stream()
                .map(stack -> StorageResourceKey.item(stack, registries))
                .toList();
    }

Comment on lines +195 to +199
private static long chargingWork(ChargingRecipe recipe) {
long rate = chargeRate(recipe);
long energy = recipe.getEnergy();
return Math.addExact(energy, rate - 1L) / rate;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the createaddition configuration is reloaded or modified at runtime such that chargeRate(recipe) returns 0 or a negative value, chargingWork will throw an ArithmeticException due to division by zero. Guarding against non-positive rates by clamping rate to at least 1L (and energy to at least 0) ensures robustness against dynamic config reloads and prevents server crashes.

Suggested change
private static long chargingWork(ChargingRecipe recipe) {
long rate = chargeRate(recipe);
long energy = recipe.getEnergy();
return Math.addExact(energy, rate - 1L) / rate;
}
private static long chargingWork(ChargingRecipe recipe) {
long rate = Math.max(1L, chargeRate(recipe));
long energy = Math.max(0L, recipe.getEnergy());
return (energy + rate - 1L) / rate;
}

@swear01
swear01 force-pushed the compat/issue-66-createaddition branch from e9a3a43 to 34aeec7 Compare August 3, 2026 03:29
@swear01
swear01 marked this pull request as ready for review August 3, 2026 03:29
@swear01
swear01 force-pushed the compat/issue-66-createaddition branch from 34aeec7 to acd9c18 Compare August 3, 2026 03:36
@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acd9c1851b

ℹ️ 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".

Comment on lines +114 to +117
private static boolean supportsRolling(RollingRecipe recipe) {
return rollingDuration() > 0
&& exact(recipe.getIngredient())
&& !recipe.getResultStack().isEmpty();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject rolling recipes outside the reviewed shape

When a datapack adds a RollingRecipe with multiple ingredients or probabilistic/multiple results, this predicate still accepts it because it examines only getIngredient() and getResultStack(). rollingPlan then consumes only that ingredient and emits only that stack, allowing Auto Storage to produce a different, potentially guaranteed result from the actual recipe. Enforce the contract's single-ingredient, no-fluid, single-100%-output shape using the inherited processing-recipe collections before exposing the recipe.

Useful? React with 👍 / 👎.

Comment on lines +220 to +224
"catalyst_tool_remainder_exact": [
{
"marker": "Create Crafts & Additions charging did not consume exact FE/work",
"source": "src/createadditionFixture/java/com/swear/autostorage/fixture/createaddition/CreateadditionIntegrationGameTests.java",
"task": "runCreateadditionGameTestServer"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Point the remainder check at a real remainder assertion

When consumedWithRemainder drops or misassigns an alternative-specific crafting remainder, this evidence still passes: the mapped charging test consumes a gold nugget, which has no crafting remainder, and never asserts any returned remainder. Compat Kit can therefore report catalyst_tool_remainder_exact as passed without testing that behavior; map this check to an actual remainder-bearing recipe/assertion or add one to this fixture.

AGENTS.md reference: AGENTS.md:L176-L176

Useful? React with 👍 / 👎.

Comment thread compat/contracts/createaddition.json Outdated
Comment on lines +262 to +266
"multi_output_merge_exact": [
{
"marker": "Create Crafts & Additions rolling did not emit exact wire output",
"source": "src/createadditionFixture/java/com/swear/autostorage/fixture/createaddition/CreateadditionIntegrationGameTests.java",
"task": "runCreateadditionGameTestServer"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Exercise multiple outputs before claiming merge evidence

When multi-output handling or duplicate-output merging regresses, this mapped test still passes because the rolling recipe emits one ItemStack whose count is two; it never constructs multiple output entries or exercises a merge. Point multi_output_merge_exact at a test that actually commits and verifies multiple/duplicate outputs instead of letting the twelve-check report claim coverage from this single-output assertion.

AGENTS.md reference: AGENTS.md:L176-L176

Useful? React with 👍 / 👎.

Comment on lines +135 to +141
private static boolean supportsCharging(ChargingRecipe recipe) {
return recipe.getEnergy() > 0
&& recipe.getMaxChargeRate() > 0
&& chargeRate(recipe) > 0
&& recipe.getIngredients().size() == 1
&& exact(recipe.getIngredients().getFirst())
&& !recipe.getResultStack().isEmpty();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject charging recipes outside the deterministic contract

When a datapack or another compatible mod version supplies a ChargingRecipe with fluid inputs/results or multiple/probabilistic processing outputs, this predicate still accepts it because it validates only the item ingredient and getResultStack(). chargingPlan then consumes the item and FE while emitting one guaranteed stack, silently discarding the other recipe semantics. Check the inherited fluid and rollable-result collections for the contract's no-fluid, exactly-one-100%-output shape before exposing the recipe.

Useful? React with 👍 / 👎.

Comment on lines +162 to +163
"gui.auto_storage.station.createaddition_rolling_mill": "Rolling Mill",
"gui.auto_storage.station.createaddition_tesla_coil": "Tesla Coil",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use logical family names for the new Processing labels

These translations become the descriptors' player-facing Processing labels, but both values repeat the installed workstation item names rather than the accepted logical families. Players therefore see Rolling Mill and Tesla Coil on Processing values where the reviewed recipe families are Rolling and Charging; use the shortest localized family/category names in both locale files and leave the concrete machine names to the installed-item tooltips.

AGENTS.md reference: AGENTS.md:L153-L159

Useful? React with 👍 / 👎.

Comment on lines +82 to +84
recipeFamilies.register(rollingId.getPath(), () ->
RecipeFamilyFactories.deterministicResources(
RollingRecipe.class,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Invalidate cached costs when Createaddition config changes

When either processing config is changed from one positive value to another while the server is running, both families remain eligible but continue using the station-work cost captured when their typed contracts were first classified. These registrations use deterministicResources, which caches the typed contract, and expose no dynamic-state token, so Rolling duration and Tesla Coil charge-rate changes do not update craft previews, commits, or the shared Craftable cache until an unrelated recipe-cache reset. Register the config-backed families through the dynamic factory with tokens derived from their live config values.

Useful? React with 👍 / 👎.

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Review-controller evidence (PR #74)

Actionable findings (coordinator)

  1. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)CreateadditionCompat.java:117 — reject rolling recipes outside reviewed shape
  2. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)CreateadditionCompat.java:141 — reject charging recipes outside deterministic contract
  3. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)CreateadditionCompat.java:84 — invalidate cached costs on Createaddition config change
  4. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)compat/contracts/createaddition.json:224 — remainder check needs real remainder assertion
  5. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)compat/contracts/createaddition.json:266 — multi-output merge evidence must exercise multiple outputs
  6. compat: add Create Crafts & Additions deterministic recipe integration #74 (comment)en_us.json:163 — Processing labels must use logical family names

No edit/commit/push/merge by review-controller.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@swear01
swear01 force-pushed the compat/issue-66-createaddition branch 2 times, most recently from 4d813a1 to 44b4c87 Compare August 3, 2026 08:37
@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44b4c87dd7

ℹ️ 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".

Comment on lines +86 to +87
|| supports(helper, fixtureRecipe("fluid_result_rolling"))
|| supports(helper, fixtureRecipe("fluid_ingredient_rolling"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require fluid fixtures to load before testing rejection

If any fluid-shape fixture fails to deserialize or is renamed, supports() returns false because byKey() returns empty, so this GameTest still passes without exercising either rejection predicate; unlike the chance fixtures, none of the four fluid fixtures is checked with recipePresent(), and the locked inventory only covers the createaddition namespace rather than auto_storage_createaddition_fixture. Require each fluid recipe to be present before asserting it is unsupported so the optional-mod fixture remains a real behavior assertion.

AGENTS.md reference: AGENTS.md:L173-L173

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 542c735f6b14b240d4b1071a3e3a5fb3e5c877e8. RED confirmed the four JSON fixtures were never loaded: Create rejected them during codec validation because Rolling/Charging allow zero fluid inputs/outputs, so the old supports(null) == false assertions were vacuous. The invalid files are removed. The fixture now constructs exact RollingRecipe and ChargingRecipe instances in memory and requires both upstream validate() rejection and Auto Storage classification rejection; loaded chance fixtures still require recipePresent(). Focused static regression and runCreateadditionGameTestServer (9/9) pass.

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 542c735f6b

ℹ️ 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".

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Review-controller evidence (PR #74)

@swear01
swear01 force-pushed the compat/issue-66-createaddition branch from 542c735 to fc532d1 Compare August 3, 2026 09:26
@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc532d117f

ℹ️ 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 static boolean supportsCharging(ChargingRecipe recipe) {
return recipe.getEnergy() > 0
&& recipe.getMaxChargeRate() > 0
&& chargeRate(recipe) > 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep reloadable rates out of eligibility

Fresh evidence in this revision is that the registrations now use dynamicDeterministicResources, while this predicate still makes family membership depend on reloadable configuration. When TESLA_COIL_RECIPE_CHARGE_RATE changes across zero, CraftableRecipeCatalog does not rebuild because it caches membership solely by the RecipeManager snapshot: a recipe indexed while positive remains present and resolving it after the reload can throw when supports() becomes false, while a recipe omitted at zero remains unavailable after the rate becomes positive until recipes reload. The rolling predicate has the same pattern at line 118; keep dynamic-family eligibility stable and fail closed through the re-resolved cost/plan instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b4bef5e. Rolling and Charging eligibility now depends only on invariant recipe shape; reloadable duration/rate is evaluated only by the current cost path, where non-positive values fail closed. Added a static regression that forbids reloadable rate access from both eligibility predicates while requiring the dynamic cost calls. Evidence: focused 3/3, runCreateadditionGameTestServer 9/9, full Python 605/605, git diff --check clean.

Comment on lines +258 to +259
if (craft(context, IRON_ROD)
|| itemCount(context.core(), createadditionItem("iron_rod")) != Long.MAX_VALUE) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Assert atomic state after checked overflow

If the checked-overflow path rejects only after consuming the iron ingot or station work, this GameTest still passes because it verifies only the failed return and unchanged saturated output. Since the contract maps this marker to checked_overflow_atomic, bundled verification can report exact atomic coverage despite a partial mutation; assert that every seeded input and the station-work balance also remain unchanged.

AGENTS.md reference: AGENTS.md:L176-L176

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b4bef5e. The Long.MAX_VALUE overflow GameTest now asserts the iron input remains 1, the full output remains Long.MAX_VALUE, and accumulated Rolling Mill work remains unchanged. Added a focused static regression. Evidence: runCreateadditionGameTestServer 9/9, full Python 605/605, git diff --check clean.

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Independent review-controller evidence

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f578d2f63

ℹ️ 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".

Comment on lines +235 to +238
return Arrays.stream(ingredient.getItems())
.filter(stack -> !stack.isEmpty())
.map(stack -> stack.copyWithCount(1))
.distinct()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Deduplicate canonical ingredient alternatives

When a valid simple datapack ingredient repeats the same item alternative, copyWithCount(1) creates distinct ItemStack objects, so this .distinct() does not remove the duplicate; itemKeys() then produces duplicate StorageResourceKey values and TypedRecipeInput throws IllegalArgumentException while the Craftable catalog resolves the recipe, preventing the terminal catalog from building. Deduplicate by canonical resource key while preserving each surviving alternative's corresponding remainder.

Useful? React with 👍 / 👎.

Comment on lines +276 to +277
ResourceLocation missing = createadditionRecipe("rolling/missing_stale_holder");
if (craft(context, missing)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Exercise an actual stale-holder transaction

This test starts with an ID that has never existed, so the first handleRecipeRequest returns before selecting or planning any recipe and never exercises the stale-holder validator used between simulation and commit. A regression that mutates resources after a selected holder is removed or replaced would still let stale_recipe_holder_atomic pass; select a real recipe first, make that holder stale, and then assert the commit is an atomic no-op.

AGENTS.md reference: AGENTS.md:L176-L176

Useful? React with 👍 / 👎.

Comment on lines +213 to +215
if (rate <= 0L) {
throw new IllegalArgumentException(
"Create Crafts & Additions charge rate must be positive");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fail closed without throwing during config refresh

When a live reload makes TESLA_COIL_RECIPE_CHARGE_RATE non-positive, the dynamic token refresh resolves every charging variant again and this exception propagates through RecipeFamily.typedContract and CraftingTerminalMenu.refreshDisplayItems, aborting the menu/server tick instead of merely hiding or disabling those recipes. Fresh evidence beyond the earlier eligibility report is this uncaught dynamic-resolution path; make a non-positive current rate yield no usable variant without throwing. Rolling has the same failure through RecipeFamilyCost.stationWork(rollingDuration()) when its duration becomes non-positive.

Useful? React with 👍 / 👎.

Comment thread docs/notes.md Outdated

2026-08-03 Create Crafts & Additions format-17 recovery:legacy format-7 32個name-shaped candidates經exact artifact `41876c37…e7e9`、clean source `84c7b2ce…4c3a`、normalized NeoForge/Minecraft `2382ea29…eb5f`與完整compile ancestry `migrate-audit`後只剩3個actual `Recipe` classes;`migrate-contract`重開後保留Rolling/Charging accept與Liquid Burning reject,並寫入新audit完整risk set(inherited ProcessingRecipe `generic_ingredients`/`randomness`/`world_mutation`)。Descriptor compile dependencies鎖5個reachable ancestry coordinates,runtime仍是Modrinth createaddition `qPr8V4G2`+Create `UjX6dr61`;isolated fixture digest `57916d79…d0a3`(110個`createaddition:*`)。不改peer descriptor/不放寬9 MiB gate。Final local gate:createaddition 8/8、bundled verify 12/12 across 5 commands、matrix 3/3(18,503 recipes;Craftable prepare 32.554 ms;shared index 3,711,264 bytes;per-menu 116,493 bytes)、`build`、`runData` no drift、Python 585/585、`git diff --check` clean。高負載下Craftable prepare曾量到52–66 ms;gate維持50 ms,安靜後重跑通過。

2026-08-03 Create Crafts & Additions review-fix gotcha:PR #74 Gemini 指出`itemKeys`對`StorageResourceKey`再`.distinct()`會讓`alternatives`比`representatives`短,`consumedWithRemainder`以index取remainder時可能`IndexOutOfBoundsException`;正確作法是保留與representatives同長的key list,不在`itemKeys`二次去重。同則建議把`chargingWork`的rate clamp成`Math.max(1L, …)`;那會在config reload成非正rate時靜默發明work量,違反No Silent Fallback。正確作法是eligibility已要求正rate,cost路徑對`rate <= 0`直接`IllegalArgumentException` fail-closed,並保留`Math.addExact` overflow檢查。Static regressions鎖住這兩點。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Correct the stale eligibility guidance

This active note says eligibility already requires a positive rate, but the final implementation deliberately removed the reloadable config rate from supportsCharging and checks only the recipe's positive maxChargeRate; the current rate is evaluated later by the cost path. Leaving the obsolete instruction encourages a future maintainer to restore the exact candidate-membership bug documented earlier in this file, so update the note to distinguish invariant recipe eligibility from the live config check.

AGENTS.md reference: AGENTS.md:L83-L90

Useful? React with 👍 / 👎.

swear01 and others added 7 commits August 3, 2026 19:24
Outcome B accepts deterministic Rolling Mill and Tesla Coil charging from
ATM10 createaddition 1.6.0, rejects Liquid Burning and viewer/datagen false
candidates, and keeps Create on the bundled compile classpath.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep itemKeys index-aligned with representatives, and fail-closed when
chargingWork sees a non-positive live charge rate instead of dividing by zero.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebase onto current main isolation and migrate the committed audit/contract
to scanner format 17 with exact 1.6.0 artifact, source, and ancestry while
preserving Rolling/Charging accept, Liquid Burning reject, and review-fix
TDD.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fail closed on unreviewed Rolling/Charging shapes, invalidate config-backed
costs through dynamicDeterministicResources, map remainder and multi-output
checks to real assertions, and use JEI family Processing labels.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refresh quiet exclusive matrix and verify evidence after additive rebase onto
origin/main a1582ad while preserving CEI, runtime transforms, and Createaddition.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace invalid fluid datapack recipes, which Create rejects before RecipeManager insertion, with exact in-memory Rolling and Charging recipes that prove both upstream validation and Auto Storage classification fail closed.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
swear01 and others added 3 commits August 3, 2026 19:24
via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capture the exclusive matrix and verify evidence after keeping reloadable
rates out of eligibility and asserting complete checked-overflow atomicity.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rebase onto Immersive Engineering main and make stale-holder, dynamic
non-positive rate refresh, canonical ingredient dedupe, and eligibility
docs fail closed without inventing work or aborting menu ticks.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@swear01
swear01 force-pushed the compat/issue-66-createaddition branch from 0f578d2 to 341c647 Compare August 3, 2026 11:38
@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor

cursor Bot commented Aug 3, 2026

Copy link
Copy Markdown

Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings.

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

bugbot run

@cursor

cursor Bot commented Aug 3, 2026

Copy link
Copy Markdown

Skipping Bugbot: Bugbot is disabled for this repository. Visit the Bugbot dashboard to update your settings.

@swear01

swear01 commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive compatibility support for the 'Create Crafts & Additions' mod, enabling deterministic 'Rolling' (Rolling Mill) and 'Charging' (Tesla Coil) recipe families while explicitly excluding liquid burning. The implementation features dynamic cost and plan resolution that fails closed gracefully on invalid configurations, canonical ingredient deduplication, and robust atomic rollback handling. It includes extensive documentation, static regression tests, and nine integration GameTests to verify correct behavior under various conditions like shortages, overflows, and stale recipe holders. No review comments were provided, so I have no feedback to offer on the review itself.

@swear01
swear01 merged commit 9e5cf0f into main Aug 3, 2026
1 check passed
@swear01
swear01 deleted the compat/issue-66-createaddition branch August 4, 2026 10:12
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.

[Compatibility] Create Crafts & Additions deterministic recipe integration

1 participant