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

NOTES=("REPTILE COMPLEMENTARY NON-SINGULAR PAST PERCEPTION AFTER RULE 338 (Rule 339). 50 rows over jalbil, kalkarrumbarr, kurmba-kurmba, jimalili, yuray, bakay, kungkun, bilbil-bilbil, bajalji, and noun jabil. Bare ngali/ngaliny/yubal/yurra/nganjin A, bare target O, Yalanji locals, and past nyajin. The selected orientation exactly complements Batch 379 / Rule 337; two-here/three-there completes that paradigm without duplicating its lower-gap inverse. 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 339 freshly reread the ten Rule 319/337/338 reptile heads and every duplicate or homonymous dictionary record.","Rule 339: 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 339: source lines."),
    ("source","Patz 1476, 2577-2584, 2834-2847, 2021-2024, 2568-2571, 3160-3162 and 4256-4265 supply fauna reference, non-singular nominatives, Yalanji locals, past nyaji-ny and perception A/O syntax; dictionary running examples supply nyajin.","Rule 339: construction evidence."),
    ("source","Fresh Patz target search found no standalone selected reptile noun; apparent kungkun hits are only unrelated verb kungkunbunga- 'watch closely' and cannot evidence snake-noun kungkun.","Rule 339: 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 339: duplicate records."),
    ("source","Jabil noun 'scrub lizard' remains distinct from transitive verb jabil 'kick'.","Rule 339: homonym boundary."),
    ("process","The 100-cell non-singular matrix contains exactly the 50 Batch 379 / Rule 337 inverse rows; all 50 selected complementary cells were empty.","Rule 339: complementary gap audit."),
    ("process","Two-here/three-there changes the current yaluy/yinyay gap from 162 to 172; the lower-gap inverse would produce 152 but is unavailable because it exactly duplicates Batch 379.","Rule 339: balance-versus-duplication ruling."),
    ("process","Target coverage before banking was jalbil 15, kalkarrumbarr 15, kurmba-kurmba 15, jimalili 16, yuray 16, bakay 17, kungkun 17, bilbil-bilbil 18, bajalji 19, jabil 20.","Rule 339: target coverage."),
    ("process","Support before banking was ngali 623, ngaliny 565, yubal 575, yurra 560, nganjin 288, deferred ngana 1115, yaluy 4362, yinyay 4524 and nyajin 2000.","Rule 339: support coverage."),
    ("lexicon","Jalbil remained lizard only; colour, size, mythological being, island and cooking story stayed closed.","Rule 339: jalbil."),
    ("lexicon","Kalkarrumbarr remained lizard only; measurement, legend, role, behavior and events stayed closed.","Rule 339: kalkarrumbarr."),
    ("lexicon","Kurmba-kurmba remained the whole lizard head; free base, productive reduplication, slipperiness, personification, kinship, marriage and story stayed closed.","Rule 339: kurmba-kurmba."),
    ("lexicon","Jimalili remained lizard only; mountain habitat, teaching, firestick and origin story stayed closed.","Rule 339: jimalili."),
    ("lexicon","Yuray remained conservative snake reference; duplicate identity, species, sea habitat, danger and poison stayed closed.","Rule 339: yuray."),
    ("lexicon","Bakay remained conservative snake reference; duplicate identity, size, colour, water habitat, danger and poison stayed closed.","Rule 339: bakay."),
    ("lexicon","Kungkun remained conservative snake reference; duplicate identity, species resolution, tree habitat, colour and unrelated kungkunbunga- stayed closed.","Rule 339: kungkun."),
    ("lexicon","Bilbil-bilbil remained the exact whole gecko head; free base, productive rule, size, shelter, night, sound, feeding and behavior stayed closed.","Rule 339: bilbil-bilbil."),
    ("lexicon","Bajalji retained the established python label; duplicate identity, poison, colour/head, distribution/place and chasing lore stayed closed.","Rule 339: bajalji."),
    ("lexicon","Jabil remained the lizard noun; kicking, verbal inflection, scrub habitat and catching stayed closed.","Rule 339: jabil."),
    ("morphology","All targets remained bare absolutive O; no case, derivation, record alignment, property or event morphology entered.","Rule 339: bare O."),
    ("morphology","Bilbil-bilbil and kurmba-kurmba remained exact whole hyphenated heads; no generated base or productive process entered.","Rule 339: reduplicated heads."),
    ("morphology","Ngali, ngaliny, yubal, yurra and nganjin remained bare nominative A; number and clusivity were preserved and ngana remained deferred, not ungrammatical.","Rule 339: pronoun A."),
    ("morphology","Yaluy, yinyay and nyajin remained fixed; no case, Nyungkul support, nonpast, purposive, reduplicated perception or hearing/smell compound entered.","Rule 339: support."),
    ("syntax","Rows 1-10 used Ngali TARGET yinyay nyajin.","Rule 339: 1du.excl there band."),
    ("syntax","Rows 11-20 used Ngaliny TARGET yaluy nyajin.","Rule 339: 1du.incl here band."),
    ("syntax","Rows 21-30 used Yubal TARGET yinyay nyajin.","Rule 339: 2du there band."),
    ("syntax","Rows 31-40 used Yurra TARGET yaluy nyajin.","Rule 339: 2pl here band."),
    ("syntax","Rows 41-50 used Nganjin TARGET yinyay nyajin.","Rule 339: 1pl.excl there band."),
    ("fidelity","English preserved participant number and clusivity, conservative creature label, here/there orientation and past seeing only.","Rule 339: literal fidelity."),
    ("fidelity","No duplicate-record prose, myth/lore, property, habitat, poison, danger, homonymous verb or prior event entered English.","Rule 339: exclusion fidelity."),
    ("register","Rows remained neutral elicitation clauses; culturally loaded stories were documented as exclusions, not synthetic-event prompts.","Rule 339: register."),
    ("process","All 50 sentences were explicit sequence-specific row calls with exact contracts; no runtime generator authored content.","Rule 339: authorship."),
    ("process","Rules 149-338 traps remained closed, including Rules 337-338 duplicate-record, cultural-story, false-hit and orientation boundaries.","Rule 339: cumulative traps."),
    ("handoff","Next batch may continue from 19,147; Rule 340 requires a fresh source/gap audit and must not infer closed reptile records, stories, properties or events.","Rule 339: handoff."),
]

