The seven laws, every stock type, the ledger vocabulary, and what to do when a number looks wrong · last reviewed 29 July 2026
Every one of them exists because something specific broke. The red line is what it prevents.
Three dimensions. A unit is in exactly one type at any instant, at exactly one location. Moving between types is a ledger row, never an edit.
| Stock type | Dimension | Sellable | Owned by | Enters on | Leaves on | Where you see it |
|---|---|---|---|---|---|---|
| STOCK | Condition | yes | i3 | GRN accept, return restock, transfer receive | sale, transfer out, damage, write-off | inventory-live |
| DISPLAY_GOOD | Condition | store only | Retail | display allocation at a store | quick-sell, return to stockroom, damage | location-detail |
| DISPLAY_DAMAGED | Condition | no | Retail | display unit found damaged | triage to repair, write-off or discount sale | damages |
| QUARANTINE | Condition | no | QC | QC hold, suspect batch, customer claim | QC decision to any of 5 buckets | grn |
| WRITTEN_OFF | Condition | no | Finance | approved write-off only | terminal · nothing leaves | damages |
| IN_TRANSIT_CUSTOMER | Custody | no | ops2 | dispatch scan, gate verify | delivered, NDR, RTO | rfid |
| IN_TRANSIT_RETURN | Custody | no | CSD / ops2 | return AWB created and picked up | returns scan at HQ_319 | returns |
| LOST_IN_TRANSIT | Custody | no | ops2 | carrier declares loss, or 21d no scan | claim settled, or found | drift |
| RTS_PENDING | Custody | no | Ops | staged for return to supplier | RTS shipped to supplier | rts |
| RESERVED | Custody | held | CSD | hold placed for an exchange or a VIP | hold released, or converted to a sale | returns |
| RECEIVED_NOT_INVOICED | Custody | no | Finance | GRN posted before the supplier invoice | invoice booked · 72h SLA | grn |
| INFLUENCER_POOL | Program | no | Marketing | allocation to the influencer pool | loan dispatched, gifted, or returned to STOCK | influencer |
| SAMPLE_POOL | Program | no | Marketing | sample classified as pool after QC | consumed, gifted, or returned to STOCK | samples |
| SAMPLE_QC | Program | no | Marketing | sample received from a supplier | classified within 72h to POOL or STOCK | samples |
| IN_PRODUCTION | Condition new | no | i3 | PO line confirmed into factory WIP | PI issued, moves to GIT_INBOUND | production |
| GIT_INBOUND | Custody new | no | i3 | PI shipped, goods left the supplier | GRN receipt at HQ_319 | git |
These 18 words explain almost every "the number looks wrong" question. Learn them once.
Work down the tree. Stop at the first yes. Nine cases out of ten it is one of the first three nodes.
Last 90 days · 214 "the number is wrong" reports, by root cause
A phase closes only when its gate holds for 7 consecutive days. Today is GATE-1 day 6.
| Gate | Phase | What it tests | Threshold | Measured now | Status | Pages behind it |
|---|---|---|---|---|---|---|
| GATE-0 | Foundation + opening balance | Opening balances signed per location, hash chain verifies | within 1% of Shopify total | 0.31% | passed 22-07 | opening-stock |
| GATE-1 | Sales and cancellations | i3 sellable vs Shopify available per location-day | < 0.10% · classifier ≥ 99.5% | 0.04% · 99.7% | day 6 of 7 | inventory-live, shopify-events |
| GATE-2 | Returns, exchanges, repairs | Every ops2 returns-scan and CSD replacement has a posting or an open case | reverse drift < 0.2% | not started | locked | returns, repairs |
| GATE-3 | Inbound: PO, PI, GIT, GRN, QC | GRN receipts post within 5 minutes, PO expected vs received reconciles | 100% within 5 min | not started | locked | inflows, grn |
| GATE-4 | Transfers, retail, consignment | In-transit balance nets to zero per completed transfer | store count vs ledger < 0.5% weekly | not started | locked | transfers, consignment |
| GATE-5 | IWMS physical layer | Carton sum vs quantity ledger in HQ zones | < 0.5% | not started | locked | cartons |
| GATE-6 | RFID serial layer | Unit count equals quantity ledger for serialized SKUs at HQ | 7 days · gate catch > 99% | shadow · 91% tagged | shadow | rfid, rfid-recon |
| GATE-7 | Programs | Influencer pool matches the Hub, every damage has an incident | exact match | not started | locked | influencer, damages |
| GATE-8 | Intelligence and finance | Monthly close reproducible from the ledger alone | finance signs one full month | not started | locked | reports |
When two systems disagree about one fact, this table decides. It is not negotiable per case.
| Fact | Authority | i3 does what |
|---|---|---|
| Order or refund exists | Shopify | accepts, never invents an order |
| Sellable and available | Shopify | cross-checks daily, writes back only after cutover |
| Dispatch, AWB, carrier events | ops2 | consumes, never creates an AWB |
| Return intent and case linkage | CSD | consumes the decision, owns the stock effect |
| Physical receipt | GRN / IWMS | posts the receipt as a ledger row |
| Carton, zone and bin position | IWMS | mirrors, does not move cartons |
| Physical presence of a serial | RFID | a gate read is immutable and wins |
| PO, PI, production status | i3 | owns it outright |
| Financial write-off approval | Finance | records the approval, cannot self-approve |
| What an event means for stock | i3 | owns it outright · law 6 |
One registry. This table and the ? dialog render from the same source, so they cannot drift apart.
| Keys | Action | Scope | Needs |
|---|---|---|---|
| ⌘ K | Open the command palette | global | viewer |
| / | Focus the page filter | any table page | viewer |
| ? | Show this shortcut list | global | viewer |
| Esc | Close the panel, palette or dialog | global | viewer |
| ⌘ . | Toggle light and dark | global | viewer |
| J K | Next and previous row | any list | viewer |
| Enter | Open the selected row | any list | viewer |
| ⌘ Enter | Open in the side panel without leaving the page | any list | viewer |
| X | Select or deselect the row | any list | viewer |
| E | Mark read | notifications | viewer |
| A | Acknowledge, stops the escalation timer | notifications | manager |
| S | Snooze until a chosen time | notifications | manager |
| M | Mute the rule, expiry and reason required | notifications | ops_manager |
| V | Cycle saved views | any table page | viewer |
| G D | Go to the dashboard | global | viewer |
| G N | Go to notifications | global | viewer |
| G S | Go to live inventory | global | viewer |
| G F | Go to drift | global | viewer |
| G T | Go to transfers | global | viewer |
| G U | Go to the audit log | global | viewer |
Fifteen modules. Each one has a specification at docs/modules/NN-*.md with its own data model, business rules and acceptance criteria.
Sorted by how often it is actually asked. Every answer ends in an action, never in "contact support".
Almost never a code bug. Three causes account for nearly all of them:
Do not overwrite the balance. Open a ledger correction so the compensating row and its reason are on the record.
Shopify is the authority on sellable. i3 is the authority on what happened. Both can be correct at once, because they measure different things.
That is correct behaviour. A composite holds no stock of its own. Its availability is computed as min(child availability) at read time, so one exhausted child takes the whole set to zero.
Check the children on the SKU page hierarchy tree. The limiting child is highlighted. If you expected the composite itself to carry stock, the recipe is wrong, not the balance.
Work in this order:
You should not have. Every alert is unique on (rule_id, dedupe_key, throttle_bucket), so a second producer cannot create a second row. If you genuinely received two, one of these is true:
Correct. Muting suppresses delivery, never the instance. The alerts still accumulate in-app and are still counted, they simply stop reaching Slack and email.
This is deliberate: a mute that hides the record is indistinguishable from a bug, and quiet is not the same as healthy. Every suppressed delivery is logged with a reason.
No. The feature exists and its data is being collected, but its reconcile gate has not held for 7 consecutive days, so the numbers are not yet authoritative. The page shows what it has, marked as shadow.
The gate, its threshold and its current measurement are named on the page and in section 05 above.
Access is per app and per role. Open login and access to see exactly what you hold on app i3, and what the page requires. There are four roles: viewer, manager, ops_manager, admin.
Store-scoped pages also depend on which stores you are rostered at. A manager rostered at two stores sees two.
You do not undo. You post a compensating row, which is a new ledger entry with the opposite delta and a link to what it reverses. The original stays.
This is law 3, and it is why the audit log is trustworthy. A system that lets you delete history cannot tell you what happened.
The quantity ledger says how many, keyed (SKU x location x stock_type). The unit ledger says which ones and where they physically are, keyed by RFID EPC serial.
They are reconciled continuously. Where units exist, the quantity is the count of units. Where they disagree, the gate read wins on physical existence and a drift case records the gap. See 3-way reconcile.