Dev console

Six tools that answer "why is this number this number" without opening a psql session. Read-only by default. Every action is written to the audit log before it executes.

Read-only ON Acting as ahmad@minimalist.ae · role admin · derived persona owner Session dev-01K1BC · started 16:38 GST · expires 17:38 Writes this session 0 needs an approver
There is no free-SQL runner on this page. The ledger console accepts a query object and compiles it to SQL, which is shown for auditability but cannot be edited. DROP, TRUNCATE and an unqualified DELETE are not forbidden here, they are unexpressible. Guardrail config →
Ledger query console read-only by construction ran against cut L-4,182,993 · 214 ms · 12 rows
Entity
Filter
Group Measure
Compiled SQL · shown for auditability · not editable
-- compiled from query_object 9f2a1b0d · engine forbids any statement other than SELECT
SELECT  st.code AS stock_type,
        le.source_type,
        SUM(le.quantity_delta) AS qty_delta,
        COUNT(*)                 AS entries
FROM    ledger_entries le
JOIN    skus s        ON s.id = le.sku_id
JOIN    stock_types st ON st.id = le.stock_type_id
WHERE   s.sku_code   = 'MST-CRM-42-BLK'
  AND   le.location_id IN (1, 3)              -- HQ_319, MCC
  AND   le.occurred_at >= '2026-07-01'
  AND   le.id <= 4182993                    -- cut id, so a re-run is reproducible
GROUP BY st.code, le.source_type
ORDER BY st.code, le.source_type;
Stock typeSource typeQty deltaEntriesFirst seenLast seen
STOCKorder_sale-28428401-07 06:1229-07 15:48
STOCKrefund_restock+413802-07 11:0428-07 09:22
STOCKgrn_receipt+420308-07 07:4024-07 08:02
STOCKtransfer_out-96805-07 14:1026-07 13:38
STOCKtransfer_in+96806-07 09:2227-07 10:14
STOCKstock_count_adjust-6214-07 18:0228-07 17:44
IN_TRANSIT_CUSTOMERfulfillment_create+28428401-07 06:1229-07 15:48
IN_TRANSIT_CUSTOMERdelivery_confirmed-26826803-07 11:2029-07 12:04
IN_TRANSIT_INTERNALtransfer_ship+96805-07 14:1026-07 13:38
IN_TRANSIT_INTERNALtransfer_receive-96806-07 09:2227-07 10:14
IN_TRANSIT_RETURNreturn_carrier_confirmed+524902-07 10:4428-07 08:18
QUARANTINEreturn_quarantine+524902-07 10:4428-07 08:18
QUARANTINEquarantine_release-413802-07 11:0428-07 09:22
GIT_INBOUNDpi_shipped+420301-07 04:0018-07 04:00
RECEIVED_NOT_INVOICEDgrn_receipt+420308-07 07:4024-07 08:02
ON_TRIALtrial_out+4411-07 16:3025-07 12:08
No stock_count_confirm rows exist and none can: a clean count moves nothing, and a zero-delta ledger row is forbidden. The 2 stock_count_adjust rows above are the variances only. The 9 clean counts on this SKU are in balance_verifications, which is where any report counting verified balances must read.
Event replay has side effects 5/min/user
event_id
evt_shopify_refund_01K1B7Q4ZC9MDF3P
topic
refunds/create
source
shopify · minimalistae.myshopify.com
received_at
28-07-2026 09:22:14 GST
reference
#MIN10482 · line 3 · CSD-4821
HMAC
verified · sha256 4a12…e2f7 · constant-time
raw body
1,284 bytes
clock skew
+2s · within the 300s window
classifier
refund_restock · confidence 0.94 · rule R-14.08
recipe pinned
recipe_id 118 rev 3 · the version the sale used
idempotency_key
shopify:refund:8829104432:3
ledger rows produced
2 · QUARANTINE +1 / IN_TRANSIT_RETURN -1
production needs an approver
WhenEventTargetResult
29-07 16:28evt_shopify_order_paid_01K1BC7Xstaging200
29-07 16:11evt_ops2_carton_moved_01K1BAF2prodsuppressed
29-07 15:52evt_grn_receipt_01K1B9Y0A8staging200
29-07 14:14evt_rfid_gate_read_01K1B7T0W9prod429
28-07 22:03evt_csd_case_transition_01K19XZ1shadow200
28-07 19:37evt_iwms_qc_outcome_01K19R2Gprod500
28-07 11:48evt_shopify_refund_01K18WSP00prod200
A replay never bypasses idempotency. suppressed is the correct outcome for a key that already posted, not an error, and it names the original row id.
Idempotency-key lookup read-only produced and suppressed
3 of 4 deliveries were suppressed. The key has no receipt sequence, so every tranche after the first computes the same key and is deduplicated away. 1,072 units were never posted.
SeqReceivedQtyOutcomeLedger row
108-07 07:40108postedL-3,918,204
214-07 06:12402suppressednone · dedup to L-3,918,204
319-07 08:22388suppressednone · dedup to L-3,918,204
424-07 08:02282suppressednone · dedup to L-3,918,204
The i3 key, for the same four deliveries
-- incumbent, keyed on the PO LINE: the second tranche is a replay
idem_key = f"receipt:{po_code}:{line['id']}"

