|
43 | 43 | _FIELDS = ("row", "decision", "words") |
44 | 44 | _DROPPED_KINDS = frozenset({"unknown_decision", "decision_missing_row", "row_decided_twice", |
45 | 45 | "decision_not_an_object", "keep_not_offered", "words_ignored_on_keep", |
46 | | - "words_ignored_on_nothing", "words_not_text"}) |
| 46 | + "words_ignored_on_nothing", "words_not_text", "example_not_offered"}) |
| 47 | + |
| 48 | + |
| 49 | +def example_blocked_rows(run_dir: Path) -> set[int]: |
| 50 | + """Rows whose ledger holds a part the data proved wrong: a statement with a mistake in it is never |
| 51 | + offered as a prompt example, whatever the page suggested. Read from each row's ledger.json.""" |
| 52 | + blocked: set[int] = set() |
| 53 | + rows_dir = run_dir / "rows" |
| 54 | + if not rows_dir.is_dir(): |
| 55 | + return blocked |
| 56 | + for row_dir in rows_dir.iterdir(): |
| 57 | + ledger = row_dir / "ledger.json" |
| 58 | + if not row_dir.name.isdigit() or not ledger.exists(): |
| 59 | + continue |
| 60 | + try: |
| 61 | + parts = json.loads(ledger.read_text(encoding="utf-8")).get("rows", []) |
| 62 | + except (OSError, ValueError): |
| 63 | + continue |
| 64 | + if any(isinstance(p, dict) and p.get("verdict") == "query_defect" for p in parts): |
| 65 | + blocked.add(int(row_dir.name)) |
| 66 | + return blocked |
47 | 67 |
|
48 | 68 |
|
49 | 69 | def keepable_rows(run_dir: Path) -> set[int]: |
@@ -81,7 +101,7 @@ def keepable_rows(run_dir: Path) -> set[int]: |
81 | 101 | return keep |
82 | 102 |
|
83 | 103 |
|
84 | | -def _key_of(line: str): |
| 104 | +def _key_of(line: str) -> str | None: |
85 | 105 | low = line.strip().lower() |
86 | 106 | for k in _KEYS: |
87 | 107 | if low.startswith(k + ":") or low == k + ":": |
@@ -112,7 +132,8 @@ def _sections(text: str) -> tuple[dict, list[str]]: |
112 | 132 | return out, repeated |
113 | 133 |
|
114 | 134 |
|
115 | | -def parse(text: str, keepable: set[int] | None = None, run: str | None = None) -> tuple[dict, list, dict | None]: |
| 135 | +def parse(text: str, keepable: set[int] | None = None, run: str | None = None, |
| 136 | + example_blocked: set[int] | None = None) -> tuple[dict, list, dict | None]: |
116 | 137 | sec, repeated = _sections(text) |
117 | 138 | anomalies: list = [{"kind": "key_repeated", "detail": key} for key in repeated] |
118 | 139 | needs: dict | None = None |
@@ -156,6 +177,9 @@ def parse(text: str, keepable: set[int] | None = None, run: str | None = None) - |
156 | 177 | if row in seen: |
157 | 178 | anomalies.append({"kind": "row_decided_twice", "row": row}) |
158 | 179 | continue |
| 180 | + if decision == "example" and row in (example_blocked or set()): |
| 181 | + anomalies.append({"kind": "example_not_offered", "row": row}) |
| 182 | + continue # dropped like a keep the run did not offer; _DROPPED_KINDS carries the kind |
159 | 183 | if decision == "keep" and row not in (keepable or set()): |
160 | 184 | # The offer's predicate belongs to the ledger: a keep the run's own files do not |
161 | 185 | # allow is not the person's to grant from a page. |
@@ -200,7 +224,7 @@ def main(argv=None) -> int: |
200 | 224 | print(json.dumps({"ok": False, "data": None, "anomalies": [{"kind": "bad_argument", "detail": str(exc)}], |
201 | 225 | "needs_judgment": {"kind": "bad_argument", "ask": "the block file could not be read"}}, indent=2)) |
202 | 226 | return 2 |
203 | | - data, anomalies, needs = parse(text, keepable_rows(run_dir), run=run_dir.name) |
| 227 | + data, anomalies, needs = parse(text, keepable_rows(run_dir), run=run_dir.name, example_blocked=example_blocked_rows(run_dir)) |
204 | 228 | print(json.dumps({"ok": needs is None, "data": data, "anomalies": anomalies, "needs_judgment": needs}, indent=2)) |
205 | 229 | return 0 |
206 | 230 |
|
|
0 commit comments