#!/usr/bin/env python3
"""Bank Batch 398: Rule 356 fish-set-F non-singular past perception."""
from __future__ import annotations
import ast,datetime as dt,json,re,sqlite3
from pathlib import Path
from bank_386 import SUPPORT_EVIDENCE as PRONOUN_EVIDENCE,source_audit as pronoun_source_audit
from bank_396 import DB,DENY_ENGLISH,DENY_KUKU as BASE_DENY,EVIDENCE as BASE_EVIDENCE,SUPPORT as FISH_SUPPORT,TARGET_ORDER,LABELS,GLOSSES,CONF,count_words,source_audit as fish_source_audit
from process_ledger import ensure_schema,record_event
LABEL="batch-398";NOW=dt.datetime.now(dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00","Z");LOG="process_logs/batch-398-linter-clean-fish-set-f-nonsingular-past-perception-after-rule355-process.md"
EXPECTED_TARGET={"kalngkan":15,"mangkurr-mangkurr":15,"dijarr":16,"julaji":16,"mawul":18,"balarri":34,"bayil":31,"dalmbal":31,"barrbal":36,"jalkay":36}
EXPECTED_SUPPORT={"ngali":713,"ngaliny":655,"yubal":665,"yurra":650,"nganjin":378,"ngana":1115,"yaluy":4782,"yinyay":4954,"nyajin":2850}
FRAMES=[("ngali","yaluy","We two, not you, saw","here","1du.excl"),("ngaliny","yinyay","You and I saw","there","1du.incl"),("yubal","yaluy","You two saw","here","2du"),("yurra","yinyay","You all saw","there","2pl"),("nganjin","yaluy","We, not you, saw","here","1pl.excl")]
SELECTED={x[0] for x in FRAMES};DENY_KUKU=(set(BASE_DENY)-SELECTED)|{"ngayu","yundu","nyulu","bula","jana","ngana","ngalingan","ngalinyan","yubalan","yurrangan","nganjinan"}
TARGET_EVIDENCE={t:f"{BASE_EVIDENCE[t]} Rule356 changes participant number and clusivity only and retains every Rule354-355 source and sense boundary." for t in TARGET_ORDER};SUPPORT=f"{FISH_SUPPORT} {PRONOUN_EVIDENCE} Rule356 follows Patz for clusivity over the dictionary defect; ngana remains grammatical and deferred."
def row(seq,en,ku,an,fr,words):
 t=words[1];return(seq,en,ku,an,fr,3,json.dumps(words,ensure_ascii=False),json.dumps([],ensure_ascii=False),f"{TARGET_EVIDENCE[t]} {SUPPORT}",CONF[t])
ROWS=[
row(1,"We two, not you, saw the kalngkan small mullet here.","Ngali kalngkan yaluy nyajin.","ngali kalngkan yaluy nyajin | 1du.excl.NOM kalngkan.small-mullet here see.PST","r356_1du_excl_here_fish_f_kalngkan",["ngali","kalngkan","yaluy","nyajin"]),
row(2,"We two, not you, saw the mangkurr-mangkurr garfish here.","Ngali mangkurr-mangkurr yaluy nyajin.","ngali mangkurr-mangkurr yaluy nyajin | 1du.excl.NOM mangkurr-mangkurr.garfish here see.PST","r356_1du_excl_here_fish_f_mangkurr",["ngali","mangkurr-mangkurr","yaluy","nyajin"]),
row(3,"We two, not you, saw the dijarr freshwater perch here.","Ngali dijarr yaluy nyajin.","ngali dijarr yaluy nyajin | 1du.excl.NOM dijarr.freshwater-perch here see.PST","r356_1du_excl_here_fish_f_dijarr",["ngali","dijarr","yaluy","nyajin"]),
row(4,"We two, not you, saw the julaji freshwater catfish here.","Ngali julaji yaluy nyajin.","ngali julaji yaluy nyajin | 1du.excl.NOM julaji.freshwater-catfish here see.PST","r356_1du_excl_here_fish_f_julaji",["ngali","julaji","yaluy","nyajin"]),
row(5,"We two, not you, saw the mawul freshwater eel here.","Ngali mawul yaluy nyajin.","ngali mawul yaluy nyajin | 1du.excl.NOM mawul.freshwater-eel here see.PST","r356_1du_excl_here_fish_f_mawul",["ngali","mawul","yaluy","nyajin"]),
row(6,"We two, not you, saw the balarri queenfish here.","Ngali balarri yaluy nyajin.","ngali balarri yaluy nyajin | 1du.excl.NOM balarri.queenfish here see.PST","r356_1du_excl_here_fish_f_balarri",["ngali","balarri","yaluy","nyajin"]),
row(7,"We two, not you, saw the bayil jungle perch here.","Ngali bayil yaluy nyajin.","ngali bayil yaluy nyajin | 1du.excl.NOM bayil.jungle-perch here see.PST","r356_1du_excl_here_fish_f_bayil",["ngali","bayil","yaluy","nyajin"]),
row(8,"We two, not you, saw the dalmbal flathead here.","Ngali dalmbal yaluy nyajin.","ngali dalmbal yaluy nyajin | 1du.excl.NOM dalmbal.flathead here see.PST","r356_1du_excl_here_fish_f_dalmbal",["ngali","dalmbal","yaluy","nyajin"]),
row(9,"We two, not you, saw the barrbal black bream here.","Ngali barrbal yaluy nyajin.","ngali barrbal yaluy nyajin | 1du.excl.NOM barrbal.black-bream here see.PST","r356_1du_excl_here_fish_f_barrbal",["ngali","barrbal","yaluy","nyajin"]),
row(10,"We two, not you, saw the jalkay salmon here.","Ngali jalkay yaluy nyajin.","ngali jalkay yaluy nyajin | 1du.excl.NOM jalkay.salmon here see.PST","r356_1du_excl_here_fish_f_jalkay",["ngali","jalkay","yaluy","nyajin"]),
row(11,"You and I saw the kalngkan small mullet there.","Ngaliny kalngkan yinyay nyajin.","ngaliny kalngkan yinyay nyajin | 1du.incl.NOM kalngkan.small-mullet there see.PST","r356_1du_incl_there_fish_f_kalngkan",["ngaliny","kalngkan","yinyay","nyajin"]),
row(12,"You and I saw the mangkurr-mangkurr garfish there.","Ngaliny mangkurr-mangkurr yinyay nyajin.","ngaliny mangkurr-mangkurr yinyay nyajin | 1du.incl.NOM mangkurr-mangkurr.garfish there see.PST","r356_1du_incl_there_fish_f_mangkurr",["ngaliny","mangkurr-mangkurr","yinyay","nyajin"]),
row(13,"You and I saw the dijarr freshwater perch there.","Ngaliny dijarr yinyay nyajin.","ngaliny dijarr yinyay nyajin | 1du.incl.NOM dijarr.freshwater-perch there see.PST","r356_1du_incl_there_fish_f_dijarr",["ngaliny","dijarr","yinyay","nyajin"]),
row(14,"You and I saw the julaji freshwater catfish there.","Ngaliny julaji yinyay nyajin.","ngaliny julaji yinyay nyajin | 1du.incl.NOM julaji.freshwater-catfish there see.PST","r356_1du_incl_there_fish_f_julaji",["ngaliny","julaji","yinyay","nyajin"]),
row(15,"You and I saw the mawul freshwater eel there.","Ngaliny mawul yinyay nyajin.","ngaliny mawul yinyay nyajin | 1du.incl.NOM mawul.freshwater-eel there see.PST","r356_1du_incl_there_fish_f_mawul",["ngaliny","mawul","yinyay","nyajin"]),
row(16,"You and I saw the balarri queenfish there.","Ngaliny balarri yinyay nyajin.","ngaliny balarri yinyay nyajin | 1du.incl.NOM balarri.queenfish there see.PST","r356_1du_incl_there_fish_f_balarri",["ngaliny","balarri","yinyay","nyajin"]),
row(17,"You and I saw the bayil jungle perch there.","Ngaliny bayil yinyay nyajin.","ngaliny bayil yinyay nyajin | 1du.incl.NOM bayil.jungle-perch there see.PST","r356_1du_incl_there_fish_f_bayil",["ngaliny","bayil","yinyay","nyajin"]),
row(18,"You and I saw the dalmbal flathead there.","Ngaliny dalmbal yinyay nyajin.","ngaliny dalmbal yinyay nyajin | 1du.incl.NOM dalmbal.flathead there see.PST","r356_1du_incl_there_fish_f_dalmbal",["ngaliny","dalmbal","yinyay","nyajin"]),
row(19,"You and I saw the barrbal black bream there.","Ngaliny barrbal yinyay nyajin.","ngaliny barrbal yinyay nyajin | 1du.incl.NOM barrbal.black-bream there see.PST","r356_1du_incl_there_fish_f_barrbal",["ngaliny","barrbal","yinyay","nyajin"]),
row(20,"You and I saw the jalkay salmon there.","Ngaliny jalkay yinyay nyajin.","ngaliny jalkay yinyay nyajin | 1du.incl.NOM jalkay.salmon there see.PST","r356_1du_incl_there_fish_f_jalkay",["ngaliny","jalkay","yinyay","nyajin"]),
row(21,"You two saw the kalngkan small mullet here.","Yubal kalngkan yaluy nyajin.","yubal kalngkan yaluy nyajin | 2du.NOM kalngkan.small-mullet here see.PST","r356_2du_here_fish_f_kalngkan",["yubal","kalngkan","yaluy","nyajin"]),
row(22,"You two saw the mangkurr-mangkurr garfish here.","Yubal mangkurr-mangkurr yaluy nyajin.","yubal mangkurr-mangkurr yaluy nyajin | 2du.NOM mangkurr-mangkurr.garfish here see.PST","r356_2du_here_fish_f_mangkurr",["yubal","mangkurr-mangkurr","yaluy","nyajin"]),
row(23,"You two saw the dijarr freshwater perch here.","Yubal dijarr yaluy nyajin.","yubal dijarr yaluy nyajin | 2du.NOM dijarr.freshwater-perch here see.PST","r356_2du_here_fish_f_dijarr",["yubal","dijarr","yaluy","nyajin"]),
row(24,"You two saw the julaji freshwater catfish here.","Yubal julaji yaluy nyajin.","yubal julaji yaluy nyajin | 2du.NOM julaji.freshwater-catfish here see.PST","r356_2du_here_fish_f_julaji",["yubal","julaji","yaluy","nyajin"]),
row(25,"You two saw the mawul freshwater eel here.","Yubal mawul yaluy nyajin.","yubal mawul yaluy nyajin | 2du.NOM mawul.freshwater-eel here see.PST","r356_2du_here_fish_f_mawul",["yubal","mawul","yaluy","nyajin"]),
row(26,"You two saw the balarri queenfish here.","Yubal balarri yaluy nyajin.","yubal balarri yaluy nyajin | 2du.NOM balarri.queenfish here see.PST","r356_2du_here_fish_f_balarri",["yubal","balarri","yaluy","nyajin"]),
row(27,"You two saw the bayil jungle perch here.","Yubal bayil yaluy nyajin.","yubal bayil yaluy nyajin | 2du.NOM bayil.jungle-perch here see.PST","r356_2du_here_fish_f_bayil",["yubal","bayil","yaluy","nyajin"]),
row(28,"You two saw the dalmbal flathead here.","Yubal dalmbal yaluy nyajin.","yubal dalmbal yaluy nyajin | 2du.NOM dalmbal.flathead here see.PST","r356_2du_here_fish_f_dalmbal",["yubal","dalmbal","yaluy","nyajin"]),
row(29,"You two saw the barrbal black bream here.","Yubal barrbal yaluy nyajin.","yubal barrbal yaluy nyajin | 2du.NOM barrbal.black-bream here see.PST","r356_2du_here_fish_f_barrbal",["yubal","barrbal","yaluy","nyajin"]),
row(30,"You two saw the jalkay salmon here.","Yubal jalkay yaluy nyajin.","yubal jalkay yaluy nyajin | 2du.NOM jalkay.salmon here see.PST","r356_2du_here_fish_f_jalkay",["yubal","jalkay","yaluy","nyajin"]),
row(31,"You all saw the kalngkan small mullet there.","Yurra kalngkan yinyay nyajin.","yurra kalngkan yinyay nyajin | 2pl.NOM kalngkan.small-mullet there see.PST","r356_2pl_there_fish_f_kalngkan",["yurra","kalngkan","yinyay","nyajin"]),
row(32,"You all saw the mangkurr-mangkurr garfish there.","Yurra mangkurr-mangkurr yinyay nyajin.","yurra mangkurr-mangkurr yinyay nyajin | 2pl.NOM mangkurr-mangkurr.garfish there see.PST","r356_2pl_there_fish_f_mangkurr",["yurra","mangkurr-mangkurr","yinyay","nyajin"]),
row(33,"You all saw the dijarr freshwater perch there.","Yurra dijarr yinyay nyajin.","yurra dijarr yinyay nyajin | 2pl.NOM dijarr.freshwater-perch there see.PST","r356_2pl_there_fish_f_dijarr",["yurra","dijarr","yinyay","nyajin"]),
row(34,"You all saw the julaji freshwater catfish there.","Yurra julaji yinyay nyajin.","yurra julaji yinyay nyajin | 2pl.NOM julaji.freshwater-catfish there see.PST","r356_2pl_there_fish_f_julaji",["yurra","julaji","yinyay","nyajin"]),
row(35,"You all saw the mawul freshwater eel there.","Yurra mawul yinyay nyajin.","yurra mawul yinyay nyajin | 2pl.NOM mawul.freshwater-eel there see.PST","r356_2pl_there_fish_f_mawul",["yurra","mawul","yinyay","nyajin"]),
row(36,"You all saw the balarri queenfish there.","Yurra balarri yinyay nyajin.","yurra balarri yinyay nyajin | 2pl.NOM balarri.queenfish there see.PST","r356_2pl_there_fish_f_balarri",["yurra","balarri","yinyay","nyajin"]),
row(37,"You all saw the bayil jungle perch there.","Yurra bayil yinyay nyajin.","yurra bayil yinyay nyajin | 2pl.NOM bayil.jungle-perch there see.PST","r356_2pl_there_fish_f_bayil",["yurra","bayil","yinyay","nyajin"]),
row(38,"You all saw the dalmbal flathead there.","Yurra dalmbal yinyay nyajin.","yurra dalmbal yinyay nyajin | 2pl.NOM dalmbal.flathead there see.PST","r356_2pl_there_fish_f_dalmbal",["yurra","dalmbal","yinyay","nyajin"]),
row(39,"You all saw the barrbal black bream there.","Yurra barrbal yinyay nyajin.","yurra barrbal yinyay nyajin | 2pl.NOM barrbal.black-bream there see.PST","r356_2pl_there_fish_f_barrbal",["yurra","barrbal","yinyay","nyajin"]),
row(40,"You all saw the jalkay salmon there.","Yurra jalkay yinyay nyajin.","yurra jalkay yinyay nyajin | 2pl.NOM jalkay.salmon there see.PST","r356_2pl_there_fish_f_jalkay",["yurra","jalkay","yinyay","nyajin"]),
row(41,"We, not you, saw the kalngkan small mullet here.","Nganjin kalngkan yaluy nyajin.","nganjin kalngkan yaluy nyajin | 1pl.excl.NOM kalngkan.small-mullet here see.PST","r356_1pl_excl_here_fish_f_kalngkan",["nganjin","kalngkan","yaluy","nyajin"]),
row(42,"We, not you, saw the mangkurr-mangkurr garfish here.","Nganjin mangkurr-mangkurr yaluy nyajin.","nganjin mangkurr-mangkurr yaluy nyajin | 1pl.excl.NOM mangkurr-mangkurr.garfish here see.PST","r356_1pl_excl_here_fish_f_mangkurr",["nganjin","mangkurr-mangkurr","yaluy","nyajin"]),
row(43,"We, not you, saw the dijarr freshwater perch here.","Nganjin dijarr yaluy nyajin.","nganjin dijarr yaluy nyajin | 1pl.excl.NOM dijarr.freshwater-perch here see.PST","r356_1pl_excl_here_fish_f_dijarr",["nganjin","dijarr","yaluy","nyajin"]),
row(44,"We, not you, saw the julaji freshwater catfish here.","Nganjin julaji yaluy nyajin.","nganjin julaji yaluy nyajin | 1pl.excl.NOM julaji.freshwater-catfish here see.PST","r356_1pl_excl_here_fish_f_julaji",["nganjin","julaji","yaluy","nyajin"]),
row(45,"We, not you, saw the mawul freshwater eel here.","Nganjin mawul yaluy nyajin.","nganjin mawul yaluy nyajin | 1pl.excl.NOM mawul.freshwater-eel here see.PST","r356_1pl_excl_here_fish_f_mawul",["nganjin","mawul","yaluy","nyajin"]),
row(46,"We, not you, saw the balarri queenfish here.","Nganjin balarri yaluy nyajin.","nganjin balarri yaluy nyajin | 1pl.excl.NOM balarri.queenfish here see.PST","r356_1pl_excl_here_fish_f_balarri",["nganjin","balarri","yaluy","nyajin"]),
row(47,"We, not you, saw the bayil jungle perch here.","Nganjin bayil yaluy nyajin.","nganjin bayil yaluy nyajin | 1pl.excl.NOM bayil.jungle-perch here see.PST","r356_1pl_excl_here_fish_f_bayil",["nganjin","bayil","yaluy","nyajin"]),
row(48,"We, not you, saw the dalmbal flathead here.","Nganjin dalmbal yaluy nyajin.","nganjin dalmbal yaluy nyajin | 1pl.excl.NOM dalmbal.flathead here see.PST","r356_1pl_excl_here_fish_f_dalmbal",["nganjin","dalmbal","yaluy","nyajin"]),
row(49,"We, not you, saw the barrbal black bream here.","Nganjin barrbal yaluy nyajin.","nganjin barrbal yaluy nyajin | 1pl.excl.NOM barrbal.black-bream here see.PST","r356_1pl_excl_here_fish_f_barrbal",["nganjin","barrbal","yaluy","nyajin"]),
row(50,"We, not you, saw the jalkay salmon here.","Nganjin jalkay yaluy nyajin.","nganjin jalkay yaluy nyajin | 1pl.excl.NOM jalkay.salmon here see.PST","r356_1pl_excl_here_fish_f_jalkay",["nganjin","jalkay","yaluy","nyajin"]),]
def literal_guard():
 m=ast.parse(Path(__file__).read_text());a=[n for n in m.body if isinstance(n,ast.Assign) and any(isinstance(t,ast.Name) and t.id=="ROWS" for t in n.targets)];issues=[]
 if len(a)!=1 or not isinstance(a[0].value,ast.List):return["ROWS"]
 if len(a[0].value.elts)!=50:issues.append("count")
 for i,e in enumerate(a[0].value.elts,1):
  if not isinstance(e,ast.Call) or not isinstance(e.func,ast.Name) or e.func.id!="row":issues.append(f"{i}:call");continue
  try:v=[ast.literal_eval(x) for x in e.args]
  except Exception:issues.append(f"{i}:literal");continue
  if len(v)!=6 or v[0]!=i:issues.append(f"{i}:args")
 return issues
def scan_static():
 issues=literal_guard()
 if len(ROWS)!=50 or [r[0] for r in ROWS]!=list(range(1,51)) or len({r[1] for r in ROWS})!=50 or len({r[2] for r in ROWS})!=50:issues.append("inventory")
 for seq,en,ku,an,fr,_tier,wjson,ljson,ev,conf in ROWS:
  p,d,prefix,loc,person=FRAMES[(seq-1)//10];t=TARGET_ORDER[(seq-1)%10];w=json.loads(wjson);den=[x for x in DENY_KUKU if re.search(rf"(^|\s){re.escape(x)}([\s\.]|$)",ku.lower())];dr=[x for x in DENY_ENGLISH if re.search(rf"\b{re.escape(x)}\b",en.lower())]
  if json.loads(ljson) or den or dr:issues.append(f"{seq}:deny {den}/{dr}")
  if ku!=f"{p.capitalize()} {t} {d} nyajin." or en!=f"{prefix} the {LABELS[t]} {loc}." or an!=f"{p} {t} {d} nyajin | {person}.NOM {GLOSSES[t]} {loc} see.PST":issues.append(f"{seq}:fields")
  if w!=[p,t,d,"nyajin"] or not fr.startswith("r356_") or TARGET_EVIDENCE[t] not in ev or SUPPORT not in ev or conf!=CONF[t]:issues.append(f"{seq}:meta")
 return issues
def main():
 fish,fh=fish_source_audit();_old,pronouns=pronoun_source_audit();issues=scan_static()
 if issues:raise SystemExit("\n".join(issues))
 db=sqlite3.connect(DB);db.execute("PRAGMA foreign_keys=ON");db.execute("BEGIN");ensure_schema(db)
 if db.execute("SELECT 1 FROM batches WHERE label=?",(LABEL,)).fetchone() or db.execute("SELECT COUNT(*) FROM sentences WHERE status='under_review'").fetchone()[0]:raise SystemExit("open")
 tc=count_words(db,TARGET_ORDER);sc=count_words(db,list(EXPECTED_SUPPORT))
 if tc!=EXPECTED_TARGET or sc!=EXPECTED_SUPPORT:raise SystemExit(f"coverage {tc}/{sc}")
 collisions=[]
 for p in SELECTED:
  for t in TARGET_ORDER:
   for d in ("yaluy","yinyay"):
    s=f"{p.capitalize()} {t} {d} nyajin.";h=db.execute("SELECT b.label,s.seq FROM sentences s JOIN batches b ON b.id=s.batch_id WHERE lower(s.kuku)=lower(?) AND s.status IN('accepted','revised','under_review')",(s,)).fetchall()
    if h:collisions.append((s,h))
 if collisions:raise SystemExit(f"matrix {collisions}")
 verified,words=db.execute("SELECT COUNT(*),SUM(LENGTH(kuku)-LENGTH(REPLACE(kuku,' ',''))+1) FROM sentences WHERE status IN('accepted','revised')").fetchone()
 if (verified,words)!=(19947,135147):raise SystemExit(f"baseline {verified}/{words}")
 notes="LINTER-CLEAN FISH SET-F NON-SINGULAR PAST PERCEPTION AFTER RULE355 (Rule356). 100 cells empty; Patz clusivity controls; fish boundaries retained; gap172->162."
 bid=db.execute("INSERT INTO batches(label,cheatsheet_version,guide_version,notes,created_at) VALUES(?,?,?,?,?)",(LABEL,"Rule356 under review","operator-guide-2026-07-10",notes,NOW)).lastrowid;db.executemany("""INSERT INTO sentences(batch_id,seq,english,kuku,analysis,frame,tier,words_used,loans_used,evidence,status,confidence,rights_status,author,created_at,updated_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",[(bid,seq,en,ku,an,fr,tier,w,l,ev,"under_review",conf,"project_approved_synthetic_pending_elder_verification","codex-main",NOW,NOW) for seq,en,ku,an,fr,tier,w,l,ev,conf in ROWS])
 events=[("source","source-audit-pass",f"Fish={fish};Patz={fh};pronouns={pronouns}; source hashes retained."),("source","pronoun-ruling","Patz ngali exclusive/ngaliny inclusive controls; ngana grammatical/deferred."),("planning","sense-preservation-audit","All Rule354-355 fish and linter boundaries retained."),("planning","construction-gap-audit","All 100 non-singular target/deictic cells absent."),("planning","balance-audit","Gap172->162."),("preflight","coverage-audit",f"targets={tc};support={sc}."),("preflight","duplicate-preflight","50 selected unique/absent."),("preflight","static-guard-pass","AST 50 literal; source/sense/clusivity/linter contracts passed.")]
 for ph,et,d in events:record_event(db,batch_label=LABEL,phase=ph,event_type=et,actor="codex",detail=d,artifact_path=LOG,created_at=NOW)
 record_event(db,batch_label=LABEL,phase="bank",event_type="bank-success",actor="codex",detail=f"Banked 50 Rule356; verified {verified}; words {words}.",command="python3 batch_scripts/bank_398.py",artifact_path=LOG,created_at=NOW);db.commit();print("banked batch-398: 50 under_review");return 0
if __name__=="__main__":raise SystemExit(main())
