Skip to content

refactor: introduce loader-agnostic IItemStorage contract#349

Merged
Indemnity83 merged 8 commits into
mc/26.1from
feat/define-itemstorage-transaction-contract
May 8, 2026
Merged

refactor: introduce loader-agnostic IItemStorage contract#349
Indemnity83 merged 8 commits into
mc/26.1from
feat/define-itemstorage-transaction-contract

Conversation

@Indemnity83
Copy link
Copy Markdown
Owner

Summary

Closes #333

Removes all net.fabricmc.fabric.api.transfer.* imports from common/ (item storage only; fluid storage is out of scope) and replaces them with four loader-agnostic interfaces. This is the prerequisite for eventually compiling common/ under NeoForge's toolchain without Fabric API on the classpath.

Changes

New interfaces in core.lib.storage:

  • IItemKey — loader-agnostic item identity (replaces ItemVariant)
  • IItemView — read-only snapshot of a slot (replaces StorageView<ItemVariant>)
  • IItemStorage — insert/extract/contents with simulate-boolean semantics (replaces Storage<ItemVariant> + Transaction)
  • ItemStorageLookup — static registry for finding IItemStorage from the world and constructing IItemKey from ItemStack
  • ContainerItemStorage — wraps vanilla Container as IItemStorage (used by Kiln, Macerator)

Fabric adapters in fabric/storage:

  • FabricItemKey — wraps ItemVariant
  • FabricItemView — wraps StorageView<ItemVariant>
  • FabricItemStorage — bidirectional adapter: wrap() (Fabric→IItemStorage) and asFabric() (IItemStorage→Fabric Storage)

Updated throughout common/:

  • HasItemStorage.itemStorage() return type: Storage<ItemVariant>IItemStorage
  • All network value objects (Order, ItemRequest, RecipeIngredient, etc.) and domain types (ProviderModule, PipeRuntime, etc.) use IItemKey instead of ItemVariant
  • PipeRuntime.transferItem() uses an instanceof PipeBlockEntity check for pipe-to-pipe routing to avoid circular wrapping, then falls back to ItemStorageLookup.find() for external inventories
  • Unit tests updated to use TestItemKey (a minimal IItemKey backed by Item identity)

Notes

  • The simulate-boolean pattern matches the existing IEnergyStorage / FabricEnergyStorage design — no ITransaction interface is needed
  • NeoForge adapter stubs were removed; they will be added when the NeoForge subproject gains a compile dependency on common/ (tracked separately)
  • Fluid storage (HasFluidStorage, FluidTankComponent) is intentionally unchanged — out of scope for this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 7, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds IItemKey/IItemStorage/IItemView and ItemStorageLookup plus ContainerItemStorage and Fabric adapter implementations. Migrates HasItemStorage, ItemInventoryComponent, network APIs/records, NetworkController/PipeNetwork/planning, pipes/modules, PipeRuntime transfer, block-entity itemStorage exposure (Kiln, Macerator, StirlingEngine, PipeItemStorage), BlockEntityUtil drops, Fabric capability wiring, and tests to the new abstraction. Tests register TestItemKey and Fabric registers FabricItemKey/FabricItemStorage adapters.

Sequence Diagram(s)

sequenceDiagram
  participant Module
  participant ItemStorageLookup
  participant IItemStorage
  participant NetworkController
  participant WorldView

  Module->>ItemStorageLookup: find(level,pos,side)
  ItemStorageLookup-->>Module: IItemStorage
  Module->>IItemStorage: extract/insert(key, amt, simulate=false)
  Module-->>NetworkController: placeOrder/notifyDelivery(key, amt)
  NetworkController->>WorldView: dispatch(provider, requester, key, amt, id)
  WorldView-->>NetworkController: dispatched amt
Loading

Possibly related issues

Possibly related PRs

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/define-itemstorage-transaction-contract

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
common/src/main/java/com/logistics/pipe/modules/SupplierModule.java (1)

296-313: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove dead code and simplify available space calculation.

The if (currentAmount == 0) branch is unreachable—storage.contents() contractually returns only non-empty views per the interface documentation and all implementations filter out empty slots. Additionally, the code only explores targetStack.getMaxStackSize() capacity by passing that as the limit to insert(), which is insufficient if the container can accommodate multiple stacks. The unnecessary iteration through contents() followed by a single insert() call with a capped amount makes this overly complex compared to a direct storage.insert(targetKey, largeAmount, true) approach (as used in InsertionModule).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/modules/SupplierModule.java` around
lines 296 - 313, The loop in SupplierModule calculating availableSpace is overly
complex and uses unreachable branches (storage.contents() only returns non-empty
IItemView), and it underestimates capacity by capping inserts to
targetStack.getMaxStackSize(); replace the entire loop with a single simulated
insert: call storage.insert(targetKey, Long.MAX_VALUE, true) (or another
sufficiently large long) to compute availableSpace, assign its result to
availableSpace and return it; remove references to currentAmount, IItemView
iteration, and the dead if (currentAmount == 0) branch so only SupplierModule's
availableSpace calculation uses storage.insert(targetKey, Long.MAX_VALUE, true).
🧹 Nitpick comments (5)
common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java (1)

42-46: ⚡ Quick win

Clarify contents() contract (currently contradictory).

The docs say empty slots “may or may not be included” but the return tag says “non-empty views.” Pick one contract so adapters behave consistently.

Doc-only fix example
- * `@return` an iterable over the non-empty views in this storage
+ * `@return` an iterable over this storage's views; implementations may include
+ * empty views unless otherwise documented
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java` around
lines 42 - 46, The Javadoc for IItemStorage.contents() is inconsistent: the
paragraph says empty slots "may or may not be included" while the `@return` says
"non-empty views"; decide on the non-empty contract and update the docs to state
clearly that contents() MUST return an Iterable of only non-empty IItemView
instances (empty slots must be omitted), then update any implementations and
unit tests of IItemStorage.contents() to conform to this contract (search for
implementations named contents or classes implementing IItemStorage to adjust
behavior).
common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java (1)

108-111: 💤 Low value

Consider caching the template stack to avoid repeated allocations.

key.toStack(1) is called multiple times (lines 110, 118, 121, 137, 150) for the same key within this tick cycle. While not a critical issue, caching it could reduce allocations in this hot path.

♻️ Optional optimization
         IItemView candidateView = slots.get(candidate);
         IItemKey key = candidateView.resource();
-        int stackSize = (int) Math.min(candidateView.amount(), key.toStack(1).getItem().getDefaultMaxStackSize());
-        ItemStack queryStack = key.toStack(stackSize);
+        ItemStack templateStack = key.toStack(1);
+        int stackSize = (int) Math.min(candidateView.amount(), templateStack.getItem().getDefaultMaxStackSize());
+        ItemStack queryStack = key.toStack(stackSize);

Then use templateStack.getItem() for logging instead of key.toStack(1).getItem().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java` around
lines 108 - 111, The code repeatedly calls key.toStack(1) for the same IItemKey
within this tick; cache that template stack once (e.g., templateStack =
key.toStack(1)) and reuse it when computing stackSize (use
templateStack.getItem().getDefaultMaxStackSize()), when creating queryStack, and
for any logging; update usages in the QuickSortModule block that reference
candidateView, key, stackSize, and queryStack to use the cached templateStack
instead to avoid repeated allocations.
common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java (1)

441-452: 💤 Low value

Unused parameter in notifyDropAndDrop.

The inserted parameter is never used — the method always notifies with item.getStack().getCount(). This is functionally correct for the drop case (we're accounting for the full dropped amount), but the parameter is misleading. Consider removing it for clarity.

♻️ Suggested cleanup
-    private static void notifyDropAndDrop(Level world, BlockPos pos, TravelingItem item, long inserted) {
+    private static void notifyDropAndDrop(Level world, BlockPos pos, TravelingItem item) {

And update call sites accordingly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java` around
lines 441 - 452, The notifyDropAndDrop method has an unused parameter inserted;
remove the inserted parameter from the notifyDropAndDrop signature and from all
call sites so the method becomes notifyDropAndDrop(Level world, BlockPos pos,
TravelingItem item), and keep the existing behavior of notifying the network
with item.getStack().getCount() and calling PipeBlockEntity.dropItem(world, pos,
item); update any places that call notifyDropAndDrop to stop passing the
now-removed inserted argument.
common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java (1)