-- i3, keyed on the RECEIPT identity: each GRN is its own event
idem_key = f"grn:{grn_number}:{line_id}"

-- so the four rows above become four postings:
grn:GRN-2026-0708:4812   -> +108
grn:GRN-2026-0714:4812   -> +402
grn:GRN-2026-0719:4812   -> +388
grn:GRN-2026-0724:4812   -> +282
Chain verification read-only names the first broken row, not just "invalid"
Journal Range
JournalRowsTookValidFirst bad idNote
ledger_entries4,182,9933m 09syes-full chain, genesis to cut
ledger_entries · i2 replay587,41242syes-balance_after computed at import, ordered by (occurred_at, id)
cost_ledger118,40211syes-value journal, 4 entry kinds
unit_ledger1,842,1181m 18syes-EPC serial hops
audit_log248,90414syes-infinite retention
ledger_entries · corruption test1,0000.2snoL-742deliberately corrupted fixture, detected at the right row
cost_ledger · corruption test5000.1snoC-118deliberately corrupted fixture, detected
unit_ledger · gap test2,0000.3snoU-1,204a skipped lifecycle hop, detected as a chain break
Corruption-test detail · what a break looks like
-- fixture FIX-2026-07-29-004, row 742 mutated by one unit
journal        : ledger_entries
first_bad_id   : 742
prev_hash      : 9c1f4a2e7b8d0c35  (matches row 741 row_hash, so the link is intact)
expected_hash  : "4b7e1c9a2f0d8365"  sha256(prev_hash || core fields)
actual_hash    : "4b7e1c9a2f0d8365"  stored value agrees with itself...
recomputed     : "e2a5f81b6c704d92"  ...but not with the row's own columns
mutated_column : quantity_delta  -2 -> -3
verdict        : row_hash was NOT recomputed after the mutation, so the
                 tamper is visible. Rows 743+ still chain to 742's stored
                 hash, which is why the FIRST bad id is the useful answer.

Verification history

nightly 04:00 · 30 days · rows per second
28,000 rows/sec 21,000 rows/sec 14,000 rows/sec 7,000 rows/sec Throughput rising as the partial index landed on 18-07 30 consecutive nights valid 16-07: run aborted at 78% when the worker was redeployed mid-pass. Not a break, an incomplete pass, and recorded as such rather than as a pass validity strip 18-07: partial index on (journal, id) cut the full pass from 7m to 3m
30-0607-0714-0721-0729-07
Passes recorded
30 of 30 nights
Valid
29 · one incomplete
Incomplete counts as
not a pass
Breaks ever found
0 in production
Fixtures detected
3 of 3
Projection debugger read-only · never writes how one balance was computed, row by row
Key Window
Divergence found at L-4,180,882. Cache says 42, the chain says 44. The cache row is marked is_reconciled = false and this key is therefore excluded from every total and every valuation until a compensating row closes it. This console will not, and cannot, write the cache back into agreement. Draft compensating pair →
Ledger idOccurredSource type Reference Delta Running balance_after Cache AgreeNote
L-4,178,20422-07 09:12opening_carryclose 2026-06-616161yescarried from the frozen June close
L-4,178,44122-07 11:04order_sale#MIN10402 line 1-2595959yes-
L-4,178,90223-07 08:22order_sale#MIN10411 line 2-1585858yes-
L-4,179,11823-07 14:38transfer_receiveTR-0921 HQ_319+12707070yesIN half of a movement pair
L-4,179,40224-07 10:14order_sale#MIN10428 line 1-3676767yes-
L-4,179,68824-07 16:02display_allocateMCC window-4636363yespaired DISPLAY_GOOD +4
L-4,179,91225-07 09:44trial_outON_TRIAL · staff-1626262yesON_TRIAL is owned, not sellable
L-4,180,20425-07 15:20refund_restockCSD-4802 line 1+2646464yesout of QUARANTINE after a physical scan
L-4,180,44126-07 08:18order_sale#MIN10444 line 3-6585858yes-
L-4,180,60226-07 13:38transfer_shipTR-0937 to YAS-8505050yesOUT half, pair id MP-2841
L-4,180,74427-07 10:02order_sale#MIN10461 line 1-4464646yes-
L-4,180,88227-07 17:44stock_count_adjustCNT-0188 MCC-2444442nocache double-applied the variance. First divergent row
L-4,181,20428-07 09:22refund_restockCSD-4821 line 3+1454543nooffset persists, exactly 2
L-4,181,60228-07 14:10order_sale#MIN10474 line 2-1444442nooffset persists
L-4,182,11829-07 11:48order_sale#MIN10481 line 1-2424240nooffset persists
L-4,182,90429-07 15:48display_returnMCC window rotate+2444442nocurrent state · delta -2

