"""Independent teaching cases, edition 2026.10.7. Standard library only.

These models do not implement any product, native protocol or transport.
Each case computes its own positive result and challenges a missing safeguard.
"""
from __future__ import annotations
import argparse
from fractions import Fraction
from itertools import product
import json
import re


def approval(guard=True):
    """One ticket, two message labels, three submissions; all 8 histories."""
    violations=[]
    for history in product(('blue','green'), repeat=3):
        used=False; executed=[]
        for message in history:
            if not used and (not guard or message=='blue'):
                used=True; executed.append(message)
        if len(executed)>1 or any(m!='blue' for m in executed):
            violations.append({'submissions':list(history),'executed':executed})
    return {'checked':8,'violations':violations}


def freshness(guard=True):
    """Two document versions; four-event histories over read/change/use."""
    failures=[]
    for history in product(('read','change','use'),repeat=4):
        version=0; observed=None
        for event in history:
            if event=='read':observed=version
            elif event=='change':version=1
            elif observed is not None and (not guard or observed==version):
                if observed!=version:failures.append(list(history));break
    return {'checked':81,'violations':failures}


def commissioning(state,event,consume=True):
    stage,voucher=state
    if event=='open' and stage=='new':return ('open',voucher)
    if event=='finish' and stage=='open' and voucher:return ('closed',False if consume else voucher)
    if event=='cancel' and stage=='open':return ('closed',False)
    return state


def founding(guard=True):
    state=('new',True);events=[];violations=[]
    for event in ('open','finish','finish'):
        state=commissioning(state,event,guard);events.append([event,*state])
        if state[0]=='closed' and state[1]:violations.append(list(events))
    # Derive a lasso from actual transitions, rather than print a claimed cycle.
    opened=commissioning(('new',True),'open',guard)
    wait=commissioning(opened,'wait',guard)
    unfair_cycle=[list(opened),list(wait)] if opened==wait and opened[0]!='closed' else []
    return {'checked':3,'violations':violations,'trace':events,'unfair_cycle':unfair_cycle,
            'progress_assumption':'Continuously enabled open and finish-or-cancel eventually occur.'}


def epoch(guard=True):
    """A name survives restart; an authorization is tied to one incarnation."""
    accepted=[]
    for current,issued in product(range(3),repeat=2):
        if not guard or current==issued:accepted.append([current,issued])
    return {'checked':9,'violations':[p for p in accepted if p[0]!=p[1]],'accepted':accepted}


def encode_pair(pair):
    if len(pair)!=2 or any(not re.fullmatch('[a-z]*',x) for x in pair):
        raise ValueError('exactly two lowercase ASCII strings required')
    return ''.join(str(len(x))+':'+x for x in pair).encode('ascii')


def decode_pair(data):
    text=data.decode('ascii');parts=[]
    for _ in range(2):
        length,sep,tail=text.partition(':')
        if not sep or not re.fullmatch('0|[1-9][0-9]*',length):raise ValueError('length')
        n=int(length)
        if len(tail)<n:raise ValueError('truncated')
        parts.append(tail[:n]);text=tail[n:]
    if text or encode_pair(parts)!=data:raise ValueError('noncanonical')
    return parts


def unsigned_fits(value,bits):
    if type(value) is not int or type(bits) is not int or bits<=0:return False
    return 0<=value<(1<<bits)


def encoding(guard=True):
    values=['','a','b','ab','bc'];seen={};collisions=[]
    for pair in product(values,repeat=2):
        data=encode_pair(pair) if guard else ''.join(pair).encode()
        if data in seen and seen[data]!=list(pair):collisions.append([seen[data],list(pair)])
        seen[data]=list(pair)
        if guard:assert decode_pair(data)==list(pair)
    rejected=[]
    if guard:
        for bad in (b'01:a1:b',b'1:a1:bc',b'2:a',b'1:A0:'):
            try:decode_pair(bad)
            except ValueError:rejected.append(bad.decode())
        assert len(rejected)==4
    return {'checked':25,'violations':collisions,'noncanonical_rejected':rejected,
            'width_counterexample':{'value':256,'unsigned_8_accepts':unsigned_fits(256,8),'unsigned_16_accepts':unsigned_fits(256,16)}}


def propose_fixed_point(fn,values,check_equation=True):
    # A faulty consumer accepts a computed value without checking the equation.
    for x in values:
        if not check_equation or fn(x)==x:return x
    return None


