98 lines
3.7 KiB
Python
98 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Slice 23 emit: five-way residual non-action semantic router — data files
|
|
========================================================================
|
|
|
|
Slice 23 reconciles corpus fast-path metadata with the production router
|
|
(TryFastPath over stage-0 grammars). The corpus builder no longer mirrors the
|
|
grammars by hand; fast_path_resolved is derived from the router, so this emit
|
|
flags exactly the rows the router genuinely leaves for the general cascade.
|
|
|
|
This script only repackages the frozen dev pool for the Go legacy baseline and
|
|
the Python experiment, writing into /tmp/mvn-s23 so the slice-22 artifacts
|
|
stay untouched. Logic is slice22_emit.py verbatim; only OUT_DIR differs.
|
|
|
|
/tmp/mvn-s23/pool.json residual non-action dev rows: idx, text, n_text,
|
|
route, tags, cv_fold, split_group, family_id,
|
|
source_id (1509 rows)
|
|
/tmp/mvn-s23/ood.json residual ACTION dev rows (720): same shape; OOD
|
|
probes only, never primary metrics
|
|
/tmp/mvn-s23/stats.json population summary (routes, families, folds)
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
|
|
import slice18_sparse # noqa: E402 (normalize_match_text, load_data, filters)
|
|
|
|
OUT_DIR = "/tmp/mvn-s23"
|
|
|
|
ROUTES = ["conversation", "knowledge", "memory_write", "system", "uncertain"]
|
|
|
|
|
|
def main():
|
|
meta, examples = slice18_sparse.load_data()
|
|
dev = slice18_sparse.filter_dev_pool(examples)
|
|
print(f"dev pool: {len(dev)} rows "
|
|
f"(meta declares dev_count={meta.get('dev_count')})")
|
|
|
|
rows = []
|
|
for i, e in enumerate(dev):
|
|
if not e["fast_path_resolved"]:
|
|
rows.append({
|
|
"idx": i,
|
|
"text": e["text"],
|
|
"n_text": slice18_sparse.normalize_match_text(e["text"]),
|
|
"route": e["route"],
|
|
"tags": sorted(set(e.get("tags", []))),
|
|
"cv_fold": e["cv_fold"],
|
|
"split_group": e["split_group"],
|
|
"family_id": e["family_id"],
|
|
"source_id": e["source_id"],
|
|
})
|
|
|
|
na = [r for r in rows if r["route"] != "action"]
|
|
ood = [r for r in rows if r["route"] == "action"]
|
|
print(f"residual rows: {len(rows)} non-action: {len(na)} action(OOD): {len(ood)}")
|
|
|
|
by_route = {}
|
|
for r in na:
|
|
by_route[r["route"]] = by_route.get(r["route"], 0) + 1
|
|
print("routes:", by_route)
|
|
assert sum(by_route.values()) == len(na)
|
|
assert set(ROUTES) == set(by_route), "route set must be the five-way"
|
|
|
|
by_family = {}
|
|
for r in na:
|
|
by_family[r["family_id"]] = by_family.get(r["family_id"], 0) + 1
|
|
by_fold = {}
|
|
for r in na:
|
|
by_fold[r["cv_fold"]] = by_fold.get(r["cv_fold"], 0) + 1
|
|
print(f"family_ids: {len(by_family)} split_groups: {len(set(r['split_group'] for r in na))}")
|
|
print("folds:", by_fold)
|
|
|
|
os.makedirs(OUT_DIR, exist_ok=True)
|
|
with open(os.path.join(OUT_DIR, "pool.json"), "w") as f:
|
|
json.dump(na, f, ensure_ascii=False, indent=1)
|
|
with open(os.path.join(OUT_DIR, "ood.json"), "w") as f:
|
|
json.dump(ood, f, ensure_ascii=False, indent=1)
|
|
with open(os.path.join(OUT_DIR, "stats.json"), "w") as f:
|
|
json.dump({
|
|
"dev_count": len(dev),
|
|
"residual_count": len(rows),
|
|
"non_action_count": len(na),
|
|
"action_ood_count": len(ood),
|
|
"routes": by_route,
|
|
"family_ids": len(by_family),
|
|
"folds": by_fold,
|
|
"top_family": dict(sorted(by_family.items(), key=lambda kv: -kv[1])[:15]),
|
|
}, f, ensure_ascii=False, indent=1)
|
|
print(f"wrote {OUT_DIR}/{{pool,ood,stats}}.json")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |