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

NOTES=("REPTILE COMPLEMENTARY SINGULAR/THIRD-PERSON PAST PERCEPTION AFTER RULE 337 (Rule 338). 50 rows over jalbil, kalkarrumbarr, kurmba-kurmba, jimalili, yuray, bakay, kungkun, bilbil-bilbil, bajalji, and noun jabil. Bare ngayu/yundu/nyulu/bula/jana A, bare target O, Yalanji locals, and past nyajin. The selected orientation exactly complements Batch 361 / Rule 319. Duplicate exact records remain uncollapsed; noun/verb homonym, myth/lore, properties, poison/danger, habitat, behavior, cultural stories, source, possession, case, and events remain closed.")

LESSONS=[
    ("source","Rule 338 freshly reread the ten Rule 319/337 reptile heads and every duplicate or homonymous dictionary record.","Rule 338: target inventory."),
    ("source","Dictionary lines reread: bajalji 387-409, bakay 635-653, bilbil-bilbil 2529-2542, jabil 6929-6951, jalbil 7374-7386, jimalili 9284-9294, kalkarrumbarr 12679-12689, kungkun 15748-15768, kurmba-kurmba 16154-16169, yuray 31016-31033.","Rule 338: source lines."),
    ("source","Patz 2577-2584 supplies ngayu, yundu, nyulu and bula; running examples at 1419, 1947, 2686, 2807-2811, 3240 and 5460 plus dictionary 7749-7759 establish jana despite one OCR table cell reading iana.","Rule 338: pronoun evidence and OCR resolution."),
    ("source","Fresh Patz target search found no standalone selected reptile noun; apparent kungkun hits are only the unrelated verb kungkunbunga- 'watch closely' and cannot evidence the snake noun.","Rule 338: lexical cross-check."),
    ("source","Yuray, bakay, kungkun and bajalji each have two exact noun records; conservative labels do not collapse identity or resolve species.","Rule 338: duplicate records."),
    ("source","Jabil noun 'scrub lizard' remains distinct from transitive verb jabil 'kick'.","Rule 338: homonym boundary."),
    ("process","The 100-cell singular/third-person matrix contains exactly the 50 Batch 361 inverse rows; all 50 selected complementary cells were empty.","Rule 338: complementary gap audit."),
    ("process","Three-here/two-there reduces the yaluy/yinyay gap from 172 to 162; the hypothetical inverse would increase it to 182.","Rule 338: balance audit."),
    ("process","Target coverage before banking was jalbil 10, kalkarrumbarr 10, kurmba-kurmba 10, jimalili 11, yuray 11, bakay 12, kungkun 12, bilbil-bilbil 13, bajalji 14, jabil 15.","Rule 338: target coverage."),
    ("process","Support before banking was ngayu 1451, yundu 1047, nyulu 722, bula 518, jana 1223, yaluy 4332, yinyay 4504 and nyajin 1950.","Rule 338: support coverage."),
    ("lexicon","Jalbil remained lizard only; colour, size, mythological being, island and cooking story stayed closed.","Rule 338: jalbil."),
    ("lexicon","Kalkarrumbarr remained lizard only; measurement, legend, role, behavior and events stayed closed.","Rule 338: kalkarrumbarr."),
    ("lexicon","Kurmba-kurmba remained the whole lizard head; free base, productive reduplication, slipperiness, personification, kinship, marriage and story stayed closed.","Rule 338: kurmba-kurmba."),
    ("lexicon","Jimalili remained lizard only; mountain habitat, teaching, firestick and origin story stayed closed.","Rule 338: jimalili."),
    ("lexicon","Yuray remained conservative snake reference; duplicate identity, species, sea habitat, danger and poison stayed closed.","Rule 338: yuray."),
    ("lexicon","Bakay remained conservative snake reference; duplicate identity, size, colour, water habitat, danger and poison stayed closed.","Rule 338: bakay."),
    ("lexicon","Kungkun remained conservative snake reference; duplicate identity, species resolution, tree habitat, colour and the unrelated kungkunbunga- verb stayed closed.","Rule 338: kungkun."),
    ("lexicon","Bilbil-bilbil remained the exact whole gecko head; free base, productive rule, size, shelter, night, sound, feeding and behavior stayed closed.","Rule 338: bilbil-bilbil."),
    ("lexicon","Bajalji retained the established python label; duplicate identity, poison, colour/head, distribution/place and chasing lore stayed closed.","Rule 338: bajalji."),
    ("lexicon","Jabil remained the lizard noun; kicking, verbal inflection, scrub habitat and catching stayed closed.","Rule 338: jabil."),
    ("morphology","All targets remained bare absolutive O; no case, derivation, record alignment, property or event morphology entered.","Rule 338: bare O."),
    ("morphology","Bilbil-bilbil and kurmba-kurmba remained exact whole hyphenated heads; no generated base or productive process entered.","Rule 338: reduplicated heads."),
    ("morphology","Ngayu, yundu, nyulu, bula and jana remained bare nominative A; non-selected and inflected pronouns stayed absent.","Rule 338: pronoun A."),
    ("morphology","Yaluy, yinyay and nyajin remained fixed; no case, Nyungkul support, nonpast, purposive, reduplicated perception or hearing/smell compound entered.","Rule 338: support."),
    ("syntax","Rows 1-10 used Ngayu TARGET yaluy nyajin.","Rule 338: 1sg here band."),
    ("syntax","Rows 11-20 used Yundu TARGET yinyay nyajin.","Rule 338: 2sg there band."),
    ("syntax","Rows 21-30 used Nyulu TARGET yaluy nyajin.","Rule 338: 3sg here band."),
    ("syntax","Rows 31-40 used Bula TARGET yinyay nyajin.","Rule 338: 3du there band."),
    ("syntax","Rows 41-50 used Jana TARGET yaluy nyajin.","Rule 338: 3pl here band."),
    ("fidelity","English preserved participant number, conservative creature label, here/there orientation and past seeing only.","Rule 338: literal fidelity."),
    ("fidelity","No duplicate-record prose, myth/lore, property, habitat, poison, danger, homonymous verb or prior event entered English.","Rule 338: exclusion fidelity."),
    ("register","Rows remained neutral elicitation clauses; culturally loaded stories were documented as exclusions, not synthetic-event prompts.","Rule 338: register."),
    ("process","All 50 sentences were explicit sequence-specific row calls with exact contracts; no runtime generator authored content.","Rule 338: authorship."),
    ("process","Rules 149-337 traps remained closed, including Rule 337 duplicate-record and cultural-story boundaries plus Rule 319 orientation.","Rule 338: cumulative traps."),
    ("handoff","Next batch may continue from 19,097; Rule 339 requires a fresh source/gap audit and must not infer closed reptile records, stories, properties or events.","Rule 338: handoff."),
]

