#!/usr/bin/env python3
"""Bank Batch 387: Rule 345 complementary non-singular reptile-set-C perception."""

from __future__ import annotations

import datetime as dt
import json
import re
import sqlite3

from bank_386 import (
    DENY_ENGLISH,
    DENY_KUKU,
    EXPECTED_HASHES,
    SUPPORT_EVIDENCE as RULE344_SUPPORT_EVIDENCE,
    TARGET_CONFIDENCE,
    TARGET_EVIDENCE as RULE344_TARGET_EVIDENCE,
    TARGET_GLOSSES,
    TARGET_LABELS,
    TARGET_ORDER,
    count_words,
    source_audit,
)
from process_ledger import ensure_schema, record_event

DB = "/mnt/donto-data/donto-resources/research/translation-training/kuku-yalanji-runpod-2026-06-30/synthetic/claude-synthetic-v1-2026-07-02/synthetic.db"
LABEL = "batch-387"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-387-complementary-sense-qualified-reptile-set-c-nonsingular-past-perception-after-rule344-process.md"
EXPECTED_TARGET_COVERAGE = {
    "kalkamuku": 20, "karrkurr": 25, "jinkalmu": 26, "barka": 28, "yalnga": 28,
    "biwul": 29, "yirku-yirku": 29, "jadi": 33, "walkarr": 35, "bajabaja": 36,
}
EXPECTED_SUPPORT_COVERAGE = {
    "ngali": 663, "ngaliny": 605, "yubal": 615, "yurra": 600, "nganjin": 328,
    "ngana": 1115, "yaluy": 4512, "yinyay": 4674, "nyajin": 2300,
}
FRAME_SPECS = [
    ("ngali", "yinyay", "I saw", "there", "1du.excl", "We two, not you, saw"),
    ("ngaliny", "yaluy", "I saw", "here", "1du.incl", "You and I saw"),
    ("yubal", "yinyay", "I saw", "there", "2du", "You two saw"),
    ("yurra", "yaluy", "I saw", "here", "2pl", "You all saw"),
    ("nganjin", "yinyay", "I saw", "there", "1pl.excl", "We, not you, saw"),
]
OPPOSITE = {"yaluy": "yinyay", "yinyay": "yaluy"}
TARGET_EVIDENCE = {
    target: f"{RULE344_TARGET_EVIDENCE[target]} Rule 345 adds only the exact opposite deictic cell and preserves every Rule 344 source and sense boundary."
    for target in TARGET_ORDER
}
SUPPORT_EVIDENCE = (
    f"{RULE344_SUPPORT_EVIDENCE} Rule 345 reasserts the Patz-over-dictionary clusivity ruling and maps each "
    "opposite cell to Batch 386 before banking; it does not infer that deferred ngana is unavailable."
)


def row(seq: int, english: str, kuku: str, analysis: str, frame: str, words: list[str]) -> tuple:
    target = words[1]
    return (
        seq, english, kuku, analysis, frame, 3,
        json.dumps(words, ensure_ascii=False), json.dumps([], ensure_ascii=False),
        f"{TARGET_EVIDENCE[target]} {SUPPORT_EVIDENCE}", TARGET_CONFIDENCE[target],
    )


