#!/usr/bin/env python3
"""Close batch-373 after main-loop five-lens review."""

from __future__ import annotations

import datetime as dt
import json
import sqlite3

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-373"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-373-low-coverage-insects-complementary-past-perception-after-rule330-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LOW-COVERAGE INSECTS COMPLEMENTARY SINGULAR/THIRD-PERSON PAST PERCEPTION AFTER RULE 330 (Rule 331). "
    "50 rows. TARGETS: jimu grasshopper, kira-kira black ant, kuran case-moth larva, kurrmaja larvae, murma "
    "wasp, durra caterpillar, jiljay grub, kandal maggot, kinga caterpillar, birinjil centipede. SUPPORT: bare "
    "nominative ngayu, yundu, nyulu, bula, jana; Yalanji yaluy/yinyay; dictionary-attested past nyajin. Initial "
    "Rule-317-orientation surfaces collided with Batch 359 for five heads, so all deictic bands were inverted and "
    "collision-probed as a complementary paradigm. No alternate sense, free base, productive reduplication, "
    "derivation, habitat, food/use, life cycle, danger, body, source, possession, target case, nonpast/purposive/"
    "reduplicated perception, support inflection, or event proposition was opened."
)

LESSONS = [
    ("source", "Rule 331 selected ten direct non-loan fauna-insect noun heads at accepted/revised coverage five to seven: jimu, kira-kira, kuran, kurrmaja, murma, durra, jiljay, kandal, kinga, and birinjil.", "Rule 331: insect inventory."),
    ("source", "Dictionary lines reread: birinjil 3118-3126, durra 6696-6707, jiljay 9160-9168, jimu 9295-9303, kandal 13147-13157, kinga and kinga-dungay 14352-14372, kira-kira 14450-14463, kuran 16065-16076, kurrmaja 16507-16515, and murma 20936-20944.", "Rule 331: dictionary source lines."),
    ("source", "Exact case-insensitive Patz search for all ten selected heads returned no occurrences; every target sense and lexical boundary therefore remains dictionary-sourced rather than silently generalized from grammar text.", "Rule 331: negative Patz occurrence audit."),
    ("source", "Patz line 1476 includes fauna among noun referents, licensing bare visible-insect reference without importing habitat, food/use, life-cycle, danger, body, source, property, or event content.", "Rule 331: fauna noun source."),
    ("source", "Patz lines 2577-2586 source ngayu, yundu, nyulu, and bula; lines 1947 and 2686 establish running third-plural jana despite OCR iana in the paradigm table; 2834-2847 source Yalanji yaluy/yinyay, 2021-2024 and 2568-2571 past nyaji-ny, 3160-3162 past -ny, and 4256-4265 perception A/O; dictionary examples 23876-23883 and 23968-23976 contain running nyajin.", "Rule 331: construction source."),
    ("source", "The structured insect audit excluded unhyphenated repeated-looking dabadaba/dujandujan and polysemous jingka-jingka/kuja/walbul-walbul/malal. Rule-317-orientation frames collided with Batch 359 for kuran, kurrmaja, murma, durra, and jiljay; inversion of every deictic band produced 50 complementary non-colliding surfaces.", "Rule 331: candidate and collision audit."),
    ("process", "Rule 331 was scoped as bare insect reference in complementary past visual perception, not alternate sense, reduplication or derivation, habitat, food/use, life cycle, danger, body, source, possession, property, or event content.", "Rule 331: bounded lexical-debt scope."),
    ("process", "All 50 rows were explicit authored calls; exact static contracts, row-level linter probes, internal uniqueness, and corpus exact-collision preflight all passed before banking.", "Rule 331: authorship and preflight."),
    ("process", "Target coverage before banking was jimu 5, kira-kira 5, kuran 5, kurrmaja 5, murma 5, durra 6, jiljay 6, kandal 6, kinga 6, and birinjil 7.", "Rule 331: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1421, yundu 1017, nyulu 692, bula 488, jana 1193, yaluy 4122, yinyay 4364, and nyajin 1600.", "Rule 331: support coverage audit."),
    ("lexicon", "Jimu was retained as grasshopper only; number, body, colour, movement, jumping, flying, swarming, feeding, habitat, season, catching, source, possession, and events stayed closed.", "Rule 331: jimu."),
    ("lexicon", "Kira-kira was retained as the exact whole black-ant head; free-base kira, productive reduplication, baby-girl homonym, colour predication, colony, nest, behavior, food, sting/bite, source, possession, and events stayed closed.", "Rule 331: kira-kira."),
    ("lexicon", "Kuran was retained as case-moth larva only; edibility, food, collection, green wood, habitat, life cycle, transformation, source, possession, and events stayed closed.", "Rule 331: kuran."),
    ("lexicon", "Kurrmaja was retained as its dictionary larvae head; green-ant behavior, eggs/pupae, colony, nest, food, medicine, collection, preparation, source, possession, and events stayed closed.", "Rule 331: kurrmaja."),
    ("lexicon", "Murma was retained as wasp only; size, paper-wasp taxonomy, yellow colour, sting, pain/danger, nest, tree habitat, behavior, source, possession, and events stayed closed.", "Rule 331: murma."),
    ("lexicon", "Durra was retained in the primary caterpillar sense only; worm equivalence, feeding, growth, wrapping, transformation, moth identity, life cycle, habitat, source, possession, and events stayed closed.", "Rule 331: durra."),
    ("lexicon", "Jiljay was retained as grub only; antbed location/habitat, gathering, fishing bait, strength, weight, catching, source, possession, and prior-row events stayed closed.", "Rule 331: jiljay."),
    ("lexicon", "Kandal was retained as maggot only; fly identity, egg/larval relation, life cycle, carrion or food spoilage, habitat, source, possession, and events stayed closed.", "Rule 331: kandal."),
    ("lexicon", "Kinga was retained as caterpillar only; adjacent derived kinga-dungay, derivational decomposition, feeding, movement, transformation, habitat, source, possession, and events stayed closed.", "Rule 331: kinga."),
    ("lexicon", "Birinjil was retained as centipede only; body/leg count, crawling, bark/stone habitat, bite/danger, blanket/bedding, source, possession, and prior-row events stayed closed.", "Rule 331: birinjil."),
    ("morphology", "All Rule 331 insect heads stayed bare absolutive objects, with no case, number, possession, derivation, habitat, event, property, source, or use morphology added.", "Rule 331: bare insect O."),
    ("morphology", "Kira-kira remained an exact whole reduplicated insect head and was not decomposed into free kira; kinga stayed distinct from derived kinga-dungay. No productive process, homonym merger, alternate sense, number reading, or equivalence was generated.", "Rule 331: lexicalized and near-form restraint."),
    ("morphology", "All subject forms stayed bare nominatives: ngayu, yundu, nyulu, bula, and jana. No accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 331: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajin stayed fixed support; no demonstrative case, Nyungkul substitution, nonpast nyajil, purposive nyaji-nka, reduplicated watching, hearing/smell compound, or support inflection was admitted.", "Rule 331: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajin for first-singular here past visual perception, complementing rather than duplicating Rule 317's there band.", "Rule 331: 1sg here band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajin for second-singular there past visual perception, complementing rather than duplicating Rule 317's here band.", "Rule 331: 2sg there band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yaluy nyajin for third-singular here past visual perception, complementing rather than duplicating Rule 317's there band.", "Rule 331: 3sg here band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajin for third-dual there past visual perception, complementing rather than duplicating Rule 317's here band.", "Rule 331: 3du there band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajin for third-plural here past visual perception, complementing rather than duplicating Rule 317's there band.", "Rule 331: 3pl here band."),
    ("fidelity", "English stayed literal past visual-perception and reference prose: selected observer, exact conservative insect label, here or there, and saw only. Labels do not assert source commentary's alternate senses, morphology, habitat, food/use, life cycle, danger, body, or event content.", "Rule 331: literal English."),
    ("fidelity", "No dictionary commentary, Patz silence, Batch 359 surface, richer historical row, homonym note, reduplication analysis, or adjacent derived form was converted into identity, habitat, behavior, food, danger, source, possession, property, equivalence, or cultural-practice claims.", "Rule 331: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style insect-reference clauses. Orthographically risky, polysemous, homonymous, derived-body-state, habitat-heavy, dangerous, and culturally/event-heavy readings were excluded rather than normalized or embellished.", "Rule 331: register and candidate ethics."),
    ("process", "Every Rule 331 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 331: explicit-row authorship evidence."),
    ("process", "Rules 149-330 carry-forward traps stayed closed, including insect alternate senses, habitat/use, life cycle, food preparation, source, danger, body, loan, polysemy, near-form, homonym, compound, productive reduplication, case, and support-inflection traps.", "Rule 331: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,747 if this closes; Rule 332 requires a fresh source and coverage audit and must not infer closed insect alternate-sense, morphology, habitat, food/use, life-cycle, danger, body, source, possession, cultural-event, case, perception, or support fields.", "Rule 331: next cadence."),
]

