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

NOTES = (
    "LOW-COVERAGE SHELLFISH/CRUSTACEAN SINGULAR/THIRD-PERSON NONPAST PERCEPTION AFTER RULE 328 "
    "(Rule 329). 50 rows. TARGETS: wurru-bulan small crab, dakaldakal trochus shell, kajarrbi clam shell, "
    "kunkun periwinkle, kurrija octopus, ngajay small crayfish, nikar oyster, wuli-wuli soldier crab, "
    "jalan sea urchin, wurrul shellfish. SUPPORT: bare nominative ngayu, yundu, nyulu, bula, jana; "
    "Yalanji yaluy/yinyay; dictionary-attested nonpast nyajil. Exact conservative marine-fauna labels only. "
    "No loans, free-base/productive reduplication, shell/animal collapse, habitat, edibility, gathering, catching, "
    "cooking, eating, source, possession, target case, past/purposive/reduplicated perception, support inflection, "
    "or event proposition was opened."
)

LESSONS = [
    ("source", "Rule 329 selected nine shellfish/crustacean noun heads at accepted/revised coverage seven to nine plus one ten-use control: wurru-bulan, dakaldakal, kajarrbi, kunkun, kurrija, ngajay, nikar, wuli-wuli, jalan, and wurrul.", "Rule 329: shellfish inventory."),
    ("source", "Dictionary lines reread: dakaldakal 4590-4603, jalan 7340-7350, kajarrbi 12013-12022, kunkun 15937-15951, kurrija 16364-16372, ngajay 21731-21741, nikar 24079-24087, wuli-wuli 27786-27799, wurru-bulan 28490-28498, and wurrul 28499-28510.", "Rule 329: dictionary source lines."),
    ("source", "Exact Patz searches found dakaldakal at line 944 in its trochus-shell sense; the other nine target heads were absent. Dictionary readings remain the source for every other admitted marine-fauna sense.", "Rule 329: Patz target occurrence and sense audit."),
    ("source", "Patz line 1476 includes fauna among noun referents, licensing bare visible shellfish/crustacean reference without inferring habitat, edibility, gathering, use, source, or event content.", "Rule 329: fauna noun source."),
    ("source", "Patz lines 2577-2586 source selected singular/third nominatives, 2834-2847 Yalanji yaluy/yinyay, 3043-3049 nonpast nyaji-l, 3149-3151 nonpast function, and 4256-4265 perception A/O; dictionary 24282-24296 attests running nyajil.", "Rule 329: construction source."),
    ("source", "The structured domain audit found ten heads at coverage zero to nine, but dictionary-final-m jirrum failed the established corpus orthotactic contract. It was excluded without adding a one-off exception, and the next-lowest direct unflagged head, ten-use wurru-bulan, was selected as a control.", "Rule 329: candidate-domain audit."),
    ("process", "Rule 329 was scoped as bare marine-fauna reference in singular and third-person nonpast visual perception, not shell/animal identity, habitat, edibility, gathering, catching, food, use, possession, source, property, or event content.", "Rule 329: 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 329: authorship and preflight."),
    ("process", "Target coverage before banking was wurru-bulan 10, dakaldakal 7, kajarrbi 8, kunkun 8, kurrija 8, ngajay 8, nikar 8, wuli-wuli 8, jalan 9, and wurrul 9 accepted/revised token rows.", "Rule 329: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1411, yundu 1007, nyulu 682, bula 478, jana 1183, yaluy 4062, yinyay 4324, and nyajil 4147.", "Rule 329: support coverage audit."),
    ("lexicon", "Wurru-bulan was retained as the exact whole small-crab head; component decomposition, productive compounding, size comparison, reef/sea habitat, movement, gathering, catching, food, cooking, eating, possession, source, and events stayed closed.", "Rule 329: wurru-bulan."),
    ("lexicon", "Dakaldakal was retained as the exact whole trochus-shell head; free-base use, productive reduplication, shell source, animal identity, gathering, carrying, tool/ornament use, and events stayed closed.", "Rule 329: dakaldakal."),
    ("lexicon", "Kajarrbi was retained as clam shell only; giant-size predication, animal/shell identity claims, sea habitat, opening, gathering, carrying, food, tool/ornament use, source, and events stayed closed.", "Rule 329: kajarrbi."),
    ("lexicon", "Kunkun was retained as periwinkle only; free-base use, productive reduplication, flatness, smoothness, shell parts, habitat, gathering, food, source, and events stayed closed.", "Rule 329: kunkun."),
    ("lexicon", "Kurrija was retained as octopus only; body parts, number, movement, water/reef habitat, catching, spearing, cooking, eating, danger, possession, source, and events stayed closed.", "Rule 329: kurrija."),
    ("lexicon", "Ngajay was retained as small crayfish only; edibility/avoidance, eating, size comparison, water habitat, catching, gathering, cooking, possession, source, and events stayed closed.", "Rule 329: ngajay."),
    ("lexicon", "Nikar was retained as oyster only; shallow-water/rock habitat, attachment, shell parts, gathering, opening, cooking, eating, possession, source, and events stayed closed.", "Rule 329: nikar."),
    ("lexicon", "Wuli-wuli was retained as the exact whole soldier-crab head; free-base use, productive reduplication, group/number claims, sand/beach habitat, movement, gathering, food, possession, source, and events stayed closed.", "Rule 329: wuli-wuli."),
    ("lexicon", "Jalan was retained as sea urchin only; shell/spines, porcupine comparison, injury, rock/sea habitat, edibility, meat, frying, gathering, carrying, source, and events stayed closed.", "Rule 329: jalan."),
    ("lexicon", "Wurrul was retained as shellfish only; species identity, shell parts, habitat, gathering, opening, cooking, eating, possession, source, equivalence to another head, and events stayed closed.", "Rule 329: wurrul."),
    ("morphology", "All Rule 329 marine-fauna heads stayed bare absolutive objects, with no case, number, possession, derivation, event, property, source, habitat, or use morphology added.", "Rule 329: bare shellfish O."),
    ("morphology", "Dakaldakal, kunkun, and wuli-wuli remained exact whole dictionary heads. Their reduplication analyses licensed no free base, decomposition, productive reduplication, new number reading, or equivalence; shell and animal labels also remained uncollapsed.", "Rule 329: lexicalized-form and shell/animal 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 329: 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 support inflection was admitted.", "Rule 329: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yaluy nyajil for first-singular here nonpast visual perception.", "Rule 329: 1sg here band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yinyay nyajil for second-singular there nonpast visual perception.", "Rule 329: 2sg there band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yaluy nyajil for third-singular here nonpast visual perception.", "Rule 329: 3sg here band."),
    ("syntax", "Rows 31-40 used Bula TARGET yinyay nyajil for third-dual there nonpast visual perception.", "Rule 329: 3du there band."),
    ("syntax", "Rows 41-50 used Jana TARGET yaluy nyajil for third-plural here nonpast visual perception.", "Rule 329: 3pl here band."),
    ("fidelity", "English stayed literal nonpast visual-perception and reference prose: selected observer, exact conservative marine-fauna label, here or there, and see only. Labels do not assert source commentary's habitat, edibility, morphology, use, relation, or event content.", "Rule 329: literal English."),
    ("fidelity", "No dictionary habitat/food note, Patz reduplication example, shell/animal alternate translation, near form, or older corpus row was converted into gathering, catching, cooking, eating, source, possession, property, equivalence, injury, or cultural-practice claims.", "Rule 329: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style marine-fauna-reference clauses. Loan status was checked, culturally loaded use fields stayed closed, and no ecological or subsistence event was generated.", "Rule 329: register and candidate ethics."),
    ("process", "Every Rule 329 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 329: explicit-row authorship evidence."),
    ("process", "Rules 149-328 carry-forward traps stayed closed, including shellfish habitat/use, food preparation, loan, source, toxicity, craft equivalence, polysemy, near-form, route, material, dialect, homograph, case, compound, productive reduplication, and support-inflection traps.", "Rule 329: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,647 if this closes; Rule 330 requires a fresh source and coverage audit and must not infer closed shellfish morphology, shell/animal identity, habitat, edibility, gathering, catching, source, possession, cultural event, case, perception, or support fields.", "Rule 329: next cadence."),
]