ROWS = [
    row(1, "We two, not you, saw the kalkamuku snake there.", "Ngali kalkamuku yinyay nyajin.", "ngali kalkamuku yinyay nyajin | 1du.excl.NOM kalkamuku.snake there see.PST", "r345_1du_excl_there_reptile_c_saw_kalkamuku", ["ngali", "kalkamuku", "yinyay", "nyajin"]),
    row(2, "We two, not you, saw the karrkurr frog there.", "Ngali karrkurr yinyay nyajin.", "ngali karrkurr yinyay nyajin | 1du.excl.NOM karrkurr.frog there see.PST", "r345_1du_excl_there_reptile_c_saw_karrkurr", ["ngali", "karrkurr", "yinyay", "nyajin"]),
    row(3, "We two, not you, saw the jinkalmu snake there.", "Ngali jinkalmu yinyay nyajin.", "ngali jinkalmu yinyay nyajin | 1du.excl.NOM jinkalmu.snake there see.PST", "r345_1du_excl_there_reptile_c_saw_jinkalmu", ["ngali", "jinkalmu", "yinyay", "nyajin"]),
    row(4, "We two, not you, saw the barka snake there.", "Ngali barka yinyay nyajin.", "ngali barka yinyay nyajin | 1du.excl.NOM barka.snake there see.PST", "r345_1du_excl_there_reptile_c_saw_barka", ["ngali", "barka", "yinyay", "nyajin"]),
    row(5, "We two, not you, saw the yalnga turtle there.", "Ngali yalnga yinyay nyajin.", "ngali yalnga yinyay nyajin | 1du.excl.NOM yalnga.turtle there see.PST", "r345_1du_excl_there_reptile_c_saw_yalnga", ["ngali", "yalnga", "yinyay", "nyajin"]),
    row(6, "We two, not you, saw the biwul snake there.", "Ngali biwul yinyay nyajin.", "ngali biwul yinyay nyajin | 1du.excl.NOM biwul.snake there see.PST", "r345_1du_excl_there_reptile_c_saw_biwul", ["ngali", "biwul", "yinyay", "nyajin"]),
    row(7, "We two, not you, saw the yirku-yirku frog there.", "Ngali yirku-yirku yinyay nyajin.", "ngali yirku-yirku yinyay nyajin | 1du.excl.NOM yirku-yirku.frog there see.PST", "r345_1du_excl_there_reptile_c_saw_yirku_yirku", ["ngali", "yirku-yirku", "yinyay", "nyajin"]),
    row(8, "We two, not you, saw the jadi goanna there.", "Ngali jadi yinyay nyajin.", "ngali jadi yinyay nyajin | 1du.excl.NOM jadi.goanna there see.PST", "r345_1du_excl_there_reptile_c_saw_jadi", ["ngali", "jadi", "yinyay", "nyajin"]),
    row(9, "We two, not you, saw the walkarr goanna there.", "Ngali walkarr yinyay nyajin.", "ngali walkarr yinyay nyajin | 1du.excl.NOM walkarr.goanna there see.PST", "r345_1du_excl_there_reptile_c_saw_walkarr", ["ngali", "walkarr", "yinyay", "nyajin"]),
    row(10, "We two, not you, saw the bajabaja lizard there.", "Ngali bajabaja yinyay nyajin.", "ngali bajabaja yinyay nyajin | 1du.excl.NOM bajabaja.lizard there see.PST", "r345_1du_excl_there_reptile_c_saw_bajabaja", ["ngali", "bajabaja", "yinyay", "nyajin"]),
    row(11, "You and I saw the kalkamuku snake here.", "Ngaliny kalkamuku yaluy nyajin.", "ngaliny kalkamuku yaluy nyajin | 1du.incl.NOM kalkamuku.snake here see.PST", "r345_1du_incl_here_reptile_c_saw_kalkamuku", ["ngaliny", "kalkamuku", "yaluy", "nyajin"]),
    row(12, "You and I saw the karrkurr frog here.", "Ngaliny karrkurr yaluy nyajin.", "ngaliny karrkurr yaluy nyajin | 1du.incl.NOM karrkurr.frog here see.PST", "r345_1du_incl_here_reptile_c_saw_karrkurr", ["ngaliny", "karrkurr", "yaluy", "nyajin"]),
    row(13, "You and I saw the jinkalmu snake here.", "Ngaliny jinkalmu yaluy nyajin.", "ngaliny jinkalmu yaluy nyajin | 1du.incl.NOM jinkalmu.snake here see.PST", "r345_1du_incl_here_reptile_c_saw_jinkalmu", ["ngaliny", "jinkalmu", "yaluy", "nyajin"]),
    row(14, "You and I saw the barka snake here.", "Ngaliny barka yaluy nyajin.", "ngaliny barka yaluy nyajin | 1du.incl.NOM barka.snake here see.PST", "r345_1du_incl_here_reptile_c_saw_barka", ["ngaliny", "barka", "yaluy", "nyajin"]),
    row(15, "You and I saw the yalnga turtle here.", "Ngaliny yalnga yaluy nyajin.", "ngaliny yalnga yaluy nyajin | 1du.incl.NOM yalnga.turtle here see.PST", "r345_1du_incl_here_reptile_c_saw_yalnga", ["ngaliny", "yalnga", "yaluy", "nyajin"]),
    row(16, "You and I saw the biwul snake here.", "Ngaliny biwul yaluy nyajin.", "ngaliny biwul yaluy nyajin | 1du.incl.NOM biwul.snake here see.PST", "r345_1du_incl_here_reptile_c_saw_biwul", ["ngaliny", "biwul", "yaluy", "nyajin"]),
    row(17, "You and I saw the yirku-yirku frog here.", "Ngaliny yirku-yirku yaluy nyajin.", "ngaliny yirku-yirku yaluy nyajin | 1du.incl.NOM yirku-yirku.frog here see.PST", "r345_1du_incl_here_reptile_c_saw_yirku_yirku", ["ngaliny", "yirku-yirku", "yaluy", "nyajin"]),
    row(18, "You and I saw the jadi goanna here.", "Ngaliny jadi yaluy nyajin.", "ngaliny jadi yaluy nyajin | 1du.incl.NOM jadi.goanna here see.PST", "r345_1du_incl_here_reptile_c_saw_jadi", ["ngaliny", "jadi", "yaluy", "nyajin"]),
    row(19, "You and I saw the walkarr goanna here.", "Ngaliny walkarr yaluy nyajin.", "ngaliny walkarr yaluy nyajin | 1du.incl.NOM walkarr.goanna here see.PST", "r345_1du_incl_here_reptile_c_saw_walkarr", ["ngaliny", "walkarr", "yaluy", "nyajin"]),
    row(20, "You and I saw the bajabaja lizard here.", "Ngaliny bajabaja yaluy nyajin.", "ngaliny bajabaja yaluy nyajin | 1du.incl.NOM bajabaja.lizard here see.PST", "r345_1du_incl_here_reptile_c_saw_bajabaja", ["ngaliny", "bajabaja", "yaluy", "nyajin"]),
    row(21, "You two saw the kalkamuku snake there.", "Yubal kalkamuku yinyay nyajin.", "yubal kalkamuku yinyay nyajin | 2du.NOM kalkamuku.snake there see.PST", "r345_2du_there_reptile_c_saw_kalkamuku", ["yubal", "kalkamuku", "yinyay", "nyajin"]),
    row(22, "You two saw the karrkurr frog there.", "Yubal karrkurr yinyay nyajin.", "yubal karrkurr yinyay nyajin | 2du.NOM karrkurr.frog there see.PST", "r345_2du_there_reptile_c_saw_karrkurr", ["yubal", "karrkurr", "yinyay", "nyajin"]),
    row(23, "You two saw the jinkalmu snake there.", "Yubal jinkalmu yinyay nyajin.", "yubal jinkalmu yinyay nyajin | 2du.NOM jinkalmu.snake there see.PST", "r345_2du_there_reptile_c_saw_jinkalmu", ["yubal", "jinkalmu", "yinyay", "nyajin"]),
    row(24, "You two saw the barka snake there.", "Yubal barka yinyay nyajin.", "yubal barka yinyay nyajin | 2du.NOM barka.snake there see.PST", "r345_2du_there_reptile_c_saw_barka", ["yubal", "barka", "yinyay", "nyajin"]),
    row(25, "You two saw the yalnga turtle there.", "Yubal yalnga yinyay nyajin.", "yubal yalnga yinyay nyajin | 2du.NOM yalnga.turtle there see.PST", "r345_2du_there_reptile_c_saw_yalnga", ["yubal", "yalnga", "yinyay", "nyajin"]),
    row(26, "You two saw the biwul snake there.", "Yubal biwul yinyay nyajin.", "yubal biwul yinyay nyajin | 2du.NOM biwul.snake there see.PST", "r345_2du_there_reptile_c_saw_biwul", ["yubal", "biwul", "yinyay", "nyajin"]),
    row(27, "You two saw the yirku-yirku frog there.", "Yubal yirku-yirku yinyay nyajin.", "yubal yirku-yirku yinyay nyajin | 2du.NOM yirku-yirku.frog there see.PST", "r345_2du_there_reptile_c_saw_yirku_yirku", ["yubal", "yirku-yirku", "yinyay", "nyajin"]),
    row(28, "You two saw the jadi goanna there.", "Yubal jadi yinyay nyajin.", "yubal jadi yinyay nyajin | 2du.NOM jadi.goanna there see.PST", "r345_2du_there_reptile_c_saw_jadi", ["yubal", "jadi", "yinyay", "nyajin"]),
    row(29, "You two saw the walkarr goanna there.", "Yubal walkarr yinyay nyajin.", "yubal walkarr yinyay nyajin | 2du.NOM walkarr.goanna there see.PST", "r345_2du_there_reptile_c_saw_walkarr", ["yubal", "walkarr", "yinyay", "nyajin"]),
    row(30, "You two saw the bajabaja lizard there.", "Yubal bajabaja yinyay nyajin.", "yubal bajabaja yinyay nyajin | 2du.NOM bajabaja.lizard there see.PST", "r345_2du_there_reptile_c_saw_bajabaja", ["yubal", "bajabaja", "yinyay", "nyajin"]),
    row(31, "You all saw the kalkamuku snake here.", "Yurra kalkamuku yaluy nyajin.", "yurra kalkamuku yaluy nyajin | 2pl.NOM kalkamuku.snake here see.PST", "r345_2pl_here_reptile_c_saw_kalkamuku", ["yurra", "kalkamuku", "yaluy", "nyajin"]),
    row(32, "You all saw the karrkurr frog here.", "Yurra karrkurr yaluy nyajin.", "yurra karrkurr yaluy nyajin | 2pl.NOM karrkurr.frog here see.PST", "r345_2pl_here_reptile_c_saw_karrkurr", ["yurra", "karrkurr", "yaluy", "nyajin"]),
    row(33, "You all saw the jinkalmu snake here.", "Yurra jinkalmu yaluy nyajin.", "yurra jinkalmu yaluy nyajin | 2pl.NOM jinkalmu.snake here see.PST", "r345_2pl_here_reptile_c_saw_jinkalmu", ["yurra", "jinkalmu", "yaluy", "nyajin"]),
    row(34, "You all saw the barka snake here.", "Yurra barka yaluy nyajin.", "yurra barka yaluy nyajin | 2pl.NOM barka.snake here see.PST", "r345_2pl_here_reptile_c_saw_barka", ["yurra", "barka", "yaluy", "nyajin"]),
    row(35, "You all saw the yalnga turtle here.", "Yurra yalnga yaluy nyajin.", "yurra yalnga yaluy nyajin | 2pl.NOM yalnga.turtle here see.PST", "r345_2pl_here_reptile_c_saw_yalnga", ["yurra", "yalnga", "yaluy", "nyajin"]),
    row(36, "You all saw the biwul snake here.", "Yurra biwul yaluy nyajin.", "yurra biwul yaluy nyajin | 2pl.NOM biwul.snake here see.PST", "r345_2pl_here_reptile_c_saw_biwul", ["yurra", "biwul", "yaluy", "nyajin"]),
    row(37, "You all saw the yirku-yirku frog here.", "Yurra yirku-yirku yaluy nyajin.", "yurra yirku-yirku yaluy nyajin | 2pl.NOM yirku-yirku.frog here see.PST", "r345_2pl_here_reptile_c_saw_yirku_yirku", ["yurra", "yirku-yirku", "yaluy", "nyajin"]),
    row(38, "You all saw the jadi goanna here.", "Yurra jadi yaluy nyajin.", "yurra jadi yaluy nyajin | 2pl.NOM jadi.goanna here see.PST", "r345_2pl_here_reptile_c_saw_jadi", ["yurra", "jadi", "yaluy", "nyajin"]),
    row(39, "You all saw the walkarr goanna here.", "Yurra walkarr yaluy nyajin.", "yurra walkarr yaluy nyajin | 2pl.NOM walkarr.goanna here see.PST", "r345_2pl_here_reptile_c_saw_walkarr", ["yurra", "walkarr", "yaluy", "nyajin"]),
    row(40, "You all saw the bajabaja lizard here.", "Yurra bajabaja yaluy nyajin.", "yurra bajabaja yaluy nyajin | 2pl.NOM bajabaja.lizard here see.PST", "r345_2pl_here_reptile_c_saw_bajabaja", ["yurra", "bajabaja", "yaluy", "nyajin"]),
    row(41, "We, not you, saw the kalkamuku snake there.", "Nganjin kalkamuku yinyay nyajin.", "nganjin kalkamuku yinyay nyajin | 1pl.excl.NOM kalkamuku.snake there see.PST", "r345_1pl_excl_there_reptile_c_saw_kalkamuku", ["nganjin", "kalkamuku", "yinyay", "nyajin"]),
    row(42, "We, not you, saw the karrkurr frog there.", "Nganjin karrkurr yinyay nyajin.", "nganjin karrkurr yinyay nyajin | 1pl.excl.NOM karrkurr.frog there see.PST", "r345_1pl_excl_there_reptile_c_saw_karrkurr", ["nganjin", "karrkurr", "yinyay", "nyajin"]),
    row(43, "We, not you, saw the jinkalmu snake there.", "Nganjin jinkalmu yinyay nyajin.", "nganjin jinkalmu yinyay nyajin | 1pl.excl.NOM jinkalmu.snake there see.PST", "r345_1pl_excl_there_reptile_c_saw_jinkalmu", ["nganjin", "jinkalmu", "yinyay", "nyajin"]),
    row(44, "We, not you, saw the barka snake there.", "Nganjin barka yinyay nyajin.", "nganjin barka yinyay nyajin | 1pl.excl.NOM barka.snake there see.PST", "r345_1pl_excl_there_reptile_c_saw_barka", ["nganjin", "barka", "yinyay", "nyajin"]),
    row(45, "We, not you, saw the yalnga turtle there.", "Nganjin yalnga yinyay nyajin.", "nganjin yalnga yinyay nyajin | 1pl.excl.NOM yalnga.turtle there see.PST", "r345_1pl_excl_there_reptile_c_saw_yalnga", ["nganjin", "yalnga", "yinyay", "nyajin"]),
    row(46, "We, not you, saw the biwul snake there.", "Nganjin biwul yinyay nyajin.", "nganjin biwul yinyay nyajin | 1pl.excl.NOM biwul.snake there see.PST", "r345_1pl_excl_there_reptile_c_saw_biwul", ["nganjin", "biwul", "yinyay", "nyajin"]),
    row(47, "We, not you, saw the yirku-yirku frog there.", "Nganjin yirku-yirku yinyay nyajin.", "nganjin yirku-yirku yinyay nyajin | 1pl.excl.NOM yirku-yirku.frog there see.PST", "r345_1pl_excl_there_reptile_c_saw_yirku_yirku", ["nganjin", "yirku-yirku", "yinyay", "nyajin"]),
    row(48, "We, not you, saw the jadi goanna there.", "Nganjin jadi yinyay nyajin.", "nganjin jadi yinyay nyajin | 1pl.excl.NOM jadi.goanna there see.PST", "r345_1pl_excl_there_reptile_c_saw_jadi", ["nganjin", "jadi", "yinyay", "nyajin"]),
    row(49, "We, not you, saw the walkarr goanna there.", "Nganjin walkarr yinyay nyajin.", "nganjin walkarr yinyay nyajin | 1pl.excl.NOM walkarr.goanna there see.PST", "r345_1pl_excl_there_reptile_c_saw_walkarr", ["nganjin", "walkarr", "yinyay", "nyajin"]),
    row(50, "We, not you, saw the bajabaja lizard there.", "Nganjin bajabaja yinyay nyajin.", "nganjin bajabaja yinyay nyajin | 1pl.excl.NOM bajabaja.lizard there see.PST", "r345_1pl_excl_there_reptile_c_saw_bajabaja", ["nganjin", "bajabaja", "yinyay", "nyajin"]),
]


