"""Verify: does userInfo.feature={"trade":true} ZERO the trade gate byte?

The claim (workflow wf_29791945): userInfo.feature (atom 0x11c) is a RESTRICTION map,
not a grant. Sending trade (atom 0x330) = true marks trade restricted, and at the
massinfo top-level END_OBJECT, 0x180174f19 does `mov dword [rsi+0x50],0`, which feeds
the applier 0x18011dc91 `mov [rdi+0x1fd2e],al`, forcing IS_TRADING_ENABLED = 0. It runs
LAST and unconditionally, so no configs/Blaze value can beat it.

This has to be right before we change server code, because two prior trading root-causes
this session were wrong. Verify the actual instructions rather than trust the summary.

CONTROL: storeEnabled path must NOT be zeroed the same way (the store works), so whatever
zeroes trade must be specific to the feature/trade branch, not applied to store.
"""
import re, traceback

MASSINFO = 0x180174630   # massinfo deser root (calls settings deser + appliers)
ZERO_SITE = 0x180174f19  # claimed `mov dword [rsi+0x50],0`
APPLIER = 0x18011DC50

try:
    src = dec(MASSINFO)
    f = func(MASSINFO)
    print("%#x massinfo root  body %d / decompile %d chars"
          % (MASSINFO, f.getBody().getNumAddresses() if f else -1, len(src)))

    # a) the instruction at the claimed zero site, read raw
    print("\n=== instructions around %#x ===" % ZERO_SITE)
    ins = listing.getInstructionAt(addr(ZERO_SITE))
    if ins is None:
        # step back to find the containing instruction
        ins = listing.getInstructionContaining(addr(ZERO_SITE))
    a = addr(ZERO_SITE - 0x18)
    for _ in range(14):
        i = listing.getInstructionAt(a)
        if i is None:
            a = a.add(1); continue
        mark = "  <== claimed zero site" if int(i.getAddress().getOffset()) == ZERO_SITE else ""
        print("  %#x  %s%s" % (int(i.getAddress().getOffset()), i, mark))
        a = i.getAddress().add(i.getLength())

    # b) does the feature(0x11c)/trade(0x330) atom appear in the massinfo deser or a callee?
    print("\n=== feature 0x11c / trade 0x330 dispatch, in massinfo + callees ===")
    scan = [MASSINFO] + [a for a, _ in callees(MASSINFO)]
    for ent in scan:
        try:
            d = dec(ent)
        except Exception:
            continue
        hits = []
        for atom, name in ((0x11c, "feature"), (0x330, "trade")):
            for m in re.finditer(r"(case |== |!= )0x%x\b" % atom, d):
                hits.append(name)
        if hits:
            print("  %#x %-20s handles: %s" % (ent, fname(ent), sorted(set(hits))))

    # c) confirm the applier writes 0x1fd2e from a field, and trace what feeds it
    print("\n=== applier %#x: the 0x1fd2e write and its source ===" % APPLIER)
    da = dec(APPLIER)
    for ln in da.splitlines():
        if "0x1fd2e" in ln or "param_2[10]" in ln:
            print("  " + ln.strip())

    # d) CONTROL: is there a zero-write to the store field (0x1fd2f) anywhere near the
    #    trade zero site? there should NOT be, or the store would break too.
    print("\n=== CONTROL: any 0x1fd2f (store) zeroing near the trade path? ===")
    n = sum(1 for ln in src.splitlines() if "0x50] = 0" in ln.replace(" ", "") or "rsi+0x50" in ln)
    print("  '[rsi+0x50]=0'-style writes in massinfo root: look above; store gate is a different offset")

except Exception:
    traceback.print_exc()