36-37: 💤 Low value

Consider adding volatile for defensive thread safety.

The static fields are written once during loader initialization and read from game tick threads. While mod loading order guarantees registration completes before gameplay, adding volatile would make the memory visibility guarantees explicit and prevent subtle issues if initialization order ever changes.

-    private static Finder finder;
-    private static KeyFactory keyFactory;
+    private static volatile Finder finder;
+    private static volatile KeyFactory keyFactory;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java`
around lines 36 - 37, The static fields in ItemStorageLookup (finder and
keyFactory) need explicit memory-visibility guarantees: change their
declarations to be volatile (e.g., make finder and keyFactory `private static
volatile Finder finder;` and `private static volatile KeyFactory keyFactory;`)
so writes during loader initialization are guaranteed visible to game tick
threads; update only the field declarations in the ItemStorageLookup class to
add volatile, no other logic changes required.
common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java (1)

49-62: 💤 Low value

Potential integer overflow when casting accepted to int.

The insert method accepts maxAmount as long but toStack((int) accepted) casts to int. While getInsertableAmount likely returns a bounded value, if accepted exceeds Integer.MAX_VALUE, the cast will silently overflow and create a stack with an incorrect (possibly negative) count.

Consider clamping before the cast:

Proposed fix
         if (!simulate) {
-            ItemStack stack = item.toStack((int) accepted);
+            ItemStack stack = item.toStack((int) Math.min(accepted, Integer.MAX_VALUE));
             pipe.acceptInsertedStack(stack, fromDirection, NO_SPEED);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java`