LEXEMES = [
    ("wurru-bulan", "noun", None, "NA", "small crab", "batch-371: exact small-crab head only; component/productive-compounding/size/habitat/movement/gathering/catching/food/cooking/eating/possession/source/event content closed."),
    ("dakaldakal", "noun", None, "NA", "trochus shell", "batch-371: exact whole head only; base/productive-reduplication/source/animal/gathering/carrying/tool/ornament/event content closed."),
    ("kajarrbi", "noun", None, "NA", "clam shell; giant clam", "batch-371: clam-shell reference only; giant/property/animal-identity/habitat/opening/gathering/carrying/food/use/source/event content closed."),
    ("kunkun", "noun", None, "NA", "periwinkle", "batch-371: periwinkle reference only; base/productive-reduplication/flatness/smoothness/shell/habitat/gathering/food/source/event content closed."),
    ("kurrija", "noun", None, "NA", "octopus", "batch-371: octopus reference only; body/number/movement/habitat/catching/spearing/cooking/eating/danger/possession/source/event content closed."),
    ("ngajay", "noun", None, "NA", "small crayfish", "batch-371: small-crayfish reference only; edibility/avoidance/size/habitat/catching/gathering/cooking/possession/source/event content closed."),
    ("nikar", "noun", None, "NA", "oyster", "batch-371: oyster reference only; shallow-water/rock/attachment/shell/gathering/opening/cooking/eating/possession/source/event content closed."),
    ("wuli-wuli", "noun", None, "NA", "soldier crab", "batch-371: exact whole head only; base/productive-reduplication/group/number/habitat/movement/gathering/food/possession/source/event content closed."),
    ("jalan", "noun", None, "NA", "sea urchin", "batch-371: sea-urchin reference only; shell/spines/comparison/injury/habitat/edibility/meat/frying/gathering/carrying/source/event content closed."),
    ("wurrul", "noun", None, "NA", "shellfish", "batch-371: shellfish reference only; species/shell/habitat/gathering/opening/cooking/eating/possession/source/equivalence/event content closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-371: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-371: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-371: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-371: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-371: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-371: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-371: bare Yalanji local demonstrative support only."),
    ("nyajil", "verb-tr", "l", "NA", "see; see.NPST", "batch-371: 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}")
    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-371-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-371-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 329 rows: bare marine-fauna O morphology, bare nominative singular/third-person pronoun A, fixed Yalanji local/nonpast support, exact dictionary shellfish/crustacean heads and conservative labels, literal English fidelity, and neutral elicitation register; all reduplication, shell/animal identity, habitat, edibility, gathering, catching, use, source, possession, 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 wurru-bulan habitat/use, dakaldakal/kunkun/wuli-wuli free-base or productive-reduplication claim, kajarrbi shell/animal collapse, kurrija catching, ngajay edibility, nikar rock habitat, jalan spines/frying, wurrul equivalence, 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 329 lessons covering source, target occurrence and sense, fauna O syntax, domain audit, 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 329 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(); ac=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-371-verify'").fetchone()[0]
    record_event(db,batch_label=LABEL,phase="close",event_type="close-success",actor="codex",detail=f"Closed Batch 371 / Rule 329: {ac} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.",command="python3 batch_scripts/close_371.py",output_excerpt=f"closed batch-371 accepted={ac} 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-371: accepted={ac}, reviews={reviews}, lessons={lessons}, lexeme_logs={logs}, verified {before}->{after}, kuku_words {words_before}->{words_after}"); return 0


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