LEXEMES = [
    ("jimu", "noun", None, "NA", "grasshopper", "batch-373: grasshopper reference only; number/body/colour/movement/swarming/feeding/habitat/season/catching/source/possession/event content closed."),
    ("kira-kira", "noun", None, "NA", "black ant", "batch-373: exact whole insect head only; base/productive-reduplication/child-homonym/colour/colony/nest/behavior/food/sting/source/possession/event content closed."),
    ("kuran", "noun", None, "NA", "case-moth larva", "batch-373: case-moth-larva reference only; edible/food/collection/green-wood/habitat/life-cycle/transformation/source/possession/event content closed."),
    ("kurrmaja", "noun", None, "NA", "larvae of green ants", "batch-373: dictionary larvae reference only; green-ant behavior/egg/pupa/colony/nest/food/medicine/collection/preparation/source/possession/event content closed."),
    ("murma", "noun", None, "NA", "wasp", "batch-373: wasp reference only; size/taxonomy/colour/sting/danger/nest/tree/behavior/source/possession/event content closed."),
    ("durra", "noun", None, "NA", "caterpillar", "batch-373: primary caterpillar sense only; worm/feeding/growth/wrapping/transformation/moth/life-cycle/habitat/source/possession/event content closed."),
    ("jiljay", "noun", None, "NA", "grub found in antbed", "batch-373: grub reference only; antbed location/gathering/bait/strength/weight/catching/source/possession/event content closed."),
    ("kandal", "noun", None, "NA", "maggot", "batch-373: maggot reference only; fly/egg/larval-relation/life-cycle/carrion/spoilage/habitat/source/possession/event content closed."),
    ("kinga", "noun", None, "NA", "caterpillar", "batch-373: caterpillar reference only; kinga-dungay/decomposition/feeding/movement/transformation/habitat/source/possession/event content closed."),
    ("birinjil", "noun", None, "NA", "centipede", "batch-373: centipede reference only; body/legs/crawling/habitat/bite/danger/blanket/bedding/source/possession/event content closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-373: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-373: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-373: preferred bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-373: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-373: corpus-normalized bare nominative subject support corresponding to Patz table OCR iana."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-373: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-373: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "ny", "NA", "see; see.PST", "batch-373: dictionary-attested past visual-perception surface corresponding to Patz nyaji-ny."),
]