around lines 49 - 62, The insert method can silently overflow when casting
accepted (long) to int for item.toStack; clamp accepted to int range before
casting: compute int toInsert = (int)Math.min(accepted, Integer.MAX_VALUE) and
use item.toStack(toInsert) and pipe.acceptInsertedStack(...) with that clamped
stack to avoid overflow; keep returning the original long accepted (or if
business logic requires, adjust the returned value to reflect the actually
inserted amount) and reference the insert method, pipe.getInsertableAmount,
item.toStack, and pipe.acceptInsertedStack when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java`:
- Around line 49-57: The comment is incorrect: after building drop stacks (using
remaining, maxStackSize, key.toStack and adding to drops) the code calls
storage.extract(key, amount, false) which performs a real extraction; update the
comment near the loop and the storage.extract call to state that we are
constructing drop stacks from the current contents and then actually removing
that amount from storage by performing a non-simulated extraction via
storage.extract(key, amount, false) so the comment matches the behavior.

In `@common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java`:
- Around line 222-223: The itemStorage(Direction) method ignores the side
parameter, breaking sided inventory rules; update itemStorage to pass the side
into a side-aware storage wrapper (e.g., add a new ContainerItemStorage(this,
side) constructor or factory) and ensure that wrapper delegates sided checks to
the block entity's WorldlyContainer methods (route canPlaceItemThroughFace and
canTakeItemThroughFace using the supplied Direction). Modify or add the
ContainerItemStorage constructor/factory to accept `@Nullable` Direction and use
it when evaluating insertion/extraction permissions so capability consumers
respect the side argument.

In `@common/src/main/java/com/logistics/pipe/block/PipeBlock.java`:
- Around line 488-491: The code treats a non-null ItemStorage as non-connectable
if it has no contents by checking storage.contents().iterator().hasNext();
remove that emptiness check and treat any non-null result from
ItemStorageLookup.find(...) as connectable for PipeConnection.Type.INVENTORY
(i.e., change the condition around ItemStorageLookup.find(world, neighborPos,
direction.getOpposite()) so a non-null storage is sufficient to set candidate =
PipeConnection.Type.INVENTORY), preserving the surrounding logic in PipeBlock
(and keep using the same storage variable and direction/opposite lookup).

In `@common/src/main/java/com/logistics/pipe/modules/BasicExtractorModule.java`:
- Around line 92-104: The loop in BasicExtractorModule recalculates toExtract
per view allowing more than itemsPerPull to be extracted in one tick; fix by
introducing a local allowance (e.g., int allowed = Math.min(itemsPerPull,
remaining)) before iterating storage.contents(), then inside the loop compute
toExtract as Math.min(allowed, remaining) and after a successful extraction
decrement both remaining and allowed by the extracted amount (so allowed tracks
the remaining quota for this tick); update references to remaining/itemsPerPull
in the extraction block (where extract(...), toStack(...), forceAddItem(...),
and anyExtracted are used) so total extracted across the loop never exceeds
itemsPerPull.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 56-112: asFabric() currently ignores Fabric TransactionContext
semantics (always calling storage.insert/extract with simulate=false) and
unsafely casts view.resource() to FabricItemKey; fix by making insert/extract
honor the provided TransactionContext: when the Fabric transaction requests
simulation, call the underlying storage with simulate=true or buffer the
operation and register a TransactionCloseCallback (or equivalent) to apply
buffered changes only on commit (implement this behavior inside the anonymous
Storage<ItemVariant> insert/extract implementations used by asFabric); and fix
getResource() in the iterator/StorageView by avoiding the direct cast to
FabricItemKey—check if view.resource() is a FabricItemKey and call
FabricItemKey.variant(), otherwise produce the ItemVariant from
view.resource().toStack(1) (e.g., via ItemVariant.of(...) or equivalent) so
non-Fabric IItemKey implementations are supported.

---

Outside diff comments:
In `@common/src/main/java/com/logistics/pipe/modules/SupplierModule.java`:
- Around line 296-313: The loop in SupplierModule calculating availableSpace is
overly complex and uses unreachable branches (storage.contents() only returns
non-empty IItemView), and it underestimates capacity by capping inserts to
targetStack.getMaxStackSize(); replace the entire loop with a single simulated
insert: call storage.insert(targetKey, Long.MAX_VALUE, true) (or another
sufficiently large long) to compute availableSpace, assign its result to
availableSpace and return it; remove references to currentAmount, IItemView
iteration, and the dead if (currentAmount == 0) branch so only SupplierModule's
availableSpace calculation uses storage.insert(targetKey, Long.MAX_VALUE, true).

---

Nitpick comments:
In `@common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java`:
- Around line 42-46: The Javadoc for IItemStorage.contents() is inconsistent:
the paragraph says empty slots "may or may not be included" while the `@return`
says "non-empty views"; decide on the non-empty contract and update the docs to
state clearly that contents() MUST return an Iterable of only non-empty
IItemView instances (empty slots must be omitted), then update any
implementations and unit tests of IItemStorage.contents() to conform to this
contract (search for implementations named contents or classes implementing
IItemStorage to adjust behavior).

In `@common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java`:
- Around line 36-37: The static fields in ItemStorageLookup (finder and
keyFactory) need explicit memory-visibility guarantees: change their
declarations to be volatile (e.g., make finder and keyFactory `private static
volatile Finder finder;` and `private static volatile KeyFactory keyFactory;`)
so writes during loader initialization are guaranteed visible to game tick
threads; update only the field declarations in the ItemStorageLookup class to
add volatile, no other logic changes required.

In `@common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java`:
- Around line 49-62: The insert method can silently overflow when casting
accepted (long) to int for item.toStack; clamp accepted to int range before
casting: compute int toInsert = (int)Math.min(accepted, Integer.MAX_VALUE) and
use item.toStack(toInsert) and pipe.acceptInsertedStack(...) with that clamped
stack to avoid overflow; keep returning the original long accepted (or if
business logic requires, adjust the returned value to reflect the actually
inserted amount) and reference the insert method, pipe.getInsertableAmount,
item.toStack, and pipe.acceptInsertedStack when making the change.

In `@common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java`:
- Around line 108-111: The code repeatedly calls key.toStack(1) for the same
IItemKey within this tick; cache that template stack once (e.g., templateStack =
key.toStack(1)) and reuse it when computing stackSize (use
templateStack.getItem().getDefaultMaxStackSize()), when creating queryStack, and
for any logging; update usages in the QuickSortModule block that reference
candidateView, key, stackSize, and queryStack to use the cached templateStack
instead to avoid repeated allocations.

In `@common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java`:
- Around line 441-452: The notifyDropAndDrop method has an unused parameter
inserted; remove the inserted parameter from the notifyDropAndDrop signature and
from all call sites so the method becomes notifyDropAndDrop(Level world,
BlockPos pos, TravelingItem item), and keep the existing behavior of notifying
the network with item.getStack().getCount() and calling
PipeBlockEntity.dropItem(world, pos, item); update any places that call
notifyDropAndDrop to stop passing the now-removed inserted argument.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: def238d3-d023-46d9-86a8-c66685e9f43b

📥 Commits

Reviewing files that changed from the base of the PR and between 8f302b5 and f68020b.

📒 Files selected for processing (69)
  • common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java
  • common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java
  • common/src/main/java/com/logistics/core/lib/block/capability/HasItemStorage.java
  • common/src/main/java/com/logistics/core/lib/items/ItemInventoryComponent.java
  • common/src/main/java/com/logistics/core/lib/network/CrafterSnapshot.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
  • common/src/main/java/com/logistics/core/lib/network/IWorldView.java
  • common/src/main/java/com/logistics/core/lib/network/IngredientChecker.java
  • common/src/main/java/com/logistics/core/lib/network/ItemRequest.java
  • common/src/main/java/com/logistics/core/lib/network/NetworkCommand.java
  • common/src/main/java/com/logistics/core/lib/network/Order.java
  • common/src/main/java/com/logistics/core/lib/network/PlanningView.java
  • common/src/main/java/com/logistics/core/lib/network/ProviderCanFulfill.java
  • common/src/main/java/com/logistics/core/lib/network/RecipeIngredient.java
  • common/src/main/java/com/logistics/core/lib/pipe/DispatchableModule.java
  • common/src/main/java/com/logistics/core/lib/pipe/Module.java
  • common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemKey.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java
  • common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java
  • common/src/main/java/com/logistics/pipe/ChassisPipe.java
  • common/src/main/java/com/logistics/pipe/Pipe.java
  • common/src/main/java/com/logistics/pipe/block/PipeBlock.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeBlockEntity.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java
  • common/src/main/java/com/logistics/pipe/modules/AdvancedExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/BasicExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/CraftingModule.java
  • common/src/main/java/com/logistics/pipe/modules/ExtractionModule.java
  • common/src/main/java/com/logistics/pipe/modules/InsertionModule.java
  • common/src/main/java/com/logistics/pipe/modules/PassiveSupplierModule.java
  • common/src/main/java/com/logistics/pipe/modules/PolymorphicSinkModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProcessModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProviderModule.java
  • common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java
  • common/src/main/java/com/logistics/pipe/modules/RequesterModule.java
  • common/src/main/java/com/logistics/pipe/modules/SupplierModule.java
  • common/src/main/java/com/logistics/pipe/network/ItemReservation.java
  • common/src/main/java/com/logistics/pipe/network/JobCoordinator.java
  • common/src/main/java/com/logistics/pipe/network/MinecraftWorldView.java
  • common/src/main/java/com/logistics/pipe/network/NetworkController.java
  • common/src/main/java/com/logistics/pipe/network/NetworkJob.java
  • common/src/main/java/com/logistics/pipe/network/NetworkSnapshotBuilder.java
  • common/src/main/java/com/logistics/pipe/network/PipeNetwork.java
  • common/src/main/java/com/logistics/pipe/network/PlanNode.java
  • common/src/main/java/com/logistics/pipe/network/PlanningContext.java
  • common/src/main/java/com/logistics/pipe/network/ProviderSnapshot.java
  • common/src/main/java/com/logistics/pipe/network/RequestPlanner.java
  • common/src/main/java/com/logistics/pipe/network/ReservationManager.java
  • common/src/main/java/com/logistics/pipe/network/WorkOrder.java
  • common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java
  • common/src/main/java/com/logistics/power/engine/block/entity/StirlingEngineBlockEntity.java
  • common/src/test/java/com/logistics/pipe/network/JobCoordinatorTest.java
  • common/src/test/java/com/logistics/pipe/network/NetworkControllerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReconciliationServiceTest.java
  • common/src/test/java/com/logistics/pipe/network/RequestPlannerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReservationManagerTest.java
  • common/src/test/java/com/logistics/pipe/network/SinkResolverTest.java
  • common/src/test/java/com/logistics/test/MinecraftTestEnvironment.java
  • common/src/test/java/com/logistics/test/TestItemKey.java
  • fabric/src/gametest/java/com/logistics/gametest/automation/KilnGameTest.java
  • fabric/src/gametest/java/com/logistics/gametest/power/EngineGameTest.java
  • fabric/src/main/java/com/logistics/fabric/capability/FabricCapabilityRegistration.java
  • fabric/src/main/java/com/logistics/fabric/capability/ItemStorageAccess.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemView.java

Comment thread common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java Outdated
Comment thread common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java Outdated
Comment thread common/src/main/java/com/logistics/pipe/block/PipeBlock.java
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
common/src/main/java/com/logistics/pipe/network/NetworkController.java (1)

224-226: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Skip deferred providers before choosing the dispatch source.

nextDispatchable() only bails out when all providers are deferred, but tryDispatch() still blindly takes entries.getFirst(). If the first provider was deferred and another provider still exists, the same deferred provider can be selected again every loop, which can stall PipeNetwork.tick() in a retry cycle.

Suggested fix
-        SupplyEntry supply = entries.getFirst();
+        SupplyEntry supply = entries.stream()
+                .filter(e -> !deferredProviders.contains(e.pos))
+                .findFirst()
+                .orElse(null);
+        if (supply == null) return null;
...
-                entries.removeFirst();
+                entries.remove(supply);
                 if (entries.isEmpty()) supplyTable.remove(order.item());
...
-        entries.removeFirst();
+        entries.remove(supply);
         if (entries.isEmpty()) supplyTable.remove(order.item());

Also applies to: 242-245, 253-255, 301-302

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/network/NetworkController.java`
around lines 224 - 226, nextDispatchable() only skips when all providers are
deferred but tryDispatch() uses entries.getFirst(), causing a deferred provider
to be repeatedly chosen; change the call sites (where tryDispatch(orderIt,
order, entries) is invoked) to first select the first non-deferred provider from
entries (e.g., find first Entry e where !deferredProviders.contains(e.pos)) and
pass a entries view or starting index that begins at that non-deferred provider,
or filter out deferred entries before calling tryDispatch; update the logic used
in tryDispatch (and the other similar call sites that use entries.getFirst()) to
respect deferredProviders so the dispatch source is never a deferred provider,
and apply the same change to the other occurrences referenced (the other
tryDispatch call sites).
common/src/main/java/com/logistics/pipe/modules/ProcessModule.java (1)

