"""Verify Figment SFT rows match the local 4B navigator harness.""" from __future__ import annotations import argparse from collections import Counter import json from pathlib import Path import sys from typing import Any PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from figment.focused_repair import build_focused_repair_prompts # noqa: E402 from figment.harness_evidence import build_harness_evidence # noqa: E402 from figment.observation_targets import required_observation_targets # noqa: E402 from figment.eval_metrics import score_expected_labels # noqa: E402 from figment.prompt_builder import build_prompt # noqa: E402 from figment.retrieval import known_card_ids # noqa: E402 from figment.retrieval import load_protocol_cards # noqa: E402 from figment.retrieval import query_from_intake # noqa: E402 from figment.retrieval import search_protocol_cards # noqa: E402 from figment.rules import run_red_flag_checks # noqa: E402 from figment.validators import urgency_floor_from_rules # noqa: E402 from figment.validators import validate_navigator_output # noqa: E402 from scripts.augment_finetune_repair_rows import _corrupt_output # noqa: E402 from scripts.augment_finetune_repair_rows import _extra_failures_for_scope # noqa: E402 from scripts.generate_finetune_data import forbidden_behavior_for_version # noqa: E402 from scripts.generate_finetune_data import ensure_retrieved_cards # noqa: E402 from scripts.generate_finetune_data import _required_retrieved_ids # noqa: E402 from scripts.generate_finetune_data import uses_v5_focused_policy # noqa: E402 from scripts.generate_finetune_data import uses_v6_observation_policy # noqa: E402 from scripts.generate_finetune_data import uses_v7_source_card_policy # noqa: E402 from scripts.generate_finetune_data import v2_policy_issues # noqa: E402 from scripts.generate_finetune_data import v3_policy_issues # noqa: E402 from scripts.generate_finetune_data import v5_policy_issues # noqa: E402 from scripts.generate_finetune_data import v6_policy_issues # noqa: E402 from scripts.generate_finetune_data import v7_source_card_closure_issues # noqa: E402 from scripts.generate_finetune_data import uses_v3_field_workflow_policy # noqa: E402 DEFAULT_DATASET = Path("data/finetune/figment_sft_v1.jsonl") DEFAULT_CASE_SPECS = Path("data/finetune/figment_sft_v1_case_specs.jsonl") ALLOWED_FACT_SOURCES = {"structured_field", "responder_note", "protocol_card"} def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--dataset", type=Path, default=DEFAULT_DATASET) parser.add_argument("--case-specs", type=Path, default=DEFAULT_CASE_SPECS) args = parser.parse_args(argv) summary = verify_rows(dataset_path=args.dataset, case_specs_path=args.case_specs) print(json.dumps(summary, indent=2, sort_keys=True)) return 0 if summary["passed"] else 1 def verify_rows(*, dataset_path: Path, case_specs_path: Path) -> dict[str, Any]: rows = _read_jsonl(dataset_path) specs = {str(item["case_id"]): item for item in _read_jsonl(case_specs_path)} rows_by_id = {str(row.get("case_id")): row for row in rows} cards_by_id = {str(card["card_id"]): card for card in load_protocol_cards()} issues: list[dict[str, Any]] = [] categories: Counter[str] = Counter() task_types: Counter[str] = Counter() for row_number, row in enumerate(rows, start=1): case_id = str(row.get("case_id", "")) categories[str(row.get("category", ""))] += 1 task_type = str(row.get("metadata", {}).get("task_type", "navigator_full")) task_types[task_type] += 1 base_case_id = str(row.get("metadata", {}).get("base_case_id") or case_id) spec = specs.get(base_case_id) if spec is None: issues.append(_issue(row_number, case_id, "missing_case_spec")) continue dataset_version = str(row.get("version") or spec.get("dataset_version") or "figment_sft_v1") messages = row.get("messages") if not isinstance(messages, list) or [item.get("role") for item in messages] != ["user", "assistant"]: issues.append(_issue(row_number, case_id, "messages_must_match_llama_cpp_user_assistant_shape")) continue intake = spec["structured_intake"] rule_results = [rule.to_dict() for rule in run_red_flag_checks(intake)] floor = urgency_floor_from_rules(rule_results) retrieved = search_protocol_cards(query_from_intake(intake), limit=6) spec_dataset_version = str(spec.get("dataset_version") or dataset_version) if uses_v7_source_card_policy(spec_dataset_version): synthetic_spec = type( "SyntheticSpecForVerification", (), { "target_protocol_card_id": str(spec.get("target_protocol_card_id") or ""), "dataset_version": spec_dataset_version, }, )() retrieved = ensure_retrieved_cards( retrieved, required_ids=_required_retrieved_ids(synthetic_spec, rule_results), cards_by_id=cards_by_id, limit=6, ) retrieved_ids = [str(item.get("card_id", "")) for item in retrieved if item.get("card_id")] harness_prompt, prompt_hash = build_prompt(intake, retrieved, rule_results, floor) expected_user_prompt = harness_prompt try: output = json.loads(str(messages[1].get("content", ""))) except json.JSONDecodeError as exc: issues.append(_issue(row_number, case_id, "assistant_content_is_not_json", error=str(exc))) continue output_text = json.dumps(output, sort_keys=True) lowered_output_text = output_text.lower() if " list[dict[str, Any]]: return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()] def _issue(row_number: int, case_id: str, issue_type: str, **details: Any) -> dict[str, Any]: return {"row_number": row_number, "case_id": case_id, "type": issue_type, **details} def _append_v5_metadata_issues( issues: list[dict[str, Any]], *, row_number: int, case_id: str, row: dict[str, Any], output: dict[str, Any], ) -> None: metadata = row.get("metadata") if isinstance(row.get("metadata"), dict) else {} if metadata.get("dataset_version") != "figment_sft_v5": issues.append(_issue(row_number, case_id, "v5_metadata_dataset_version_missing")) if metadata.get("training_focus") != row.get("category"): issues.append( _issue( row_number, case_id, "v5_metadata_training_focus_mismatch", training_focus=metadata.get("training_focus"), category=row.get("category"), ) ) excluded = metadata.get("excluded_eval_case_ids") if not isinstance(excluded, list) or not { "field_workflow_holdout_v1-000054", "field_workflow_holdout_v1-000099", } <= {str(item) for item in excluded}: issues.append(_issue(row_number, case_id, "v5_metadata_excluded_eval_case_ids_missing")) source_cards = set(_string_list(output.get("source_cards"))) missing_source = [card_id for card_id in _string_list(metadata.get("must_include_source_cards")) if card_id not in source_cards] if missing_source: issues.append(_issue(row_number, case_id, "v5_metadata_must_include_source_cards_missing", missing=missing_source)) required_selected_ids = _string_list(metadata.get("must_include_selected_required_observation_ids")) selected_ids = set(_string_list(output.get("selected_required_observation_ids"))) missing_selected = [target_id for target_id in required_selected_ids if target_id not in selected_ids] if missing_selected: issues.append( _issue( row_number, case_id, "v5_metadata_must_include_selected_required_observation_ids_missing", missing=missing_selected, ) ) def _append_v6_metadata_issues( issues: list[dict[str, Any]], *, row_number: int, case_id: str, row: dict[str, Any], output: dict[str, Any], ) -> None: metadata = row.get("metadata") if isinstance(row.get("metadata"), dict) else {} dataset_version = str(metadata.get("dataset_version") or row.get("version") or "") if not dataset_version.startswith("figment_sft_v6"): issues.append(_issue(row_number, case_id, "v6_metadata_dataset_version_missing")) if metadata.get("training_focus") != row.get("category"): issues.append( _issue( row_number, case_id, "v6_metadata_training_focus_mismatch", training_focus=metadata.get("training_focus"), category=row.get("category"), ) ) if metadata.get("v6_training_policy_version") != 1: issues.append(_issue(row_number, case_id, "v6_metadata_policy_version_missing")) required_targets = metadata.get("required_observation_targets") if not isinstance(required_targets, list): issues.append(_issue(row_number, case_id, "v6_metadata_required_observation_targets_missing")) forbidden_cues = metadata.get("harness_metadata_cues_not_observations") if not isinstance(forbidden_cues, list) or "source card ids" not in {str(item).lower() for item in forbidden_cues}: issues.append(_issue(row_number, case_id, "v6_metadata_harness_cues_missing")) required_selected_ids = _string_list(metadata.get("must_include_selected_required_observation_ids")) selected_ids = set(_string_list(output.get("selected_required_observation_ids"))) missing_selected = [target_id for target_id in required_selected_ids if target_id not in selected_ids] if missing_selected: issues.append( _issue( row_number, case_id, "v6_metadata_must_include_selected_required_observation_ids_missing", missing=missing_selected, ) ) def _string_list(value: Any) -> list[str]: if isinstance(value, list): return [str(item) for item in value if str(item)] return [] def _candidate_ids(value: Any) -> list[str]: if not isinstance(value, list): return [] ids = [] for item in value: if isinstance(item, dict) and item.get("card_id"): ids.append(str(item["card_id"])) return ids def _forbidden_behavior_for_dataset_version(dataset_version: str) -> list[str]: return forbidden_behavior_for_version(dataset_version) def _stable_hash_content(value: str) -> str: from figment.trace import stable_hash return stable_hash(value) if __name__ == "__main__": raise SystemExit(main())