def main() -> int:
    if len(LESSONS) != 35: raise SystemExit(f"lesson inventory changed: {len(LESSONS)} != 35")
    if len(LEXEMES) != 18: raise SystemExit(f"lexeme inventory changed: {len(LEXEMES)} != 18")
    db = sqlite3.connect(DB); db.execute("PRAGMA foreign_keys=ON"); db.execute("BEGIN"); ensure_schema(db)
    batch = db.execute("SELECT id FROM batches WHERE label=?", (LABEL,)).fetchone()
    if not batch: raise SystemExit(f"{LABEL} has not been banked")
    bid = batch[0]; total, ur, ac = db.execute("SELECT COUNT(*),COUNT(*) FILTER(WHERE status='under_review'),COUNT(*) FILTER(WHERE status IN ('accepted','revised')) FROM sentences WHERE batch_id=?", (bid,)).fetchone()
    if total != 50 or ur != 50 or ac: raise SystemExit(f"close precheck failed total={total} under_review={ur} accepted={ac}")
    er = db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (bid,)).fetchone()[0]; el = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (bid,)).fetchone()[0]; eg = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-373-verify'").fetchone()[0]
    if er or el or eg: raise SystemExit(f"non-destructive close precheck failed reviews={er} lessons={el} logs={eg}")
    total_rows = db.execute("SELECT COUNT(*) FROM sentences WHERE status!='rejected'").fetchone()[0]; before, words_before = db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')").fetchone(); ids = [r[0] for r in db.execute("SELECT id FROM sentences WHERE batch_id=? ORDER BY seq", (bid,))]
    db.executemany("INSERT INTO reviews(sentence_id,round,lens,verdict,issues,suggested_fix,reviewer,created_at) VALUES(?,?,?,?,?,?,?,?)", [(sid, 1, lens, "pass", None, None, "codex-main-five-lens", NOW) for sid in ids for lens in LENSES])
    db.executemany("INSERT INTO lessons(batch_id,category,lesson,guide_change,created_at) VALUES(?,?,?,?,?)", [(bid, c, l, g, NOW) for c, l, g in LESSONS])
    for head, pos, conj, case_class, gloss, note in LEXEMES:
        senses = json.dumps([{"sense": gloss, "definition": note, "status": "attested"}], ensure_ascii=False); att = json.dumps([{"source": LABEL, "ref": "five-lens close", "quote": note}], ensure_ascii=False)
        db.execute("""INSERT INTO lexemes(headword,phonemic,pos,conj_class,case_class,gloss,senses,attestation,allomorphy,morphology,collocations,usage_notes,antonyms_contrasts,corpus_freq,status,verified_at,notes) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT(headword) DO UPDATE SET verified_at=excluded.verified_at,status=excluded.status,notes=CASE WHEN lexemes.notes IS NULL OR lexemes.notes='' THEN excluded.notes WHEN instr(lexemes.notes,?)>0 THEN lexemes.notes ELSE lexemes.notes||'; '||excluded.notes END""", (head, None, pos, conj, case_class, gloss, senses, att, None, None, None, note, None, 0, "verified", NOW, note, LABEL))
        db.execute("INSERT INTO lexeme_log(headword,action,detail,created_at) VALUES(?,?,?,?)", (head, "batch-373-verify", note, NOW))
    record_event(db, batch_label=LABEL, phase="lint", event_type="under-review-lint-green", actor="codex", detail=f"After banking, whole-corpus lint scanned {total_rows} rows and found 0 issues; verified remained {before} before close.", command="python3 lint_corpus.py", output_excerpt=f"lint: {total_rows} rows scanned, 0 issues; GOAL {before}/20000 ({words_before} words)", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="five-lens-pass", actor="codex", detail="Manual five-lens review passed all 50 Rule 331 rows: bare insect O morphology, bare nominative singular/third-person pronoun A, fixed Yalanji local/past support, exact dictionary insect heads and conservative labels, literal English fidelity, and neutral elicitation register; every alternate-sense, morphology, habitat, food/use, life-cycle, danger, body, source, possession, and event field remained closed.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="review-detail", actor="codex", detail="No kira-kira free-base/child-homonym claim, kuran edibility/wood claim, kurrmaja colony/use claim, murma colour/sting/nest claim, durra worm equivalence, jiljay antbed event, kandal fly/life-cycle claim, kinga-dungay merger, birinjil body/danger claim, target case, nonpast/purposive/reduplicated perception, or support-inflection drift remained.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lesson-inventory", actor="codex", detail=f"Inserted {len(LESSONS)} Rule 331 lessons covering source, negative occurrence audit, target senses, candidate/collision handling, coverage, lexical boundaries, morphology, syntax, fidelity, register, authorship, traps, and handoff.", artifact_path=PROCESS_LOG, created_at=NOW)
    record_event(db, batch_label=LABEL, phase="review", event_type="lexeme-source-log", actor="codex", detail=f"Inserted {len(LEXEMES)} lexeme/source-log rows: ten targets and eight support heads.", artifact_path=PROCESS_LOG, created_at=NOW)
    db.execute("UPDATE sentences SET status='accepted',updated_at=? WHERE batch_id=?", (NOW, bid)); db.execute("UPDATE batches SET notes=?,cheatsheet_version=?,guide_version=? WHERE id=?", (NOTES, "Rule 331 accepted", "operator-guide-2026-07-10", bid))
    after, words_after = db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN ('accepted','revised')").fetchone(); accepted = db.execute("SELECT COUNT(*) FROM sentences WHERE batch_id=? AND status='accepted'", (bid,)).fetchone()[0]; reviews = db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (bid,)).fetchone()[0]; lessons = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (bid,)).fetchone()[0]; logs = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-373-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 373 / Rule 331: {accepted} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_373.py", output_excerpt=f"closed batch-373 accepted={accepted} reviews={reviews} lessons={lessons} lexeme_logs={logs} verified {before}->{after} words {words_before}->{words_after}", artifact_path=PROCESS_LOG, created_at=NOW)
    db.commit(); print(f"closed batch-373: accepted={accepted}, reviews={reviews}, lessons={lessons}, lexeme_logs={logs}, verified {before}->{after}, kuku_words {words_before}->{words_after}"); return 0


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