Spaces:
Running
Running
| #!/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() | |