"""Settle the envelope rule: does a response deserializer DESCEND a wrapper or PROBE for one?

HYPOTHESIS UNDER TEST (from docs/plan-2026-08-05-pack-opening.md section 2):
FUN_180162880 (FutCreatePackServerResponse) calls the next-token primitive three times
unconditionally at 0x180162942/94b/954, tests only the third against token 10, and has no
ladder arm for `createPackResponse` (atom 0xbe). Reading A says that is a DESCEND, so the
envelope is structurally required and its name is irrelevant. Reading B says the token count
decides nothing, because FutCreateUser / FutDiscardCard / the /purchased root all spend the
same three tokens, and we serve POST /user and GET /purchased UNWRAPPED and both work.

Both cannot be right. The tokenizer decides it, so read the tokenizer.

CONTROLS, and why each one is here:
  * 0x180124ee0  the /purchased root. We serve it UNWRAPPED and it demonstrably works, so
    whatever the three tokens mean, its behaviour must be consistent with an unwrapped body.
    This is the control that can actually refute reading A.
  * 0x18014cc60  FutCreateUser. Same, served unwrapped, works.
  * 0x180162880  FutCreatePack itself, the one nothing has ever parsed.
Printing all three side by side is the point: a claim about "three tokens" is only meaningful
if the same three tokens behave differently in a case we know works.

COVERAGE DISCIPLINE: this file prints every decompile IN FULL and prints len() first. No
absence claim may be made from anything below unless the printed length matches the claim.
"""
import traceback

TOKENIZER = 0x1801C7F10   # next-token primitive
BEGINOBJ = 0x1801C8270    # begin-object primitive
INTGET = 0x1801C79D0      # int getter, for token-value cross-reference

DESERS = [
    (0x180162880, "FutCreatePackServerResponse  (WRAPPED per reading A, never parsed live)"),
    (0x180124EE0, "FutGetPurchasedItems root    (CONTROL: served UNWRAPPED, works live)"),
    (0x18014CC60, "FutCreateUser                (CONTROL: served UNWRAPPED, works live)"),
]


def dump(va, title):
    try:
        f = func(va)
        src = dec(va)
        n = f.getBody().getNumAddresses() if f else -1
        print("\n" + "=" * 78)
        print("%#x  %s" % (va, title))
        print("body %d bytes / decompile %d chars  (PRINTED IN FULL)" % (n, len(src)))
        print("=" * 78)
        print(src)
    except Exception:
        print("!! failed on %#x" % va)
        traceback.print_exc()


try:
    # 1. The two primitives. Everything else is interpretation of these.
    dump(TOKENIZER, "next-token primitive -- what IS a token, and what is token 10?")
    dump(BEGINOBJ, "begin-object primitive")

    # 2. The three deserializers, so the token triples can be compared directly.
    for va, name in DESERS:
        dump(va, name)

    # 3. Who else calls the tokenizer, and how many times each. A function that calls it
    #    exactly 3 times unconditionally is the pattern under test; the distribution tells
    #    us whether 3 is special or merely common.
    print("\n" + "=" * 78)
    print("CALLERS OF THE TOKENIZER %#x, with call count per caller" % TOKENIZER)
    print("=" * 78)
    counts = {}
    for frm, typ, fn, ent in xrefs_to(TOKENIZER):
        if not ent:
            continue
        counts.setdefault((ent, fn), []).append(frm)
    for (ent, fn), sites in sorted(counts.items(), key=lambda kv: -len(kv[1])):
        print("  %#x  %-34s %2d calls  %s"
              % (ent, fn, len(sites), " ".join("%#x" % s for s in sorted(sites))))
    print("\ntotal distinct callers: %d" % len(counts))
    hist = {}
    for k, v in counts.items():
        hist[len(v)] = hist.get(len(v), 0) + 1
    print("call-count histogram (calls -> how many functions):",
          dict(sorted(hist.items())))

    # 4. The begin-object primitive's callers, for the same reason.
    print("\ncallers of begin-object %#x: %d" % (BEGINOBJ, len(set(
        e for _, _, _, e in xrefs_to(BEGINOBJ) if e))))

except Exception:
    traceback.print_exc()