LEXEMES=[
    ("jalbil","noun",None,"NA","lizard","batch-380: bare reptile perception only; colour/size/myth/island/story closed."),
    ("kalkarrumbarr","noun",None,"NA","lizard","batch-380: bare reptile perception only; size/legend/role/event closed."),
    ("kurmba-kurmba","noun",None,"NA","lizard","batch-380: exact whole head only; base/redup/person/kin/marriage/story closed."),
    ("jimalili","noun",None,"NA","lizard","batch-380: bare reptile perception only; mountain/firestick/teaching/story closed."),
    ("yuray","noun",None,"NA","snake","batch-380: conservative snake label; duplicate/species/habitat/danger/poison closed."),
    ("bakay","noun",None,"NA","snake","batch-380: conservative snake label; duplicate/size/colour/water/danger closed."),
    ("kungkun","noun",None,"NA","snake","batch-380: conservative snake label; duplicate/species/tree/colour/kungkunbunga- verb closed."),
    ("bilbil-bilbil","noun",None,"NA","gecko","batch-380: exact whole head; base/productive process/property/habitat/behavior closed."),
    ("bajalji","noun",None,"NA","python","batch-380: established conservative label; duplicate/poison/place/lore/danger closed."),
    ("jabil","noun",None,"NA","lizard","batch-380: noun only; kick verb/inflection/habitat/catching closed."),
    ("ngayu","pronoun",None,"NA","first singular nominative","batch-380: bare A only."),
    ("yundu","pronoun",None,"NA","second singular nominative","batch-380: bare A only."),
    ("nyulu","pronoun",None,"NA","third singular nominative","batch-380: bare A only."),
    ("bula","pronoun",None,"NA","third dual nominative","batch-380: bare A only."),
    ("jana","pronoun",None,"NA","third plural nominative","batch-380: bare A only; Patz running-form/dictionary spelling."),
    ("yaluy","demonstrative",None,"NA","here","batch-380: Yalanji local support only."),
    ("yinyay","demonstrative",None,"NA","there","batch-380: Yalanji local support only."),
    ("nyajin","verb-tr","l","NA","see; see.PST","batch-380: l-conjugation root nyaji-l with past -ny; running surface nyajin."),
]

