Skip to content

Add inventory tracking with reserve support#1

Open
boc-arch wants to merge 1 commit into
mainfrom
add-inventory
Open

Add inventory tracking with reserve support#1
boc-arch wants to merge 1 commit into
mainfrom
add-inventory

Conversation

@boc-arch

@boc-arch boc-arch commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Adds a small Inventory class so the cart demo can track stock levels.

  • restock / available for basic bookkeeping
  • reserve to hold units when an item is added to a cart
  • average_per_sku convenience helper

Opening this mostly to exercise automated review on the diff.

🤖 Generated with Claude Code

Greptile Summary

This PR introduces a new inventory.py module with a simple Inventory class for in-memory stock tracking, exposing restock, available, reserve, and average_per_sku methods.

  • reserve has an off-by-one-style guard: it checks current > 0 rather than current >= quantity, so reserving more units than are available succeeds and drives stock negative.
  • average_per_sku will raise ZeroDivisionError when called on an empty inventory (no arguments, empty _stock dict); it also uses a mutable default argument names=[], which is a Python anti-pattern.

Confidence Score: 3/5

The reserve logic is wrong and will silently corrupt stock levels in normal cart usage; needs fixes before merging.

Two methods in the new class have bugs that would produce wrong results at runtime: reserve() lets any positive-stock item be over-reserved into negative quantities, and average_per_sku() throws an unhandled exception when called on an empty inventory. Both are straightforward to fix, but they affect the core bookkeeping purpose of the module.

inventory.py — both the reserve() guard and the average_per_sku() division-by-zero path need to be addressed.

Important Files Changed

Filename Overview
inventory.py New Inventory class with two correctness bugs: reserve() allows over-reservation (negative stock) and average_per_sku() crashes with ZeroDivisionError on an empty inventory; also uses a mutable default argument.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Cart
    participant Inventory

    Cart->>Inventory: restock("widget", 3)
    Inventory-->>Cart: "(stock["widget"] = 3)"

    Cart->>Inventory: reserve("widget", 5)
    Note over Inventory: current=3, checks current > 0
    Inventory-->>Cart: True (incorrect, stock now -2)

    Cart->>Inventory: available("widget")
    Inventory-->>Cart: -2 (negative stock)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Cart
    participant Inventory

    Cart->>Inventory: restock("widget", 3)
    Inventory-->>Cart: "(stock["widget"] = 3)"

    Cart->>Inventory: reserve("widget", 5)
    Note over Inventory: current=3, checks current > 0
    Inventory-->>Cart: True (incorrect, stock now -2)

    Cart->>Inventory: available("widget")
    Inventory-->>Cart: -2 (negative stock)
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
inventory.py:18-19
**Insufficient stock check allows negative inventory.** The guard only checks `current > 0`, not `current >= quantity`. A call like `reserve("widget", 5)` when only 1 unit is stocked will succeed and set the stock to `-4`, silently corrupting the ledger for all future callers.

```suggestion
        if current >= quantity:
            self._stock[name] = current - quantity
```

### Issue 2 of 3
inventory.py:27-28
**`ZeroDivisionError` when inventory is empty.** If `average_per_sku()` is called with no arguments on an empty `Inventory`, `names` falls through to `list(self._stock.keys())` which is `[]`, and `len(names)` is `0`, causing an unhandled division by zero.

```suggestion
        if not names:
            return 0
        total = sum(self.available(n) for n in names)
        return total / len(names)
```

### Issue 3 of 3
inventory.py:23
**Mutable default argument.** `names=[]` is a classic Python footgun — the list object is created once at function-definition time and shared across all calls. Any caller that mutates `names` inside the function would affect future calls. Prefer `None` as the sentinel and assign an empty list in the body.

```suggestion
    def average_per_sku(self, names=None):
```

Reviews (1): Last reviewed commit: "Add inventory tracking with reserve supp..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread inventory.py
Comment on lines +18 to +19
if current > 0:
self._stock[name] = current - quantity

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 Insufficient stock check allows negative inventory. The guard only checks current > 0, not current >= quantity. A call like reserve("widget", 5) when only 1 unit is stocked will succeed and set the stock to -4, silently corrupting the ledger for all future callers.

Suggested change
if current > 0:
self._stock[name] = current - quantity
if current >= quantity:
self._stock[name] = current - quantity
Prompt To Fix With AI
This is a comment left during a code review.
Path: inventory.py
Line: 18-19

Comment:
**Insufficient stock check allows negative inventory.** The guard only checks `current > 0`, not `current >= quantity`. A call like `reserve("widget", 5)` when only 1 unit is stocked will succeed and set the stock to `-4`, silently corrupting the ledger for all future callers.

```suggestion
        if current >= quantity:
            self._stock[name] = current - quantity
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread inventory.py
Comment on lines +27 to +28
total = sum(self.available(n) for n in names)
return total / len(names)

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 ZeroDivisionError when inventory is empty. If average_per_sku() is called with no arguments on an empty Inventory, names falls through to list(self._stock.keys()) which is [], and len(names) is 0, causing an unhandled division by zero.

Suggested change
total = sum(self.available(n) for n in names)
return total / len(names)
if not names:
return 0
total = sum(self.available(n) for n in names)
return total / len(names)
Prompt To Fix With AI
This is a comment left during a code review.
Path: inventory.py
Line: 27-28

Comment:
**`ZeroDivisionError` when inventory is empty.** If `average_per_sku()` is called with no arguments on an empty `Inventory`, `names` falls through to `list(self._stock.keys())` which is `[]`, and `len(names)` is `0`, causing an unhandled division by zero.

```suggestion
        if not names:
            return 0
        total = sum(self.available(n) for n in names)
        return total / len(names)
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread inventory.py
return True
return False

def average_per_sku(self, names=[]):

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 Mutable default argument. names=[] is a classic Python footgun — the list object is created once at function-definition time and shared across all calls. Any caller that mutates names inside the function would affect future calls. Prefer None as the sentinel and assign an empty list in the body.

Suggested change
def average_per_sku(self, names=[]):
def average_per_sku(self, names=None):
Prompt To Fix With AI
This is a comment left during a code review.
Path: inventory.py
Line: 23

Comment:
**Mutable default argument.** `names=[]` is a classic Python footgun — the list object is created once at function-definition time and shared across all calls. Any caller that mutates `names` inside the function would affect future calls. Prefer `None` as the sentinel and assign an empty list in the body.

```suggestion
    def average_per_sku(self, names=None):
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant