Paradaux

PAR-234

0

chestshop_sale.txn_id is never populated (100% NULL) — link sales to their ledger txn

BacklogUnassignedChestShopBug

Finding (prod)

In the democracycraft prod economy DB, all 787,092 chestshop_sale rows have txn_id = NULL (SELECT COUNT(*) WHERE txn_id IS NOT NULL → 0). So the analytics sales table is completely unlinked from the authoritative ledger — you can't drill from a recorded sale to the money movement, reconcile a sale's total_price against the ledger posting, or join chestshop_sale → ledger_txns. The idx_cs_txn index is therefore indexing an all‑NULL column (dead weight). Assume statecraft is the same (same capture path).

Root cause

The plumbing already exists end‑to‑end on the Treasury side:

  • ChestShopSaleRecord.txnId (treasury-api/.../market/ChestShopSaleRecord.java) — documented "nullable if unlinkable".
  • MarketApiImpl.recordSale passes s.txnId(); ChestShopMarketMapper.insertSale writes txn_id.

The gap is the caller: ChestShop‑3's MarketListener/MarketHook builds the ChestShopSaleRecord with txnId = null. Under the current Vault subtract/deposit two‑hop bridge (see PAR‑158) a sale isn't a single transfer — it's two SYSTEM‑bridged txns (buyer→ChestShop System, System→seller) — so there's no single clean txn id to attach, which is exactly why it's always left null.

Fix

Best done as part of / right after PAR‑158 (switch player‑shop sales to a native TreasuryApi.transfer(buyer→seller)): thread the transfer's resulting txn_id into the ChestShopSaleRecord so recordSale persists it. For admin/server shops (single faucet/sink leg, no buyer→seller), link that leg's txn id.

Value

Sale→ledger drill‑through, sale‑vs‑posting reconciliation, makes idx_cs_txn useful (or lets us drop it), and gives PAR‑159's two‑hop pairing a direct key instead of fuzzy matching.

Acceptance

  • New player‑shop sales record a non‑null txn_id that matches the ledger transfer; admin‑shop sales link their faucet/sink txn.
  • The explorer/analytics can join chestshop_sale.txn_id → ledger_txns.txn_id.

Backfilling the existing ~787K NULL rows is the sibling task (see linked backfill issue). Related: PAR‑158 (forward single‑transfer fix), PAR‑159 (two‑hop collapse in explorer views).

Resources

Comments

tesks · Jun 18, 2026, 9:05 PM

Sibling backfill task for the existing ~787K NULL rows: PAR-235. Both share the ledger‑pairing logic with PAR-159 and are gated by the PAR-158 single‑transfer fix.

Activity

  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a pull request — PR #2 open — Last major release
  • ParadauxIO linked a commit — Commit 0e659ef — Migrate logging to slf4j (@Slf4j); drop the shop file-log (PAR-309)
  • ParadauxIO linked a commit — Commit 95d4f40 — Link recorded ChestShop sales to their ledger txn (PAR-234)
  • tesks commented
  • tesks created the issue