def main()->int:
    if len(LESSONS)!=35: raise SystemExit(f"lessons {len(LESSONS)}")
    if len(LEXEMES)!=18: raise SystemExit(f"lexemes {len(LEXEMES)}")
    db=sqlite3.connect(DB);db.execute("PRAGMA foreign_keys=ON");db.execute("BEGIN");ensure_schema(db)
    r=db.execute("SELECT id FROM batches WHERE label=?",(LABEL,)).fetchone()
    if not r: raise SystemExit("not banked")
    bid=r[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,ur,ac)!=(50,50,0): raise SystemExit(f"precheck {total}/{ur}/{ac}")
    if db.execute("SELECT COUNT(*) FROM reviews WHERE sentence_id IN(SELECT id FROM sentences WHERE batch_id=?)",(bid,)).fetchone()[0] or db.execute("SELECT COUNT(*) FROM lessons WHERE batch_id=?",(bid,)).fetchone()[0] or db.execute("SELECT COUNT(*) FROM lexeme_log WHERE action='batch-380-verify'").fetchone()[0]: raise SystemExit("close artifacts exist")
    total_rows=db.execute("SELECT COUNT(*) FROM sentences WHERE status!='rejected'").fetchone()[0];before,wb=db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN('accepted','revised')").fetchone();ids=[x[0] for x 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,l,"pass",None,None,"codex-main-five-lens",NOW) for sid in ids for l 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,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,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-380-verify",note,NOW))
    ev=[
        ("lint","under-review-lint-green",f"Whole-corpus lint scanned {total_rows} rows with zero issues; verified remained {before}."),
        ("review","five-lens-pass","All 250 morphology, lexicon, syntax, fidelity and register judgments passed; exact complementary orientation, conservative labels and participant contrasts retained."),
        ("review","review-detail","Duplicate record identity, jabil kick verb, kungkunbunga- false lexical hit, redup bases, myths/lore, colour/size/habitat/poison/danger/source/events and all support drift remained closed."),
        ("review","lesson-inventory",f"Inserted {len(LESSONS)} Rule 338 lessons."),
        ("review","lexeme-source-log",f"Inserted {len(LEXEMES)} target/support lexeme logs."),
    ]
    for phase,etype,detail in ev:record_event(db,batch_label=LABEL,phase=phase,event_type=etype,actor="codex",detail=detail,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 338 accepted","operator-guide-2026-07-10",bid))
    after,wa=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-380-verify'").fetchone()[0]
    record_event(db,batch_label=LABEL,phase="close",event_type="close-success",actor="codex",detail=f"Closed Rule 338: accepted={accepted}, reviews={reviews}, lessons={lessons}, logs={logs}; verified {before}->{after}; words {wb}->{wa}.",command="python3 batch_scripts/close_380.py",artifact_path=PROCESS_LOG,created_at=NOW)
    db.commit();print(f"closed batch-380: accepted={accepted} reviews={reviews} lessons={lessons} logs={logs} verified {before}->{after} words {wb}->{wa}");return 0

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