def construction(guard=True):
    functions={'flip':lambda x:1-x,'identity':lambda x:x,'constant':lambda x:0}
    roots={name:[x for x in (0,1) if x==f(x)] for name,f in functions.items()}
    proposals={n:propose_fixed_point(f,(0,1),guard) for n,f in functions.items()}
    violations=[{'function':n,'proposal':x,'image':functions[n](x)} for n,x in proposals.items()
                if x is not None and functions[n](x)!=x]
    return {'checked':6,'violations':violations,'solutions':roots,'proposals':proposals}


def visibility(guard=True):
    old=(2,8);staged=[2,8];published=old;observations=[]
    for index,value in enumerate((5,5)):
        staged[index]=value
        if not guard or index==1:published=tuple(staged)
        observations.append(list(published))
    return {'checked':2,'violations':[v for v in observations if sum(v)!=10],'observations':observations}


def uncertainty(guard=True):
    worlds=[{'committed':False,'ack':False},{'committed':True,'ack':False}]
    decisions=['unknown' if guard else 'not_done' for _ in worlds]
    failures=[w for w,d in zip(worlds,decisions) if d=='not_done' and w['committed']]
    return {'checked':2,'violations':failures,'worlds':worlds,'decisions':decisions}


def projection(guard=True):
    desired={'quantity':4,'unit':'items'}
    candidates=[{'quantity':4,'unit':'items'},{'quantity':4,'unit':'boxes'},{'quantity':5,'unit':'items'}]
    accepted=[c for c in candidates if c==desired or (not guard and c['quantity']==desired['quantity'])]
    return {'checked':3,'violations':[c for c in accepted if c!=desired],'accepted':accepted}


def custody(guard=True):
    controllers={'a':'group-one','b':'group-one','c':'group-two'}
    accepted=[]
    for voters in (('a','b'),('a','c'),('b','c')):
        count=len({controllers[v] for v in voters}) if guard else len(voters)
        if count>=2:accepted.append(list(voters))
    return {'checked':3,'violations':[v for v in accepted if len({controllers[x] for x in v})<2],'accepted':accepted}


def budget(guard=True):
    issued=11;available=11;reserved=0;spent=0;burned=0;trace=[]
    for event,amount in [('reserve',4),('spend',3),('burn',2)]:
        if event=='reserve':available-=amount;reserved+=amount
        elif event=='spend':reserved-=amount;spent+=amount
        else:burned+=amount
        accounted=available+reserved+spent+(0 if guard else burned)
        trace.append({'event':event,'accounted':accounted,'issued':issued})
    return {'checked':3,'violations':[r for r in trace if r['accounted']!=r['issued']],
            'trace':trace,'state':{'issued':issued,'available':available,'reserved':reserved,'spent':spent,'burned_subset':burned}}


def calibration(guard=True):
    outcomes=(0,0,1,1);forecasts=(Fraction(1,4),)*4
    loss=sum((p-y)**2 for p,y in zip(forecasts,outcomes))/4
    base=sum((Fraction(1,2)-y)**2 for y in outcomes)/4
    used=base if guard else Fraction(1,2)
    skill=1-loss/used
    return {'checked':4,'violations':[] if skill==Fraction(-1,4) else [{'reported_skill':str(skill)}],
            'loss':str(loss),'baseline':str(used),'skill':str(skill)}

CASES={f.__name__:f for f in (approval,freshness,founding,epoch,encoding,construction,visibility,uncertainty,projection,custody,budget,calibration)}

def run(case=None):
    results={}
    for name,fn in CASES.items():
        if case and name!=case:continue
        positive,negative=fn(True),fn(False)
        assert not positive['violations'],(name,'safeguard failed')
        assert negative['violations'],(name,'negative control did not challenge property')
        results[name]={'positive':positive,'negative':negative,'passed':True}
    return {'edition':'2026.10.7','method':'author-executed independent synthetic cases','independently_reproduced':False,'results':results}

if __name__=='__main__':
    p=argparse.ArgumentParser();p.add_argument('--case',choices=CASES);p.add_argument('--mutant',action='store_true');a=p.parse_args()
    if a.mutant:
        if not a.case:p.error('--mutant requires --case')
        r=CASES[a.case](False);print(json.dumps(r,indent=2));raise SystemExit(1 if r['violations'] else 0)
    print(json.dumps(run(a.case),indent=2,sort_keys=True))
