#!/usr/bin/env python3 """Deterministic generator for the BAUD reasoning-trace seed set. This is the same challenge construction the Mint Protocol uses for the MHOP (multi-hop inference) class, exported as a dataset so the format is public and reproducible before any live mining has happened. python generate.py --n 250 --out data/seed-v0.jsonl Every row is reproducible from (seed, index): same inputs, same challenge, same reference answer. Nothing here is scraped or model-generated. """ import argparse import hashlib import json import os import random # A small closed-world fact graph. Entities are deliberately mundane so the # difficulty comes from the hop structure, not from memorised trivia. FACTS = [ ("the Baudot code", "was patented by", "Emile Baudot"), ("Emile Baudot", "worked for", "the French Telegraph Administration"), ("the French Telegraph Administration", "operated in", "France"), ("France", "uses the currency", "the euro"), ("the teleprinter", "descended from", "the Baudot code"), ("the teleprinter", "transmitted over", "telegraph wire"), ("telegraph wire", "carried", "five bit symbols"), ("five bit symbols", "encode", "thirty two characters"), ("ASCII", "replaced", "the Baudot code"), ("the modem", "measured speed in", "baud"), ("baud", "is named after", "Emile Baudot"), ("BNB Chain", "settles", "BEP20 tokens"), ("BEP20 tokens", "are held by", "agent wallets"), ("agent wallets", "are controlled by", "AI agents"), ("AI agents", "are billed in", "inference tokens"), ("inference tokens", "are metered by", "context length"), ("context length", "constrains", "retrieval depth"), ("retrieval depth", "affects", "answer accuracy"), ] CONSTRAINT_POOL = [ ("max_tokens", [40, 60, 80]), ("must_cite", [True]), ("answer_schema", ["entity", "entity", "json"]), ("forbid", [["speculation"], ["speculation", "hedging"]]), ] def build_index(facts): """subject -> list of (relation, object)""" idx = {} for s, r, o in facts: idx.setdefault(s, []).append((r, o)) return idx def walk(idx, rng, hops): """Walk the graph for `hops` steps, return (start, chain, answer) or None.""" starts = [s for s in idx if idx[s]] rng.shuffle(starts) for start in starts: node, chain = start, [] ok = True for _ in range(hops): if node not in idx or not idx[node]: ok = False break rel, nxt = rng.choice(idx[node]) chain.append((node, rel, nxt)) node = nxt if ok and len(chain) == hops: return start, chain, node return None def make_row(i, seed): rng = random.Random(f"{seed}:{i}") hops = rng.choice([2, 2, 3, 3, 4]) idx = build_index(FACTS) walked = walk(idx, rng, hops) if walked is None: return None start, chain, answer = walked constraints = {} for key, options in CONSTRAINT_POOL: constraints[key] = rng.choice(options) relations = " then ".join(f'"{r}"' for _, r, _ in chain) facts_block = "\n".join(f"- {s} {r} {o}." for s, r, o in FACTS) prompt = ( f"Facts:\n{facts_block}\n\n" f'Question: starting from "{start}", follow {hops} links: {relations}. ' f"Name the final entity.\n" f"Answer with the entity only and cite the facts you used with [n] markers." ) # difficulty band: hops plus constraint pressure, clamped 1..5 difficulty = min(5, max(1, hops - 1 + (1 if constraints["max_tokens"] <= 40 else 0))) cid = "mhop_" + hashlib.sha256(f"{seed}:{i}".encode()).hexdigest()[:10] return { "id": cid, "class": "MHOP", "domain": "inference@1.0.0", "difficulty": difficulty, "hops": hops, "prompt": prompt, "constraints": constraints, "reference_answer": answer, "reasoning_chain": [{"subject": s, "relation": r, "object": o} for s, r, o in chain], "seed": f"{seed}:{i}", } def main(): ap = argparse.ArgumentParser() ap.add_argument("--n", type=int, default=250) ap.add_argument("--seed", default="baud-v0") ap.add_argument("--out", default="data/seed-v0.jsonl") args = ap.parse_args() os.makedirs(os.path.dirname(args.out) or ".", exist_ok=True) written, seen = 0, set() with open(args.out, "w", encoding="utf-8") as f: i = 0 while written < args.n and i < args.n * 20: row = make_row(i, args.seed) i += 1 if not row or row["id"] in seen: continue seen.add(row["id"]) f.write(json.dumps(row, ensure_ascii=False) + "\n") written += 1 print(f"wrote {written} rows to {args.out}") if __name__ == "__main__": main()