308-337: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rollback already-created input orders when dispatch aborts.

If one input order is placed and a later input fails satellite resolution, this method returns 0 but leaves the earlier order(s) live. That can leak reservations and route ingredients for a process job that was never queued.

Possible localized fix
                 orderDest = network.findSatellite(effectiveDest);
                 if (orderDest == null) {
+                    for (int j = 0; j < orderIds.size(); j++) {
+                        String uuidStr = NbtCompat.getStringAt(orderIds, j, "");
+                        if (!uuidStr.isEmpty()) {
+                            try { network.cancelOrder(UUID.fromString(uuidStr)); } catch (Exception ignored) {}
+                        }
+                    }
                     NetDbg.out("[Process @ {}] Dispatch rejected: satellite '{}' not found for input {}", ctx.pos(), effectiveDest, i);
                     LogisticsPipe.LOGGER.warn("[Process @ {}] Satellite '{}' not found for input {}; aborting dispatch", ctx.pos(), effectiveDest, i);
                     return 0;
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/pipe/modules/ProcessModule.java` around
lines 308 - 337, The code in ProcessModule places multiple input orders (using
network.placeOrder) but if a later input fails satellite resolution the method
returns 0 without cancelling earlier orders; change the logic to track created
order UUIDs (e.g., a List<UUID> createdOrderIds alongside the existing orderIds
ListTag) and when you hit the satellite-not-found branch (where
network.findSatellite(effectiveDest) returns null) iterate createdOrderIds and
call the network cancel API for each created order (e.g.,
network.cancelOrder(orderId)) before logging and returning 0, ensuring you clean
up any reservations created by network.placeOrder and keep orderIds consistent.
♻️ Duplicate comments (1)
common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java (1)

200-201: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Respect the side argument when exposing item storage.

Line 201 ignores side, so callers can bypass kiln face restrictions defined by WorldlyContainer sided methods.

Suggested fix
 `@Override`
 public IItemStorage itemStorage(`@Nullable` Direction side) {
-    return new ContainerItemStorage(this);
+    return new ContainerItemStorage(this, side);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java`
around lines 200 - 201, KilnBlockEntity.itemStorage currently ignores the side
parameter and returns a raw ContainerItemStorage, bypassing WorldlyContainer
sided rules; change itemStorage(`@Nullable` Direction side) to return a storage
that enforces sided access (e.g., wrap or construct a sided-aware adapter using
the KilnBlockEntity/WorldlyContainer APIs) so interactions respect the provided
side—replace the direct new ContainerItemStorage(this) with a sided wrapper that
consults the side argument when exposing slots.
🧹 Nitpick comments (4)
common/src/main/java/com/logistics/core/lib/storage/IItemView.java (1)

3-15: ⚡ Quick win

Clarify whether IItemView entries can be empty/zero-amount.

Please make the contract explicit (e.g., non-null resource() and amount() > 0) so adapters and consumers implement the same semantics.

📝 Proposed Javadoc refinement
 /**
  * Read-only view of a slot or resource within an {`@link` IItemStorage}.
  *
  * <p>Equivalent to Fabric's {`@code` StorageView<ItemVariant>} in the loader-agnostic API.
  * Instances are obtained by iterating {`@link` IItemStorage#contents()}.
+ * Implementations should expose only non-empty views:
+ * {`@link` `#resource`()} must be non-null and {`@link` `#amount`()} must be {`@code` > 0}.
  */
 public interface IItemView {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/core/lib/storage/IItemView.java` around
lines 3 - 15, Clarify the IItemView contract by updating its Javadoc to state
explicitly that resource() never returns null and amount() is always > 0 for any
entry produced by IItemStorage#contents(); ensure adapters and consumers
enforce/assume these semantics (e.g., validate or filter out empty slots at the
storage iteration boundary) and document whether implementations must
throw/avoid creating views with amount() == 0 so everyone implements the same
non-empty-view invariant for IItemView, resource(), and amount().
fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java (1)

17-19: ⚡ Quick win

Add a fail-fast null guard in constructor.

A null ItemVariant would currently fail later in unrelated methods; fail early at construction.

Suggested patch
+import java.util.Objects;
+
 public final class FabricItemKey implements IItemKey {
@@
     private final ItemVariant variant;
 
     public FabricItemKey(ItemVariant variant) {
-        this.variant = variant;
+        this.variant = Objects.requireNonNull(variant, "variant");
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java` around
lines 17 - 19, The FabricItemKey constructor currently accepts a possibly null
ItemVariant which defers failures; add a fail-fast null guard in the
FabricItemKey(ItemVariant variant) constructor (the FabricItemKey class and its
variant field) by validating variant != null and throwing an appropriate
unchecked exception (e.g., NullPointerException or IllegalArgumentException)
with a clear message if null, before assigning this.variant = variant.
common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java (1)

19-27: ⚡ Quick win

Tighten contract semantics for non-positive amounts and return bounds.

Please define maxAmount <= 0 behavior and explicitly require non-negative return values for both methods to keep adapters consistent.

Suggested Javadoc tightening
     /**
      * Insert items into this storage.
@@
-     * `@param` maxAmount the maximum number of items to insert
+     * `@param` maxAmount the maximum number of items to insert; non-positive values must return {`@code` 0}
@@
-     * `@return` the amount actually inserted (or that would be inserted if simulating)
+     * `@return` the amount actually inserted (or that would be inserted if simulating), always {`@code` >= 0}
      */
@@
     /**
      * Extract items from this storage.
@@
-     * `@param` maxAmount the maximum number of items to extract
+     * `@param` maxAmount the maximum number of items to extract; non-positive values must return {`@code` 0}
@@
-     * `@return` the amount actually extracted (or that would be extracted if simulating)
+     * `@return` the amount actually extracted (or that would be extracted if simulating), always {`@code` >= 0}
      */

Also applies to: 30-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java` around
lines 19 - 27, Update the Javadoc for IItemStorage.insert (and likewise for
IItemStorage.extract) to explicitly define behavior when maxAmount <= 0 (treat
as no-op and return 0) and require implementations to always return a
non-negative value not exceeding the requested maxAmount; mention that
simulate=true performs a dry run without mutating state and the returned value
is the amount that would be inserted/extracted. Reference the methods by name
(insert, extract) and tighten the contract so adapters can rely on non-negative,
bounded return values and consistent handling of non-positive input amounts.
common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java (1)

34-38: ⚡ Quick win

Update the API docs to describe IItemKey, not “item variant”.

This interface is now one of the main loader-agnostic extension points, so the stale Fabric-era wording is misleading for callers and addon authors.

Also applies to: 67-78, 117-118, 138-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java`
around lines 34 - 38, Update the Javadoc in the ILogisticsNetwork interface to
replace the stale phrase "item variant" with "IItemKey" (and briefly describe
that IItemKey is the loader-agnostic item identifier) wherever it appears (e.g.,
the registerSupply method signature and the other Javadoc blocks in this
interface). Ensure the parameter descriptions (for maps/keys/collections)
reference IItemKey instead of "item variant" and adjust phrasing to make it
clear callers should pass IItemKey instances as the item identifier for
supply/request/storage-related methods.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java`:
- Around line 41-58: BlockEntityUtil iterates storage.contents() and calls
storage.extract() during that iteration which can break on live iterables; fix
by first collecting the IItemView elements into a temporary List (e.g.,
List<IItemView> views = new ArrayList<>(); for (IItemView v :
storage.contents()) views.add(v);) and then iterate that list to build drops and
call storage.extract(key, amount, false); ensure you reference the same
variables (IItemView, IItemKey, amount, storage.extract) so behavior is
unchanged but iteration is now safe for live iterables.

In
`@common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java`:
- Around line 58-74: The insertIntoSlot method misses a container.setChanged()
call when placing a new stack into an empty slot: after the branch that does
container.setItem(slot, item.toStack((int) toInsert)) (inside insertIntoSlot)
add a container.setChanged() when simulate is false and toInsert > 0 so the
container is marked dirty like the existing-stack branch; ensure you only call
setChanged() in the non-simulate path to mirror the grow((int) toInsert)
behavior.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 129-143: The insert and extract methods in FabricItemStorage
unsafely cast IItemKey to FabricItemKey (in insert(...) and extract(...)),
risking ClassCastException; change both methods to follow the getResource()
pattern: detect if the incoming IItemKey is a FabricItemKey and use its
variant(), otherwise convert/fallback via the same helper/path used by
getResource() to obtain an ItemVariant (or handle non-Fabric keys safely) before
calling storage.insert(...) or storage.extract(...), preserving the existing
simulate/transaction semantics.
- Around line 97-101: StorageView.extract in FabricItemStorage currently
constructs an IItemKey (FabricItemKey) then calls storage.extract(key,
maxAmount, false), ignoring the provided
net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext tx and thus
bypassing Fabric transaction semantics; change the implementation to use the
provided tx so extractions participate in rollback — i.e. mirror the outer
insert/extract pattern: convert the ItemVariant to IItemKey (FabricItemKey) as
before, then call the transaction-aware storage.extract path by forwarding or
adapting tx (use the same tx->storage callback/wrapper used elsewhere in this
class) so storage.extract receives the TransactionContext (or is invoked inside
tx.run/adapter) instead of hardcoding false. Ensure you reference
StorageView.extract, FabricItemKey, storage.extract and the TransactionContext
tx when making the change.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemView.java`:
- Around line 19-22: Update FabricItemStorage.contents() to skip StorageView
entries whose amount() == 0 before wrapping them in FabricItemView so callers no
longer receive blank views; specifically iterate the StorageView iterator
(StorageView.iterator()), filter out views where view.amount() == 0, and only
create new FabricItemView(view) for non-empty views, ensuring
FabricItemView.resource() and other callers no longer need to perform redundant
amount checks.

---

Outside diff comments:
In `@common/src/main/java/com/logistics/pipe/modules/ProcessModule.java`:
- Around line 308-337: The code in ProcessModule places multiple input orders
(using network.placeOrder) but if a later input fails satellite resolution the
method returns 0 without cancelling earlier orders; change the logic to track
created order UUIDs (e.g., a List<UUID> createdOrderIds alongside the existing
orderIds ListTag) and when you hit the satellite-not-found branch (where
network.findSatellite(effectiveDest) returns null) iterate createdOrderIds and
call the network cancel API for each created order (e.g.,
network.cancelOrder(orderId)) before logging and returning 0, ensuring you clean
up any reservations created by network.placeOrder and keep orderIds consistent.

In `@common/src/main/java/com/logistics/pipe/network/NetworkController.java`:
- Around line 224-226: nextDispatchable() only skips when all providers are
deferred but tryDispatch() uses entries.getFirst(), causing a deferred provider
to be repeatedly chosen; change the call sites (where tryDispatch(orderIt,
order, entries) is invoked) to first select the first non-deferred provider from
entries (e.g., find first Entry e where !deferredProviders.contains(e.pos)) and
pass a entries view or starting index that begins at that non-deferred provider,
or filter out deferred entries before calling tryDispatch; update the logic used
in tryDispatch (and the other similar call sites that use entries.getFirst()) to
respect deferredProviders so the dispatch source is never a deferred provider,
and apply the same change to the other occurrences referenced (the other
tryDispatch call sites).

---

Duplicate comments:
In `@common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java`:
- Around line 200-201: KilnBlockEntity.itemStorage currently ignores the side
parameter and returns a raw ContainerItemStorage, bypassing WorldlyContainer
sided rules; change itemStorage(`@Nullable` Direction side) to return a storage
that enforces sided access (e.g., wrap or construct a sided-aware adapter using
the KilnBlockEntity/WorldlyContainer APIs) so interactions respect the provided
side—replace the direct new ContainerItemStorage(this) with a sided wrapper that
consults the side argument when exposing slots.

---

Nitpick comments:
In `@common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java`:
- Around line 34-38: Update the Javadoc in the ILogisticsNetwork interface to
replace the stale phrase "item variant" with "IItemKey" (and briefly describe
that IItemKey is the loader-agnostic item identifier) wherever it appears (e.g.,
the registerSupply method signature and the other Javadoc blocks in this
interface). Ensure the parameter descriptions (for maps/keys/collections)
reference IItemKey instead of "item variant" and adjust phrasing to make it
clear callers should pass IItemKey instances as the item identifier for
supply/request/storage-related methods.

In `@common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java`:
- Around line 19-27: Update the Javadoc for IItemStorage.insert (and likewise
for IItemStorage.extract) to explicitly define behavior when maxAmount <= 0
(treat as no-op and return 0) and require implementations to always return a
non-negative value not exceeding the requested maxAmount; mention that
simulate=true performs a dry run without mutating state and the returned value
is the amount that would be inserted/extracted. Reference the methods by name
(insert, extract) and tighten the contract so adapters can rely on non-negative,
bounded return values and consistent handling of non-positive input amounts.

In `@common/src/main/java/com/logistics/core/lib/storage/IItemView.java`:
- Around line 3-15: Clarify the IItemView contract by updating its Javadoc to
state explicitly that resource() never returns null and amount() is always > 0
for any entry produced by IItemStorage#contents(); ensure adapters and consumers
enforce/assume these semantics (e.g., validate or filter out empty slots at the
storage iteration boundary) and document whether implementations must
throw/avoid creating views with amount() == 0 so everyone implements the same
non-empty-view invariant for IItemView, resource(), and amount().

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java`:
- Around line 17-19: The FabricItemKey constructor currently accepts a possibly
null ItemVariant which defers failures; add a fail-fast null guard in the
FabricItemKey(ItemVariant variant) constructor (the FabricItemKey class and its
variant field) by validating variant != null and throwing an appropriate
unchecked exception (e.g., NullPointerException or IllegalArgumentException)
with a clear message if null, before assigning this.variant = variant.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0a262c54-ddc0-42c6-b2eb-3a35ead2e219

📥 Commits

Reviewing files that changed from the base of the PR and between 8f302b5 and e2bec3c.

📒 Files selected for processing (69)
  • common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java
  • common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java
  • common/src/main/java/com/logistics/core/lib/block/capability/HasItemStorage.java
  • common/src/main/java/com/logistics/core/lib/items/ItemInventoryComponent.java
  • common/src/main/java/com/logistics/core/lib/network/CrafterSnapshot.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
  • common/src/main/java/com/logistics/core/lib/network/IWorldView.java
  • common/src/main/java/com/logistics/core/lib/network/IngredientChecker.java
  • common/src/main/java/com/logistics/core/lib/network/ItemRequest.java
  • common/src/main/java/com/logistics/core/lib/network/NetworkCommand.java
  • common/src/main/java/com/logistics/core/lib/network/Order.java
  • common/src/main/java/com/logistics/core/lib/network/PlanningView.java
  • common/src/main/java/com/logistics/core/lib/network/ProviderCanFulfill.java
  • common/src/main/java/com/logistics/core/lib/network/RecipeIngredient.java
  • common/src/main/java/com/logistics/core/lib/pipe/DispatchableModule.java
  • common/src/main/java/com/logistics/core/lib/pipe/Module.java
  • common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemKey.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java
  • common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java
  • common/src/main/java/com/logistics/pipe/ChassisPipe.java
  • common/src/main/java/com/logistics/pipe/Pipe.java
  • common/src/main/java/com/logistics/pipe/block/PipeBlock.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeBlockEntity.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java
  • common/src/main/java/com/logistics/pipe/modules/AdvancedExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/BasicExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/CraftingModule.java
  • common/src/main/java/com/logistics/pipe/modules/ExtractionModule.java
  • common/src/main/java/com/logistics/pipe/modules/InsertionModule.java
  • common/src/main/java/com/logistics/pipe/modules/PassiveSupplierModule.java
  • common/src/main/java/com/logistics/pipe/modules/PolymorphicSinkModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProcessModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProviderModule.java
  • common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java
  • common/src/main/java/com/logistics/pipe/modules/RequesterModule.java
  • common/src/main/java/com/logistics/pipe/modules/SupplierModule.java
  • common/src/main/java/com/logistics/pipe/network/ItemReservation.java
  • common/src/main/java/com/logistics/pipe/network/JobCoordinator.java
  • common/src/main/java/com/logistics/pipe/network/MinecraftWorldView.java
  • common/src/main/java/com/logistics/pipe/network/NetworkController.java
  • common/src/main/java/com/logistics/pipe/network/NetworkJob.java
  • common/src/main/java/com/logistics/pipe/network/NetworkSnapshotBuilder.java
  • common/src/main/java/com/logistics/pipe/network/PipeNetwork.java
  • common/src/main/java/com/logistics/pipe/network/PlanNode.java
  • common/src/main/java/com/logistics/pipe/network/PlanningContext.java
  • common/src/main/java/com/logistics/pipe/network/ProviderSnapshot.java
  • common/src/main/java/com/logistics/pipe/network/RequestPlanner.java
  • common/src/main/java/com/logistics/pipe/network/ReservationManager.java
  • common/src/main/java/com/logistics/pipe/network/WorkOrder.java
  • common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java
  • common/src/main/java/com/logistics/power/engine/block/entity/StirlingEngineBlockEntity.java
  • common/src/test/java/com/logistics/pipe/network/JobCoordinatorTest.java
  • common/src/test/java/com/logistics/pipe/network/NetworkControllerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReconciliationServiceTest.java
  • common/src/test/java/com/logistics/pipe/network/RequestPlannerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReservationManagerTest.java
  • common/src/test/java/com/logistics/pipe/network/SinkResolverTest.java
  • common/src/test/java/com/logistics/test/MinecraftTestEnvironment.java
  • common/src/test/java/com/logistics/test/TestItemKey.java
  • fabric/src/gametest/java/com/logistics/gametest/automation/KilnGameTest.java
  • fabric/src/gametest/java/com/logistics/gametest/power/EngineGameTest.java
  • fabric/src/main/java/com/logistics/fabric/capability/FabricCapabilityRegistration.java
  • fabric/src/main/java/com/logistics/fabric/capability/ItemStorageAccess.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemView.java

Comment thread common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java`:
- Around line 106-119: The contents() method currently iterates all slots but
insert()/extract() apply side-scoped slot filtering; update contents() to mirror
that behavior by checking if side != null and container instanceof
WorldlyContainer and, if so, iterate only the slots returned by
((WorldlyContainer)container).getSlotsForFace(side), otherwise iterate all slots
as before; refactor the ItemView creation into a small helper (e.g.,
createItemView(ItemStack) or createItemViewForSlot(int)) and use it from
contents() to reduce duplication and keep slot access consistent with
insert()/extract().
- Around line 58-74: insertIntoSlot currently only respects the item's max stack
size and can exceed the container's per-slot limit; update both branches to
clamp insertion by the container's limit (container.getMaxStackSize()) as well
as the item's template/current stack limit. For the empty-slot branch (inside
insertIntoSlot where current.isEmpty()), compute toInsert = min(remaining,
template.getMaxStackSize(), container.getMaxStackSize()) before creating the
stack and calling container.setItem/container.setChanged. For the existing-stack
branch, compute slotLimit = min(current.getMaxStackSize(),
container.getMaxStackSize()), then canFit = max(0, slotLimit -
current.getCount()) and use toInsert = min(remaining, canFit); only call
current.grow and container.setChanged when toInsert > 0 and !simulate. This
prevents overfilling and avoids negative canFit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 39e15ad9-c67c-4570-a740-28c1411be660

📥 Commits

Reviewing files that changed from the base of the PR and between e2bec3c and 8594830.

📒 Files selected for processing (10)
  • common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java
  • common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
  • common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/pipe/modules/ProcessModule.java
  • common/src/main/java/com/logistics/pipe/network/NetworkController.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java
✅ Files skipped from review due to trivial changes (3)
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
🚧 Files skipped from review as they are similar to previous changes (4)
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java
  • common/src/main/java/com/logistics/pipe/modules/ProcessModule.java
  • common/src/main/java/com/logistics/pipe/network/NetworkController.java
  • common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java

- Fix BlockEntityUtil comment: label the extraction as real, not simulated
- Mandate non-empty views in IItemStorage.contents() Javadoc
- Add volatile to ItemStorageLookup.finder and keyFactory fields
- Remove contents().hasNext() guard from PipeBlock inventory detection
- Clamp PipeItemStorage accepted count before int cast
- Cache key.toStack(1) in QuickSortModule to avoid redundant allocation
- Remove unused inserted param from PipeRuntime.notifyDropAndDrop
- Simplify SupplierModule.getAvailableSpace to single insert(simulate=true)
- Fix BasicExtractorModule to cap total extraction to itemsPerPull
- Add Direction-aware ContainerItemStorage constructor; pass side in MaceratorBlockEntity
- Fix FabricItemStorage.asFabric to honor TransactionContext via close callback; fix unsafe FabricItemKey cast in getResource
- Snapshot contents() before extracting in BlockEntityUtil to avoid live-iterable mutation
- Add container.setChanged() in ContainerItemStorage empty-slot insert path
- Pass side to ContainerItemStorage in KilnBlockEntity (WorldlyContainer sided access)
- Fix unsafe FabricItemKey cast in FabricItemStorage insert/extract methods
- Honor TransactionContext in FabricItemStorage StorageView.extract via close callback
- Filter zero-amount views from FabricItemStorage.contents() iterator
- Add null guard to FabricItemKey constructor
- Cancel earlier orders in ProcessModule when satellite resolution fails mid-loop
- Fix NetworkController.tryDispatch to skip deferred providers via index rather than getFirst()
- Tighten IItemStorage insert/extract contract Javadoc (maxAmount <= 0, return bounds)
- Clarify IItemView contract: resource() non-null, amount() always > 0
- Fix ILogisticsNetwork placeOrder Javadoc: "item variant" -> "IItemKey"
@Indemnity83 Indemnity83 force-pushed the feat/define-itemstorage-transaction-contract branch from 27e49e0 to ab1884f Compare May 7, 2026 23:03
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@common/src/main/java/com/logistics/pipe/block/PipeBlock.java`:
- Around line 488-490: The current null check against
ItemStorageLookup.find(...) in PipeBlock incorrectly treats non-null sided
wrappers with zero accessible slots as valid inventories; instead, after
obtaining storage (via ItemStorageLookup.find(world, neighborPos,
direction.getOpposite())), explicitly verify that the storage actually exposes
at least one accessible slot on that side (for example by querying the storage
for slot views/iterators for that side, or testing whether any slot allows
insertion/extraction for the given direction) and only classify the face as
INVENTORY when such sided-accessibility is present; update the branch around
storage (the variable named storage and the logic that marks faces as INVENTORY)
to treat storages with no accessible slots as if null so pipes won’t connect to
dead faces.

In `@common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java`:
- Around line 64-66: QuickSortModule currently persists LAST_SLOT_SCANNED /
LAST_SUCCESS_SLOT assuming storage.contents() are stable indices, but the new
storage.contents() API returns ephemeral IItemView objects and extraction is
key-wide via extract(...); update QuickSortModule to stop storing numeric slot
indices across ticks — instead track a stable item key or view identity provided
by the storage API (e.g., use the IItemView's stable key/identifier if
available) or switch to re-resolving candidateView each tick by searching
storage.contents() for a matching key before calling extract(...); remove
reliance on candidate index comparisons and adjust any logic that references
LAST_SLOT_SCANNED / LAST_SUCCESS_SLOT (and the code paths around candidateView,
storage.contents(), and extract(...)) so decisions are based on item keys or
fresh view lookups rather than persisted slot numbers.

In
`@common/src/main/java/com/logistics/power/engine/block/entity/StirlingEngineBlockEntity.java`:
- Around line 148-168: In StirlingEngineBlockEntity.insert, the empty-slot
branch currently places maxAmount items without clamping to the item's stack
limit; change the logic to use the already-created incoming ItemStack but with
its count limited to Math.min(maxAmount, incoming.getMaxStackSize()) (or
equivalent) so you never set an oversized stack; when !simulate set
inventory.setItem(0, the clamped incoming) and return the clamped amount,
otherwise return the clamped amount without mutating inventory.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 97-107: The extract implementation in
FabricItemStorage.StorageView incorrectly allows extracting any requested
resource and uses the caller maxAmount instead of the view's available amount;
update the StorageView.extract method to first compare the requested ItemVariant
with this view's getResource() (or construct keys from getResource()) and
immediately return 0 if they don't match, then compute the allowed amount as
Math.min(maxAmount, getAmount()) and use that bounded value for the simulated
storage.extract call and the final commit callback (still using
IItemKey/FabricItemKey and storage.extract for the actual mutation); keep the
TransactionContext callback logic but ensure it commits only the simulated
bounded amount.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4c4e0055-a5e7-4ad8-bf68-f7fef9f6e09b

📥 Commits

Reviewing files that changed from the base of the PR and between 8594830 and ab1884f.

📒 Files selected for processing (69)
  • common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java
  • common/src/main/java/com/logistics/core/lib/block/BlockEntityUtil.java
  • common/src/main/java/com/logistics/core/lib/block/capability/HasItemStorage.java
  • common/src/main/java/com/logistics/core/lib/items/ItemInventoryComponent.java
  • common/src/main/java/com/logistics/core/lib/network/CrafterSnapshot.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
  • common/src/main/java/com/logistics/core/lib/network/IWorldView.java
  • common/src/main/java/com/logistics/core/lib/network/IngredientChecker.java
  • common/src/main/java/com/logistics/core/lib/network/ItemRequest.java
  • common/src/main/java/com/logistics/core/lib/network/NetworkCommand.java
  • common/src/main/java/com/logistics/core/lib/network/Order.java
  • common/src/main/java/com/logistics/core/lib/network/PlanningView.java
  • common/src/main/java/com/logistics/core/lib/network/ProviderCanFulfill.java
  • common/src/main/java/com/logistics/core/lib/network/RecipeIngredient.java
  • common/src/main/java/com/logistics/core/lib/pipe/DispatchableModule.java
  • common/src/main/java/com/logistics/core/lib/pipe/Module.java
  • common/src/main/java/com/logistics/core/lib/storage/ContainerItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemKey.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java
  • common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java
  • common/src/main/java/com/logistics/pipe/ChassisPipe.java
  • common/src/main/java/com/logistics/pipe/Pipe.java
  • common/src/main/java/com/logistics/pipe/block/PipeBlock.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeBlockEntity.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java
  • common/src/main/java/com/logistics/pipe/modules/AdvancedExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/BasicExtractorModule.java
  • common/src/main/java/com/logistics/pipe/modules/CraftingModule.java
  • common/src/main/java/com/logistics/pipe/modules/ExtractionModule.java
  • common/src/main/java/com/logistics/pipe/modules/InsertionModule.java
  • common/src/main/java/com/logistics/pipe/modules/PassiveSupplierModule.java
  • common/src/main/java/com/logistics/pipe/modules/PolymorphicSinkModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProcessModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProviderModule.java
  • common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java
  • common/src/main/java/com/logistics/pipe/modules/RequesterModule.java
  • common/src/main/java/com/logistics/pipe/modules/SupplierModule.java
  • common/src/main/java/com/logistics/pipe/network/ItemReservation.java
  • common/src/main/java/com/logistics/pipe/network/JobCoordinator.java
  • common/src/main/java/com/logistics/pipe/network/MinecraftWorldView.java
  • common/src/main/java/com/logistics/pipe/network/NetworkController.java
  • common/src/main/java/com/logistics/pipe/network/NetworkJob.java
  • common/src/main/java/com/logistics/pipe/network/NetworkSnapshotBuilder.java
  • common/src/main/java/com/logistics/pipe/network/PipeNetwork.java
  • common/src/main/java/com/logistics/pipe/network/PlanNode.java
  • common/src/main/java/com/logistics/pipe/network/PlanningContext.java
  • common/src/main/java/com/logistics/pipe/network/ProviderSnapshot.java
  • common/src/main/java/com/logistics/pipe/network/RequestPlanner.java
  • common/src/main/java/com/logistics/pipe/network/ReservationManager.java
  • common/src/main/java/com/logistics/pipe/network/WorkOrder.java
  • common/src/main/java/com/logistics/pipe/runtime/PipeRuntime.java
  • common/src/main/java/com/logistics/power/engine/block/entity/StirlingEngineBlockEntity.java
  • common/src/test/java/com/logistics/pipe/network/JobCoordinatorTest.java
  • common/src/test/java/com/logistics/pipe/network/NetworkControllerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReconciliationServiceTest.java
  • common/src/test/java/com/logistics/pipe/network/RequestPlannerTest.java
  • common/src/test/java/com/logistics/pipe/network/ReservationManagerTest.java
  • common/src/test/java/com/logistics/pipe/network/SinkResolverTest.java
  • common/src/test/java/com/logistics/test/MinecraftTestEnvironment.java
  • common/src/test/java/com/logistics/test/TestItemKey.java
  • fabric/src/gametest/java/com/logistics/gametest/automation/KilnGameTest.java
  • fabric/src/gametest/java/com/logistics/gametest/power/EngineGameTest.java
  • fabric/src/main/java/com/logistics/fabric/capability/FabricCapabilityRegistration.java
  • fabric/src/main/java/com/logistics/fabric/capability/ItemStorageAccess.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemView.java
✅ Files skipped from review due to trivial changes (20)
  • common/src/main/java/com/logistics/core/lib/network/ProviderCanFulfill.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemView.java
  • common/src/main/java/com/logistics/core/lib/network/RecipeIngredient.java
  • common/src/main/java/com/logistics/core/lib/network/IngredientChecker.java
  • common/src/main/java/com/logistics/core/lib/network/Order.java
  • fabric/src/main/java/com/logistics/fabric/capability/ItemStorageAccess.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemView.java
  • common/src/main/java/com/logistics/core/lib/network/PlanningView.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemKey.java
  • common/src/main/java/com/logistics/core/lib/block/capability/HasItemStorage.java
  • common/src/main/java/com/logistics/pipe/network/RequestPlanner.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemKey.java
  • common/src/main/java/com/logistics/core/lib/network/CrafterSnapshot.java
  • common/src/test/java/com/logistics/test/TestItemKey.java
  • common/src/main/java/com/logistics/core/lib/storage/ItemStorageLookup.java
  • common/src/main/java/com/logistics/pipe/modules/RequesterModule.java
  • common/src/main/java/com/logistics/core/lib/storage/IItemStorage.java
  • common/src/main/java/com/logistics/core/lib/network/ILogisticsNetwork.java
  • common/src/main/java/com/logistics/pipe/modules/CraftingModule.java
  • common/src/main/java/com/logistics/pipe/modules/ProviderModule.java
🚧 Files skipped from review as they are similar to previous changes (10)
  • common/src/main/java/com/logistics/automation/kiln/KilnBlockEntity.java
  • common/src/main/java/com/logistics/core/macerator/MaceratorBlockEntity.java
  • common/src/main/java/com/logistics/pipe/network/ItemReservation.java
  • common/src/main/java/com/logistics/pipe/Pipe.java
  • common/src/main/java/com/logistics/pipe/modules/AdvancedExtractorModule.java
  • fabric/src/main/java/com/logistics/fabric/capability/FabricCapabilityRegistration.java
  • common/src/main/java/com/logistics/core/lib/items/ItemInventoryComponent.java
  • common/src/main/java/com/logistics/pipe/block/entity/PipeItemStorage.java
  • common/src/main/java/com/logistics/pipe/network/JobCoordinator.java
  • common/src/main/java/com/logistics/core/lib/network/ItemRequest.java

Comment thread common/src/main/java/com/logistics/pipe/block/PipeBlock.java
Comment thread common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java Outdated
Comment thread fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java Outdated
…maxStackSize; guard FabricStorageView.extract by resource and view amount
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 60-80: The current asFabric() implementation (methods insert,
extract, iterator and the StorageView.extract path) only simulates against the
live IItemStorage and defers real mutations via transaction.addCloseCallback,
which breaks transaction-local visibility; instead introduce a
per-TransactionContext staged delta map (keyed by IItemKey / FabricItemKey) that
all fabric-facing operations consult and update during simulate calls so
multiple operations in the same TransactionContext see each other; on
addCloseCallback (or better, register a SnapshotParticipant/attach to the
TransactionContext) apply the accumulated staged deltas to the real storage only
if the transaction commits; update insert, extract, iterator and
StorageView.extract to read/write the staged view and to record deltas rather
than calling storage.insert/storage.extract immediately, and ensure the staged
map is cleared on rollback.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 35fe8b66-9cf1-4361-adb8-a99eeb93b80a

📥 Commits

Reviewing files that changed from the base of the PR and between ab1884f and abfe7f1.

📒 Files selected for processing (3)
  • common/src/main/java/com/logistics/pipe/modules/QuickSortModule.java
  • common/src/main/java/com/logistics/power/engine/block/entity/StirlingEngineBlockEntity.java
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java

Comment thread fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java (1)

137-179: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

StagedStorage is still not transaction-correct for general Fabric callers.

The per-IItemKey delta map only makes same-resource operations compose. A common swap like “extract cobblestone, then insert dirt into that freed slot” still fails in one transaction because the dirt insert probes live state and never sees the staged cobblestone removal. Also, the close callback applies deltas when the current TransactionContext closes, so committing a nested transaction can mutate live storage before an outer transaction decides to roll back. This needs an outer-transaction snapshot / SnapshotParticipant-style model rather than per-key totals.

In Fabric Transfer API v1, should nested transaction commits remain rollback-able by an outer transaction, and should a Storage<ItemVariant> implementation expose transaction-local visibility for cross-resource operations like extracting one item and inserting a different item into the freed slot within the same transaction?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`
around lines 137 - 179, StagedStorage's current per-TransactionContext delta map
and close callback apply committed deltas immediately and only per-key totals,
so nested commits mutate live storage and cross-resource ops (extract A then
insert B) don't see transaction-local frees; fix by switching to a
SnapshotParticipant-style transaction-local view: replace the IdentityHashMap
staged with a TransactionContext-scoped participant that on first access
registers as a snapshot participant (instead of applying directly in
deltas(TransactionContext) via addCloseCallback), keep per-transaction maps that
on nested commit merge into the parent transaction's map (not into live storage)
and only flush to live storage when the outermost transaction commits; update
deltas(TransactionContext), insert(..., TransactionContext), and extract(...,
TransactionContext) to compute effectiveCapacity/effectiveAvailable by combining
the live storage probe (storage.insert/storage.extract with probing=true) with
the cumulative staged deltas from the current transaction and all its ancestor
transaction maps so cross-resource operations see transaction-local state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 166-177: The storage probe calls inside
FabricItemStorage.insert(...) and FabricItemStorage.extract(...) use
Integer.MAX_VALUE, which incorrectly caps probes to 2_147_483_647; change those
probe arguments to Long.MAX_VALUE (or the appropriate long max constant) when
calling storage.insert(...) and storage.extract(...), and update the other
occurrences referenced (the similar probe around the later lines) so all
capacity/availability probes use long max values instead of Integer.MAX_VALUE.

---

Duplicate comments:
In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 137-179: StagedStorage's current per-TransactionContext delta map
and close callback apply committed deltas immediately and only per-key totals,
so nested commits mutate live storage and cross-resource ops (extract A then
insert B) don't see transaction-local frees; fix by switching to a
SnapshotParticipant-style transaction-local view: replace the IdentityHashMap
staged with a TransactionContext-scoped participant that on first access
registers as a snapshot participant (instead of applying directly in
deltas(TransactionContext) via addCloseCallback), keep per-transaction maps that
on nested commit merge into the parent transaction's map (not into live storage)
and only flush to live storage when the outermost transaction commits; update
deltas(TransactionContext), insert(..., TransactionContext), and extract(...,
TransactionContext) to compute effectiveCapacity/effectiveAvailable by combining
the live storage probe (storage.insert/storage.extract with probing=true) with
the cumulative staged deltas from the current transaction and all its ancestor
transaction maps so cross-resource operations see transaction-local state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 333b2cad-ba04-448e-a19e-80ee5a7ff70d

📥 Commits

Reviewing files that changed from the base of the PR and between abfe7f1 and f5c0905.

📒 Files selected for processing (1)
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java

Comment thread fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java Outdated
@Indemnity83
Copy link
Copy Markdown
Owner Author

@coderabbitai resume
@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 8, 2026

Tip

For best results, initiate chat on the files or code changes.

@Indemnity83 Sure! Resuming reviews and triggering a review of PR #349 now.

[resume]
[review]

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java`:
- Around line 136-199: StagedStorage currently records only per-key
pendingDeltas which breaks slot-based shared-slot implementations; change the
staging model to track slot-level (or full-inventory) staged state and make all
reads consult that staged snapshot: replace pendingDeltas with a stagedSlots map
or a full staged contents copy created in createSnapshot()/readSnapshot(),
update deltas(TransactionContext) to return that staged view, modify
insert(ItemVariant,...)/extract(...) to compute
effectiveCapacity/effectiveAvailable by applying staged slot changes (not just
per-key delta), ensure iterator() and any StorageView/getCapacity logic return
views derived from the staged snapshot, and keep onFinalCommit() applying staged
slot changes back to storage and then clearing the staged snapshot.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: eb0099e4-2993-4eb0-908a-2123b343eaa6

📥 Commits

Reviewing files that changed from the base of the PR and between abfe7f1 and 5adc66f.

📒 Files selected for processing (1)
  • fabric/src/main/java/com/logistics/fabric/storage/FabricItemStorage.java

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.

Define IItemStorage / ITransaction contract (primary pipe abstraction)

1 participant