Chain versus cache

the gap opens once and never closes on its own
72 units 62 units 52 units 42 units Chain balance from balance_after: ends at 44 Cached balance: diverges at row 12 and ends at 42 The 2-unit gap, from L-4,180,882 onward L-4,180,882 First divergent row: the count variance was applied twice to the cache
chain · balance_after cache · inventory_balance.qty gap 2 units · AED 340 at layer cost

Why this tool exists

The incumbent backbone has no running-balance column at all. A grep for balance_after across every migration and every Python file in i2 returns zero occurrences. The cache did not drift away from a check that existed and was skipped: there was never anything to check against.

So balance_after is a new invariant in i3, not a restored one. Nobody has ever seen it work, and a column nobody trusts is a column nobody uses. This tool exists to make it inspectable: pick any key, see every row that built it, and watch the two numbers agree or not.

It also fixes nothing, deliberately. An unreconciled key drops out of every total and stays out until a compensating pair closes it. A console that could quietly write the cache back into agreement would recreate the exact failure it is here to detect.

Keys sampled nightly
500 random plus all recently moved
Divergent today
1 of 500
Excluded from totals
4 keys · 118 units
Repair path
compensating pair only
This console writes
never
i2 replay ordering
(occurred_at, id), recorded
Fixture generator staging and shadow only seeded · idempotent · revertible
Scenario
Target Seed Events
BatchScenarioTargetEventsSeedStateWhat it proves
FIX-2026-07-29-004composite_sale_then_partial_refundstaging2488104liverefund replays the pinned recipe, not the live one
FIX-2026-07-29-003split_delivery_four_tranchesstaging841022liveall four tranches post, none deduplicated away
FIX-2026-07-29-002clean_count_no_variancestaging1270118livea clean count writes a verification, never a zero-delta row
FIX-2026-07-28-006cost_revision_after_closeshadow610488revertedfrozen period unchanged, adjustment lands in the open one
FIX-2026-07-28-005transfer_half_pair_orphanstaging422841reverteda half-move cannot commit
FIX-2026-07-28-004exchange_pair_size_swapstaging1064012revertedone anchor key, two legs, no double deduction
FIX-2026-07-28-003sku_rename_orphans_tagsstaging1833907revertedunit ledger survives a rename because it keys on sku_id
FIX-2026-07-27-002chain_corruption_single_rowstaging100074210revertedverifier names the right first bad id
FIX-2026-07-27-001balance_cache_double_applystaging1618088reverteddivergent key is excluded, not repaired
FIX-2026-07-26-003rni_ownership_monotonicshadow950204revertedowned_qty does not dip when a pallet lands
FIX-2026-07-26-002carrier_status_cannot_creditshadow791104reverteda returned string moves units to QUARANTINE, never STOCK
FIX-2026-07-26-001composite_parent_never_holdsstaging1442188revertedbalance(composite) = 0 at every location and type
Same seed gives the same events, so a scenario is a regression test rather than an anecdote. Revert writes compensating rows carrying the batch code; it never deletes. A fixture that cannot be undone is a production write with a friendly name.
Guardrails enforced in code
Dual approvalAny production write · replay to production · flag promotion to authoritative · secret rotation · reopening a filed close. Approval tokens are valid 15 minutes and route through alert.raise, never a direct Slack post.
Rate limitedReplay 5/min/user · ledger query 30/min · API 120/min · chain verify 2/hour on the full range. A 429 is recorded in the activity log like any other outcome.
Always allowedLedger queries on the replica · flag reads · chain verify on a bounded range · projection debug · idempotency lookup · fixture generate against staging.
Never allowed, and unexpressibleDROP · TRUNCATE · DELETE without a predicate · raw shell · a fixture targeting production · writing the balance cache · revealing a secret value.
Secrets on this page
HeaderRendered as
AuthorizationBearer <SSO session>
X-I3-Signature<computed server-side>
I3_WEBHOOK_SECRET[see ~/.env.master]
SSO_JWT_SECRET[see ~/.env.master]

A masked value with a real prefix and a real last-four is still a disclosure: it confirms the key family, the environment and enough of the tail to correlate against a leaked log. The secret registry has no value column, so there is nothing here to leak by accident.

Activity log last 14 · written before the action executes, so a crash is still audited · retained 180d Full audit log
WhenActorActionTargetLatencyReadWroteResult
16:42:18ahmad@minimalist.aeledger_queryledger_entries · MST-CRM-42-BLK214ms160ok
16:41:04ahmad@minimalist.aeprojection_debugMST-CRM-42-BLK / MCC / STOCK88ms160divergent
16:28:52ahmad@minimalist.aeevent_replayevt_shopify_order_paid_01K1BC7X to staging164ms12200
16:22:04i3-worker@systemchain_verifyledger_entries 1 to 4,182,9933m 09s4.18M0valid
16:11:18ahmad@minimalist.aeevent_replayevt_ops2_carton_moved_01K1BAF2 to prod98ms10suppressed
15:58:30fatima@minimalist.aeidem_lookupinv1 · receipt:PO-2026-118:481242ms40ok
15:52:11ahmad@minimalist.aefixture_generateFIX-2026-07-29-004 to staging1.2s024ok
15:14:44omar@minimalist.aeledger_queryclose_lines · 2026-07 residual308ms880ok
14:14:40ahmad@minimalist.aeevent_replayevt_rfid_gate_read_01K1B7T0W9 to prod78ms10429
13:51:09omar@minimalist.aeflag_flipRFID_UNIT_LEDGER shadow requested authoritative-00blocked · gate
12:38:02fatima@minimalist.aeprojection_debugMIN-2159 / HQ_319 / STOCK104ms420agrees
11:04:22ahmad@minimalist.aefixture_revertFIX-2026-07-28-006 · 6 compensating rows640ms66ok
09:22:14i3-worker@systemchain_verifycost_ledger 1 to 118,40211s118K0valid
08:14:51rania@minimalist.aeledger_querybalance_verifications · MCC last 30d62ms280ok
Two write rows in fourteen, both fixtures against staging. flag_flip at 13:51 was refused by a database CHECK, not by the UI: RFID_UNIT_LEDGER is bound to GATE-6, and GATE-6 has held for 0 days.

No session activity yet

You have opened the console but run nothing. Every tool here is read-only until you request write access, so there is no risk in starting: pick a SKU and location in the projection debugger, or paste an event id into replay. The activity log will fill from your first query.

Read replica unreachable

POST /api/dev/ledger-query returned 503. The console reads the replica by design and will not fall back to the primary, because an unbounded exploratory query against the write path is how a debugging session becomes an incident. Retry, or narrow the range and try again in a minute.

Projection debugger only

The console needs role = admin plus the dev_console feature. You have ops_manager, so the projection debugger and the idempotency lookup are available read-only and every other tool is hidden. Those two are safe for any operator because neither can write and both only explain numbers you can already see. Role mapping →

Replay and fixtures paused

Postgres minor upgrade, 02:00 to 02:40 GST. Read tools stay available against the replica. Replay and fixture generation are paused because an event landing mid-failover could commit its ledger row and lose its outbox row, which is the split-write i3 exists to prevent.

Unit-ledger tools are gate-blocked behind GATE-6

The unit_ledger entity in the query console and the serial branch of the projection debugger need GATE-6 to have held for 7 days. It has held 0. Both are still listed and still queryable in shadow, and every result carries a not authoritative stamp, so you can watch the unit and quantity ledgers converge instead of waiting blind. Gate tracker →

Connected to Ops health Settings + flags Reports + close Cash + valuation Audit log Shopify events Sibling events Drift Corrections Counts Help + glossary
⌘↵ run · Q query · R replay · I idempotency · V verify chain · P projection · F fixtures · ⌘K palette Query history 30d · activity log 180d · replay history 90d · bookmarks per user