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

NOTES = (
    "LOW-COVERAGE BIRDS COMPLEMENTARY SINGULAR/THIRD-PERSON PAST PERCEPTION AFTER RULE 332 (Rule 333). "
    "50 rows. TARGETS: jiwal-jiwal kingfisher, kalmbangarr black diver bird, karkunbay stockwhip bird, mirrki "
    "kidney bird, mulumu dove, karunkurr crested pigeon, munungkul ground pigeon, jurriyan satin bower bird, "
    "juku-juku bronzewing dove, dawa-dawa magpie. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana; "
    "Yalanji yaluy/yinyay; dictionary-attested past nyajin. Exact spelling/reduplication variants, overlapping "
    "bird labels, Patz tree homonym, and secondary cultural senses remain separate. Selected three-here layout "
    "has zero collisions and reduces the deictic gap; opposite layout collides with five Batch 363 dawa-dawa "
    "rows. No variant equivalence, free base, productive morphology, body/colour, call/song, habitat, behavior, "
    "totem/moiety, ceremony, omen/death, source, possession, target case, nonpast/purposive/reduplicated "
    "perception, support inflection, or event proposition was opened."
)

LESSONS = [
    ("source", "Rule 333 selected ten exact non-loan fauna-bird noun heads at accepted/revised coverage five to eight: jiwal-jiwal, kalmbangarr, karkunbay, mirrki, mulumu, karunkurr, munungkul, jurriyan, juku-juku, and dawa-dawa.", "Rule 333: bird inventory."),
    ("source", "Dictionary lines reread: dawa-dawa/dawadawa 5326-5354, jiwal-jiwal 9998-10011, juku-juku/jukujuku 10350-10379, jurriyam/jurriyan 11298-11318, kalmbangarr/kalmnbagarr 12791-12808, karkunbay 13524-13533, karunkurr 13815-13823, kurkumbay/kurkunbay 16124-16143, mirrki/mirrku 19792-19813, mulumu 20512-20524, and munungkul 20827-20835.", "Rule 333: dictionary source lines."),
    ("source", "Fresh exact Patz target/variant search found only juku-juku at lines 1941 and 1976, where it means reduplicated 'trees'; that grammar homonym licenses no bronzewing-dove morphology, tree identity, or event claim.", "Rule 333: Patz occurrence and homonym audit."),
    ("source", "Patz line 1476 includes fauna among noun referents, licensing bare visible-bird reference without importing body, call, habitat, behavior, cultural role, source, property, or event content.", "Rule 333: fauna noun source."),
    ("source", "Patz lines 2577-2586 plus running jana at 1947/2686 source selected nominatives, 2834-2847 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 333: construction source."),
    ("source", "Exact record boundaries kept kalmbangarr/kalmnbagarr, karkunbay/kurkunbay/kurkumbay, mirrki/mirrku, jurriyan/jurriyam, juku-juku/jukujuku/tree homonym, and dawa-dawa/dawadawa distinct; mulumu dove stayed separate from wood/corroboree. Selected layout has zero collisions; opposite layout reproduces five Batch 363 dawa-dawa rows.", "Rule 333: variant, sense, and collision audit."),
    ("process", "Rule 333 was scoped as bare bird reference in complementary past visual perception, not variant equivalence, free-base/productive morphology, body/colour, call/song, habitat, behavior, totem/moiety, ceremony, omen/death, source, possession, property, or event content.", "Rule 333: bounded lexical-debt scope."),
    ("process", "All 50 rows were explicit authored calls; exact static contracts, row-level linter probes, internal uniqueness, and selected/alternate orientation collision matrices all passed before banking.", "Rule 333: authorship and preflight."),
    ("process", "Target coverage before banking was jiwal-jiwal 5, kalmbangarr 5, karkunbay 5, mirrki 5, mulumu 5, karunkurr 6, munungkul 6, jurriyan 6, juku-juku 7, and dawa-dawa 8.", "Rule 333: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1431, yundu 1027, nyulu 702, bula 498, jana 1203, yaluy 4182, yinyay 4404, and nyajin 1700.", "Rule 333: support coverage audit."),
    ("lexicon", "Jiwal-jiwal was retained as the exact whole kingfisher head; free-base use, productive reduplication, tail/colour property, flight, call, hunting, water habitat, source, possession, and events stayed closed.", "Rule 333: jiwal-jiwal."),
    ("lexicon", "Kalmbangarr was retained as exact black-diver-bird reference using its complete phonemic record; kalmnbagarr normalization/equivalence, colour predication, diving, habitat, source, possession, and events stayed closed.", "Rule 333: kalmbangarr."),
    ("lexicon", "Karkunbay was retained as exact stockwhip-bird reference; kurkunbay/kurkumbay equivalence, butcherbird identity, call/sound, behavior, source, possession, and events stayed closed.", "Rule 333: karkunbay."),
    ("lexicon", "Mirrki was retained as exact kidney-bird reference; mirrku identity/equivalence, totem, dabu, moiety, ceremony, source, possession, and events stayed closed.", "Rule 333: mirrki."),
    ("lexicon", "Mulumu was retained in the primary dove sense only; wood/material identity, sacred/corroboree use, ceremony, source, possession, and events stayed closed.", "Rule 333: mulumu."),
    ("lexicon", "Karunkurr was retained as crested pigeon only; crest/body property, walking, feeding, seed, track, habitat, source, possession, and events stayed closed.", "Rule 333: karunkurr."),
    ("lexicon", "Munungkul was retained as ground pigeon only; ground/location predication, feeding, leaves, trees, habitat, source, possession, and events stayed closed.", "Rule 333: munungkul."),
    ("lexicon", "Jurriyan was retained as the exact final-n satin-bower-bird head; final-m jurriyam normalization/equivalence, feather/colour, collecting/stealing, bower behavior, source, possession, and events stayed closed.", "Rule 333: jurriyan."),
    ("lexicon", "Juku-juku was retained only in the exact dictionary bronzewing-dove sense; free-base/productive reduplication, Patz tree homonym, unhyphenated jukujuku identity, omen, stranger, death, call, source, possession, and events stayed closed.", "Rule 333: juku-juku."),
    ("lexicon", "Dawa-dawa was retained as the exact hyphenated magpie head; free-base/productive reduplication, unhyphenated dawadawa identity/equivalence, call/song, time/news, country, source, possession, and events stayed closed.", "Rule 333: dawa-dawa."),
    ("morphology", "All Rule 333 bird heads stayed bare absolutive objects, with no case, number, possession, derivation, variant, habitat, event, property, source, or use morphology added.", "Rule 333: bare bird O."),
    ("morphology", "Jiwal-jiwal, juku-juku, and dawa-dawa remained exact whole hyphenated heads. No free base, productive reduplication, unhyphenated-form equivalence, spelling normalization, homonym merger, derivation, number reading, or identity claim was generated.", "Rule 333: lexicalized and variant-form restraint."),
    ("morphology", "All subject forms stayed bare nominatives: ngayu, yundu, nyulu, bula, and jana. No non-singular alternative, accusative, dative, locative, ablative, comitative, possessive, or expanded pronoun was admitted.", "Rule 333: 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 333: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajin for first-singular here past visual perception.", "Rule 333: 1sg here band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajin for second-singular there past visual perception.", "Rule 333: 2sg there band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yaluy nyajin for third-singular here past visual perception.", "Rule 333: 3sg here band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajin for third-dual there past visual perception.", "Rule 333: 3du there band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajin for third-plural here past visual perception.", "Rule 333: 3pl here band."),
    ("fidelity", "English stayed literal past visual-perception and reference prose: selected observer, exact conservative bird label, here or there, and saw only. Labels do not assert variant identity, morphology, body, call, habitat, behavior, cultural role, source, or event content.", "Rule 333: literal English."),
    ("fidelity", "No dictionary cross-reference, nearby spelling, Patz tree homonym, secondary cultural sense, earlier rich bird row, reduplication note, or overlapping English bird label was converted into equivalence, ecology, behavior, omen, ceremony, source, possession, property, or cultural-practice claims.", "Rule 333: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style bird-reference clauses. Totem/moiety, sacred-corroboree, omen/death, call/news/time, hunting, habitat, and culturally/event-heavy readings were explicitly left closed rather than repurposed as synthetic narrative.", "Rule 333: register and cultural restraint."),
    ("process", "Every Rule 333 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 333: explicit-row authorship evidence."),
    ("process", "Rules 149-332 carry-forward traps stayed closed, including bird variant identity, homonym, body/colour, flight/call/song, habitat, behavior, totem/moiety, ceremony, omen/death, source, possession, loan, polysemy, case, productive reduplication, and support-inflection traps.", "Rule 333: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,847 if this closes; Rule 334 requires a fresh source and coverage audit and must not infer closed bird variant-equivalence, morphology, homonym, body/call, habitat, behavior, cultural-role, source, possession, event, case, perception, or support fields.", "Rule 333: next cadence."),
]