LEXEMES=[
    ("jalbil","noun",None,"NA","lizard","batch-381: bare reptile perception only; colour/size/myth/island/story closed."),
    ("kalkarrumbarr","noun",None,"NA","lizard","batch-381: bare reptile perception only; size/legend/role/event closed."),
    ("kurmba-kurmba","noun",None,"NA","lizard","batch-381: exact whole head only; base/redup/person/kin/marriage/story closed."),
    ("jimalili","noun",None,"NA","lizard","batch-381: bare reptile perception only; mountain/firestick/teaching/story closed."),
    ("yuray","noun",None,"NA","snake","batch-381: conservative snake label; duplicate/species/habitat/danger/poison closed."),
    ("bakay","noun",None,"NA","snake","batch-381: conservative snake label; duplicate/size/colour/water/danger closed."),
    ("kungkun","noun",None,"NA","snake","batch-381: conservative snake label; duplicate/species/tree/colour/kungkunbunga- verb closed."),
    ("bilbil-bilbil","noun",None,"NA","gecko","batch-381: exact whole head; base/productive process/property/habitat/behavior closed."),
    ("bajalji","noun",None,"NA","python","batch-381: established conservative label; duplicate/poison/place/lore/danger closed."),
    ("jabil","noun",None,"NA","lizard","batch-381: noun only; kick verb/inflection/habitat/catching closed."),
    ("ngali","pronoun",None,"NA","first dual exclusive nominative","batch-381: bare A only; exclusive."),
    ("ngaliny","pronoun",None,"NA","first dual inclusive nominative","batch-381: bare A only; inclusive."),
    ("yubal","pronoun",None,"NA","second dual nominative","batch-381: bare A only."),
    ("yurra","pronoun",None,"NA","second plural nominative","batch-381: bare A only."),
    ("nganjin","pronoun",None,"NA","first plural exclusive nominative","batch-381: bare A only; ngana remains distinct/deferred."),
    ("yaluy","demonstrative",None,"NA","here","batch-381: Yalanji local support only."),
    ("yinyay","demonstrative",None,"NA","there","batch-381: Yalanji local support only."),
    ("nyajin","verb-tr","l","NA","see; see.PST","batch-381: 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-381-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-381-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 Batch 379 complement, number/clusivity, 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 339 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 339 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-381-verify'").fetchone()[0]
    record_event(db,batch_label=LABEL,phase="close",event_type="close-success",actor="codex",detail=f"Closed Rule 339: accepted={accepted}, reviews={reviews}, lessons={lessons}, logs={logs}; verified {before}->{after}; words {wb}->{wa}.",command="python3 batch_scripts/close_381.py",artifact_path=PROCESS_LOG,created_at=NOW)
    db.commit();print(f"closed batch-381: accepted={accepted} reviews={reviews} lessons={lessons} logs={logs} verified {before}->{after} words {wb}->{wa}");return 0

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


