Files
logan 611a1a5952 docs: client-perf analysis, bench harness and work journal
Everything the next agent needs to run the Phase 2 optimisation loop on a
machine that can launch the client:

- analysis/client-perf/: LEVERS (ranked levers + corrections), BENCH-MATRIX
  (world, scenes, config IDs, blocks B0-B14 with decision rules),
  PLAYER-TUNING, SPAWN-TUNING, research briefs, the jar scanner and its
  output, observed default configs, and proposed-configs/ (build.py
  generates tiers and bench variants and fails on unknown keys;
  apply_variant.py applies a variant and merges options.txt).
- analysis/client-perf/bench/onion-bench/: bench-world datapack (scene
  teleports, Create grid, mob pen, sound storm, 120 s teleport tour).
- analysis/audit/: the static recipe/dependency audit, including gen_fixes.py,
  which generates the shipped Paxi datapack and was never tracked.
- phase0/: per-machine measurement harness (Steam Deck, 7700K/1060,
  6700K/1080 Ti).
- .pi/journal.md: running work log; read it first.

All of it is packwizignored, so nothing here ships to players.
2026-10-14 18:15:32 -04:00

145 lines
6.3 KiB
Python

import pickle,json,collections,sys
sys.setrecursionlimit(10000)
exec(open("recipes.py").read().split("# ---------- active recipes")[0].split("# ---------- resource-level")[0]) # imports only
A=pickle.load(open("active.pkl","rb")); active=A["active"]; tagcache=A["tagcache"]
exec(open("recipes.py").read().split("# ---------- ingredients ----------")[1].split("# ---------- active recipes")[0].replace("resolve(","R("))
def full(x): return x if ":" in x else "minecraft:"+x
def R(t): return tagcache.get(t,set())
def ns(x): return x.split(":")[0]
EMPTY=frozenset(["<empty>"])
def shaped(j):
pat=j.get("pattern"); key=j.get("key",{})
if not pat: return None
g=[]
for row in pat:
r=[]
for ch in row:
if ch==" ": r.append(EMPTY)
else:
s=ing(key.get(ch))
if s is None: return None
r.append(s)
g.append(tuple(r))
return tuple(g)
def mirror(g): return tuple(tuple(reversed(r)) for r in g)
def inter(a,b): return bool(a&b)
def grid_match(a,b):
return len(a)==len(b) and len(a[0])==len(b[0]) and all(inter(x,y) for ra,rb in zip(a,b) for x,y in zip(ra,rb))
def bip(a,b):
if len(a)!=len(b): return False
match={}
def tr(i,seen):
for k in range(len(b)):
if k in seen or not inter(a[i],b[k]): continue
seen.add(k)
if k not in match or tr(match[k],seen): match[k]=i; return True
return False
return all(tr(i,set()) for i in range(len(a)))
def out(j):
try: return result(j)
except Exception: return str(j.get("result"))[:80]
groups=collections.defaultdict(list)
for rid,(jar,j) in active.items(): groups[j.get("type","?")].append((rid,jar,j))
print({k:len(v) for k,v in sorted(groups.items(),key=lambda x:-len(x[1]))[:40]})
res=collections.defaultdict(list)
def report(kind,a,b,same):
res[(kind,same)].append((a,b))
# --- crafting: shaped vs shaped, shapeless vs shapeless, shaped vs shapeless ---
SH=[]; SL=[]
for rid,jar,j in groups["minecraft:crafting_shaped"]:
g=shaped(j)
if g: SH.append((rid,g,out(j)))
for rid,jar,j in groups["minecraft:crafting_shapeless"]:
l=[ing(x) for x in j.get("ingredients",[])]
if None in l or not l: continue
SL.append((rid,l,out(j)))
idx=collections.defaultdict(set)
for i,(rid,g,o) in enumerate(SH):
for it in g[0][0]: idx[(len(g),len(g[0]),it)].add(i)
pairs=set()
for i,(rid,g,o) in enumerate(SH):
for gg in (g,mirror(g)):
for it in gg[0][0]:
for k in idx[(len(g),len(g[0]),it)]:
if k>i and grid_match(gg,SH[k][1]): pairs.add((i,k))
for i,k in pairs:
a,b=SH[i],SH[k]; report("shaped",(a[0],a[2]),(b[0],b[2]),a[2]==b[2])
idx=collections.defaultdict(set)
for i,(rid,l,o) in enumerate(SL):
for it in set().union(*l): idx[(len(l),it)].add(i)
pairs=set()
for i,(rid,l,o) in enumerate(SL):
small=min(l,key=len)
for it in small:
for k in idx[(len(l),it)]:
if k>i and bip(l,SL[k][1]): pairs.add((i,k))
for i,k in pairs:
a,b=SL[i],SL[k]; report("shapeless",(a[0],a[2]),(b[0],b[2]),a[2]==b[2])
# shaped vs shapeless (shapeless matches any arrangement with same nonempty cells)
for rid,g,o in SH:
cells=[c for r in g for c in r if c is not EMPTY]
for it in cells[0]:
for k in idx[(len(cells),it)]:
if bip(cells,SL[k][1]): report("shaped~shapeless",(rid,o),(SL[k][0],SL[k][2]),o==SL[k][2])
# --- single-input processing types ---
def single(j):
x=j.get("ingredient")
if x is None and isinstance(j.get("ingredients"),list) and len(j["ingredients"])==1: x=j["ingredients"][0]
return ing(x) if x is not None else None
for t in ["minecraft:smelting","minecraft:blasting","minecraft:smoking","minecraft:campfire_cooking"]:
L=[(rid,single(j),out(j)) for rid,jar,j in groups[t]]
L=[x for x in L if x[1]]
idx=collections.defaultdict(list)
for i,(rid,s,o) in enumerate(L):
for it in s: idx[it].append(i)
seen=set()
for it,ix in idx.items():
for a in ix:
for b in ix:
if a<b and (a,b) not in seen:
seen.add((a,b)); report(t,(L[a][0],L[a][2]),(L[b][0],L[b][2]),L[a][2]==L[b][2])
# cutting board
def tool(j):
t=j.get("tool")
if isinstance(t,dict) and t.get("type","").endswith("ability"): return ("ability",t.get("action") or t.get("item_ability"))
s=ing(t); return ("items",s)
def tools_overlap(a,b):
if a[0]!=b[0]: return False
return a[1]==b[1] if a[0]=="ability" else inter(a[1] or frozenset(),b[1] or frozenset())
for t in [k for k in groups if k.endswith(":cutting")]:
L=[]
for rid,jar,j in groups[t]:
s=ing(j.get("ingredients"));
if s: L.append((rid,s,tool(j),out(j)))
idx=collections.defaultdict(list)
for i,x in enumerate(L):
for it in x[1]: idx[it].append(i)
seen=set()
for it,ix in idx.items():
for a in ix:
for b in ix:
if a<b and (a,b) not in seen and tools_overlap(L[a][2],L[b][2]):
seen.add((a,b)); report(t,(L[a][0],L[a][3],sorted(L[a][1])[:2] if len(L[a][1])>2 else sorted(L[a][1])),(L[b][0],L[b][3]),L[a][3]==L[b][3])
# multi-ingredient machine types (exact multiset w/ overlap): cooking pots, mixers etc
GENERIC=[k for k in groups if not k.startswith("minecraft:") and not k.endswith(":cutting")]
for t in GENERIC:
L=[]
for rid,jar,j in groups[t]:
x=j.get("ingredients") or ([j["ingredient"]] if "ingredient" in j else None)
if not isinstance(x,list): continue
l=[ing(y) for y in x]
if None in l or not l or any(len(s)==0 for s in l): continue
extra=json.dumps({k:j.get(k) for k in ("container","tool","heatRequirement","heat_requirement","processing_time","fluid","inputFluid") if k in j},sort_keys=True)
L.append((rid,l,out(j),extra))
idx=collections.defaultdict(set)
for i,(rid,l,o,e) in enumerate(L):
for it in set().union(*l): idx[(len(l),it)].add(i)
for i,(rid,l,o,e) in enumerate(L):
for it in min(l,key=len):
for k in idx[(len(l),it)]:
if k>i and L[k][3]==e and bip(l,L[k][1]):
report(t,(rid,o),(L[k][0],L[k][2]),o==L[k][2])
pickle.dump(dict(res),open("coll.pkl","wb"))
for (kind,same),l in sorted(res.items()):
print(f"## {kind} {'SAME-OUTPUT(dup)' if same else 'CONFLICT'}: {len(set(map(str,l)))}")