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

NOTES = (
    "LOW-COVERAGE CRAFT MATERIALS/OBJECTS SINGULAR/THIRD-PERSON PAST PERCEPTION AFTER RULE 326 "
    "(Rule 327). 50 rows. TARGETS: duburan directional sign, jila beeswax, makarra streaky yellow "
    "ochre, makirr yellow ochre, ngurran rope, nyumbirr beeswax, warkal bailer shell, wuba red "
    "ochre, wuju grass sponge, yikari hardened beeswax. SUPPORT: bare nominative ngayu, yundu, "
    "nyulu, bula, jana; Yalanji yaluy/yinyay; dictionary-attested past nyajin. Exact conservative "
    "object labels only. No alternate polysemy, wax/ochre equivalence, source, manufacture, use, "
    "material decomposition, target case, nonpast/purposive/reduplicated perception, support "
    "inflection, or event proposition was opened."
)

LESSONS = [
    ("source", "Rule 327 selected ten direct-dictionary, noun-typed, low-coverage craft-material or object heads: duburan, jila, makarra, makirr, ngurran, nyumbirr, warkal, wuba, wuju, and yikari.", "Rule 327: craft-object inventory."),
    ("source", "Dictionary lines reread: duburan 6196-6209, jila 9038-9063, makarra 17184-17193, makirr 17194-17202, ngurran 23861-23872, nyumbirr 24750-24760, warkal 26443-26453, wuba 27407-27417, wuju 27620-27630, and yikari 29896-29906.", "Rule 327: dictionary source lines."),
    ("source", "Exact Patz searches found wuju at lines 5171-5172 in its grass-sop use and jila at lines 7088 and 7091 only in the smell sense; the other eight target heads were absent. Dictionary readings remain the source for every admitted object sense.", "Rule 327: Patz target occurrence and sense audit."),
    ("source", "Patz line 1476 includes artifacts and other objects of human habitat among noun referents, licensing bare object reference without inferring manufacture, use, ownership, source, or cultural event content.", "Rule 327: artifact noun source."),
    ("source", "Patz lines 2577-2586 source the selected bare nominatives, lines 2834-2847 Yalanji yaluy/yinyay, 2021-2024 and 2568-2571 past nyaji-ny, 3160-3162 past -ny, and 4256-4265 perception A/O; dictionary 23876-23883 and 23968-23976 attest running nyajin.", "Rule 327: construction source."),
    ("source", "The craft-object audit excluded loans, weapons and coercive implements, place or euphemism homonyms, mortuary yinkar, culturally unresolved candidates, and heads lacking a stable direct referential reading.", "Rule 327: candidate exclusions."),
    ("process", "Rule 327 was scoped as bare craft-material or object reference in singular and third-person past visual perception, not alternate polysemy, material composition, source, manufacture, use, possession, equivalence, property predication, or event content.", "Rule 327: 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 327: authorship and preflight."),
    ("process", "Target coverage before banking was duburan 4, jila 9, makarra 0, makirr 6, ngurran 0, nyumbirr 0, warkal 6, wuba 5, wuju 6, and yikari 1 accepted/revised token rows.", "Rule 327: target coverage audit."),
    ("process", "Support coverage before banking was ngayu 1401, yundu 997, nyulu 672, bula 468, jana 1173, yaluy 4022, yinyay 4264, and nyajin 1450.", "Rule 327: support coverage audit."),
    ("lexicon", "Duburan was retained as directional sign only; carrying ring or wreath, women, body placement, direction giving, route use, stone or grass composition, making, positioning, and events stayed closed.", "Rule 327: duburan."),
    ("lexicon", "Jila was retained as beeswax only; smell, sweat or perspiration, crocodile source, body state, derivatives, sensory event, source or use, and equivalence to other wax heads stayed closed.", "Rule 327: jila."),
    ("lexicon", "Makarra was retained as streaky yellow ochre only; equivalence to makirr, property predication, inferred streak pattern, source, mining, grinding, painting, body or ceremony use, and events stayed closed.", "Rule 327: makarra."),
    ("lexicon", "Makirr was retained as yellow ochre only; equivalence to makarra, streakiness, property predication, source, mining, grinding, painting, body or ceremony use, and events stayed closed.", "Rule 327: makirr."),
    ("lexicon", "Ngurran was retained as rope only; rope-dilly-bag sense, material-source relation, karra substitution, tying, carrying, making, weaving, possession, and events stayed closed.", "Rule 327: ngurran."),
    ("lexicon", "Nyumbirr was retained as beeswax only; bee or source event, collecting, heating, hardening, softening, attaching, medicine, honey, manufacture or use, and equivalence to jila or yikari stayed closed.", "Rule 327: nyumbirr."),
    ("lexicon", "Warkal was retained as bailer shell only; billy or container function, water, carrying, bailing, cooking, food, old-time practice, shell source, possession, and events stayed closed.", "Rule 327: warkal."),
    ("lexicon", "Wuba was retained as red ochre only; property predication, pigment function, source, digging, grinding, painting, body or ceremony use, comparison with yellow ochres, and events stayed closed.", "Rule 327: wuba."),
    ("lexicon", "Wuju was retained as grass sponge only; grass or material decomposition, honey, soup, food, soaking, eating, obtaining, making, carrying, possession, and events stayed closed.", "Rule 327: wuju."),
    ("lexicon", "Yikari was retained as hardened beeswax only; ironwood, root, juice, extraction, heating, hardening process, spear manufacture, attaching, material use, and equivalence to jila or nyumbirr stayed closed.", "Rule 327: yikari."),
    ("morphology", "All Rule 327 craft heads stayed bare absolutive objects, with no case, number, possession, derivation, event, property, source, or material morphology added.", "Rule 327: bare craft-object O."),
    ("morphology", "The three wax heads jila, nyumbirr, and yikari and the three ochre heads makarra, makirr, and wuba remained distinct exact dictionary entries. No synonymy, equivalence, normalization, decomposition, or productive derivation was asserted.", "Rule 327: wax and ochre distinction 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 327: bare pronoun A forms."),
    ("morphology", "Yaluy, yinyay, and nyajin stayed fixed support; no demonstrative case, nonpast nyajil, purposive nyaji-nka, reduplicated watching, hearing or smell compound, or support inflection was admitted.", "Rule 327: fixed support morphology."),
    ("syntax", "Rows 1-10 used Ngayu TARGET yinyay nyajin for first-singular there past visual perception.", "Rule 327: 1sg there band."),
    ("syntax", "Rows 11-20 used Yundu TARGET yaluy nyajin for second-singular here past visual perception.", "Rule 327: 2sg here band."),
    ("syntax", "Rows 21-30 used Nyulu TARGET yinyay nyajin for third-singular there past visual perception.", "Rule 327: 3sg there band."),
    ("syntax", "Rows 31-40 used Bula TARGET yaluy nyajin for third-dual here past visual perception.", "Rule 327: 3du here band."),
    ("syntax", "Rows 41-50 used Jana TARGET yinyay nyajin for third-plural there past visual perception.", "Rule 327: 3pl there band."),
    ("fidelity", "English stayed literal past visual-perception and reference prose: selected observer, exact conservative craft label, here or there, and saw only. Labels do not assert source commentary's composition, manufacture, use, relation, or event content.", "Rule 327: literal English."),
    ("fidelity", "No dictionary example, Patz smell occurrence, polysemous sense, synonym, near form, material note, cultural-use note, or older corpus row was converted into source, manufacture, possession, use, property, equivalence, food, ceremony, or weapon claims.", "Rule 327: source and prior-row restraint."),
    ("register", "Rows remained neutral elicitation-style object-reference clauses. Loans, weapons, coercive implements, place or euphemism homonyms, mortuary vocabulary, culturally unresolved candidates, and event-heavy readings were excluded.", "Rule 327: register and candidate ethics."),
    ("process", "Every Rule 327 sentence is an explicit sequence-specific row call with exact Kuku, English, analysis, evidence, and confidence contracts; no runtime generator authored content.", "Rule 327: explicit-row authorship evidence."),
    ("process", "Rules 149-326 carry-forward traps stayed closed, including craft source and use, wax or ochre equivalence, polysemy, near-form, route, material, dialect, homograph, case, compound, productive reduplication, fauna, flora, human, environment, and support-inflection traps.", "Rule 327: cumulative trap closure."),
    ("handoff", "Next batch may continue from 18,547 if this closes; Rule 328 requires a fresh source and coverage audit and must not infer closed craft polysemy, material, source, manufacture, use, equivalence, cultural event, morphology, case, perception, or support fields.", "Rule 327: next cadence."),
]

