Sprint 003 findings + Sprint 004 pipeline decision audit plan
- split_prereq_op_dataset.py: extract accepted/rejected/schema-drift rows per gate - gen_prereq_op_rsa_data.py: convert accepted rows to Fabricate TSV format - 1000-run extracted dataset: 1297 accepted prereq_op rows, 24 schema-drift - Key finding: needs_validate_intake always True; effective gate is binary (needs_resolve_dependencies 77%, needs_architect_review 20%) - Key finding: run corpus text is template-driven (17 unique inputs) — not suitable for text-based training; RSA exists before ideal input is available - ROADMAP: gate lifecycle framing — goal is choice of backend, not forced determinism; RSA operates on imperfect/mixed/incomplete input by design - training_data_strategy.md: taskitem-as-self-contained-work-unit constraint - SPRINT-003: updated with 1000-run results, text audit findings, design constraints - SPRINT-004: pipeline decision audit — manual walkthrough of every decision from project description to generated artifact; execute next session Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
117
tools/split_prereq_op_dataset.py
Normal file
117
tools/split_prereq_op_dataset.py
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Split extracted gate rows into prereq_op_selector accepted / rejected / schema-drift buckets.
|
||||
|
||||
Reads an NDJSON file of extracted gate rows (from extract_gate_rows.py) and
|
||||
produces three output files covering only prereq_op_selector rows:
|
||||
|
||||
accepted.ndjson — rows with no rejection flags
|
||||
rejected.ndjson — rows with any rejection flag
|
||||
schema_drift.ndjson — subset of rejected rows where rejection is caused by
|
||||
invalid_prerequisite_values (schema-drift label pollution)
|
||||
|
||||
Also prints a brief summary to stdout.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
SCHEMA_DRIFT_FLAG_PREFIX = "invalid_prerequisite_values"
|
||||
|
||||
|
||||
def is_schema_drift(row: dict) -> bool:
|
||||
return any(f.startswith(SCHEMA_DRIFT_FLAG_PREFIX) for f in row.get("rejection_flags", []))
|
||||
|
||||
|
||||
def write_ndjson(path: Path, rows: list[dict]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("w", encoding="utf-8") as fh:
|
||||
for row in rows:
|
||||
fh.write(json.dumps(row, sort_keys=True) + "\n")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--input",
|
||||
default="semantic/extracted_gate_rows_slice.ndjson",
|
||||
help="NDJSON file produced by extract_gate_rows.py.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output-dir",
|
||||
default="semantic/prereq_op_dataset",
|
||||
help="Directory where accepted/rejected/schema_drift files are written.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
repo_root = Path(__file__).resolve().parent.parent
|
||||
input_path = Path(args.input)
|
||||
if not input_path.is_absolute():
|
||||
input_path = (repo_root / input_path).resolve()
|
||||
output_dir = Path(args.output_dir)
|
||||
if not output_dir.is_absolute():
|
||||
output_dir = (repo_root / output_dir).resolve()
|
||||
|
||||
accepted: list[dict] = []
|
||||
rejected: list[dict] = []
|
||||
schema_drift: list[dict] = []
|
||||
skipped = 0
|
||||
|
||||
with input_path.open("r", encoding="utf-8") as fh:
|
||||
for line in fh:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
row = json.loads(line)
|
||||
if row.get("gate_id") != "prereq_op_selector":
|
||||
skipped += 1
|
||||
continue
|
||||
flags = row.get("rejection_flags", [])
|
||||
if not flags:
|
||||
accepted.append(row)
|
||||
else:
|
||||
rejected.append(row)
|
||||
if is_schema_drift(row):
|
||||
schema_drift.append(row)
|
||||
|
||||
write_ndjson(output_dir / "accepted.ndjson", accepted)
|
||||
write_ndjson(output_dir / "rejected.ndjson", rejected)
|
||||
write_ndjson(output_dir / "schema_drift.ndjson", schema_drift)
|
||||
|
||||
# Flag breakdown across rejected rows
|
||||
flag_counts: dict[str, int] = {}
|
||||
for row in rejected:
|
||||
for f in row.get("rejection_flags", []):
|
||||
flag_counts[f] = flag_counts.get(f, 0) + 1
|
||||
|
||||
# Label distribution for accepted rows
|
||||
label_counts: dict[str, int] = {
|
||||
"needs_validate_intake": 0,
|
||||
"needs_architect_review": 0,
|
||||
"needs_resolve_dependencies": 0,
|
||||
}
|
||||
for row in accepted:
|
||||
label = row.get("decision_label", {})
|
||||
for key in label_counts:
|
||||
if label.get(key):
|
||||
label_counts[key] += 1
|
||||
|
||||
summary = {
|
||||
"input": str(input_path),
|
||||
"output_dir": str(output_dir),
|
||||
"rows_accepted": len(accepted),
|
||||
"rows_rejected": len(rejected),
|
||||
"rows_schema_drift": len(schema_drift),
|
||||
"rows_skipped_other_gates": skipped,
|
||||
"rejection_flag_breakdown": flag_counts,
|
||||
"accepted_label_distribution": label_counts,
|
||||
}
|
||||
print(json.dumps(summary, indent=2, sort_keys=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user