def scan_static() -> list[str]:
    issues: list[str] = []
    if len(ROWS) != 50:
        issues.append(f"row count {len(ROWS)} != 50")
    if [item[0] for item in ROWS] != list(range(1, 51)):
        issues.append("sequence is not 1..50")
    if len({item[1] for item in ROWS}) != 50 or len({item[2] for item in ROWS}) != 50:
        issues.append("duplicate authored surface")
    for seq, english, kuku, analysis, frame, _tier, words_json, loans_json, evidence, confidence in ROWS:
        band = (seq - 1) // 10
        target = TARGET_ORDER[(seq - 1) % 10]
        pronoun, demo, _unused, location, person, prefix = FRAME_SPECS[band]
        words = json.loads(words_json)
        expected_kuku = f"{pronoun.capitalize()} {target} {demo} nyajin."
        expected_english = f"{prefix} the {TARGET_LABELS[target]} {location}."
        expected_analysis = f"{pronoun} {target} {demo} nyajin | {person}.NOM {TARGET_GLOSSES[target]} {location} see.PST"
        if json.loads(loans_json):
            issues.append(f"{seq}: loans")
        denied = sorted(word for word in DENY_KUKU if re.search(rf"(^|\s){re.escape(word)}([\s\.]|$)", kuku.lower()))
        if denied:
            issues.append(f"{seq}: denied Kuku {denied}")
        drift = [term for term in DENY_ENGLISH if re.search(rf"\b{re.escape(term)}\b", english.lower())]
        if drift:
            issues.append(f"{seq}: English drift {drift}")
        if kuku != expected_kuku:
            issues.append(f"{seq}: Kuku mismatch")
        if english != expected_english:
            issues.append(f"{seq}: English mismatch")
        if analysis != expected_analysis:
            issues.append(f"{seq}: analysis mismatch")
        if words != [pronoun, target, demo, "nyajin"]:
            issues.append(f"{seq}: words mismatch")
        if kuku.lower().rstrip(".") != " ".join(words):
            issues.append(f"{seq}: surface/words mismatch")
        if not frame.startswith("r345_"):
            issues.append(f"{seq}: frame mismatch")
        if TARGET_EVIDENCE[target] not in evidence or SUPPORT_EVIDENCE not in evidence:
            issues.append(f"{seq}: evidence mismatch")
        if confidence != TARGET_CONFIDENCE[target]:
            issues.append(f"{seq}: confidence mismatch")
    return issues


def main() -> int:
    target_records, support_records = source_audit()
    issues = scan_static()
    if issues:
        print("\n".join(issues))
        raise SystemExit(1)
    db = sqlite3.connect(DB)
    db.execute("PRAGMA foreign_keys=ON")
    db.execute("BEGIN")
    ensure_schema(db)
    if db.execute("SELECT 1 FROM batches WHERE label=?", (LABEL,)).fetchone():
        raise SystemExit(f"{LABEL} exists")
    if db.execute("SELECT COUNT(*) FROM sentences WHERE status='under_review'").fetchone()[0]:
        raise SystemExit("another batch is under review")
    target_coverage = count_words(db, TARGET_ORDER)
    support_coverage = count_words(db, list(EXPECTED_SUPPORT_COVERAGE))
    if target_coverage != EXPECTED_TARGET_COVERAGE:
        raise SystemExit(f"target coverage changed: {target_coverage}")
    if support_coverage != EXPECTED_SUPPORT_COVERAGE:
        raise SystemExit(f"support coverage changed: {support_coverage}")
    for seq, _english, kuku, _analysis, _frame, _tier, words_json, _loans, _evidence, _confidence in ROWS:
        words = json.loads(words_json)
        candidate_hits = db.execute(
            """SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id
               WHERE lower(s.kuku)=lower(?) AND s.status!='rejected' ORDER BY b.id,s.seq""",
            (kuku,),
        ).fetchall()
        if candidate_hits:
            raise SystemExit(f"candidate collision {seq}: {candidate_hits}")
        opposite_surface = f"{words[0].capitalize()} {words[1]} {OPPOSITE[words[2]]} nyajin."
        opposite_hits = db.execute(
            """SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id
               WHERE lower(s.kuku)=lower(?) AND s.status!='rejected' ORDER BY b.id,s.seq""",
            (opposite_surface,),
        ).fetchall()
        if opposite_hits != [("batch-386", seq)]:
            raise SystemExit(f"opposite mismatch {seq}: {opposite_hits}")
    verified, words = db.execute(
        """SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1)
           FROM sentences WHERE status IN ('accepted','revised')"""
    ).fetchone()
    if (verified, words) != (19397, 132947):
        raise SystemExit(f"baseline changed {verified}/{words}")
    notes = (
        "COMPLEMENTARY SENSE-QUALIFIED REPTILE SET-C NON-SINGULAR PAST PERCEPTION AFTER RULE 344 (Rule 345). "
        "50 under-review exact deictic complements; candidates 50/50 empty and opposites exactly Batch 386 seq "
        "1-50. Fresh source/record and Patz-over-dictionary clusivity rulings unchanged; ngana remains grammatical. "
        "All target sense/source boundaries remain closed. Completion necessarily changes gap 162->172."
    )
    cur = db.execute(
        "INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",
        (LABEL, "Rule 345 under review", "operator-guide-2026-07-10", notes, NOW),
    )
    batch_id = cur.lastrowid
    db.executemany(
        """INSERT INTO sentences(
             batch_id,seq,english,kuku,analysis,frame,tier,words_used,loans_used,evidence,status,confidence,
             rights_status,author,created_at,updated_at
           ) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
        [
            (
                batch_id, seq, english, kuku, analysis, frame, tier, words_json, loans_json, evidence,
                "under_review", confidence, "project_approved_synthetic_pending_elder_verification",
                "codex-main", NOW, NOW,
            )
            for seq, english, kuku, analysis, frame, tier, words_json, loans_json, evidence, confidence in ROWS
        ],
    )
    events = [
        ("source", "source-hash-pass", f"Dictionary and Patz hashes match Rule 345 expectations: {EXPECTED_HASHES}."),
        ("source", "source-readback", f"Fresh target records={target_records}; support records={support_records}; Patz and target passages reread."),
        ("source", "pronoun-conflict-ruling", "Patz still controls ngali=1du.excl and ngaliny=1du.incl over dictionary misgloss/omission; deferred ngana remains grammatical."),
        ("planning", "sense-preservation-audit", "Rule 342-344 generic labels and all record/polysemy/taxonomy/cultural/food/whole-head/property/habitat/case/source/event boundaries retained."),
        ("planning", "complement-map-audit", "All 50 candidate cells absent; every opposite exactly Batch 386 sequences 1-50; full 100-cell matrix accounted for."),
        ("planning", "deictic-balance-audit", "Before banking yaluy=4512 and yinyay=4674, gap 162; completion projects 172. The apparent 152-gap inverse is Batch 386 duplication."),
        ("preflight", "coverage-audit", f"Coverage before banking: targets={target_coverage}; support={support_coverage}."),
        ("preflight", "duplicate-preflight", "All 50 selected Kuku and English surfaces internally unique and absent; opposites proved one-for-one."),
        ("preflight", "static-guard-pass", "50 explicit Rule 345 rows; source, clusivity, sense, morphology, frame, words, gloss, evidence, confidence, loan and exclusion contracts passed."),
    ]
    for phase, event_type, detail in events:
        record_event(
            db, batch_label=LABEL, phase=phase, event_type=event_type, actor="codex",
            detail=detail, artifact_path=PROCESS_LOG, created_at=NOW,
        )
    record_event(
        db, batch_label=LABEL, phase="bank", event_type="bank-success", actor="codex",
        detail=f"Banked 50 Rule 345 complementary rows under_review; verified remains {verified}; words {words}.",
        command="python3 batch_scripts/bank_387.py", output_excerpt="50 under_review",
        artifact_path=PROCESS_LOG, created_at=NOW,
    )
    db.commit()
    print("banked batch-387: 50 rows under_review")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