LEXEMES = [
    ("duburan", "noun", None, "NA", "directional sign", "batch-369: directional-sign reference only; ring/wreath/body/direction/route/composition/making/positioning/event content closed."),
    ("jila", "noun", None, "NA", "beeswax", "batch-369: beeswax reference only; smell/sweat/crocodile/body/derivative/source/use/equivalence/event content closed."),
    ("makarra", "noun", None, "NA", "streaky yellow ochre", "batch-369: streaky-yellow-ochre reference only; makirr equivalence/property/source/mining/grinding/painting/body/ceremony/event content closed."),
    ("makirr", "noun", None, "NA", "yellow ochre", "batch-369: yellow-ochre reference only; makarra equivalence/streakiness/property/source/mining/grinding/painting/body/ceremony/event content closed."),
    ("ngurran", "noun", None, "NA", "rope", "batch-369: rope reference only; rope-bag/material-source/karra/tying/carrying/making/weaving/possession/event content closed."),
    ("nyumbirr", "noun", None, "NA", "beeswax", "batch-369: beeswax reference only; source/collecting/heating/hardening/softening/attaching/medicine/honey/use/equivalence/event content closed."),
    ("warkal", "noun", None, "NA", "bailer shell", "batch-369: bailer-shell reference only; container/water/carrying/bailing/cooking/food/old-time/source/possession/event content closed."),
    ("wuba", "noun", None, "NA", "red ochre", "batch-369: red-ochre reference only; property/pigment/source/digging/grinding/painting/body/ceremony/comparison/event content closed."),
    ("wuju", "noun", None, "NA", "grass sponge", "batch-369: grass-sponge reference only; material decomposition/honey/soup/food/soaking/eating/obtaining/making/carrying/possession/event content closed."),
    ("yikari", "noun", None, "NA", "hardened beeswax", "batch-369: hardened-beeswax reference only; ironwood/root/juice/extraction/heating/process/spear/attaching/use/equivalence/event content closed."),
    ("ngayu", "pronoun", None, "NA", "first singular nominative", "batch-369: bare nominative subject support only."),
    ("yundu", "pronoun", None, "NA", "second singular nominative", "batch-369: bare nominative subject support only."),
    ("nyulu", "pronoun", None, "NA", "third singular nominative", "batch-369: bare nominative subject support only."),
    ("bula", "pronoun", None, "NA", "third dual nominative", "batch-369: bare nominative subject support only."),
    ("jana", "pronoun", None, "NA", "third plural nominative", "batch-369: bare nominative subject support only."),
    ("yaluy", "demonstrative", None, "NA", "here", "batch-369: bare Yalanji local demonstrative support only."),
    ("yinyay", "demonstrative", None, "NA", "there", "batch-369: bare Yalanji local demonstrative support only."),
    ("nyajin", "verb-tr", "ny", "NA", "see; see.PST", "batch-369: 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, 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-369-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-369-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 327 rows: bare craft-object O morphology, bare nominative singular or third-person pronoun A, fixed Yalanji local and past support, exact dictionary craft heads and conservative labels, literal English fidelity, and neutral elicitation register; all polysemy, source, manufacture, use, material, equivalence, cultural-event, 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 duburan ring or route, jila smell or sweat, makarra/makirr equivalence, ngurran bag or karra substitution, wax-source or process claims, warkal container use, wuba pigment use, wuju food use, yikari spear manufacture, 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 327 lessons covering source, target occurrence and sense, artifact 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 327 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-369-verify'").fetchone()[0]
    record_event(db, batch_label=LABEL, phase="close", event_type="close-success", actor="codex", detail=f"Closed Batch 369 / Rule 327: {accepted_count} accepted, {reviews} reviews, {lessons} lessons, {logs} lexeme logs; verified {before}->{after}; Kuku words {words_before}->{words_after}.", command="python3 batch_scripts/close_369.py", output_excerpt=f"closed batch-369 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-369: accepted={accepted_count}, reviews={reviews}, lessons={lessons}, lexeme_logs={logs}, verified {before}->{after}, kuku_words {words_before}->{words_after}")
    return 0


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