#!/usr/bin/env python3
"""Close batch-367 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-367"
NOW = dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
PROCESS_LOG = "process_logs/batch-367-low-coverage-fauna-singular-third-nonpast-perception-after-rule324-process.md"
LENSES = ("morphology", "lexicon", "syntax", "fidelity", "register")

NOTES = (
    "LOW-COVERAGE FAUNA SINGULAR/THIRD-PERSON NONPAST PERCEPTION AFTER RULE 324 (Rule 325). 50 rows. TARGETS: "
    "dirrmbay seagull, diri-diri sandfly, jawurraji ant bed, juku-juku bronzewing dove, jalan sea urchin, "
    "kaya-kaya dogs, kubu-kubu tadpole, murral tree kangaroo, ngamu-murramu dingo, wurarr-wurarr dragonfly. "
    "SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana; Yalanji yaluy/yinyay; dictionary-attested nonpast "
    "nyajil. Exact conservative fauna labels only. No dialect substitution, tree/wood homonym, solid/hyphenated "
    "equivalence, omen/death, food/injury, habitat, hunting, ownership, transformation, source-story event, "
    "productive compound/reduplication, target case, past/purposive/reduplicated perception, support inflection, "
    "or carried trap was opened."
)

LESSONS = [
    ("source", "Rule 325 selected ten direct-dictionary, noun-typed, low-coverage fauna heads: dirrmbay, diri-diri, jawurraji, juku-juku, jalan, kaya-kaya, kubu-kubu, murral, ngamu-murramu, and wurarr-wurarr.", "Rule 325: low-coverage fauna inventory."),
    ("source", "Dictionary lines reread: dirrmbay 6035-6063, diri-diri 5930-5945, jawurraji 8551-8562, juku-juku 10350-10377, jalan 7340-7350, kaya-kaya 13966-13979, kubu-kubu 14707-14729, murral 20999-21009, ngamu-murramu 22184-22194, wurarr-wurarr 28305-28318.", "Rule 325: dictionary source lines."),
    ("source", "Exact Patz searches found juku-juku at lines 1941 and 1976 only in the distinct plural-trees sense and found none of the other nine target heads. The selected bronzewing-dove and all other fauna readings therefore remain dictionary-sourced.", "Rule 325: Patz target occurrence and homonym audit."),
    ("source", "Patz line 1476 explicitly includes fauna among corporeal objects denoted by nouns, licensing the selected heads as noun objects rather than inferred behaviors or events.", "Rule 325: fauna noun source."),
    ("source", "Patz lines 2577-2586 source singular/third nominatives; 2834-2847 Yalanji yaluy/yinyay; 3043-3049 nonpast nyaji-l; 3149-3151 nonpast function; 4256-4265 perception A/O; dictionary 24282-24296 running-form nyajil.", "Rule 325: construction source."),
    ("source", "The fauna audit excluded Nyungkul-only kanyaji, kumurbina, and yidilnyul, undefined or linter-invalid solid reduplications, loans, ambiguous place names, and culturally loaded story/totem candidates where cleaner direct entries existed.", "Rule 325: candidate exclusions."),
    ("process", "Rule 325 was scoped as bare fauna entity reference in singular/third-person nonpast visual perception, not dialect alignment, behavior, habitat, food, danger, ownership, transformation, hunting, omen, source-story, or event content.", "Rule 325: bounded lexical-debt scope."),
    ("process", "All 50 rows were explicit authored calls; static contracts, row-level linter probes, internal uniqueness, and corpus exact-collision preflight all passed before banking.", "Rule 325: authorship and preflight."),
    ("process", "Target coverage before banking ranged from zero to four accepted/revised token rows: two zero-use heads, three one-use heads, four two/three-use heads, and two four-use heads.", "Rule 325: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1391, yundu 987, nyulu 662, bula 458, jana 1163, yaluy 3972, yinyay 4214, nyajil 4047.", "Rule 325: support coverage audit."),
    ("lexicon", "Dirrmbay was retained as basic seagull only; storm warning, weather prediction, call/music, corroboree, death/corpse messaging, flight, feeding, fishing, and events stayed closed.", "Rule 325: dirrmbay."),
    ("lexicon", "Diri-diri was retained as the exact sandfly head; base diri, synonym munyurri, productive reduplication, biting, pain/itch, season, habitat, smoke/repellent, and events stayed closed.", "Rule 325: diri-diri."),
    ("lexicon", "Jawurraji was retained as ant bed only; ants, grubs, habitation, size predication, digging, roasting, food, location, construction, material use, and events stayed closed.", "Rule 325: jawurraji."),
    ("lexicon", "Juku-juku was retained as the exact dictionary bronzewing-dove head; Patz trees, solid jukujuku, variant equivalence, omen, stranger/death, song/call, drinking, hunting, and events stayed closed.", "Rule 325: juku-juku."),
    ("lexicon", "Jalan was retained as sea urchin only; shell/spines, injury, feet, rock/reef/sea habitat, food, edibility, frying, gathering, carrying, and events stayed closed.", "Rule 325: jalan."),
    ("lexicon", "Kaya-kaya was retained as the exact dogs head; base kaya, productive reduplication, loan history, number derivation, ownership, biting, hunting, following, feeding, and events stayed closed.", "Rule 325: kaya-kaya."),
    ("lexicon", "Kubu-kubu was retained as the exact tadpole head; bare kubu smoke, productive reduplication, water/pool habitat, swimming, rain/season, frog transformation, growth, and events stayed closed.", "Rule 325: kubu-kubu."),
    ("lexicon", "Murral was retained as the Yalanji tree-kangaroo term; Nyungkul jarrabina, tree/canopy habitat, climbing, sleeping, visibility, hunting, spearing, catching, food, and events stayed closed.", "Rule 325: murral."),
    ("lexicon", "Ngamu-murramu was retained as one dingo head; decomposition into ngamu/murramu, mother/kin interpretation, synonym/dog equivalence, wild/domestic property, hunting, biting, ownership, movement, and events stayed closed.", "Rule 325: ngamu-murramu."),
    ("lexicon", "Wurarr-wurarr was retained as the exact dragonfly head; base wurarr, productive reduplication, flight/hovering, water indication, navigation/life-saving, pools/young, season, habitat, and events stayed closed.", "Rule 325: wurarr-wurarr."),
    ("morphology", "All Rule 325 fauna heads stayed bare absolutive objects, with no case, number, possession, derivation, behavior, or property morphology added.", "Rule 325: bare fauna O."),
    ("morphology", "Diri-diri, juku-juku, kaya-kaya, kubu-kubu, ngamu-murramu, and wurarr-wurarr were copied as exact whole dictionary heads. No component, base, new reduplicative form, compound decomposition, equivalence, or derivation was generated.", "Rule 325: lexicalized-form restraint."),
    ("morphology", "All subject forms stayed bare nominatives; no accusative, dative, locative, ablative, comitative, possessive, alternative, expanded, or non-selected pronoun was admitted.", "Rule 325: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajil stayed fixed support; no demonstrative case, past nyajin, purposive nyaji-nka, reduplicated watching, hearing/smell compound, or perception compound was admitted.", "Rule 325: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajil for first-singular there nonpast visual perception.", "Rule 325: 1sg there band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajil for second-singular here nonpast visual perception.", "Rule 325: 2sg here band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajil for third-singular there nonpast visual perception.", "Rule 325: 3sg there band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajil for third-dual here nonpast visual perception.", "Rule 325: 3du here band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajil for third-plural there nonpast visual perception.", "Rule 325: 3pl there band."),
    ("fidelity", "English stayed literal nonpast visual-perception/reference prose: selected observer, exact conservative fauna label, here/there, and see/sees only. Lexical labels do not assert source commentary's behaviors, habitats, uses, or events.", "Rule 325: literal English."),
    ("fidelity", "No dictionary commentary, Patz tree homonym, or older corpus row was converted into warning, biting, food, omen, injury, habitat, dog behavior, frog transformation, hunting, navigation, ownership, or life-saving claims.", "Rule 325: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style fauna-reference clauses. Dialect-only, culturally sensitive story/totem, death/omen, coercive, loan, place-name, and unresolved entries were excluded or explicitly sense-bounded.", "Rule 325: register and candidate ethics."),
    ("process", "Every Rule 325 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 325: explicit-row authorship evidence."),
    ("process", "Rules 149-324 carry-forward traps stayed closed, including fauna behavior/use, dialect, food, danger, habitat, homograph, case, compound, productive-reduplication, human, flora, anatomy, and support-inflection traps.", "Rule 325: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,447 if this closes; Rule 326 requires a fresh source and coverage audit and must not infer closed fauna dialect, behavior, habitat, food, danger, ownership, transformation, hunting, omen, morphology, case, perception, or support fields.", "Rule 325: next cadence."),
]

LEXEMES = [
    ("dirrmbay", "noun", None, "NA", "seagull", "batch-367: basic seagull nonpast-perception reference only; storm/warning/music/corroboree/death/message/behavior/event content closed."),
    ("diri-diri", "noun", None, "NA", "sandfly", "batch-367: exact sandfly head only; base/synonym/productive reduplication/bite/pain/season/habitat/repellent/event content closed."),
    ("jawurraji", "noun", None, "NA", "ant bed", "batch-367: ant-bed reference only; ants/grubs/habitation/size/digging/food/location/construction/use/event content closed."),
    ("juku-juku", "noun", None, "NA", "bronzewing dove", "batch-367: exact dictionary bird sense only; Patz trees, solid omen variant, equivalence/song/death/hunting/event content closed."),
    ("jalan", "noun", None, "NA", "sea urchin", "batch-367: sea-urchin reference only; shell/spines/injury/habitat/food/edibility/frying/gathering/event content closed."),
    ("kaya-kaya", "noun", None, "NA", "dogs", "batch-367: exact dogs head only; base/productive reduplication/loan history/ownership/behavior/hunting/feeding/event content closed."),
    ("kubu-kubu", "noun", None, "NA", "tadpole", "batch-367: exact tadpole head only; kubu smoke/reduplication/habitat/swimming/rain/frog transformation/growth/event content closed."),
    ("murral", "noun", None, "NA", "tree kangaroo", "batch-367: Yalanji tree-kangaroo reference only; Nyungkul substitution/habitat/climbing/hunting/catching/food/event content closed."),
    ("ngamu-murramu", "noun", None, "NA", "dingo", "batch-367: indivisible dingo head only; decomposition/kin/dog equivalence/wildness/ownership/hunting/behavior/event content closed."),
    ("wurarr-wurarr", "noun", None, "NA", "dragonfly", "batch-367: exact dragonfly head only; base/reduplication/flight/water/navigation/life-saving/habitat/event content closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-367: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-367: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-367: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-367: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-367: bare nominative subject support only; Patz table OCR iana reconciled to dictionary/corpus jana."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-367: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-367: bare Yalanji local demonstrative support only."),
    ("nyajil", "verb-tr", "l", "NA", "see; see.NPST", "batch-367: dictionary-attested nonpast visual-perception surface corresponding to Patz nyaji-l."),
]


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, under_review, accepted = 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 under_review != 50 or accepted:
        raise SystemExit(f"close precheck failed total={total} under_review={under_review} accepted={accepted}")
    existing_reviews = db.execute(
        "SELECT COUNT(*) FROM reviews WHERE sentence_id IN (SELECT id FROM sentences WHERE batch_id=?)", (bid,)
    ).fetchone()[0]
    existing_lessons = db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?", (bid,)).fetchone()[0]
    existing_logs = db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-367-verify'").fetchone()[0]
    if existing_reviews or existing_lessons or existing_logs:
        raise SystemExit(
            f"non-destructive close precheck failed reviews={existing_reviews} lessons={existing_lessons} logs={existing_logs}"
        )
    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, category, lesson, guide_change, NOW) for category, lesson, guide_change in LESSONS],
    )
    for head, pos, conj, case_class, gloss, note in LEXEMES:
        senses = json.dumps([{"sense": gloss, "definition": note, "status": "attested"}], ensure_ascii=False)
        attestation = 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, attestation, None, None, None, note, None, 0,
             "verified", NOW, note, LABEL),
        )
        db.execute(
            "INSERT INTO lexeme_log(headword,action,detail,created_at) VALUES(?,?,?,?)",
            (head, "batch-367-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 325 rows: bare fauna O morphology, nominative singular/third pronoun A, fixed Yalanji local/nonpast support, exact dictionary fauna heads and conservative labels, literal English fidelity, and neutral elicitation register; all dialect, homonym, omen, behavior, habitat, food, danger, ownership, transformation, hunting, and event semantics 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 dirrmbay warning/death/music, diri bite/season, jawurraji grub/food, juku-juku tree/solid-omen drift, jalan spine/food/habitat, kaya ownership/behavior, kubu smoke/frog transformation, murral Nyungkul/hunting, ngamu-murramu decomposition/kin, wurarr navigation/life-saving, target case, past/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 325 lessons covering source, target occurrence/semantic homonym, fauna O syntax, candidate exclusions, coverage, lexical boundaries, morphology, syntax, fidelity, register, explicit 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 325 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_count = 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-367-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 367 / Rule 325: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_367.py", output_excerpt=f"closed batch-367 accepted={accepted_count} 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-367: accepted={accepted_count}, reviews={reviews}, lessons={lessons}, "
        f"lexeme_logs={logs}, verified {before}->{after}, kuku_words {words_before}->{words_after}"
    )
    return 0


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