# Phase 2 builder: sources -> per-source staged shards -> interleaved mixed shards. # # Two stages, because one stage cannot produce a mixed corpus without re-streaming. # # stage per source: stream -> normalise -> language/quality gate -> dedup -> tokenise # -> write stage//shard-####.bin # merge read all staged shards together, emit documents round-robin in proportion to each source's # target, and write the final mixed mix/shard-####.bin # # Why the merge exists (memory/ERRORS.md E-016). The first version consumed one source to its target and # only then started the next, and it flushed a shard when the buffer filled. Since fineweb-edu's target is # 300M tokens = 37 shards of 8M, the first 37 shards of the mix would have been nothing but web text, then # textbooks, then math. A shuffle inside the buffer cannot fix that -- the buffer only ever held one # source. That is a curriculum drift across the first third of the main run, and no LR schedule repairs # ordering like that. Mixing must happen between sources, not inside them. # # Shard layout is shared by both stages and carries a per-document offset table, so document boundaries # survive to the training reader (E-016's second latent bug: the old format stored a doc *count*, from # which boundaries cannot be recovered): # # header : = 3 def h64(s): """64-bit digest of a string. digest()[:8] is 8 BYTES; hexdigest()[:16] is 16 *characters* and broke the first version (E-015).""" return struct.unpack("= args.budget_tokens: print("stage: overall budget reached", flush=True) break import datasets try: ds = datasets.load_dataset(src["repo"], src["config"], split="train", streaming=True) except Exception as e: print(f"!! stage: {key} could not load: {type(e).__name__}: {str(e)[:200]}", flush=True) rec["error"] = f"{type(e).__name__}: {str(e)[:200]}" st.d["staged"][key] = rec st.commit([], []) continue got = docs_seen = 0 drops = {"short_or_low_score": 0, "non_english": 0, "exact_dup": 0, "key_dup": 0, "too_few_tokens": 0, "no_column": 0} cols = None buf, new_h, new_k = [], [], [] sd = os.path.join(st.stage_dir, key) os.makedirs(sd, exist_ok=True) shards = rec.get("shards", []) t0 = time.monotonic() for row in ds: if got >= want: break if args.sec_per_source and time.monotonic() - t0 > args.sec_per_source: break if cols is None: cols = set(row.keys()) if src["col"] not in cols: print(f"!! stage: {key} has no column {src['col']!r}; seen {sorted(cols)[:10]}", flush=True) drops["no_column"] = -1 break raw = row.get(src["col"]) if not isinstance(raw, str): continue docs_seen += 1 s = normalize(raw) if len(s) < args.min_chars: drops["short_or_low_score"] += 1 continue if src.get("min_score") is not None: sc = row.get("int_score", row.get("score")) try: if sc is not None and float(sc) < src["min_score"]: drops["short_or_low_score"] += 1 continue except (TypeError, ValueError): pass if src.get("en_filter") and not looks_english(s): drops["non_english"] += 1 continue h = h64(s) if h in st.seen_exact: drops["exact_dup"] += 1 continue u = key_of(row, cols) ku = h64(u) if u else None if ku is not None and ku in st.seen_key: drops["key_dup"] += 1 continue ids = tokenizer.encode(s[:args.max_chars], add_special_tokens=False).ids[:ROW_TOKEN_CAP] if len(ids) < 16: drops["too_few_tokens"] += 1 continue st.seen_exact.add(h) new_h.append(h) if ku is not None: st.seen_key.add(ku) new_k.append(ku) buf.append(array.array("H", ids)) got += len(ids) if sum(len(b) for b in buf) >= TOKENS_PER_SHARD: idx = len(shards) p = os.path.join(sd, f"shard-{idx:04d}.bin") nd, nt, dg, bs = write_shard(p, tokenizer.get_vocab_size(), buf) shards.append({"file": os.path.relpath(p, st.root), "docs": nd, "tokens": nt, "sha256": dg, "bytes": bs}) st.seen_exact.update(new_h) st.d["staged"][key] = {"complete": False, "shards": shards, "tokens": got, "docs_seen": docs_seen, "dropped": drops} st.commit(new_h, new_k) new_h, new_k = [], [] buf = [] print(f" staged {key} shard {idx:04d}: {nt:,} tok [{time.monotonic() - t0:.0f}s]", flush=True) if buf: idx = len(shards) p = os.path.join(sd, f"shard-{idx:04d}.bin") nd, nt, dg, bs = write_shard(p, tokenizer.get_vocab_size(), buf) shards.append({"file": os.path.relpath(p, st.root), "docs": nd, "tokens": nt, "sha256": dg, "bytes": bs}) print(f" staged {key} shard {idx:04d}: {nt:,} tok (tail)", flush=True) complete = got >= want st.d["staged"][key] = {"complete": bool(complete), "shards": shards, "tokens": got, "docs_seen": docs_seen, "dropped": dict(drops), "target": want, "seconds": round(time.monotonic() - t0, 1)} st.commit(new_h, new_k) # /kaggle/working is destroyed when the session ends, so a source that took 40 minutes to stage # must not exist only there. Published per source, because that is the unit a resume can skip. if complete and HS and args.hub_repo: with open(os.path.join(st.stage_dir, key, "record.json"), "w") as f: json.dump({"key": key, "src": {k: v for k, v in src.items()}, "shards": shards, "tokens": got, "docs_seen": docs_seen, "dropped": dict(drops)}, f, indent=1) try: n = HS.upload_source(st.root, key, args.hub_repo) print(f" published {key} -> {args.hub_repo}/stage/{key} ({n} files)", flush=True) except Exception as e: print(f"!! publish FAILED for {key}: {type(e).__name__}: {str(e)[:160]} -- " f"this source will have to be re-staged if the session dies", flush=True) el = time.monotonic() - t0 print(f"stage: {key} {got:,} tok of {want:,} from {docs_seen:,} docs; " f"dup={drops['exact_dup']} keydup={drops['key_dup']} lang={drops['non_english']} " f"short={drops['short_or_low_score']} [{got / max(1e-9, el):,.0f} tok/s]", flush=True) # --------------------------------------------------------------------- merge def merge(args, st, tokenizer): """Interleave staged documents proportionally to each source's staged token total. --exclude-dir applies per-source uint8 masks written by audit_contamination --write-filter: a 1 byte means "this document's 13-grams appear in a benchmark train/validation/dev split, do not emit it" (§3.3). Masks are indexed by document ordinal within the source, which is stable because both the audit and the merge replay the source's own record.json shard order. """ vocab = tokenizer.get_vocab_size() masks, dropped, filter_digest = {}, {}, None if args.exclude_dir: fj = os.path.join(args.exclude_dir, "filter.json") if not os.path.exists(fj): print(f"FATAL: --exclude-dir {args.exclude_dir} contains no filter.json", flush=True) sys.exit(5) filter_digest = hashlib.sha256(open(fj, "rb").read()).hexdigest() fj_obj = json.load(open(fj)) if not fj_obj.get("scanned_sources") and not fj_obj.get("sources"): print("FATAL: filter.json names no sources at all -- nothing was scanned, so merging with it " "would publish an unfiltered mix under a filter claim", flush=True) sys.exit(5) if not fj_obj.get("scanned_sources"): # The completeness field post-dates some archived masks. It is a proxy; the real invariant is # "a mask exists for every source this merge will read", which is checked per-source below. print(f"WARNING: filter.json predates the scanned_sources field; trusting its " f"{len(fj_obj.get('sources', {}))} per-source entries because every merged source must " "still carry a mask or the merge refuses", flush=True) dropped = fj_obj.get("sources", {}) for key in sorted(os.listdir(args.exclude_dir)): if key.endswith(".u8"): with open(os.path.join(args.exclude_dir, key), "rb") as fh: masks[key[:-3]] = fh.read() print(f"exclude: {len(masks)} mask(s), " f"{sum(len(m) for m in masks.values()):,} docs covered, " f"{sum(int(v.get('dropped_docs', 0)) for v in dropped.values()):,} flagged", flush=True) streams = [] for src in SOURCES: key = src_key(src) rec = st.d["staged"].get(key) if not rec or not rec.get("shards"): continue staged_docs = sum(int(s.get("docs", 0)) for s in rec["shards"]) m = masks.get(key) if m is not None and len(m) != staged_docs: # A short mask would silently keep exactly the documents the audit did not reach. print(f"FATAL: mask for {key} covers {len(m)} docs but {staged_docs} are staged", flush=True) sys.exit(5) weight = rec.get("tokens") or sum(s["tokens"] for s in rec["shards"]) weight = weight - int((dropped.get(key) or {}).get("dropped_tokens", 0)) if weight <= 0: print(f" {key}: fully excluded, dropped from the merge", flush=True) continue iters = [iter_shard_docs(os.path.join(st.root, s["file"])) for s in rec["shards"]] def gen(its=iters, m=m): if m is None: for it in its: for d in it: yield d return i = 0 for it in its: for d in it: if not m[i]: yield d i += 1 streams.append({"key": key, "weight": float(weight), "credit": 0.0, "it": gen(iters), "pending": None, "emitted_tokens": 0, "exhausted": False}) if not streams: # The cold-resume rehearsal exited 0 here while producing an empty mix, and verify_mix then # reported recount_matches_manifest: true because 0 == 0. An empty mix is the worst possible # silent success in this pipeline, so it is a failure and not a return. print("FATAL merge: nothing staged. Refusing to emit an empty mix.", flush=True) sys.exit(4) if args.exclude_dir: # A missing mask must never mean "this source is clean" (review finding): it means the audit # never scanned it, and the default behaviour would have been to merge every contaminated doc. unscanned = [s["key"] for s in streams if s["key"] not in masks] if unscanned: print(f"FATAL merge: --exclude-dir has no mask for {unscanned}. Refusing to merge sources " "the contamination audit did not read.", flush=True) sys.exit(5) # A re-merge is only correct if it starts from nothing. The loop below stops when merged_tokens() # reaches the input total, so on a mixroot that already holds 141 shards it would emit ZERO new # shards, exit 0, and let the manifest claim a filter that never happened (found in review while # Gate 2c was running against exactly this path). Resume-after-a-kill stays legal -- it is the same # inputs -- so the test is on a digest of the merge's inputs, not on whether shards exist. digest = hashlib.sha256(json.dumps({ "streams": [[s["key"], round(s["weight"]) ] for s in streams], "seed": SHUFFLE_SEED, "tokens_per_shard": TOKENS_PER_SHARD, "val_stride": VAL_STRIDE, "filter": filter_digest}, sort_keys=True).encode()).hexdigest() prior = st.d.get("merge_inputs") if prior is not None and prior != digest and st.d["merged_shards"]: if not (args.rebuild_merged or args.exclude_dir): print("FATAL merge: the mix root already holds shards merged from DIFFERENT inputs " f"(recorded {prior[:12]}, now {digest[:12]}). Continuing would be a silent no-op. " "Pass --rebuild-merged to discard them deliberately.", flush=True) sys.exit(6) n_old = len(st.d["merged_shards"]) + len(st.d.get("val_shards", [])) for grp in ("merged_shards", "val_shards"): for rec in st.d.get(grp, []): p = os.path.join(st.root, rec["file"]) if os.path.exists(p): os.remove(p) st.d["merged_shards"] = [] st.d["val_shards"] = [] print(f"merge: inputs changed ({prior[:12]} -> {digest[:12]}); discarded {n_old} old shard(s) " "and rebuilding from the staged sources", flush=True) st.d["merge_inputs"] = digest total_w = sum(s["weight"] for s in streams) print(f"merge: {len(streams)} sources, " f"{sum(s['weight'] for s in streams) / 1e6:,.0f}M staged tokens", flush=True) def next_doc(s): if s["pending"] is None and not s["exhausted"]: try: s["pending"] = next(s["it"]) except StopIteration: s["exhausted"] = True return s["pending"] cap = args.merge_budget_tokens or int(total_w) buf, buf_src, buf_tokens = [], [], 0 val_buf, val_tokens, docs_seq = [], 0, 0 out_dir = os.path.join(st.root, "mix") os.makedirs(out_dir, exist_ok=True) t0 = time.monotonic() def flush_val(): nonlocal val_buf, val_tokens if not val_buf: return idx = len(st.d.get("val_shards", [])) p = os.path.join(st.root, "val", f"shard-{idx:04d}.bin") os.makedirs(os.path.dirname(p), exist_ok=True) tmp = p + ".tmp" offs = array.array("I", [0]) ids = array.array("H") for d in val_buf: ids.extend(d) offs.append(len(ids)) with open(tmp, "wb") as f: f.write(struct.pack("= VAL_TOKENS_PER_SHARD: flush_val() pick["emitted_tokens"] += len(d) pick["pending"] = None took += 1 continue buf.append((d, pick["key"])) buf_tokens += len(d) pick["emitted_tokens"] += len(d) pick["pending"] = None took += 1 if buf_tokens >= TOKENS_PER_SHARD: flush() break if all(s["pending"] is None and s["exhausted"] for s in streams): break flush() flush_val() print(f"merge: {len(st.d['val_shards']) if 'val_shards' in st.d else 0} val shards, " f"{sum(s['tokens'] for s in st.d.get('val_shards', [])):,} held-out tokens", flush=True) print(f"merge: {len(st.d['merged_shards'])} shards, " f"{sum(s['tokens'] for s in st.d['merged_shards']):,} tokens", flush=True) # --------------------------------------------------------------------- entry def main(): ap = argparse.ArgumentParser() ap.add_argument("--root", default="/kaggle/working/mixroot") ap.add_argument("--budget-tokens", type=int, default=1_310_000_000, help="stage cap") ap.add_argument("--merge-budget-tokens", type=int, default=0, help="0 = take everything staged") ap.add_argument("--cap-tokens-per-source", type=int, default=0, help="smoke test knob") ap.add_argument("--min-chars", type=int, default=300) ap.add_argument("--max-chars", type=int, default=100_000) ap.add_argument("--sec-per-source", type=int, default=0) ap.add_argument("--only", default="", help="comma list of config names to stage") ap.add_argument("--hub-repo", default="Cion-lab/ounce100m-mix-stage", help="staged sources are published here so a session kill cannot lose them; " "empty string disables sync") ap.add_argument("--stage-only", action="store_true") ap.add_argument("--merge-only", action="store_true") ap.add_argument("--exclude-dir", default="", help="directory of per-source .u8 contamination masks + filter.json written by " "audit_contamination --write-filter; documents flagged there are not merged (§3.3)") ap.add_argument("--rebuild-merged", action="store_true", help="discard shards already recorded in build_state.json before merging. Implied by " "--exclude-dir, because a filter changes every shard's contents") args = ap.parse_args() if args.only: keep = set(args.only.split(",")) SOURCES[:] = [s for s in SOURCES if s["config"] in keep or src_key(s) in keep] print(f"--only: {len(SOURCES)} source(s)", flush=True) from tokenizers import Tokenizer from huggingface_hub import hf_hub_download tok_path = hf_hub_download("HuggingFaceTB/SmolLM2-135M", "tokenizer.json") tk = Tokenizer.from_file(tok_path) tk.no_truncation() assert tk.get_vocab_size() <= 65536, "uint16 shard layout breaks above 65,536" print(f"tokenizer vocab={tk.get_vocab_size()} " f"sha256={hashlib.sha256(open(tok_path, 'rb').read()).hexdigest()[:12]}", flush=True) global HS HS = None # Sync is best-effort to SET UP but not to USE: if the Hub cannot be reached or written, turning it # off silently would reintroduce the exact failure this exists to prevent (a killed session losing # hours of streaming). So a configured repo that cannot be initialised is fatal unless --no-hub. if args.hub_repo: try: import hubsync as HS_mod HS = HS_mod HS.ensure_repo(args.hub_repo) except Exception as e: print(f"FATAL hub sync could not initialise: {type(e).__name__}: {str(e)[:200]}", flush=True) print("Refusing to run a multi-hour build that is not interruption-safe. Resolve the Hub " "write path, or pass --hub-repo '' only if you accept losing all staged work when the " "session ends.", flush=True) sys.exit(3) st = State(args.root) if args.hub_repo and not st.d["staged"]: # The state file lives on /kaggle/working too, so in a fresh session it is empty even when the # Hub holds a complete stage. Rebuild the stage bookkeeping from the Hub's record.json files -- # without this, --merge-only on a new instance would find nothing and quietly emit an empty mix. try: remote = HS.remote_stage_files(args.hub_repo) keys = sorted({p.split("/")[1] for p in remote if p.startswith("stage/") and "/" in p}) pulled = HS.download_missing(args.root, keys, args.hub_repo, remote=remote) for k in keys: rp = os.path.join(args.root, "stage", k, "record.json") if not os.path.exists(rp): continue j = json.load(open(rp)) st.d["staged"][k] = {"complete": True, "shards": j["shards"], "tokens": j["tokens"], "docs_seen": j["docs_seen"], "dropped": j["dropped"], "target": j["tokens"], "restored_from_hub": True} st.commit([], []) print(f"hub: restored {len(st.d['staged'])} staged source(s) " f"({st.staged_tokens_total():,} tokens)", flush=True) except Exception as e: print(f"FATAL hub restore failed: {type(e).__name__}: {str(e)[:200]}", flush=True) sys.exit(3) t0 = time.monotonic() if not args.merge_only: stage(args, st, tk) if not args.stage_only: merge(args, st, tk) manifest = { "tokenizer": {"id": "HuggingFaceTB/SmolLM2-135M:tokenizer.json", "vocab_size": tk.get_vocab_size(), "sha256": hashlib.sha256(open(tok_path, "rb").read()).hexdigest()}, "layout": {"dtype": "uint16", "header": "