LEXEMES = [
    ("jiwal-jiwal", "noun", None, "NA", "kingfisher", "batch-375: exact whole kingfisher head only; base/productive-reduplication/tail/colour/flight/call/hunting/habitat/source/possession/event content closed."),
    ("kalmbangarr", "noun", None, "NA", "black diver bird", "batch-375: exact complete-record head only; kalmnbagarr normalization/equivalence/colour/diving/habitat/source/possession/event content closed."),
    ("karkunbay", "noun", None, "NA", "stockwhip bird", "batch-375: exact head only; kurkunbay/kurkumbay equivalence/butcherbird/call/behavior/source/possession/event content closed."),
    ("mirrki", "noun", None, "NA", "kidney bird", "batch-375: exact head only; mirrku equivalence/totem/dabu/moiety/ceremony/source/possession/event content closed."),
    ("mulumu", "noun", None, "NA", "dove", "batch-375: primary dove sense only; wood/material/sacred/corroboree/ceremony/source/possession/event content closed."),
    ("karunkurr", "noun", None, "NA", "crested pigeon", "batch-375: crested-pigeon reference only; crest/body/walking/feeding/seed/track/habitat/source/possession/event content closed."),
    ("munungkul", "noun", None, "NA", "ground pigeon", "batch-375: ground-pigeon reference only; ground/location/feeding/leaves/trees/habitat/source/possession/event content closed."),
    ("jurriyan", "noun", None, "NA", "satin bower bird", "batch-375: exact final-n head only; jurriyam normalization/equivalence/feather/colour/collecting/bower/source/possession/event content closed."),
    ("juku-juku", "noun", None, "NA", "bronzewing dove", "batch-375: exact dictionary bird head only; base/productive-reduplication/tree homonym/jukujuku equivalence/omen/stranger/death/call/source/possession/event content closed."),
    ("dawa-dawa", "noun", None, "NA", "magpie", "batch-375: exact hyphenated head only; base/productive-reduplication/dawadawa equivalence/call/song/time/news/country/source/possession/event content closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-375: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-375: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-375: preferred bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-375: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-375: running Patz/corpus bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-375: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-375: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "ny", "NA", "see; see.PST", "batch-375: 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-375-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-375-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 333 rows: bare bird O morphology, bare nominative singular/third-person pronoun A, fixed Yalanji local/past support, exact dictionary bird heads and conservative labels, literal English fidelity, and neutral elicitation register; every variant-equivalence, secondary-sense, homonym, cultural-role, morphology, habitat, behavior, 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 kalmbangarr/kalmnbagarr, karkunbay/kurkunbay/kurkumbay, mirrki/mirrku, jurriyan/jurriyam, juku-juku/jukujuku/tree-homonym, or dawa-dawa/dawadawa identity claim; no mulumu wood/corroboree, mirrki totem/moiety, juku-juku omen/death, call/song, target case, nonpast/purposive/reduplicated perception, or support 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 333 lessons covering source, Patz homonym, variant boundaries, candidate/collision handling, coverage, lexical senses, morphology, syntax, fidelity, cultural 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 333 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-375-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 375 / Rule 333: {accepted} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_375.py", output_excerpt=f"closed batch-375 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-375: 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())
