Something went wrong. Try again.
My version of https://github.com/vercel-labs/fx
Something went wrong. Try again.
619 kB · 15931 lines
Zig
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932const std = @import("std");const io_mod = @import("../../core/shared/io.zig");const types = @import("../../core/shared/types.zig");const command_output_content = @import("../../core/tooling/command_output_content.zig");const full_transcript_screen = @import("../full_transcript_screen.zig");const input_visual_layout = @import("../input/visual_layout.zig");const render_engine = @import("../render_engine.zig");const command_output_runtime = @import("command_output_runtime.zig");const transcript_painter = @import("painter.zig");const transcript_runtime = @import("runtime.zig");const transcript_store = @import("store.zig");const transcript_writer = @import("writer.zig");const ui_render = @import("../render.zig");const user_message_card = @import("../assistant/user_message_card.zig");const vt_emulator = @import("../../core/terminal/engine.zig");
const Allocator = std.mem.Allocator;const Layout = types.Layout;const Metrics = types.Metrics;const transcript_blocks = render_engine.transcript_blocks;const viewport_selection = render_engine.viewport_selection;
const RawEntryClass = transcript_blocks.RawEntryClass;const Styles = transcript_blocks.Styles;const ToolDetailRecord = transcript_blocks.ToolDetailRecord;const TranscriptPreparationSource = transcript_runtime.TranscriptPreparationSource;const TranscriptRuntime = transcript_runtime.TranscriptRuntime;const HardLineStarts = viewport_selection.HardLineStarts;const TranscriptBuffer = viewport_selection.TranscriptBuffer;const VisibleTranscriptLine = viewport_selection.VisibleTranscriptLine;fn renderEntriesToBytes(alloc: Allocator, entries: []const transcript_blocks.TranscriptEntry, cols: u16) ![]u8 { return transcript_runtime.renderEntriesToBytes(alloc, entries, cols, .{});}const visualRowsForLine = transcript_blocks.visualRowsForLine;
fn resolveAndSealTranscriptTransitionForTest( runtime: *TranscriptRuntime, alloc: Allocator, source: *TranscriptPreparationSource, prepared: *transcript_painter.PreparedTranscriptSurfacePaint, target_layout: render_engine.frame_layout.CommittedLayoutSnapshot, plan: *render_engine.paint_plan.PaintPlan, scroll_plan: render_engine.frame_scroll_plan.FrameScrollPlan,) !transcript_runtime.TranscriptTransition { const scroll_facts = try runtime.prepareTranscriptScrollFactsForFrame( alloc, source, prepared, false, false, ); const destructive_invalidation = render_engine.frame_retention.transcriptAreaHasDestructiveInvalidation( runtime.committed_frame_layout.transcript_area, plan.invalidation, ); const resolved = try runtime.resolveTranscriptTransitionTargetForFrame( alloc, source, prepared, target_layout, scroll_plan, scroll_facts, destructive_invalidation, plan.activity == .overlay_entry, ); resolved.applyToPaintPlan(plan); return runtime.sealTranscriptTransition( alloc, source, prepared, plan, resolved, );}
fn resolveVisibleLineForTest(line: VisibleTranscriptLine, buf: TranscriptBuffer) []const u8 { return switch (line) { .transcript => |t| t.ref.resolve(buf), .folded_line => |f| f.text, };}
fn commandOutputTestRuntime(sink: std.Io.File) TranscriptRuntime { return .{ .stdout_file = sink, .maxxing_mode = .legacy, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, };}
fn testSelection(start_line: usize) viewport_selection.ViewportSelection { return .{ .top_row = 1, .bottom_row = 4, .start_line = start_line, .partial_skip_rows = 0, .line_count = 16, };}
fn transcriptTestLayout(cols: u16, rows: u16, content_bottom: u16) Layout { return .{ .rows = rows, .cols = cols, .content_bottom = content_bottom, .divider_top_row = content_bottom + 1, .input_row = content_bottom + 2, .divider_bottom_row = content_bottom + 3, .hint_row = rows, };}
fn makeLongPastePrompt(alloc: Allocator, line_count: usize) ![]u8 { var out: std.Io.Writer.Allocating = .init(alloc); defer out.deinit();
try out.writer.writeAll("LONG_PASTE_FIRST_MARKER\n"); var index: usize = 0; while (index < line_count) : (index += 1) { try out.writer.print("long-paste-line-{d}\n", .{index}); } try out.writer.writeAll("LONG_PASTE_LAST_MARKER\n"); return out.toOwnedSlice();}
fn installStableAnchorWithOriginForTest( runtime: *TranscriptRuntime, alloc: Allocator, flow: []const u8, selection: viewport_selection.ViewportSelection, visual_offset: u32, cursor_row: u16, cursor_col: u16, layout_id: u64, measured_history_origin: ?transcript_painter.MeasuredHistoryOrigin,) !void { var target_cache: std.ArrayList(u8) = .empty; errdefer target_cache.deinit(alloc); try target_cache.appendSlice(alloc, flow); var transition = transcript_runtime.TranscriptTransition{ .scroll_plan = render_engine.frame_scroll_plan.FrameScrollPlan.none( runtime.layout.rows, runtime.owned_top_row, ), .document_append = .{}, .materialized_without_append = .{}, .target_flow = try alloc.dupe(u8, flow), .target_cache = target_cache, .target_cache_origin_untrimmed = runtime.transcript_cache_origin_untrimmed, .folded_summary_indices = &.{}, .target_layout = .{ .layout_id = layout_id, .owned_top = runtime.owned_top_row, .owned_band = .{ .top = runtime.owned_top_row, .bottom = runtime.layout.rows }, .body_area = .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, .transcript_area = .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, .footer_area = .{ .top = runtime.layout.content_bottom + 1, .bottom = runtime.layout.rows }, .solved_frame_height = runtime.layout.rows - runtime.owned_top_row + 1, .terminal_rows = runtime.layout.rows, .terminal_cols = runtime.layout.cols, }, .selection = selection, .visual_offset = visual_offset, .history_visual_offset = visual_offset, .total_visual_rows = visual_offset + 64, .cursor_row = cursor_row, .cursor_col = cursor_col, .replaceable_last_line = false, .replaceable_start = 0, .replaceable_row = cursor_row, .trace_transcript_frame = false, .trace_visible_rows = selection.bottom_row - selection.top_row + 1, .measured_history_origin = measured_history_origin, }; defer transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 0, .changed_cells = 0, .full_repaint = false, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = cursor_row, .committed_cursor_col = cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });}
fn installStableAnchorForTest( runtime: *TranscriptRuntime, alloc: Allocator, flow: []const u8, selection: viewport_selection.ViewportSelection, visual_offset: u32, cursor_row: u16, cursor_col: u16, layout_id: u64,) !void { return installStableAnchorWithOriginForTest( runtime, alloc, flow, selection, visual_offset, cursor_row, cursor_col, layout_id, null, );}
fn stableHistoryVisualOffsetForTest(runtime: *const TranscriptRuntime) !u32 { return switch (runtime.transcript_commit_state) { .stable => |anchor| anchor.history_visual_offset, .invalid, .recovering => error.TestExpectedStableTranscript, };}
fn expectStableNormalBufferRecoveryForTest( runtime: *const TranscriptRuntime, expected_history_visual_offset: u32,) !void { switch (runtime.transcript_commit_state) { .stable => |anchor| { try std.testing.expect(anchor.normal_buffer_recovery_pending); try std.testing.expectEqual( expected_history_visual_offset, anchor.history_visual_offset, ); }, .invalid, .recovering => return error.TestExpectedStableTranscript, }}
fn testPaintPlan( runtime: *const TranscriptRuntime, selection: viewport_selection.ViewportSelection,) render_engine.paint_plan.PaintPlan { const footer_top = runtime.layout.content_bottom + 1; return .{ .layout = runtime.layout, .viewport = selection, .footer = .{ .top = footer_top, .top_divider = footer_top, .banner = footer_top, .banner_active = false, .input_base = @min(footer_top + 1, runtime.layout.rows), .picker_divider = @min(footer_top + 2, runtime.layout.rows), .picker_start = runtime.layout.rows, .bottom_divider = @min(footer_top + 2, runtime.layout.rows), .hint = runtime.layout.rows, .total_rows = runtime.layout.rows - footer_top + 1, }, .activity = .none, .preserved_band = if (runtime.owned_top_row > 1) .{ .top = 1, .bottom = runtime.owned_top_row - 1, .owner = .preserved_shell } else render_engine.paint_plan.FrameBand.empty(.preserved_shell), .transcript_band = .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom, .owner = .transcript, }, .activity_band = render_engine.paint_plan.FrameBand.empty(.activity), .footer_band = .{ .top = footer_top, .bottom = runtime.layout.rows, .owner = .footer, }, .invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), .footer_clean_allowed = true, .synchronized_update = true, .cursor_target = .{ .row = selection.bottom_row, .col = 1, .visible = true }, .footer_reservation_source = .none, .bottom_reserved_rows = 0, .preserve_scrollback = true, };}
const TestTranscriptFixedPointFrame = struct { layout: render_engine.frame_layout.FrameLayout, scroll_plan: render_engine.frame_scroll_plan.FrameScrollPlan,};
fn solveTestTranscriptFixedPointFrame( runtime: *TranscriptRuntime, alloc: Allocator, metrics: *Metrics, source: *const TranscriptPreparationSource, footer_rows: u16, prepared: *?transcript_painter.PreparedTranscriptSurfacePaint,) !TestTranscriptFixedPointFrame { var release_floor_rows: u16 = 0; var previous_candidate_owned_top: ?u16 = null;
while (true) { const release = render_engine.frame_layout.solveWithPreservedRowRelease(.{ .terminal = runtime.layout, .owned_top = runtime.owned_top_row, .footer = .{ .natural_rows = footer_rows, .min_rows = footer_rows, .max_rows = footer_rows, }, .transcript = source.preview, .prior = runtime.committed_frame_layout, }, release_floor_rows); const candidate = release.layout; if (previous_candidate_owned_top) |previous| { if (candidate.owned_top >= previous) return error.InvalidFrameScrollPlan; }
if (prepared.*) |*paint| { paint.deinit(alloc); prepared.* = null; } var inline_advance_rows: u16 = 0; if (!candidate.transcript_area.isEmpty()) { prepared.* = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, metrics, source, candidate.transcript_area, ); inline_advance_rows = runtime.planTranscriptScroll(&prepared.*.?).planned_rows; } const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, release.released_rows, inline_advance_rows, ); if (candidate.owned_top == scroll_plan.post_scroll_owned_top) { return .{ .layout = candidate, .scroll_plan = scroll_plan, }; } previous_candidate_owned_top = candidate.owned_top; release_floor_rows = scroll_plan.preserved_release_rows; }}
fn testPaintPlanForFrame( layout: render_engine.frame_layout.FrameLayout, selection: viewport_selection.ViewportSelection, cursor_row: u16, cursor_col: u16,) render_engine.paint_plan.PaintPlan { const footer_rows = render_engine.footer_layout.resolve(.{ .footer_top_for_extra = layout.footer_area.top, .terminal_rows = layout.terminal.rows, .activity_offset = 0, .extra_input_rows = 0, .input_extra = 0, .picker_rows = 0, .banner_active = false, .allocated_rows = layout.footer_area.height(), }); return layout.toPaintPlan(.{ .footer_rows = footer_rows, .viewport = selection, .cursor_target = .{ .row = cursor_row, .col = cursor_col, .visible = true, }, });}
fn testSource( alloc: Allocator, bytes: []const u8, cols: u16,) !TranscriptPreparationSource { return .{ .bytes = try alloc.dupe(u8, bytes), .folded_summary_indices = &.{}, .preview = .{ .natural_visual_rows = 4 }, .tail_kind = null, .tracked_entry_id = null, .tracked_entry_start_line = null, .replaceable_last_line = false, .replaceable_start = 0, .replaceable_row = 1, .welcome_cut_line = null, .welcome_boundary = null, .cols = cols, };}
fn testFoldedSource( alloc: Allocator, bytes: []const u8, cols: u16, summary_transcript_index: usize,) !TranscriptPreparationSource { var source = try testSource(alloc, bytes, cols); errdefer source.deinit(alloc); source.folded_summary_indices = try alloc.dupe( usize, &.{summary_transcript_index}, ); return source;}
fn testSourceWithReplaceableTail( alloc: Allocator, bytes: []const u8, cols: u16, replaceable_start: usize,) !TranscriptPreparationSource { var source = try testSource(alloc, bytes, cols); source.replaceable_last_line = true; source.replaceable_start = replaceable_start; return source;}
fn appendFoldedLineForTest( runtime: *TranscriptRuntime, alloc: Allocator, block_index: usize, text: []const u8,) !void { const owned = try alloc.dupe(u8, text); errdefer alloc.free(owned); try runtime.folded_command_blocks.items[block_index].lines.append(alloc, .{ .stream = .stdout, .text = owned, });}
fn prepareTestSourceForCurrentArea( runtime: *TranscriptRuntime, alloc: Allocator, source: *const TranscriptPreparationSource,) !transcript_painter.PreparedTranscriptSurfacePaint { var metrics: Metrics = .{}; return runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, source, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom, }, );}
fn preparedVisualOffsetForTest( prepared: *const transcript_painter.PreparedTranscriptSurfacePaint,) u32 { var offset: u32 = 0; const end = @min( prepared.selection.start_line, prepared.sourceVisualRows().len, ); for (prepared.sourceVisualRows()[0..end]) |rows| offset += rows; return offset + prepared.selection.partial_skip_rows;}
test "unchanged transcript keeps stable projection during footer reflow" { const alloc = std.testing.allocator; const flow = "line 00\n" ++ "line 01\n" ++ "line 02\n" ++ "line 03\n" ++ "line 04\n" ++ "line 05\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(60, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var metrics = Metrics{};
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var compact = try runtime.prepareTranscriptSurfacePaintFromSourceForFrame( alloc, &metrics, &source, .{ .top = 1, .bottom = 4 }, false, ); defer compact.deinit(alloc); try std.testing.expectEqual(@as(usize, 2), compact.selection.start_line); try installStableAnchorWithOriginForTest( &runtime, alloc, flow, compact.selection, preparedVisualOffsetForTest(&compact), compact.cursor.cursor_row, compact.cursor.cursor_col, 800, .{ .source_cols = runtime.layout.cols, .source_visual_offset = preparedVisualOffsetForTest(&compact), }, );
var expanded = try runtime.prepareTranscriptSurfacePaintFromSourceForFrame( alloc, &metrics, &source, .{ .top = 1, .bottom = 6 }, true, ); defer expanded.deinit(alloc);
try std.testing.expectEqual(compact.selection.start_line, expanded.selection.start_line); try std.testing.expectEqual(compact.selection.last_visible_row, expanded.selection.last_visible_row);}
test "structured user turn source keeps full prompt beyond byte cache cap" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 18, 14), .owned_top_row = 1, .max_transcript_bytes = 256, }; defer runtime.deinit(alloc);
const prompt = try makeLongPastePrompt(alloc, 512); try std.testing.expect(prompt.len > runtime.max_transcript_bytes); _ = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{}, }); const assistant_id = try runtime.appendAssistantTurnEntry(alloc); const assistant = runtime.lookupAssistantSegments(assistant_id) orelse unreachable; try assistant.text.appendSlice(alloc, "assistant after long prompt\n");
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc);
try std.testing.expect(source.bytes.len > runtime.max_transcript_bytes); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "LONG_PASTE_FIRST_MARKER") != null); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "LONG_PASTE_LAST_MARKER") != null); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "assistant after long prompt") != null);}
test "large current user turn survives assistant retention pass" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 18, 14), .owned_top_row = 1, .max_transcript_bytes = 256, .max_retained_transcript_bytes = 128, }; defer runtime.deinit(alloc);
const prompt = try makeLongPastePrompt(alloc, 64); const user_id = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{}, }); const assistant_id = try runtime.appendAssistantTurnEntry(alloc); const assistant = runtime.lookupAssistantSegments(assistant_id) orelse unreachable; try assistant.text.appendSlice(alloc, "assistant begins\n");
try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expectEqual(user_id, runtime.entries.items[0].id()); try std.testing.expectEqual(assistant_id, runtime.entries.items[1].id());
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "LONG_PASTE_FIRST_MARKER") != null); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "assistant begins") != null);}
test "finalize transcript transition rejects frame inline row mismatch" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var source = try testSource(alloc, "line\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(u16, 0), runtime.planTranscriptScroll(&prepared).planned_rows);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, 1, ); var plan = testPaintPlan(&runtime, prepared.selection); try std.testing.expectError( error.InvalidFrameScrollPlan, resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ), );}
test "child full transcript finalizer consumes one complete transition" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try std.testing.expect( try runtime.setTranscriptPresentationDepth(alloc, .full), );
var source = try testSource(alloc, "child full transcript\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScrollForFrame(&prepared, false, false); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try runtime.finalizeTranscriptTransitionForFrame( alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, false, false, ); defer transition.deinit(alloc);
runtime.consumeFrameScrollCommit(alloc, scroll_plan, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = !transition.document_append.isEmpty(), .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }, &transition);
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expectEqual( transition.target_layout.layout_id, runtime.committed_frame_layout.layout_id, );}
fn commitPreparedForTest( runtime: *TranscriptRuntime, alloc: Allocator, source: *TranscriptPreparationSource, prepared: *transcript_painter.PreparedTranscriptSurfacePaint,) !void { const facts = runtime.planTranscriptScroll(prepared); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, source, prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = !transition.document_append.isEmpty(), .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });}
fn commitPreparedPartiallyForTest( runtime: *TranscriptRuntime, alloc: Allocator, source: *TranscriptPreparationSource, prepared: *transcript_painter.PreparedTranscriptSurfacePaint,) !void { const facts = runtime.planTranscriptScroll(prepared); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, source, prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = transition.materialized.cursor_row, .committed_cursor_col = transition.materialized.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });}
fn setPreparedVisualOffsetForTest( prepared: *transcript_painter.PreparedTranscriptSurfacePaint, target: u32,) !void { var remaining = target; var line_index: usize = 0; while (line_index < prepared.sourceVisualRows().len and remaining >= prepared.sourceVisualRows()[line_index]) : (line_index += 1) { remaining -= prepared.sourceVisualRows()[line_index]; } if (line_index >= prepared.sourceVisualRows().len) { return error.TestExpectedRepresentableVisualOffset; } prepared.selection.start_line = line_index; prepared.selection.partial_skip_rows = @intCast(remaining); prepared.selection.line_count = prepared.sourceVisualRows().len;}
const MeasuredEndpointMode = enum { seeded_exact, natural_null, seeded_inexact,};
fn expectZeroReverseRestoresSourceOrigin( runtime: *TranscriptRuntime, alloc: Allocator, wide_source: *TranscriptPreparationSource, narrow_source: *TranscriptPreparationSource, positive_delta: i32, endpoint_mode: MeasuredEndpointMode,) !void { var wide_prepared = try prepareTestSourceForCurrentArea( runtime, alloc, wide_source, ); defer wide_prepared.deinit(alloc); const source_origin = preparedVisualOffsetForTest(&wide_prepared); try std.testing.expect(source_origin > 0); try installStableAnchorForTest( runtime, alloc, wide_source.bytes, wide_prepared.selection, source_origin, wide_prepared.cursor.cursor_row, wide_prepared.cursor.cursor_col, 700, );
runtime.layout = transcriptTestLayout(narrow_source.cols, 8, 4); runtime.resize_history_row_delta = positive_delta; var narrow_prepared = try prepareTestSourceForCurrentArea( runtime, alloc, narrow_source, ); defer narrow_prepared.deinit(alloc); const natural_endpoint = if (narrow_prepared.measured_history_origin) |origin| origin.endpoint else null; if (endpoint_mode == .seeded_inexact) { try std.testing.expect(natural_endpoint == null); } if (endpoint_mode != .natural_null) { narrow_prepared.measured_history_origin = .{ .source_cols = wide_source.cols, .source_visual_offset = source_origin, .endpoint = .{ .span_start_flow_offset = 0, .flow_offset = 0, .hard_row_cols = wide_source.cols, }, }; } try std.testing.expectEqual( endpoint_mode != .natural_null, if (narrow_prepared.measured_history_origin) |origin| origin.endpoint != null else false, ); const narrow_origin = preparedVisualOffsetForTest(&narrow_prepared); try std.testing.expect(narrow_origin > source_origin); try commitPreparedForTest(runtime, alloc, narrow_source, &narrow_prepared); const narrowed = runtime.stableTranscriptProjectionForFlow( wide_source.bytes, ) orelse return error.TestExpectedStableTranscript; const retained_origin = narrowed.measured_history_origin orelse return error.TestExpectedMeasuredHistoryOrigin; try std.testing.expectEqual(source_origin, retained_origin.source_visual_offset); try std.testing.expectEqual(wide_source.cols, retained_origin.source_cols); try std.testing.expectEqual( endpoint_mode != .natural_null, retained_origin.endpoint != null, );
runtime.layout = transcriptTestLayout(wide_source.cols, 12, 8); runtime.resize_history_row_delta = 0; var restored = try prepareTestSourceForCurrentArea( runtime, alloc, wide_source, ); defer restored.deinit(alloc); try std.testing.expectEqual( source_origin, preparedVisualOffsetForTest(&restored), );}
fn totalVisualRowsForTest(line_rows: []const u16) u32 { var total: u32 = 0; for (line_rows) |rows| total += rows; return total;}
test "semantic row identity remains exact beyond 65535 rows" { const alloc = std.testing.allocator; const row_count: usize = 65_540; var flow_writer: std.Io.Writer.Allocating = .init(alloc); defer flow_writer.deinit(); for (0..row_count) |index| { if (index > 0) try flow_writer.writer.writeByte('\n'); try flow_writer.writer.print("semantic-row-{d}", .{index}); } const flow = flow_writer.written();
var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc);
try std.testing.expectEqual(row_count, prepared.sourceVisualRows().len); try std.testing.expectEqual( @as(u32, @intCast(row_count)), totalVisualRowsForTest(prepared.sourceVisualRows()), ); try std.testing.expectEqual(row_count - 8, prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 0), prepared.selection.partial_skip_rows);
const boundary_indices = [_]usize{ 65_534, 65_535, 65_536, row_count - 1 }; for (boundary_indices) |index| { var marker_buf: [32]u8 = undefined; const marker = try std.fmt.bufPrint( &marker_buf, "semantic-row-{d}", .{index}, ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, flow, marker), ); try std.testing.expectEqualStrings( marker, resolveVisibleLineForTest( prepared.visible_lines.items[index], .{ .bytes = prepared.bytes }, ), ); }
try commitPreparedForTest(&runtime, alloc, &source, &prepared); const stable = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestExpectedStableTranscript; try std.testing.expectEqual(row_count - 8, stable.selection.start_line); try std.testing.expectEqual( @as(u32, @intCast(row_count - 8)), stable.visual_offset, ); try std.testing.expectEqual( @as(u32, @intCast(row_count)), stable.total_visual_rows, );}
fn makeSyntheticPreparedRenderable( prepared: *transcript_painter.PreparedTranscriptSurfacePaint, alloc: Allocator,) !void { const line_count = prepared.line_visual_rows.items.len; try prepared.visible_lines.ensureTotalCapacity(alloc, line_count); while (prepared.visible_lines.items.len < line_count) { prepared.visible_lines.appendAssumeCapacity(.{ .transcript = .{ .ref = .{ .ref = .{ .start = 0, .len = 0 }, }, }, }); } prepared.selection.line_count = line_count; prepared.total_lines = line_count;}
fn enterRendererDerivedSemanticRecovery( runtime: *TranscriptRuntime, alloc: Allocator, flow: []const u8, attempt_content_bottom: u16, accepted_semantic_rows: u16, replaceable_start: ?usize,) !u32 { var stable_source = if (replaceable_start) |start| try testSourceWithReplaceableTail(alloc, flow, runtime.layout.cols, start) else try testSource(alloc, flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 0), stable_prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 0), stable_prepared.selection.partial_skip_rows); try installStableAnchorForTest( runtime, alloc, flow, stable_prepared.selection, 0, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 91, );
runtime.layout = transcriptTestLayout( runtime.layout.cols, runtime.layout.rows, attempt_content_bottom, ); var attempt_source = if (replaceable_start) |start| try testSourceWithReplaceableTail(alloc, flow, runtime.layout.cols, start) else try testSource(alloc, flow, runtime.layout.cols); defer attempt_source.deinit(alloc); var attempt_prepared = try prepareTestSourceForCurrentArea( runtime, alloc, &attempt_source, ); defer attempt_prepared.deinit(alloc);
const attempt_facts = runtime.planTranscriptScroll(&attempt_prepared); try std.testing.expect(attempt_facts.semantic_rows > accepted_semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, attempt_facts.planned_rows, ); var plan = testPaintPlan(runtime, attempt_prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &attempt_source, &attempt_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = if (accepted_semantic_rows > 0) 1 else 0, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = accepted_semantic_rows, .document_append_committed = false, .committed_cursor_row = attempt_prepared.cursor.cursor_row, .committed_cursor_col = attempt_prepared.cursor.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, ); return attempt_facts.target_visual_offset;}
fn expectFinalizedRecoveryProjectionPaintsCoherently( runtime: *TranscriptRuntime, alloc: Allocator, plan: render_engine.paint_plan.PaintPlan, prepared: *const transcript_painter.PreparedTranscriptSurfacePaint, transition: *const transcript_runtime.TranscriptTransition, expected_first_row_text: ?[]const u8,) !void { var shadow = try vt_emulator.Grid.init(alloc, plan.layout.cols, plan.layout.rows); defer shadow.deinit(); var surface = try render_engine.frame_surface.FrameSurface.initFromShadow( alloc, plan, shadow, ); defer surface.deinit();
const result = try runtime.paintPreparedTranscriptIntoSurface( alloc, &surface, prepared, ); try std.testing.expectEqualDeep(transition.selection, surface.plan.viewport); try std.testing.expectEqual( transition.selection.last_visible_row, result.last_row, ); try std.testing.expectEqual( transition.selection.replaceable_start_row, result.replaceable_start_row, ); try std.testing.expectEqual( transition.cursor_row, surface.cursor_target.?.row, ); try std.testing.expectEqual( transition.cursor_col, surface.cursor_target.?.col, ); try std.testing.expectEqual( transition.replaceable_row, prepared.cursor.replaceable_row, );
if (expected_first_row_text) |expected| { var target = try surface.copyToTargetGrid(alloc); defer target.deinit(); var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); try target.rowText(plan.viewport.top_row, &row_text); try std.testing.expect(std.mem.startsWith(u8, row_text.items, expected)); } if (transition.selection.last_visible_row_blank) { var col: u16 = 1; while (col <= surface.cols) : (col += 1) { const cell = surface.cellAt( transition.selection.last_visible_row, col, ).?; try std.testing.expectEqual(@as(u21, ' '), cell.codepoint); } }}
const OwnedBandInvalidationProbe = struct { saw_owned_band_change: bool = false,
fn paint(ctx: *anyopaque, surface: *render_engine.frame_surface.FrameSurface) anyerror!void { const self: *OwnedBandInvalidationProbe = @ptrCast(@alignCast(ctx)); for (surface.plan.invalidation.ranges()) |range| { if (range.reason == .owned_band_change) { self.saw_owned_band_change = true; } } }};
const PreparedTranscriptFramePainter = struct { runtime: *TranscriptRuntime, alloc: Allocator, prepared: *const transcript_painter.PreparedTranscriptSurfacePaint,
fn paint(ctx: *anyopaque, surface: *render_engine.frame_surface.FrameSurface) anyerror!void { const self: *PreparedTranscriptFramePainter = @ptrCast(@alignCast(ctx)); _ = try self.runtime.paintPreparedTranscriptIntoSurface( self.alloc, surface, self.prepared, ); }};
fn appendGridRows( alloc: Allocator, grid: *const vt_emulator.Grid, first_row: u16, row_count: u16, history: *std.ArrayList(u8), row_text: *std.ArrayList(u8),) !void { var row_offset: u16 = 0; while (row_offset < row_count) : (row_offset += 1) { row_text.clearRetainingCapacity(); try grid.rowTextTrimmed(first_row + row_offset, row_text); try std.testing.expect(row_text.items.len > 0); if (history.items.len > 0) try history.append(alloc, '\n'); try history.appendSlice(alloc, row_text.items); }}
fn countExactHistoryLine(history: []const u8, expected: []const u8) usize { var count: usize = 0; var lines = std.mem.splitScalar(u8, history, '\n'); while (lines.next()) |line| { if (std.mem.eql(u8, line, expected)) count += 1; } return count;}
fn cloneRecoveryTransitionForTest( alloc: Allocator, source: *const transcript_runtime.TranscriptTransition,) !transcript_runtime.TranscriptTransition { std.debug.assert(!source.consumed); std.debug.assert(source.document_append.isEmpty()); std.debug.assert(source.document_append_bytes.len == 0);
var clone = source.*; clone.document_append.bytes = &.{}; clone.document_append_bytes = &.{}; clone.target_flow = &.{}; clone.target_cache = .empty; clone.folded_summary_indices = &.{}; errdefer clone.deinit(alloc);
clone.target_flow = try alloc.dupe(u8, source.target_flow); try clone.target_cache.appendSlice(alloc, source.target_cache.items); clone.folded_summary_indices = try alloc.dupe( usize, source.folded_summary_indices, ); return clone;}
fn createProductionCappedFoldedRecoveryTransition( alloc: Allocator, cols: u16, viewport_rows: u16,) !transcript_runtime.TranscriptTransition { const stable_flow = "summary"; const initial_owned_top = viewport_rows + 1; const content_bottom = initial_owned_top + viewport_rows - 1; const raw_line_count: usize = 3; const wrapped_rows_per_line: usize = (@as(usize, std.math.maxInt(u16)) + 1) / raw_line_count + 1; const raw_line_bytes = wrapped_rows_per_line * @as(usize, cols);
var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile( std.testing.io, "production-folded-capped-attempt.log", .{ .read = true }, ); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = transcriptTestLayout( cols, content_bottom + 4, content_bottom, ), .owned_top_row = initial_owned_top, .max_transcript_bytes = 2 * 1024 * 1024, .max_retained_transcript_bytes = 2 * 1024 * 1024, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.shadow_vt.?.feed("shell0\r\nshell1\r\nshell2\r\nshell3");
try runtime.transcript.appendSlice(alloc, stable_flow); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 1, }); var fold_index: usize = 0; while (fold_index < viewport_rows) : (fold_index += 1) { var fold_buf: [16]u8 = undefined; const fold = try std.fmt.bufPrint(&fold_buf, "fold{d}", .{fold_index}); try appendFoldedLineForTest(&runtime, alloc, 0, fold); }
var metrics: Metrics = .{}; var stable_source = try runtime.prepareTranscriptSource(alloc, null); defer stable_source.deinit(alloc); try std.testing.expectEqualStrings(stable_flow, stable_source.bytes); try std.testing.expectEqual(@as(usize, 1), stable_source.folded_summary_indices.len); try std.testing.expectEqual(@as(usize, 1), stable_source.folded_summary_indices[0]); try std.testing.expectEqual(viewport_rows, stable_source.preview.natural_visual_rows);
var stable_prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (stable_prepared) |*paint| paint.deinit(alloc); const stable_frame = try solveTestTranscriptFixedPointFrame( &runtime, alloc, &metrics, &stable_source, 4, &stable_prepared, ); const stable_paint = &stable_prepared.?; try std.testing.expectEqual( stable_frame.layout.owned_top, stable_frame.scroll_plan.post_scroll_owned_top, ); var stable_plan = testPaintPlanForFrame( stable_frame.layout, stable_paint.selection, stable_paint.cursor.cursor_row, stable_paint.cursor.cursor_col, ); var stable_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &stable_source, stable_paint, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(stable_frame.layout), &stable_plan, stable_frame.scroll_plan, ); defer stable_transition.deinit(alloc); try std.testing.expect(stable_transition.document_append.isEmpty());
var stable_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = stable_paint, }; const stable_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = stable_plan, .scroll_plan = stable_frame.scroll_plan, .document_append = stable_transition.document_append, .body_painter = .{ .ctx = &stable_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, stable_result.shadow_state, ); runtime.ackPreservedRowReleaseAssumeValid( stable_frame.scroll_plan, stable_result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &stable_transition, stable_result); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
var raw_line: std.ArrayList(u8) = .empty; defer raw_line.deinit(alloc); var raw_line_index: usize = 0; while (raw_line_index < raw_line_count) : (raw_line_index += 1) { try runtime.transcript.appendSlice(alloc, "\n"); raw_line.clearRetainingCapacity(); try raw_line.appendNTimes( alloc, 'a' + @as(u8, @intCast(raw_line_index)), raw_line_bytes, ); try std.testing.expectEqual( @as(u16, @intCast(wrapped_rows_per_line)), visualRowsForLine(raw_line.items, cols), ); try runtime.transcript.appendSlice(alloc, raw_line.items); }
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual( @as(u16, std.math.maxInt(u16)), source.preview.natural_visual_rows, ); try std.testing.expectEqual(@as(usize, 1), source.folded_summary_indices.len); try std.testing.expectEqual(@as(usize, 1), source.folded_summary_indices[0]);
var prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (prepared) |*paint| paint.deinit(alloc); const frame = try solveTestTranscriptFixedPointFrame( &runtime, alloc, &metrics, &source, 8, &prepared, ); const paint = &prepared.?; const facts = runtime.planTranscriptScroll(paint); try std.testing.expect(facts.semantic_rows > std.math.maxInt(u16)); try std.testing.expectEqual(viewport_rows, facts.planned_rows); try std.testing.expectEqual( frame.layout.owned_top, frame.scroll_plan.post_scroll_owned_top, ); try std.testing.expectEqual( viewport_rows, frame.scroll_plan.acceptedInlineRows( frame.scroll_plan.terminal_scroll_rows, ), );
var plan = testPaintPlanForFrame( frame.layout, paint.selection, paint.cursor.cursor_row, paint.cursor.cursor_col, ); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, paint, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(frame.layout), &plan, frame.scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty()); try std.testing.expectEqual(@as(?usize, null), transition.materialized.flow_len); try std.testing.expectEqual(viewport_rows, transition.materialized.visual_rows); try std.testing.expectEqual( @as(u32, viewport_rows), transition.materialized.visual_offset, ); var transition_template = try cloneRecoveryTransitionForTest( alloc, &transition, ); errdefer transition_template.deinit(alloc);
var painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = paint, }; const result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = plan, .scroll_plan = frame.scroll_plan, .document_append = transition.document_append, .body_painter = .{ .ctx = &painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, result.shadow_state, ); try std.testing.expectEqual( frame.scroll_plan.terminal_scroll_rows, result.terminal_scroll_rows_committed, ); try std.testing.expect(!result.document_append_committed); runtime.ackPreservedRowReleaseAssumeValid( frame.scroll_plan, result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &transition, result);
const diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, diagnostic.state, ); try std.testing.expectEqual(transition.visual_offset, diagnostic.visual_offset); try std.testing.expect(diagnostic.remaining_inline_rows > 0); try std.testing.expectEqual( facts.semantic_rows - facts.planned_rows, diagnostic.remaining_inline_rows, );
return transition_template;}
fn testSelectionInArea( start_line: usize, top_row: u16, bottom_row: u16,) viewport_selection.ViewportSelection { var selection = testSelection(start_line); selection.top_row = top_row; selection.bottom_row = bottom_row; return selection;}
fn enterSemanticAppendRecovery( runtime: *TranscriptRuntime, alloc: Allocator, stable_flow: []const u8, attempt_flow: []const u8, attempt_visual_rows: []const u16,) !void { const stable_selection = testSelectionInArea( 0, runtime.owned_top_row, runtime.layout.content_bottom, ); try installStableAnchorForTest( runtime, alloc, stable_flow, stable_selection, 0, runtime.layout.content_bottom, 1, 45, );
var source = try testSource(alloc, attempt_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelectionInArea( 4, runtime.owned_top_row, runtime.layout.content_bottom, ), .cursor = .{ .cursor_row = runtime.layout.content_bottom, .cursor_col = 1, .replaceable_row = runtime.layout.content_bottom, }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, attempt_visual_rows); try makeSyntheticPreparedRenderable(&prepared, alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 0), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 4), facts.semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 3, facts.planned_rows, ); try std.testing.expectEqual(@as(u16, 1), scroll_plan.remaining_inline_advance_rows);
var plan = testPaintPlan(runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty());
runtime.ackPreservedRowReleaseAssumeValid( scroll_plan, scroll_plan.terminal_scroll_rows, ); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = false, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = runtime.layout.content_bottom, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u32, 3), recovery.visual_offset); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);}
fn consumeUnacceptedSemanticRecoveryRetry( runtime: *TranscriptRuntime, alloc: Allocator, flow: []const u8, visual_rows: []const u16, start_line: usize,) !void { var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelectionInArea( start_line, runtime.owned_top_row, runtime.layout.content_bottom, ), .cursor = .{ .cursor_row = runtime.layout.content_bottom, .cursor_col = 1, .replaceable_row = runtime.layout.content_bottom, }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, visual_rows); try makeSyntheticPreparedRenderable(&prepared, alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 0), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = runtime.layout.content_bottom, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u32, 3), recovery.visual_offset); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);}
fn enterResizeReflowRecovery( runtime: *TranscriptRuntime, alloc: Allocator, resize_history_row_delta: ?i32, shadow_state: render_engine.terminal_diff.ShadowCommitState,) !void { return enterResizeReflowRecoveryWithAcceptedRows( runtime, alloc, resize_history_row_delta, shadow_state, 1, );}
fn enterResizeReflowRecoveryWithAcceptedRows( runtime: *TranscriptRuntime, alloc: Allocator, resize_history_row_delta: ?i32, shadow_state: render_engine.terminal_diff.ShadowCommitState, accepted_rows: u16,) !void { const flow = "stable\nbase\n"; try runtime.enableShadowVt(alloc); try installStableAnchorForTest( runtime, alloc, flow, testSelectionInArea(0, 1, 4), 0, 4, 1, 46, ); const shadow = runtime.shadow_vt.?; shadow.cells[19].codepoint = 'x'; shadow.cursor_row = 8; shadow.cursor_col = 1;
runtime.viewport_clear_pending = true; runtime.layout = transcriptTestLayout(10, 8, 2); runtime.resize_history_row_delta = resize_history_row_delta;
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 2), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), facts.semantic_rows); try std.testing.expect(accepted_rows < facts.planned_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = accepted_rows, .document_append_committed = false, .committed_cursor_row = 2, .committed_cursor_col = 1, .shadow_state = shadow_state, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(facts.target_visual_offset, recovery.visual_offset); try std.testing.expectEqual( facts.planned_rows - accepted_rows, recovery.remaining_inline_rows, );}
test "committed resize deferral installs target layout before recovery" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
try enterResizeReflowRecoveryWithAcceptedRows( &runtime, alloc, null, .committed, 0, );
const expected_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( testPaintPlan(&runtime, testSelectionInArea(0, 1, 2)), ); try std.testing.expectEqualDeep(expected_layout, runtime.committed_frame_layout); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, );}
const RecoveryAttemptOutcome = struct { facts: transcript_runtime.TranscriptScrollFacts, visual_offset: u32,};
fn consumeRendererRecoveryAttempt( runtime: *TranscriptRuntime, alloc: Allocator, flow: []const u8, committed_inline_rows: u16, shadow_state: render_engine.terminal_diff.ShadowCommitState,) !RecoveryAttemptOutcome { var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); try std.testing.expect(committed_inline_rows <= scroll_plan.terminal_scroll_rows); var plan = testPaintPlan(runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); const visual_offset = transition.visual_offset;
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = committed_inline_rows, .document_append_committed = !transition.document_append.isEmpty(), .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = shadow_state, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); return .{ .facts = facts, .visual_offset = visual_offset, };}
fn expectDocumentWireEqualsLogical( alloc: Allocator, logical: []const u8, wire: []const u8,) !void { var decoded: std.ArrayList(u8) = .empty; defer decoded.deinit(alloc); var index: usize = 0; while (index < wire.len) { if (wire[index] == '\n') return error.TestExpectedCarriageReturn; if (wire[index] == '\r' and index + 1 < wire.len and wire[index + 1] == '\n') { try decoded.append(alloc, '\n'); index += 2; } else { try decoded.append(alloc, wire[index]); index += 1; } } try std.testing.expectEqualStrings(logical, decoded.items);}
fn expectRendererAppendRestored( runtime: *TranscriptRuntime, alloc: Allocator, stable_flow: []const u8, grown_flow: []const u8,) !void { var source = try testSource(alloc, grown_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(!facts.recovery_rebase); try std.testing.expect(facts.semantic_rows > 0); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[stable_flow.len..], transition.document_append.bytes, );}
fn checkTranscriptTransitionStagingAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest(&runtime, alloc, "old\n", testSelection(0), 0, 3, 1, 71); const committed_before = runtime.transcriptCommitDiagnostic();
var source = try testSource(alloc, "old\nnew\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelection(1), .cursor = .{ .cursor_row = 4, .cursor_col = 1, .replaceable_row = 4 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &.{ 1, 1 }); const scroll_plan = render_engine.frame_scroll_plan.merge(runtime.layout.rows, 1, 0, 1); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ) catch |err| { try std.testing.expectEqualDeep(committed_before, runtime.transcriptCommitDiagnostic()); try std.testing.expect(runtime.stableTranscriptProjectionForFlow("old\n") != null); return err; }; defer transition.deinit(alloc);
try std.testing.expectEqualDeep(committed_before, runtime.transcriptCommitDiagnostic()); try std.testing.expect(runtime.stableTranscriptProjectionForFlow("old\n") != null);}
fn commandOutputTestStyles() Styles { return .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", };}
fn commandOutputAnsiTestStyles() Styles { return .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "\x1b[0m", .dim_style = "\x1b[2m", .red_style = "\x1b[31m", };}
fn semanticNoticePaletteA() Styles { return .{ .system_notice_text_style = "\x1b[37m", .reset_style = "\x1b[0m", .notice_information_style = "\x1b[36m", .notice_success_style = "\x1b[32m", .notice_warning_style = "\x1b[33m", .notice_error_style = "\x1b[31m", .notice_cancelled_style = "\x1b[90m", };}
fn semanticNoticePaletteB() Styles { return .{ .system_notice_text_style = "\x1b[35m", .reset_style = "\x1b[0m", .notice_information_style = "\x1b[34m", .notice_success_style = "\x1b[92m", .notice_warning_style = "\x1b[93m", .notice_error_style = "\x1b[91m", .notice_cancelled_style = "\x1b[2m", };}
test "semantic notice append and replacement preserve ownership identity and timestamp" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(32, 16, 12) }; defer runtime.deinit(alloc); runtime.setCommandOutputRenderPolicy(semanticNoticePaletteA());
const entry_id = try runtime.appendReplaceableSemanticNotice(alloc, .{ .topic = "build", .tone = .warning, .body = "first body", }); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .semantic_notice); try std.testing.expect(runtime.entries.items[0].semantic_notice.pending_replacement); const created_at_ms = runtime.entries.items[0].createdAtMs(); try std.testing.expectEqualStrings("build", runtime.entries.items[0].semantic_notice.topic); try std.testing.expectEqualStrings("first body", runtime.entries.items[0].semantic_notice.body);
try std.testing.expect(try runtime.replaceSemanticNotice(alloc, entry_id, .{ .topic = "deploy", .tone = .success, .body = "replacement body with /tmp/output/path", .visibility = .full_only, })); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); try std.testing.expectEqual(created_at_ms, runtime.entries.items[0].createdAtMs()); try std.testing.expectEqualStrings("deploy", runtime.entries.items[0].semantic_notice.topic); try std.testing.expectEqual(types.NoticeTone.success, runtime.entries.items[0].semantic_notice.tone); try std.testing.expectEqualStrings("replacement body with /tmp/output/path", runtime.entries.items[0].semantic_notice.body); try std.testing.expectEqual(types.NoticeVisibility.full_only, runtime.entries.items[0].semantic_notice.visibility); try std.testing.expectEqualStrings("", runtime.transcript.items); // The finished replacement clears the pending-replacement pin, making // the entry immutable history: a second in-place replacement is refused. try std.testing.expect(!runtime.entries.items[0].semantic_notice.pending_replacement); try std.testing.expectError( error.MissingNoticeReplacementPin, runtime.replaceSemanticNotice(alloc, entry_id, .{ .topic = "again", .tone = .information, .body = "must not apply", }), ); try std.testing.expect(!(try runtime.replaceSemanticNotice(alloc, entry_id + 1, .{ .topic = "missing", .tone = .information, .body = "unchanged", })));}
fn checkSemanticNoticeAppendAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(32, 16, 12) }; defer runtime.deinit(alloc); const entry_id = try runtime.appendSemanticNotice(alloc, .{ .topic = "allocator", .tone = .@"error", .body = "owned topic and body", }); try std.testing.expectEqual(@as(u32, 1), entry_id); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqualStrings("allocator", runtime.entries.items[0].semantic_notice.topic); try std.testing.expectEqualStrings("owned topic and body", runtime.entries.items[0].semantic_notice.body);}
test "semantic notice append is allocator safe" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkSemanticNoticeAppendAllocationFailures, .{}, );}
fn checkSemanticNoticeReplacementAllocationFailures(alloc: Allocator) !void { const base = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(32, 16, 12) }; defer runtime.deinit(base); const entry_id = try runtime.appendReplaceableSemanticNotice(base, .{ .topic = "before", .tone = .information, .body = "stable body", }); const created_at_ms = runtime.entries.items[0].createdAtMs(); const next_entry_id = runtime.next_entry_id;
const replaced = runtime.replaceSemanticNotice(alloc, entry_id, .{ .topic = "after", .tone = .cancelled, .body = "replacement body", }) catch |err| { try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); try std.testing.expectEqual(created_at_ms, runtime.entries.items[0].createdAtMs()); try std.testing.expectEqualStrings("before", runtime.entries.items[0].semantic_notice.topic); try std.testing.expectEqualStrings("stable body", runtime.entries.items[0].semantic_notice.body); try std.testing.expectEqual(next_entry_id, runtime.next_entry_id); return err; }; try std.testing.expect(replaced); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); try std.testing.expectEqual(created_at_ms, runtime.entries.items[0].createdAtMs()); try std.testing.expectEqualStrings("after", runtime.entries.items[0].semantic_notice.topic); try std.testing.expectEqualStrings("replacement body", runtime.entries.items[0].semantic_notice.body); try std.testing.expectEqual(next_entry_id, runtime.next_entry_id);}
test "semantic notice replacement is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkSemanticNoticeReplacementAllocationFailures, .{}, );}
test "one retained semantic notice reflows through compact and full projection with retained palettes" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(36, 24, 20) }; defer runtime.deinit(alloc); const notice: types.SemanticNotice = .{ .topic = "paths", .tone = .information, .body = "review /workspace/packages/terminal/rendering.zig before continuing", }; const entry_id = try runtime.appendSemanticNotice(alloc, notice);
const cases = [_]struct { cols: u16, styles: Styles }{ .{ .cols = 36, .styles = semanticNoticePaletteA() }, .{ .cols = 18, .styles = semanticNoticePaletteB() }, }; for (cases) |case| { runtime.layout = transcriptTestLayout(case.cols, 24, 20); runtime.setCommandOutputRenderPolicy(case.styles); const expected = try transcript_blocks.renderSemanticNotice(alloc, notice, case.styles, case.cols); defer alloc.free(expected);
var compact = try runtime.prepareTranscriptSource(alloc, null); defer compact.deinit(alloc); try std.testing.expect(std.mem.find(u8, compact.bytes, expected) != null);
var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const full = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, case.cols, 64, 0, null, ); defer alloc.free(full); try std.testing.expect(std.mem.find(u8, full, expected) != null); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); }}
test "visible overflow after committed frame leaves scroll planning to viewport selection" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .viewport_top_row = 4, .owned_top_row = 4, .cursor_row = 8, .cursor_col = 1, .has_painted_transcript = true, .has_committed_frame = true, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.writeTranscript(alloc, &metrics, "overflow\n", true);
try std.testing.expectEqual(@as(u16, 4), runtime.owned_top_row); try std.testing.expectEqual(@as(u16, 4), runtime.viewport_top_row);}
test "neutral transcript flow preview reports natural rows without footer reservation" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .viewport_top_row = 1, .owned_top_row = 1, .cursor_row = 8, .cursor_col = 1, .has_painted_transcript = true, .last_paint_bottom_reserved_rows = 3, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.transcript.appendSlice(alloc, "line 1\nline 2\nline 3\n");
const preview = try runtime.previewTranscriptFlow(alloc);
try std.testing.expectEqual(@as(u16, 3), preview.natural_visual_rows); try std.testing.expectEqual(@as(u16, 1), preview.cursor_col); try std.testing.expectEqual(@as(u16, 3), runtime.last_paint_bottom_reserved_rows);}
test "stable transcript planning uses visual rows and partial skips" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest(&runtime, alloc, "stable", testSelection(0), 0, 3, 1, 41);
var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = try alloc.dupe(u8, "stable"), .selection = testSelection(1), }; defer prepared.deinit(alloc); prepared.selection.partial_skip_rows = 2; try prepared.line_visual_rows.appendSlice(alloc, &.{ 3, 4, 2, 1 });
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u32, 5), facts.target_visual_offset); try std.testing.expectEqual(@as(u16, 5), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 5), facts.planned_rows);}
test "compatible growth beyond one frame retains exact semantic debt" { const alloc = std.testing.allocator; const stable_flow = "base\n"; const extra_row_count: usize = @as(usize, std.math.maxInt(u16)) + 8; var grown_flow: std.ArrayList(u8) = .empty; defer grown_flow.deinit(alloc); try grown_flow.ensureTotalCapacity( alloc, stable_flow.len + extra_row_count * "x\n".len, ); grown_flow.appendSliceAssumeCapacity(stable_flow); for (0..extra_row_count) |_| { grown_flow.appendSliceAssumeCapacity("x\n"); }
var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, stable_flow, testSelection(0), 0, 2, 1, 411, );
var probe_source = try testSource(alloc, grown_flow.items, runtime.layout.cols); defer probe_source.deinit(alloc); var probe_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &probe_source, ); defer probe_prepared.deinit(alloc); const probe_facts = runtime.planTranscriptScroll(&probe_prepared); const exact_semantic_rows = probe_facts.target_visual_offset; try std.testing.expect(exact_semantic_rows > std.math.maxInt(u16)); try std.testing.expectEqual( exact_semantic_rows, @as(u32, probe_facts.semantic_rows), ); try std.testing.expectEqual( std.math.maxInt(u16), probe_facts.planned_rows, );
const accepted_rows = std.math.maxInt(u16); const initial = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow.items, accepted_rows, .committed, ); try std.testing.expectEqual( exact_semantic_rows, @as(u32, initial.facts.semantic_rows), ); const remaining_after_cap = exact_semantic_rows - accepted_rows; try std.testing.expectEqual( remaining_after_cap, @as(u32, runtime.transcriptCommitDiagnostic().remaining_inline_rows), ); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty); runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const repeated = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow.items, 1, .terminal_partial_write, ); try std.testing.expectEqual( remaining_after_cap, @as(u32, repeated.facts.semantic_rows), ); const remaining_semantic_rows = remaining_after_cap - 1; try std.testing.expectEqual( remaining_semantic_rows, @as(u32, runtime.transcriptCommitDiagnostic().remaining_inline_rows), );
const complete = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow.items, @intCast(remaining_semantic_rows), .committed, ); try std.testing.expectEqual( remaining_semantic_rows, @as(u32, complete.facts.semantic_rows), ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const stable = runtime.stableTranscriptProjectionForFlow(grown_flow.items) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(exact_semantic_rows, stable.visual_offset);}
test "oversized compatible growth materializes only each accepted projection" { const alloc = std.testing.allocator; const stable_flow = "base\n"; const filler_row_count: usize = @as(usize, std.math.maxInt(u16)) - 1; const staged_tail = "cap 0\n" ++ "cap 1\n" ++ "cap 2\n" ++ "cap 3\n" ++ "gap\n" ++ "tail 0\n" ++ "tail 1\n" ++ "tail 2\n" ++ "tail 3"; var grown_flow: std.ArrayList(u8) = .empty; defer grown_flow.deinit(alloc); try grown_flow.ensureTotalCapacity( alloc, stable_flow.len + filler_row_count * "x\n".len + staged_tail.len, ); grown_flow.appendSliceAssumeCapacity(stable_flow); for (0..filler_row_count) |_| { grown_flow.appendSliceAssumeCapacity("x\n"); } grown_flow.appendSliceAssumeCapacity(staged_tail);
var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile( std.testing.io, "oversized-staged-projection.log", .{ .read = true }, ); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.shadow_vt.?.feed(stable_flow);
var stable_source = try testSource(alloc, stable_flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, stable_flow, stable_prepared.selection, 0, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 412, );
var materialized_append: std.ArrayList(u8) = .empty; defer materialized_append.deinit(alloc);
var first_source = try testSource(alloc, grown_flow.items, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expectEqual( @as(u16, std.math.maxInt(u16)), first_facts.planned_rows, ); try std.testing.expect(first_facts.semantic_rows > first_facts.planned_rows); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc);
try std.testing.expectEqual( @as(u32, std.math.maxInt(u16)), first_transition.visual_offset, ); try std.testing.expectEqual( first_facts.target_visual_offset + 4, first_transition.total_visual_rows, ); try std.testing.expectEqual(@as(u16, 5), first_transition.cursor_row); try std.testing.expectEqual(@as(u16, 1), first_transition.cursor_col); try std.testing.expect(!first_transition.document_append.isEmpty()); try std.testing.expect(first_transition.materialized.flow_len.? < grown_flow.items.len); try materialized_append.appendSlice( alloc, first_transition.document_append.bytes, );
var first_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = &first_prepared, }; var metrics: Metrics = .{}; const first_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = first_plan, .scroll_plan = first_scroll_plan, .document_append = first_transition.document_append, .body_painter = .{ .ctx = &first_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, first_result.shadow_state, ); var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); try runtime.shadow_vt.?.rowTextTrimmed(1, &row_text); try std.testing.expectEqualStrings("cap 0", row_text.items); row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(4, &row_text); try std.testing.expectEqualStrings("cap 3", row_text.items);
runtime.consumeTranscriptTransition(alloc, &first_transition, first_result); const after_first = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, after_first.state, ); try std.testing.expectEqual( first_facts.semantic_rows - first_facts.planned_rows, after_first.remaining_inline_rows, ); try std.testing.expectEqual( @as(u32, std.math.maxInt(u16)), after_first.visual_offset, );
var retry_source = try testSource(alloc, grown_flow.items, runtime.layout.cols); defer retry_source.deinit(alloc); var retry_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &retry_source, ); defer retry_prepared.deinit(alloc); const retry_facts = runtime.planTranscriptScroll(&retry_prepared); try std.testing.expectEqual( after_first.remaining_inline_rows, retry_facts.semantic_rows, ); const retry_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, retry_facts.planned_rows, ); var retry_plan = testPaintPlan(&runtime, retry_prepared.selection); var retry_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &retry_source, &retry_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(retry_plan), &retry_plan, retry_scroll_plan, ); defer retry_transition.deinit(alloc); try std.testing.expectEqual( retry_facts.target_visual_offset, retry_transition.visual_offset, ); try std.testing.expect(!retry_transition.document_append.isEmpty()); try std.testing.expectEqual( first_transition.cursor_row, retry_transition.document_append.start_row, ); try std.testing.expectEqual( first_transition.cursor_col, retry_transition.document_append.start_col, ); try materialized_append.appendSlice( alloc, retry_transition.document_append.bytes, ); try expectDocumentWireEqualsLogical( alloc, grown_flow.items[stable_flow.len..], materialized_append.items, );
var retry_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = &retry_prepared, }; const retry_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = retry_plan, .scroll_plan = retry_scroll_plan, .document_append = retry_transition.document_append, .body_painter = .{ .ctx = &retry_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, retry_result.shadow_state, ); row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(1, &row_text); try std.testing.expectEqualStrings("tail 0", row_text.items); row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(4, &row_text); try std.testing.expectEqualStrings("tail 3", row_text.items);
runtime.consumeTranscriptTransition(alloc, &retry_transition, retry_result); const stable = runtime.stableTranscriptProjectionForFlow(grown_flow.items) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(retry_facts.target_visual_offset, stable.visual_offset); try std.testing.expectEqual(retry_transition.cursor_row, stable.cursor_row); try std.testing.expectEqual(retry_transition.cursor_col, stable.cursor_col);}
test "folded inexact growth advances only materialized viewport rows" { const alloc = std.testing.allocator; const cols: u16 = 16; const viewport_rows: u16 = 4; const growth_rows: usize = @as(usize, viewport_rows) * 2; const growth_rows_u32: u32 = @intCast(growth_rows); const initial_owned_top = viewport_rows + 1; const content_bottom = initial_owned_top + viewport_rows - 1; const stable_flow = "summary"; var seed_transition = try createProductionCappedFoldedRecoveryTransition( alloc, cols, viewport_rows, ); defer seed_transition.deinit(alloc); try std.testing.expectEqual(@as(?usize, null), seed_transition.materialized.flow_len); try std.testing.expect( seed_transition.semantic_rows > seed_transition.scroll_plan.requested_inline_advance_rows, );
var grown_flow: std.ArrayList(u8) = .empty; defer grown_flow.deinit(alloc); try grown_flow.ensureTotalCapacity( alloc, stable_flow.len + growth_rows * "\ng00000".len, ); grown_flow.appendSliceAssumeCapacity(stable_flow); var growth_index: usize = 0; while (growth_index < growth_rows) : (growth_index += 1) { var line_buf: [16]u8 = undefined; const line = try std.fmt.bufPrint( &line_buf, "\ng{d:0>5}", .{growth_index}, ); grown_flow.appendSliceAssumeCapacity(line); }
var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile( std.testing.io, "folded-staged-projection.log", .{ .read = true }, ); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = transcriptTestLayout( cols, content_bottom + 4, content_bottom, ), .owned_top_row = initial_owned_top, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.shadow_vt.?.feed("shell0\r\nshell1\r\nshell2\r\nshell3"); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 1, }); var fold_index: usize = 0; while (fold_index < viewport_rows) : (fold_index += 1) { var fold_buf: [16]u8 = undefined; const fold = try std.fmt.bufPrint(&fold_buf, "fold{d}", .{fold_index}); try appendFoldedLineForTest(&runtime, alloc, 0, fold); }
var metrics: Metrics = .{}; var stable_source = try testFoldedSource( alloc, stable_flow, runtime.layout.cols, 1, ); defer stable_source.deinit(alloc); var stable_fixed_prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (stable_fixed_prepared) |*prepared| prepared.deinit(alloc); const stable_frame = try solveTestTranscriptFixedPointFrame( &runtime, alloc, &metrics, &stable_source, 4, &stable_fixed_prepared, ); const stable_fixed = &stable_fixed_prepared.?; try std.testing.expectEqual(@as(u32, 0), preparedVisualOffsetForTest(stable_fixed)); try std.testing.expectEqual( @as(u32, viewport_rows), totalVisualRowsForTest(stable_fixed.sourceVisualRows()), ); try std.testing.expectEqual( stable_frame.layout.owned_top, stable_frame.scroll_plan.post_scroll_owned_top, ); var stable_plan = testPaintPlanForFrame( stable_frame.layout, stable_fixed.selection, stable_fixed.cursor.cursor_row, stable_fixed.cursor.cursor_col, ); var stable_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &stable_source, stable_fixed, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(stable_frame.layout), &stable_plan, stable_frame.scroll_plan, ); defer stable_transition.deinit(alloc); var stable_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = stable_fixed, }; const stable_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = stable_plan, .scroll_plan = stable_frame.scroll_plan, .body_painter = .{ .ctx = &stable_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); runtime.ackPreservedRowReleaseAssumeValid( stable_frame.scroll_plan, stable_result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &stable_transition, stable_result); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); try runtime.shadow_vt.?.rowTextTrimmed(initial_owned_top, &row_text); try std.testing.expectEqualStrings("│ fold0", row_text.items); row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(content_bottom, &row_text); try std.testing.expectEqualStrings("│ fold3", row_text.items);
var history: std.ArrayList(u8) = .empty; defer history.deinit(alloc); var seed_source = try testFoldedSource( alloc, grown_flow.items, runtime.layout.cols, 1, ); defer seed_source.deinit(alloc); seed_source.preview.natural_visual_rows = @intCast(@as(u32, viewport_rows) + growth_rows_u32); const seed_release = render_engine.frame_layout.solveWithPreservedRowRelease(.{ .terminal = runtime.layout, .owned_top = runtime.owned_top_row, .footer = .{ .natural_rows = 8, .min_rows = 8, .max_rows = 8, }, .transcript = seed_source.preview, .prior = runtime.committed_frame_layout, }, 0); const compact_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, seed_release.released_rows, seed_transition.scroll_plan.requested_inline_advance_rows, ); try std.testing.expectEqualDeep(seed_transition.scroll_plan, compact_scroll_plan); try std.testing.expectEqual( seed_release.layout.owned_top, seed_transition.scroll_plan.post_scroll_owned_top, ); const seed_target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(seed_release.layout); try std.testing.expectEqualDeep(seed_transition.target_layout, seed_target_layout);
var seed_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &seed_source, ); defer seed_prepared.deinit(alloc); const seed_target_offset = preparedVisualOffsetForTest(&seed_prepared); try std.testing.expectEqual(growth_rows_u32, seed_target_offset); const seed_total_visual_rows = totalVisualRowsForTest(seed_prepared.sourceVisualRows()); try std.testing.expectEqual( @as(u32, viewport_rows) + growth_rows_u32, seed_total_visual_rows, ); const seed_projection = try transcript_painter.stagePreparedTranscriptForVisualOffset( alloc, runtime.layout, &seed_prepared, seed_release.layout.transcript_area, seed_transition.visual_offset, ); try std.testing.expectEqual( seed_transition.materialized.flow_len, seed_projection.flow_end, ); try std.testing.expectEqual( seed_transition.materialized.visual_rows, seed_prepared.projection_visual_rows.?, ); try std.testing.expectEqual( seed_transition.materialized.visual_offset, seed_transition.visual_offset, );
var contract_selection = seed_prepared.selection; contract_selection.line_count = seed_transition.selection.line_count; contract_selection.tail_kind = seed_transition.selection.tail_kind; try std.testing.expectEqualDeep(seed_transition.selection, contract_selection); try std.testing.expectEqual( seed_transition.materialized.cursor_row, seed_prepared.cursor.cursor_row, ); try std.testing.expectEqual( seed_transition.materialized.cursor_col, seed_prepared.cursor.cursor_col, ); try std.testing.expectEqual( seed_transition.cursor_row, seed_prepared.cursor.cursor_row, ); try std.testing.expectEqual( seed_transition.cursor_col, seed_prepared.cursor.cursor_col, ); try std.testing.expectEqual( seed_transition.replaceable_last_line, seed_prepared.replaceable_last_line, ); try std.testing.expectEqual( seed_transition.replaceable_start, seed_prepared.replaceable_start, ); try std.testing.expectEqual( seed_transition.replaceable_row, seed_prepared.cursor.replaceable_row, ); try std.testing.expectEqualSlices( usize, seed_transition.folded_summary_indices, seed_source.folded_summary_indices, ); try std.testing.expect(seed_transition.document_append.isEmpty()); try std.testing.expectEqual(@as(usize, 0), seed_transition.document_append_bytes.len);
const compact_target_flow = try alloc.dupe(u8, grown_flow.items); if (seed_transition.target_flow.len > 0) alloc.free(seed_transition.target_flow); seed_transition.target_flow = compact_target_flow; seed_transition.target_cache.clearRetainingCapacity(); try seed_transition.target_cache.appendSlice(alloc, grown_flow.items); seed_transition.semantic_rows = growth_rows_u32; seed_transition.semantic_progress_rows = growth_rows_u32; seed_transition.selection = seed_prepared.selection; seed_transition.source_endpoint_visual_offset = seed_target_offset; seed_transition.total_visual_rows = seed_total_visual_rows;
try appendGridRows( alloc, runtime.shadow_vt.?, 1, seed_transition.scroll_plan.terminal_scroll_rows, &history, &row_text, ); const seed_plan = testPaintPlanForFrame( seed_release.layout, seed_prepared.selection, seed_prepared.cursor.cursor_row, seed_prepared.cursor.cursor_col, ); var seed_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = &seed_prepared, }; const seed_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = seed_plan, .scroll_plan = seed_transition.scroll_plan, .document_append = seed_transition.document_append, .body_painter = .{ .ctx = &seed_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, seed_result.shadow_state, ); try std.testing.expectEqual( seed_transition.scroll_plan.terminal_scroll_rows, seed_result.terminal_scroll_rows_committed, ); try std.testing.expect(!seed_result.document_append_committed); runtime.ackPreservedRowReleaseAssumeValid( seed_transition.scroll_plan, seed_result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &seed_transition, seed_result); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expectEqual( seed_transition.visual_offset, runtime.transcriptCommitDiagnostic().visual_offset, ); try std.testing.expectEqual( growth_rows_u32 - seed_transition.scroll_plan.requested_inline_advance_rows, runtime.transcriptCommitDiagnostic().remaining_inline_rows, );
var attempt_count: usize = 0; while (runtime.transcriptCommitDiagnostic().state == .recovering) : (attempt_count += 1) { var source = try testFoldedSource( alloc, grown_flow.items, runtime.layout.cols, 1, ); defer source.deinit(alloc); source.preview.natural_visual_rows = @intCast(@as(u32, viewport_rows) + growth_rows_u32); var prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (prepared) |*paint| paint.deinit(alloc); const frame = try solveTestTranscriptFixedPointFrame( &runtime, alloc, &metrics, &source, 8, &prepared, ); const paint = &prepared.?; try std.testing.expectEqual( frame.layout.owned_top, frame.scroll_plan.post_scroll_owned_top, ); try std.testing.expectEqual( viewport_rows, frame.scroll_plan.acceptedInlineRows( frame.scroll_plan.terminal_scroll_rows, ), ); try appendGridRows( alloc, runtime.shadow_vt.?, 1, frame.scroll_plan.terminal_scroll_rows, &history, &row_text, );
var plan = testPaintPlanForFrame( frame.layout, paint.selection, paint.cursor.cursor_row, paint.cursor.cursor_col, ); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, paint, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(frame.layout), &plan, frame.scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty()); try std.testing.expectEqual( @as(?usize, null), transition.materialized.flow_len, ); try std.testing.expectEqual( viewport_rows, transition.materialized.visual_rows, );
var painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = paint, }; const result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = plan, .scroll_plan = frame.scroll_plan, .document_append = transition.document_append, .body_painter = .{ .ctx = &painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, result.shadow_state, ); try std.testing.expectEqual( frame.scroll_plan.terminal_scroll_rows, result.terminal_scroll_rows_committed, ); runtime.ackPreservedRowReleaseAssumeValid( frame.scroll_plan, result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &transition, result); } try std.testing.expectEqual(@as(usize, 1), attempt_count);
const stable = runtime.stableTranscriptProjectionForFlow(grown_flow.items) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(growth_rows_u32, stable.visual_offset); try std.testing.expectEqual(@as(u16, 4), stable.cursor_row); try std.testing.expectEqual(@as(u16, 7), stable.cursor_col); try std.testing.expectEqual(runtime.shadow_vt.?.cursor_row, stable.cursor_row); try std.testing.expectEqual(runtime.shadow_vt.?.cursor_col, stable.cursor_col);
const followup_rows: usize = 5; const followup_append = "\ng00008\ng00009\ng00010\ng00011\ng00012"; var followup_flow: std.ArrayList(u8) = .empty; defer followup_flow.deinit(alloc); try followup_flow.appendSlice(alloc, grown_flow.items); try followup_flow.appendSlice(alloc, followup_append); var followup_source = try testFoldedSource( alloc, followup_flow.items, runtime.layout.cols, 1, ); defer followup_source.deinit(alloc); followup_source.preview.natural_visual_rows = @intCast(@as(usize, viewport_rows) + growth_rows + followup_rows); var followup_prepared: ?transcript_painter.PreparedTranscriptSurfacePaint = null; defer if (followup_prepared) |*paint| paint.deinit(alloc); const followup_frame = try solveTestTranscriptFixedPointFrame( &runtime, alloc, &metrics, &followup_source, 4, &followup_prepared, ); const followup_paint = &followup_prepared.?; try std.testing.expectEqual( followup_frame.layout.owned_top, followup_frame.scroll_plan.post_scroll_owned_top, ); const followup_facts = runtime.planTranscriptScroll(followup_paint); try std.testing.expectEqual(@as(u32, 1), followup_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), followup_facts.planned_rows); try appendGridRows( alloc, runtime.shadow_vt.?, 1, followup_frame.scroll_plan.terminal_scroll_rows, &history, &row_text, ); var followup_plan = testPaintPlanForFrame( followup_frame.layout, followup_paint.selection, followup_paint.cursor.cursor_row, followup_paint.cursor.cursor_col, ); var followup_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &followup_source, followup_paint, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(followup_frame.layout), &followup_plan, followup_frame.scroll_plan, ); defer followup_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, followup_append, followup_transition.document_append.bytes, ); try std.testing.expectEqual( followup_flow.items.len, followup_transition.materialized.flow_len.?, ); try std.testing.expectEqual(@as(u16, 4), followup_transition.document_append.start_row); try std.testing.expectEqual(@as(u16, 7), followup_transition.document_append.start_col);
var followup_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = followup_paint, }; const followup_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = followup_plan, .scroll_plan = followup_frame.scroll_plan, .document_append = followup_transition.document_append, .body_painter = .{ .ctx = &followup_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, followup_result.shadow_state, ); try std.testing.expect(followup_result.document_append_committed); try std.testing.expectEqual( @as(u16, 1), followup_result.terminal_scroll_rows_committed, );
runtime.ackPreservedRowReleaseAssumeValid( followup_frame.scroll_plan, followup_result.terminal_scroll_rows_committed, ); runtime.consumeTranscriptTransition(alloc, &followup_transition, followup_result); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
try appendGridRows( alloc, runtime.shadow_vt.?, followup_frame.layout.transcript_area.top, followup_frame.layout.transcript_area.height(), &history, &row_text, ); const expected_history = "shell0\n" ++ "shell1\n" ++ "shell2\n" ++ "shell3\n" ++ "│ fold0\n" ++ "│ fold1\n" ++ "│ fold2\n" ++ "│ fold3\n" ++ "g00000\n" ++ "g00001\n" ++ "g00002\n" ++ "g00003\n" ++ "g00004\n" ++ "g00005\n" ++ "g00006\n" ++ "g00007\n" ++ "g00008\n" ++ "g00009\n" ++ "g00010\n" ++ "g00011\n" ++ "g00012"; try std.testing.expectEqualStrings(expected_history, history.items); try std.testing.expect(std.mem.indexOf(u8, history.items, "\n\n") == null);
fold_index = 0; while (fold_index < viewport_rows) : (fold_index += 1) { var expected_buf: [16]u8 = undefined; const expected = try std.fmt.bufPrint( &expected_buf, "│ fold{d}", .{fold_index}, ); try std.testing.expectEqual( @as(usize, 1), countExactHistoryLine(history.items, expected), ); } growth_index = 0; while (growth_index < growth_rows + followup_rows) : (growth_index += 1) { var expected_buf: [16]u8 = undefined; const expected = try std.fmt.bufPrint( &expected_buf, "g{d:0>5}", .{growth_index}, ); try std.testing.expectEqual( @as(usize, 1), countExactHistoryLine(history.items, expected), ); }}
test "staged soft-wrapped presentation resumes across committed projections" { const alloc = std.testing.allocator; const cols: u16 = 8; const stable_flow = "base\n"; const filler_row_count: usize = @as(usize, std.math.maxInt(u16)) - 3; const link_url = "https://staged.example"; const link_params = "id=fx-42"; const presentation_open = "\x1b[1;31m\x1b[9m" ++ "\x1b]8;" ++ link_params ++ ";" ++ link_url ++ "\x1b\\"; const presentation_close = "\x1b]8;;\x1b\\\x1b[29m\x1b[0m"; const resume_bytes = "\x1b[0m\x1b[1m\x1b[9m\x1b[31m" ++ "\x1b]8;" ++ link_params ++ ";" ++ link_url ++ "\x1b\\"; const steady_bytes = "\x1b]8;;\x1b\\\x1b[0m\r"; const linked_row_symbols = "0123456789A";
var linked_text = try alloc.alloc(u8, linked_row_symbols.len * cols); defer alloc.free(linked_text); for (linked_row_symbols, 0..) |symbol, row| { @memset(linked_text[row * cols .. (row + 1) * cols], symbol); }
var grown_flow: std.ArrayList(u8) = .empty; defer grown_flow.deinit(alloc); try grown_flow.ensureTotalCapacity( alloc, stable_flow.len + filler_row_count * "x\n".len + presentation_open.len + linked_text.len + presentation_close.len, ); grown_flow.appendSliceAssumeCapacity(stable_flow); for (0..filler_row_count) |_| { grown_flow.appendSliceAssumeCapacity("x\n"); } grown_flow.appendSliceAssumeCapacity(presentation_open); grown_flow.appendSliceAssumeCapacity(linked_text); grown_flow.appendSliceAssumeCapacity(presentation_close);
var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile( std.testing.io, "staged-presentation.log", .{ .read = true }, ); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = transcriptTestLayout(cols, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.shadow_vt.?.feed(stable_flow);
var stable_source = try testSource(alloc, stable_flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, stable_flow, stable_prepared.selection, 0, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 414, );
var raw_append_bytes: std.ArrayList(u8) = .empty; defer raw_append_bytes.deinit(alloc);
var first_source = try testSource(alloc, grown_flow.items, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expectEqual( @as(u16, std.math.maxInt(u16)), first_facts.planned_rows, ); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc);
const first_raw_end = first_transition.materialized.flow_len orelse return error.TestUnexpectedResult; const first_raw_append = grown_flow.items[stable_flow.len..first_raw_end]; try std.testing.expect(first_raw_end < grown_flow.items.len); try std.testing.expect(std.mem.endsWith( u8, first_transition.document_append.bytes, steady_bytes, )); try expectDocumentWireEqualsLogical( alloc, first_raw_append, first_transition.document_append.bytes[0 .. first_transition.document_append.bytes.len - steady_bytes.len], ); try raw_append_bytes.appendSlice(alloc, first_raw_append);
var first_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = &first_prepared, }; var metrics: Metrics = .{}; const first_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = first_plan, .scroll_plan = first_scroll_plan, .document_append = first_transition.document_append, .body_painter = .{ .ctx = &first_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, first_result.shadow_state, ); try std.testing.expect(runtime.shadow_vt.?.current_style.eql(.{})); try std.testing.expect(!runtime.shadow_vt.?.pending_wrap);
var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); for ("2345", 1..) |symbol, row| { row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(@intCast(row), &row_text); var expected_row: [cols]u8 = undefined; @memset(&expected_row, symbol); try std.testing.expectEqualStrings(&expected_row, row_text.items); const cell = runtime.shadow_vt.?.cellAt(@intCast(row), 1).?; try std.testing.expect(cell.style.flags.bold); try std.testing.expect(cell.style.flags.strike); try std.testing.expect(cell.style.fg.eql(.{ .indexed = 1 })); try std.testing.expect(cell.style.hyperlink_id != 0); try std.testing.expectEqualStrings( link_url, runtime.shadow_vt.?.hyperlinkUrl(cell.style.hyperlink_id).?, ); }
runtime.consumeTranscriptTransition(alloc, &first_transition, first_result); const after_first = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, after_first.state, ); try std.testing.expect(after_first.remaining_inline_rows > 0);
var retry_source = try testSource(alloc, grown_flow.items, runtime.layout.cols); defer retry_source.deinit(alloc); var retry_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &retry_source, ); defer retry_prepared.deinit(alloc); const retry_facts = runtime.planTranscriptScroll(&retry_prepared); const retry_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, retry_facts.planned_rows, ); var retry_plan = testPaintPlan(&runtime, retry_prepared.selection); var retry_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &retry_source, &retry_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(retry_plan), &retry_plan, retry_scroll_plan, ); defer retry_transition.deinit(alloc);
const retry_raw_append = grown_flow.items[first_raw_end..]; try std.testing.expect(std.mem.startsWith( u8, retry_transition.document_append.bytes, resume_bytes, )); try expectDocumentWireEqualsLogical( alloc, retry_raw_append, retry_transition.document_append.bytes[resume_bytes.len..], ); try raw_append_bytes.appendSlice(alloc, retry_raw_append); try std.testing.expectEqualStrings( grown_flow.items[stable_flow.len..], raw_append_bytes.items, );
var retry_painter = PreparedTranscriptFramePainter{ .runtime = &runtime, .alloc = alloc, .prepared = &retry_prepared, }; const retry_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = retry_plan, .scroll_plan = retry_scroll_plan, .document_append = retry_transition.document_append, .body_painter = .{ .ctx = &retry_painter, .paint = PreparedTranscriptFramePainter.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, retry_result.shadow_state, ); try std.testing.expect(runtime.shadow_vt.?.current_style.eql(.{})); try std.testing.expect(!runtime.shadow_vt.?.pending_wrap);
for ("789A", 1..) |symbol, row| { row_text.clearRetainingCapacity(); try runtime.shadow_vt.?.rowTextTrimmed(@intCast(row), &row_text); var expected_row: [cols]u8 = undefined; @memset(&expected_row, symbol); try std.testing.expectEqualStrings(&expected_row, row_text.items); const cell = runtime.shadow_vt.?.cellAt(@intCast(row), 1).?; try std.testing.expect(cell.style.flags.bold); try std.testing.expect(cell.style.flags.strike); try std.testing.expect(cell.style.fg.eql(.{ .indexed = 1 })); try std.testing.expect(cell.style.hyperlink_id != 0); try std.testing.expectEqualStrings( link_url, runtime.shadow_vt.?.hyperlinkUrl(cell.style.hyperlink_id).?, ); }
runtime.consumeTranscriptTransition(alloc, &retry_transition, retry_result); const stable = runtime.stableTranscriptProjectionForFlow(grown_flow.items) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(retry_facts.target_visual_offset, stable.visual_offset); try std.testing.expectEqual( @as(?usize, grown_flow.items.len), retry_transition.materialized.flow_len, );}
test "uncommitted stable-origin append retries from the materialized source endpoint" { const alloc = std.testing.allocator; const stable_flow = "base\n"; const grown_flow = stable_flow ++ "0\n1\n2\n3\n4"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var stable_source = try testSource(alloc, stable_flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, stable_flow, stable_prepared.selection, 0, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 413, );
var first_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); const first_facts = runtime.planTranscriptScroll(&first_prepared); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[stable_flow.len..], first_transition.document_append.bytes, );
runtime.consumeTranscriptTransition(alloc, &first_transition, .{ .bytes_written = 1, .changed_cells = 0, .full_repaint = false, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = stable_prepared.cursor.cursor_row, .committed_cursor_col = stable_prepared.cursor.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
var retry_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer retry_source.deinit(alloc); var retry_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &retry_source, ); defer retry_prepared.deinit(alloc); const retry_facts = runtime.planTranscriptScroll(&retry_prepared); const retry_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, retry_facts.planned_rows, ); var retry_plan = testPaintPlan(&runtime, retry_prepared.selection); var retry_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &retry_source, &retry_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(retry_plan), &retry_plan, retry_scroll_plan, ); defer retry_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[stable_flow.len..], retry_transition.document_append.bytes, );}
test "staged wrapped projection clips paint and flow at one renderer boundary" { const alloc = std.testing.allocator; const flow = "base\nabcdefghijklmnopqrst"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(5, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc); const projection = try transcript_painter.stagePreparedTranscriptForVisualOffset( alloc, runtime.layout, &prepared, .{ .top = 1, .bottom = 2 }, 2, ); try std.testing.expectEqual(@as(?usize, "base\n".len + 15), projection.flow_end); try std.testing.expectEqual(@as(usize, 1), prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 1), prepared.selection.partial_skip_rows); try std.testing.expectEqual(@as(u16, 3), prepared.cursor.cursor_row); try std.testing.expectEqual(@as(u16, 1), prepared.cursor.cursor_col);
var shadow = try vt_emulator.Grid.init( alloc, runtime.layout.cols, runtime.layout.rows, ); defer shadow.deinit(); var plan = testPaintPlan(&runtime, prepared.selection); plan.viewport = prepared.selection; var surface = try render_engine.frame_surface.FrameSurface.initFromShadow( alloc, plan, shadow, ); defer surface.deinit(); _ = try runtime.paintPreparedTranscriptIntoSurface( alloc, &surface, &prepared, ); var target = try surface.copyToTargetGrid(alloc); defer target.deinit(); var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); try target.rowTextTrimmed(1, &row_text); try std.testing.expectEqualStrings("fghij", row_text.items); row_text.clearRetainingCapacity(); try target.rowTextTrimmed(2, &row_text); try std.testing.expectEqualStrings("klmno", row_text.items); try std.testing.expectEqual(@as(u16, 3), target.cursor_row); try std.testing.expectEqual(@as(u16, 1), target.cursor_col);}
test "width change does not compare semantic offsets across projections" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest(&runtime, alloc, "stable", testSelection(4), 4, 3, 1, 42); runtime.layout = transcriptTestLayout(10, 8, 4);
var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = try alloc.dupe(u8, "stable"), .selection = testSelection(9), }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &([_]u16{1} ** 16));
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u16, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), facts.planned_rows);}
test "stable origin projection rebase narrow to wide survives repeated partial and restores append" { const alloc = std.testing.allocator; const flow = "abcdefghijklmnopqrstuvwxyz0123456789\n" ++ "one\n" ++ "two\n" ++ "three\n" ++ "four\n" ++ "five\n"; const grown_flow = flow ++ "six\nseven\neight\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(5, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var stable_source = try testSource(alloc, flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); const narrow_offset = preparedVisualOffsetForTest(&stable_prepared); try std.testing.expect(narrow_offset > 0); try installStableAnchorForTest( &runtime, alloc, flow, stable_prepared.selection, narrow_offset, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 420, );
runtime.layout = transcriptTestLayout(20, 8, 4); var first_source = try testSource(alloc, flow, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); const wide_offset = preparedVisualOffsetForTest(&first_prepared); try std.testing.expect(wide_offset < narrow_offset);
const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expect(first_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), first_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), first_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), first_facts.planned_rows); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc); try std.testing.expect(first_transition.recovery_rebase); try std.testing.expect(first_transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &first_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = first_transition.cursor_row, .committed_cursor_col = first_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); var recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(wide_offset, recovery.visual_offset); try std.testing.expectEqual(@as(u16, 0), recovery.remaining_inline_rows); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null);
var repeated_source = try testSource(alloc, flow, runtime.layout.cols); defer repeated_source.deinit(alloc); var repeated_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &repeated_source, ); defer repeated_prepared.deinit(alloc); const repeated_facts = runtime.planTranscriptScroll(&repeated_prepared); try std.testing.expect(repeated_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), repeated_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.planned_rows); const repeated_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, repeated_facts.planned_rows, ); var repeated_plan = testPaintPlan(&runtime, repeated_prepared.selection); var repeated_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &repeated_source, &repeated_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(repeated_plan), &repeated_plan, repeated_scroll_plan, ); defer repeated_transition.deinit(alloc); try std.testing.expect(repeated_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &repeated_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = repeated_transition.cursor_row, .committed_cursor_col = repeated_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(wide_offset, recovery.visual_offset);
var complete_source = try testSource(alloc, flow, runtime.layout.cols); defer complete_source.deinit(alloc); var complete_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &complete_source, ); defer complete_prepared.deinit(alloc); const complete_facts = runtime.planTranscriptScroll(&complete_prepared); try std.testing.expect(complete_facts.recovery_rebase); const complete_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, complete_facts.planned_rows, ); var complete_plan = testPaintPlan(&runtime, complete_prepared.selection); var complete_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &complete_source, &complete_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(complete_plan), &complete_plan, complete_scroll_plan, ); defer complete_transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &complete_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = complete_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = complete_transition.cursor_row, .committed_cursor_col = complete_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const stable = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(wide_offset, stable.visual_offset);
var append_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer append_source.deinit(alloc); var append_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &append_source, ); defer append_prepared.deinit(alloc); const append_facts = runtime.planTranscriptScroll(&append_prepared); try std.testing.expect(!append_facts.recovery_rebase); try std.testing.expect(append_facts.semantic_rows > 0); const append_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, append_facts.planned_rows, ); var append_plan = testPaintPlan(&runtime, append_prepared.selection); var append_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &append_source, &append_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(append_plan), &append_plan, append_scroll_plan, ); defer append_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[flow.len..], append_transition.document_append.bytes, );}
test "stable origin projection rebase wide to narrow retains debt until exhausted" { const alloc = std.testing.allocator; const flow = "stable\nbase\n"; const grown_flow = flow ++ "next\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try enterResizeReflowRecovery( &runtime, alloc, null, .terminal_partial_write, );
var repeated_source = try testSource(alloc, flow, runtime.layout.cols); defer repeated_source.deinit(alloc); var repeated_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &repeated_source, ); defer repeated_prepared.deinit(alloc); const repeated_facts = runtime.planTranscriptScroll(&repeated_prepared); try std.testing.expect(repeated_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 1), repeated_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), repeated_facts.planned_rows); const repeated_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, repeated_facts.planned_rows, ); var repeated_plan = testPaintPlan(&runtime, repeated_prepared.selection); var repeated_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &repeated_source, &repeated_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(repeated_plan), &repeated_plan, repeated_scroll_plan, ); defer repeated_transition.deinit(alloc); try std.testing.expect(repeated_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &repeated_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = repeated_transition.cursor_row, .committed_cursor_col = repeated_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); var recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null);
var complete_source = try testSource(alloc, flow, runtime.layout.cols); defer complete_source.deinit(alloc); var complete_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &complete_source, ); defer complete_prepared.deinit(alloc); const complete_facts = runtime.planTranscriptScroll(&complete_prepared); try std.testing.expect(complete_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 1), complete_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), complete_facts.planned_rows); const complete_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, complete_facts.planned_rows, ); var complete_plan = testPaintPlan(&runtime, complete_prepared.selection); var complete_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &complete_source, &complete_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(complete_plan), &complete_plan, complete_scroll_plan, ); defer complete_transition.deinit(alloc); try std.testing.expect(complete_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &complete_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = complete_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = complete_transition.cursor_row, .committed_cursor_col = complete_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, recovery.state, ); try std.testing.expectEqual(@as(u16, 0), recovery.remaining_inline_rows);
var append_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer append_source.deinit(alloc); var append_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &append_source, ); defer append_prepared.deinit(alloc); const append_facts = runtime.planTranscriptScroll(&append_prepared); try std.testing.expect(!append_facts.recovery_rebase); try std.testing.expect(append_facts.semantic_rows > 0); const append_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, append_facts.planned_rows, ); var append_plan = testPaintPlan(&runtime, append_prepared.selection); var append_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &append_source, &append_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(append_plan), &append_plan, append_scroll_plan, ); defer append_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[flow.len..], append_transition.document_append.bytes, );}
test "stable origin projection rebase measured history is not semantic debt" { const alloc = std.testing.allocator; const flow = "0\n1\n2\n3\n4\n5\n6\n7"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var stable_source = try testSource(alloc, flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); const stable_offset = preparedVisualOffsetForTest(&stable_prepared); try installStableAnchorForTest( &runtime, alloc, flow, stable_prepared.selection, stable_offset, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 421, );
runtime.layout = transcriptTestLayout(20, 8, 4); runtime.resize_history_row_delta = 2; var first_source = try testSource(alloc, flow, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); const measured_offset = preparedVisualOffsetForTest(&first_prepared); try std.testing.expect(measured_offset > stable_offset);
const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expect(first_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), first_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), first_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), first_facts.planned_rows); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &first_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = first_transition.cursor_row, .committed_cursor_col = first_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null);
var repeated_source = try testSource(alloc, flow, runtime.layout.cols); defer repeated_source.deinit(alloc); var repeated_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &repeated_source, ); defer repeated_prepared.deinit(alloc); const repeated_facts = runtime.planTranscriptScroll(&repeated_prepared); try std.testing.expect(repeated_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), repeated_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.planned_rows); const repeated_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, repeated_facts.planned_rows, ); var repeated_plan = testPaintPlan(&runtime, repeated_prepared.selection); var repeated_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &repeated_source, &repeated_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(repeated_plan), &repeated_plan, repeated_scroll_plan, ); defer repeated_transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &repeated_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = repeated_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = repeated_transition.cursor_row, .committed_cursor_col = repeated_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); runtime.resize_history_row_delta = null;
const projection = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(measured_offset, projection.visual_offset);}
test "overlay frame retains an exact-end measured history floor after reset" { const alloc = std.testing.allocator; const flow = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 40, 36), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc);
var history_offset: u32 = 0; for (prepared.sourceVisualRows()) |rows| history_offset += rows; var history_selection = prepared.selection; history_selection.start_line = prepared.sourceVisualRows().len; history_selection.partial_skip_rows = 0; history_selection.last_visible_row = 1;
var plan = testPaintPlan(&runtime, prepared.selection); plan.activity = .{ .overlay_entry = 1 }; const committed_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); runtime.committed_frame_layout = committed_layout; try installStableAnchorForTest( &runtime, alloc, flow, history_selection, history_offset, 1, 1, committed_layout.layout_id, );
const facts = runtime.planTranscriptScroll(&prepared); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, committed_layout, &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqual(history_offset, transition.visual_offset); try std.testing.expectEqual( prepared.sourceVisualRows().len, transition.selection.start_line, );}
test "zero measured reverse restores exact source origin" { const alloc = std.testing.allocator; const flow = "line 00 abcdefghij\n" ++ "line 01 abcdefghij\n" ++ "line 02 abcdefghij\n" ++ "line 03 abcdefghij\n" ++ "line 04 abcdefghij\n" ++ "line 05 abcdefghij\n" ++ "line 06 abcdefghij\n" ++ "line 07 abcdefghij\n" ++ "line 08 abcdefghij\n" ++ "line 09 abcdefghij\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var narrow_source = try testSource(alloc, flow, 12); defer narrow_source.deinit(alloc);
try expectZeroReverseRestoresSourceOrigin( &runtime, alloc, &wide_source, &narrow_source, 2, .seeded_exact, );}
test "zero measured reverse restores folded source origin without endpoint" { const alloc = std.testing.allocator; const flow = "head abcdefghij\n" ++ "summary\n" ++ "tail 00 abcdefghij\n" ++ "tail 01 abcdefghij\n" ++ "tail 02 abcdefghij\n" ++ "tail 03 abcdefghij\n" ++ "tail 04 abcdefghij\n" ++ "tail 05 abcdefghij\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2, }); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output alpha"); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output beta");
var wide_source = try testFoldedSource(alloc, flow, runtime.layout.cols, 2); defer wide_source.deinit(alloc); var narrow_source = try testFoldedSource(alloc, flow, 12, 2); defer narrow_source.deinit(alloc);
try expectZeroReverseRestoresSourceOrigin( &runtime, alloc, &wide_source, &narrow_source, 2, .natural_null, );}
test "zero measured reverse restores folded source origin with inexact endpoint mapping" { const alloc = std.testing.allocator; const flow = "head abcdefghij\n" ++ "summary\n" ++ "tail 00 abcdefghij\n" ++ "tail 01 abcdefghij\n" ++ "tail 02 abcdefghij\n" ++ "tail 03 abcdefghij\n" ++ "tail 04 abcdefghij\n" ++ "tail 05 abcdefghij\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2, }); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output alpha"); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output beta");
var wide_source = try testFoldedSource(alloc, flow, runtime.layout.cols, 2); defer wide_source.deinit(alloc); var narrow_source = try testFoldedSource(alloc, flow, 12, 2); defer narrow_source.deinit(alloc);
try expectZeroReverseRestoresSourceOrigin( &runtime, alloc, &wide_source, &narrow_source, 2, .seeded_inexact, );}
test "measured history origin matrix restores hard soft wide and folded sources" { const alloc = std.testing.allocator; const Case = struct { source_cols: u16, target_cols: u16, positive_delta: i32, flow: []const u8, folded: bool = false, endpoint_mode: MeasuredEndpointMode, }; const cases = [_]Case{ .{ .source_cols = 24, .target_cols = 12, .positive_delta = 2, .flow = "hard 00\nhard 01\nhard 02\nhard 03\nhard 04\nhard 05\n" ++ "hard 06\nhard 07\nhard 08\nhard 09\nhard 10\nhard 11\n", .endpoint_mode = .seeded_exact, }, .{ .source_cols = 20, .target_cols = 8, .positive_delta = 3, .flow = "soft-wrap-alpha-000\nsoft-wrap-beta-001\nsoft-wrap-gamma-002\n" ++ "soft-wrap-delta-003\nsoft-wrap-epsilon-004\nsoft-wrap-zeta-005\n" ++ "soft-wrap-eta-006\nsoft-wrap-theta-007\nsoft-wrap-iota-008\n" ++ "soft-wrap-kappa-009\n", .endpoint_mode = .seeded_exact, }, .{ .source_cols = 16, .target_cols = 8, .positive_delta = 2, .flow = "wide 界界 00\nwide 界界 01\nwide 界界 02\nwide 界界 03\n" ++ "wide 界界 04\nwide 界界 05\nwide 界界 06\nwide 界界 07\n" ++ "wide 界界 08\nwide 界界 09\nwide 界界 10\nwide 界界 11\n", .endpoint_mode = .seeded_exact, }, .{ .source_cols = 24, .target_cols = 12, .positive_delta = 2, .flow = "head abcdefghij\nsummary\ntail 00 abcdefghij\n" ++ "tail 01 abcdefghij\ntail 02 abcdefghij\ntail 03 abcdefghij\n" ++ "tail 04 abcdefghij\ntail 05 abcdefghij\n", .folded = true, .endpoint_mode = .natural_null, }, .{ .source_cols = 30, .target_cols = 10, .positive_delta = 3, .flow = "head abcdefghij\nsummary\ntail 00 abcdefghij\n" ++ "tail 01 abcdefghij\ntail 02 abcdefghij\ntail 03 abcdefghij\n" ++ "tail 04 abcdefghij\ntail 05 abcdefghij\n", .folded = true, .endpoint_mode = .seeded_inexact, }, };
for (cases) |case| { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(case.source_cols, 12, 8), .owned_top_row = 1, .full_transcript = .{ .depth = if (case.folded) .review else .inline_mode }, }; defer runtime.deinit(alloc); if (case.folded) { try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2, }); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output alpha"); try appendFoldedLineForTest(&runtime, alloc, 0, "folded output beta"); }
var wide_source = if (case.folded) try testFoldedSource(alloc, case.flow, case.source_cols, 2) else try testSource(alloc, case.flow, case.source_cols); defer wide_source.deinit(alloc); var narrow_source = if (case.folded) try testFoldedSource(alloc, case.flow, case.target_cols, 2) else try testSource(alloc, case.flow, case.target_cols); defer narrow_source.deinit(alloc);
try expectZeroReverseRestoresSourceOrigin( &runtime, alloc, &wide_source, &narrow_source, case.positive_delta, case.endpoint_mode, ); }}
test "positive measured shrink retains split source origin without exact endpoint" { const alloc = std.testing.allocator; const flow = "line 00 abcdefghij\n" ++ "line 01 abcdefghij\n" ++ "line 02 abcdefghij\n" ++ "line 03 abcdefghij\n" ++ "line 04 abcdefghij\n" ++ "line 05 abcdefghij\n" ++ "line 06 abcdefghij\n" ++ "line 07 abcdefghij\n" ++ "line 08 abcdefghij\n" ++ "line 09 abcdefghij\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var wide_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer wide_prepared.deinit(alloc); var split_selection = wide_prepared.selection; split_selection.split_active = true; split_selection.split_prefix_lines = 1; split_selection.split_suffix_start_line = split_selection.start_line; const source_origin = preparedVisualOffsetForTest(&wide_prepared); try installStableAnchorForTest( &runtime, alloc, flow, split_selection, source_origin, wide_prepared.cursor.cursor_row, wide_prepared.cursor.cursor_col, 705, );
runtime.layout = transcriptTestLayout(12, 8, 4); runtime.resize_history_row_delta = 2; var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); const origin = narrow_prepared.measured_history_origin orelse return error.TestExpectedMeasuredHistoryOrigin; try std.testing.expectEqual(@as(u16, 24), origin.source_cols); try std.testing.expectEqual(source_origin, origin.source_visual_offset); try std.testing.expect(origin.endpoint == null);}
test "zero measured history controls do not consume a nonqualifying origin" { const alloc = std.testing.allocator; const flow = "line 00 abcdefghij\n" ++ "line 01 abcdefghij\n" ++ "line 02 abcdefghij\n" ++ "line 03 abcdefghij\n" ++ "line 04 abcdefghij\n" ++ "line 05 abcdefghij\n";
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(12, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); const offset = preparedVisualOffsetForTest(&prepared); try installStableAnchorForTest( &runtime, alloc, flow, prepared.selection, offset, prepared.cursor.cursor_row, prepared.cursor.cursor_col, 706, ); runtime.resize_history_row_delta = 0; var generic_zero = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer generic_zero.deinit(alloc); try std.testing.expectEqual(offset, preparedVisualOffsetForTest(&generic_zero)); try std.testing.expect(!generic_zero.measured_history_origin_consumed); }
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(12, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); const narrow_offset = preparedVisualOffsetForTest(&narrow_prepared); try installStableAnchorWithOriginForTest( &runtime, alloc, flow, narrow_prepared.selection, narrow_offset, narrow_prepared.cursor.cursor_row, narrow_prepared.cursor.cursor_col, 707, .{ .source_cols = 24, .source_visual_offset = 1, }, );
runtime.resize_history_row_delta = 0; var same_width = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer same_width.deinit(alloc); try std.testing.expectEqual( narrow_offset, preparedVisualOffsetForTest(&same_width), ); try std.testing.expect(!same_width.measured_history_origin_consumed);
runtime.layout = transcriptTestLayout(18, 10, 6); var middle_source = try testSource(alloc, flow, runtime.layout.cols); defer middle_source.deinit(alloc); var non_source_width = try prepareTestSourceForCurrentArea( &runtime, alloc, &middle_source, ); defer non_source_width.deinit(alloc); try std.testing.expect(!non_source_width.measured_history_origin_consumed); }}
test "negative measured rewind consumes the retained exact origin" { const alloc = std.testing.allocator; const flow = "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n" ++ "abcdefghijklmnopqrst\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var wide_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer wide_prepared.deinit(alloc); try setPreparedVisualOffsetForTest(&wide_prepared, 10); try installStableAnchorForTest( &runtime, alloc, flow, wide_prepared.selection, 10, wide_prepared.cursor.cursor_row, wide_prepared.cursor.cursor_col, 708, );
runtime.layout = transcriptTestLayout(12, 8, 4); runtime.resize_history_row_delta = 2; var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); const origin = narrow_prepared.measured_history_origin orelse return error.TestExpectedMeasuredHistoryOrigin; narrow_prepared.measured_history_origin = .{ .source_cols = origin.source_cols, .source_visual_offset = origin.source_visual_offset, .endpoint = .{ .span_start_flow_offset = 210, .flow_offset = 231, .hard_row_cols = 24, }, }; try std.testing.expectEqual(@as(u32, 22), preparedVisualOffsetForTest(&narrow_prepared)); try commitPreparedForTest(&runtime, alloc, &narrow_source, &narrow_prepared);
runtime.layout = transcriptTestLayout(18, 10, 6); runtime.resize_history_row_delta = -1; var rewind_source = try testSource(alloc, flow, runtime.layout.cols); defer rewind_source.deinit(alloc); var rewound = try prepareTestSourceForCurrentArea( &runtime, alloc, &rewind_source, ); defer rewound.deinit(alloc); try std.testing.expectEqual(@as(u32, 21), preparedVisualOffsetForTest(&rewound)); try std.testing.expect(rewound.measured_history_origin_consumed); try commitPreparedForTest(&runtime, alloc, &rewind_source, &rewound); const stable = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestExpectedStableTranscript; try std.testing.expect(stable.measured_history_origin == null);}
test "incompatible transcript replacement clears the retained origin" { const alloc = std.testing.allocator; const flow = "stable 0\nstable 1\nstable 2\nstable 3\nstable 4\nstable 5\n"; const replacement = "replacement 0\nreplacement 1\nreplacement 2\nreplacement 3\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(12, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); var stable_source = try testSource(alloc, flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try installStableAnchorWithOriginForTest( &runtime, alloc, flow, stable_prepared.selection, preparedVisualOffsetForTest(&stable_prepared), stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 709, .{ .source_cols = 24, .source_visual_offset = 2, }, );
var replacement_source = try testSource( alloc, replacement, runtime.layout.cols, ); defer replacement_source.deinit(alloc); var replacement_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &replacement_source, ); defer replacement_prepared.deinit(alloc); try commitPreparedForTest( &runtime, alloc, &replacement_source, &replacement_prepared, ); const stable = runtime.stableTranscriptProjectionForFlow(replacement) orelse return error.TestExpectedStableTranscript; try std.testing.expect(stable.measured_history_origin == null);}
test "zero measured reverse restores source origin from recovery receipt" { const alloc = std.testing.allocator; const flow = "line 00 abcdefghij\n" ++ "line 01 abcdefghij\n" ++ "line 02 abcdefghij\n" ++ "line 03 abcdefghij\n" ++ "line 04 abcdefghij\n" ++ "line 05 abcdefghij\n" ++ "line 06 abcdefghij\n" ++ "line 07 abcdefghij\n" ++ "line 08 abcdefghij\n" ++ "line 09 abcdefghij\n" ++ "line 10 abcdefghij\n" ++ "line 11 abcdefghij\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var wide_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer wide_prepared.deinit(alloc); const natural_origin = preparedVisualOffsetForTest(&wide_prepared); const source_origin = natural_origin + 2; try setPreparedVisualOffsetForTest(&wide_prepared, source_origin); try installStableAnchorForTest( &runtime, alloc, flow, wide_prepared.selection, source_origin, wide_prepared.cursor.cursor_row, wide_prepared.cursor.cursor_col, 710, );
runtime.layout = transcriptTestLayout(12, 8, 4); runtime.resize_history_row_delta = 2; var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); try commitPreparedPartiallyForTest( &runtime, alloc, &narrow_source, &narrow_prepared, ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null); const recovering_origin = runtime.measuredHistoryOriginForFlow(flow) orelse return error.TestExpectedMeasuredHistoryOrigin; try std.testing.expectEqual( source_origin, recovering_origin.origin.source_visual_offset, );
runtime.layout = transcriptTestLayout(24, 12, 8); runtime.resize_history_row_delta = 0; var restored = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer restored.deinit(alloc); try std.testing.expectEqual( source_origin, preparedVisualOffsetForTest(&restored), ); try commitPreparedForTest(&runtime, alloc, &wide_source, &restored); const recovered = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestExpectedStableTranscript; try std.testing.expectEqual(source_origin, recovered.visual_offset); try std.testing.expect(recovered.measured_history_origin == null); runtime.resize_history_row_delta = null; try expectRendererAppendRestored( &runtime, alloc, flow, flow ++ "recovered append 0\nrecovered append 1\nrecovered append 2\n" ++ "recovered append 3\nrecovered append 4\nrecovered append 5\n", );}
test "zero measured reverse restores source origin after compatible paint" { const alloc = std.testing.allocator; const flow = "line 00 abcdefghij\n" ++ "line 01 abcdefghij\n" ++ "line 02 abcdefghij\n" ++ "line 03 abcdefghij\n" ++ "line 04 abcdefghij\n" ++ "line 05 abcdefghij\n" ++ "line 06 abcdefghij\n" ++ "line 07 abcdefghij\n" ++ "line 08 abcdefghij\n" ++ "line 09 abcdefghij\n" ++ "line 10 abcdefghij\n" ++ "line 11 abcdefghij\n"; const grown_flow = flow ++ "compatible append\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var wide_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer wide_prepared.deinit(alloc); const source_origin = preparedVisualOffsetForTest(&wide_prepared) + 2; try setPreparedVisualOffsetForTest(&wide_prepared, source_origin); try installStableAnchorForTest( &runtime, alloc, flow, wide_prepared.selection, source_origin, wide_prepared.cursor.cursor_row, wide_prepared.cursor.cursor_col, 720, );
runtime.layout = transcriptTestLayout(12, 8, 4); runtime.resize_history_row_delta = 2; var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); try commitPreparedForTest( &runtime, alloc, &narrow_source, &narrow_prepared, );
runtime.resize_history_row_delta = null; var grown_narrow_source = try testSource( alloc, grown_flow, runtime.layout.cols, ); defer grown_narrow_source.deinit(alloc); var grown_narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &grown_narrow_source, ); defer grown_narrow_prepared.deinit(alloc); try commitPreparedForTest( &runtime, alloc, &grown_narrow_source, &grown_narrow_prepared, ); const compatible = runtime.stableTranscriptProjectionForFlow(grown_flow) orelse return error.TestExpectedStableTranscript; const compatible_origin = compatible.measured_history_origin orelse return error.TestExpectedMeasuredHistoryOrigin; try std.testing.expectEqual( source_origin, compatible_origin.source_visual_offset, );
runtime.layout = transcriptTestLayout(24, 12, 8); runtime.resize_history_row_delta = 0; var grown_wide_source = try testSource( alloc, grown_flow, runtime.layout.cols, ); defer grown_wide_source.deinit(alloc); var restored = try prepareTestSourceForCurrentArea( &runtime, alloc, &grown_wide_source, ); defer restored.deinit(alloc); try std.testing.expectEqual( source_origin, preparedVisualOffsetForTest(&restored), ); try commitPreparedForTest( &runtime, alloc, &grown_wide_source, &restored, ); const restored_projection = runtime.stableTranscriptProjectionForFlow( grown_flow, ) orelse return error.TestExpectedStableTranscript; try std.testing.expectEqual(source_origin, restored_projection.visual_offset); try std.testing.expect(restored_projection.measured_history_origin == null); runtime.resize_history_row_delta = null; try expectRendererAppendRestored( &runtime, alloc, grown_flow, grown_flow ++ "post-restore append 0\npost-restore append 1\n" ++ "post-restore append 2\npost-restore append 3\n" ++ "post-restore append 4\npost-restore append 5\n", );}
test "unrepresentable zero reverse rebases to natural source projection" { const alloc = std.testing.allocator; const flow = "line 00\n" ++ "line 01\n" ++ "line 02\n" ++ "line 03\n" ++ "line 04\n" ++ "line 05\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(12, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); var narrow_source = try testSource(alloc, flow, runtime.layout.cols); defer narrow_source.deinit(alloc); var narrow_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &narrow_source, ); defer narrow_prepared.deinit(alloc); try installStableAnchorWithOriginForTest( &runtime, alloc, flow, narrow_prepared.selection, preparedVisualOffsetForTest(&narrow_prepared), narrow_prepared.cursor.cursor_row, narrow_prepared.cursor.cursor_col, 730, .{ .source_cols = 24, .source_visual_offset = 99, }, );
runtime.layout = transcriptTestLayout(24, 12, 8); runtime.resize_history_row_delta = null; var wide_source = try testSource(alloc, flow, runtime.layout.cols); defer wide_source.deinit(alloc); var natural = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer natural.deinit(alloc); const natural_offset = preparedVisualOffsetForTest(&natural);
runtime.resize_history_row_delta = 0; var rebased = try prepareTestSourceForCurrentArea( &runtime, alloc, &wide_source, ); defer rebased.deinit(alloc); try std.testing.expectEqual( natural_offset, preparedVisualOffsetForTest(&rebased), ); try std.testing.expect(rebased.measured_history_origin_consumed);}
test "measured resize history excludes synthetic reflow fallback" { const alloc = std.testing.allocator; const flow = "stable 00\nstable 01\nstable 02\nstable 03\nstable 04\n" ++ "stable 05\nstable 06\nstable 07\nstable 08\nstable 09\n" ++ "stable 10\nstable 11\nstable 12\nstable 13\nstable 14\n" ++ "stable 15\nstable 16\nstable 17\nstable 18\nstable 19\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, flow, testSelectionInArea(0, 1, 4), 0, 4, 1, 46, );
const shadow = runtime.shadow_vt.?; shadow.cells[19].codepoint = 'x'; shadow.cursor_row = 8; shadow.cursor_col = 1; runtime.viewport_clear_pending = true; runtime.layout = transcriptTestLayout(10, 8, 2);
runtime.resize_history_row_delta = 2; var measured_source = try testSource(alloc, flow, runtime.layout.cols); defer measured_source.deinit(alloc); var measured_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &measured_source, ); defer measured_prepared.deinit(alloc); const measured = runtime.planTranscriptScroll(&measured_prepared); try std.testing.expect(measured.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), measured.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), measured.semantic_rows); try std.testing.expectEqual(@as(u16, 0), measured.planned_rows); if (measured_prepared.measured_history_origin == null) { return error.TestExpectedMeasuredHistoryOrigin; } const prepared_endpoint = measured_prepared.measured_history_origin.?.endpoint;
runtime.resize_history_row_delta = 0; var zero_source = try testSource(alloc, flow, runtime.layout.cols); defer zero_source.deinit(alloc); var zero_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &zero_source, ); defer zero_prepared.deinit(alloc); const zero = runtime.planTranscriptScroll(&zero_prepared); try std.testing.expect(zero.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), zero.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), zero.semantic_rows); try std.testing.expectEqual(@as(u16, 0), zero.planned_rows);
runtime.resize_history_row_delta = null; var fallback_source = try testSource(alloc, flow, runtime.layout.cols); defer fallback_source.deinit(alloc); var fallback_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &fallback_source, ); defer fallback_prepared.deinit(alloc); const fallback = runtime.planTranscriptScroll(&fallback_prepared); try std.testing.expect(fallback.recovery_rebase); try std.testing.expectEqual(@as(u16, 2), fallback.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), fallback.semantic_rows); try std.testing.expectEqual(@as(u16, 2), fallback.planned_rows);
runtime.resize_history_row_delta = 2; try commitPreparedForTest( &runtime, alloc, &measured_source, &measured_prepared, ); const committed = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestExpectedStableTranscript; try std.testing.expectEqualDeep( prepared_endpoint, committed.measured_history_origin.?.endpoint, );}
test "measured resize releases one physical boundary row" { const alloc = std.testing.allocator; const flow = "stable 00\nstable 01\nstable 02\nstable 03\nstable 04\n" ++ "stable 05\nstable 06\nstable 07\nstable 08\nstable 09\n" ++ "stable 10\nstable 11\nstable 12\nstable 13\nstable 14\n" ++ "stable 15\nstable 16\nstable 17\nstable 18\nstable 19\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, flow, testSelectionInArea(0, 1, 4), 0, 4, 1, 46, );
const shadow = runtime.shadow_vt.?; shadow.cells[19].codepoint = 'x'; shadow.cursor_row = 8; shadow.cursor_col = 1; runtime.viewport_clear_pending = true; runtime.layout = transcriptTestLayout(10, 8, 3); runtime.resize_history_row_delta = 2;
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&prepared);
try std.testing.expect(facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 1), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), facts.planned_rows);}
test "same-source semantic debt survives narrow to wide projection rebase" { const alloc = std.testing.allocator; const flow = "abcdefghijk\n" ++ "one\n" ++ "two\n" ++ "three\n" ++ "four\n" ++ "five\n"; const grown_flow = flow ++ "six\nseven\n"; const appended_flow = grown_flow ++ "eight\nnine\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(5, 10, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try enterRendererDerivedSemanticRecovery( &runtime, alloc, flow, 4, 1, null, ); const retained_semantic_rows = runtime.transcriptCommitDiagnostic().remaining_inline_rows; try std.testing.expect(retained_semantic_rows > 0);
runtime.layout = transcriptTestLayout(20, 10, 4); const first = try consumeRendererRecoveryAttempt( &runtime, alloc, flow, 0, .terminal_partial_write, ); try std.testing.expect(first.facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), first.facts.resize_reflow_rows); try std.testing.expectEqual(retained_semantic_rows, first.facts.semantic_rows); try std.testing.expectEqual(retained_semantic_rows, first.facts.planned_rows); try std.testing.expectEqual( retained_semantic_rows, runtime.transcriptCommitDiagnostic().remaining_inline_rows, ); try std.testing.expectEqual( first.facts.target_visual_offset, first.visual_offset, );
const growth = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 0, .terminal_partial_write, ); try std.testing.expect(growth.facts.recovery_rebase); try std.testing.expect(growth.facts.semantic_rows > retained_semantic_rows); const growth_rows = growth.facts.semantic_rows - retained_semantic_rows; try std.testing.expectEqual( first.visual_offset + growth_rows, growth.visual_offset, ); try std.testing.expect( runtime.stableTranscriptProjectionForFlow(grown_flow) == null, );
const repeated = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 0, .terminal_partial_write, ); try std.testing.expectEqual( growth.facts.semantic_rows, repeated.facts.semantic_rows, ); try std.testing.expectEqual(growth.visual_offset, repeated.visual_offset);
const complete = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, @intCast(repeated.facts.semantic_rows), .committed, ); try std.testing.expectEqual( repeated.facts.semantic_rows, complete.facts.semantic_rows, ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const stable = runtime.stableTranscriptProjectionForFlow(grown_flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(growth.visual_offset, stable.visual_offset); try expectRendererAppendRestored( &runtime, alloc, grown_flow, appended_flow, );}
test "same-source semantic and resize debt survive wide to narrow rebase in order" { const alloc = std.testing.allocator; const flow = "stable\nbase\n"; const grown_flow = flow ++ "growth one\ngrowth two\n"; const appended_flow = grown_flow ++ "after one\nafter two\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try enterResizeReflowRecoveryWithAcceptedRows( &runtime, alloc, null, .terminal_partial_write, 0, );
const growth = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 0, .terminal_partial_write, ); try std.testing.expectEqual(@as(u16, 2), growth.facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 2), growth.facts.semantic_rows);
runtime.layout = transcriptTestLayout(5, 8, 2); const first = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 1, .terminal_partial_write, ); try std.testing.expect(first.facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 2), first.facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 2), first.facts.semantic_rows); try std.testing.expectEqual(@as(u16, 4), first.facts.planned_rows); try std.testing.expectEqual( @as(u16, 3), runtime.transcriptCommitDiagnostic().remaining_inline_rows, );
const second = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 1, .terminal_partial_write, ); try std.testing.expectEqual(@as(u16, 1), second.facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 2), second.facts.semantic_rows); try std.testing.expectEqual( @as(u16, 2), runtime.transcriptCommitDiagnostic().remaining_inline_rows, ); try std.testing.expectEqual(first.visual_offset, second.visual_offset);
const third = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 1, .terminal_partial_write, ); try std.testing.expectEqual(@as(u16, 0), third.facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 2), third.facts.semantic_rows); try std.testing.expectEqual( @as(u16, 1), runtime.transcriptCommitDiagnostic().remaining_inline_rows, ); try std.testing.expectEqual(first.visual_offset, third.visual_offset);
const complete = try consumeRendererRecoveryAttempt( &runtime, alloc, grown_flow, 1, .committed, ); try std.testing.expectEqual(@as(u16, 0), complete.facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), complete.facts.semantic_rows); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const stable = runtime.stableTranscriptProjectionForFlow(grown_flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(first.visual_offset, stable.visual_offset); try expectRendererAppendRestored( &runtime, alloc, grown_flow, appended_flow, );}
test "same-source semantic debt survives measured history rebase" { const alloc = std.testing.allocator; const flow = "0\n1\n2\n3\n4\n5\n6\n7\n"; const grown_flow = flow ++ "8\n9\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try enterRendererDerivedSemanticRecovery( &runtime, alloc, flow, 4, 1, null, ); const retained_semantic_rows = runtime.transcriptCommitDiagnostic().remaining_inline_rows; try std.testing.expect(retained_semantic_rows > 1);
runtime.resize_history_row_delta = 2; const measured = try consumeRendererRecoveryAttempt( &runtime, alloc, flow, 0, .committed, ); try std.testing.expect(measured.facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 0), measured.facts.resize_reflow_rows); try std.testing.expectEqual( retained_semantic_rows, measured.facts.semantic_rows, ); try std.testing.expectEqual( retained_semantic_rows, runtime.transcriptCommitDiagnostic().remaining_inline_rows, );
runtime.resize_history_row_delta = null; const repeated = try consumeRendererRecoveryAttempt( &runtime, alloc, flow, 1, .terminal_partial_write, ); try std.testing.expectEqual( retained_semantic_rows, repeated.facts.semantic_rows, ); try std.testing.expectEqual( retained_semantic_rows - 1, runtime.transcriptCommitDiagnostic().remaining_inline_rows, ); try std.testing.expectEqual(measured.visual_offset, repeated.visual_offset); try std.testing.expect( runtime.stableTranscriptProjectionForFlow(flow) == null, );
const remaining = retained_semantic_rows - 1; const complete = try consumeRendererRecoveryAttempt( &runtime, alloc, flow, @intCast(remaining), .committed, ); try std.testing.expectEqual(remaining, complete.facts.semantic_rows); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const stable = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(measured.visual_offset, stable.visual_offset); try expectRendererAppendRestored(&runtime, alloc, flow, grown_flow);}
test "finalized transcript transition owns append suffix and commits one anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest(&runtime, alloc, "old\n", testSelection(0), 0, 3, 1, 43);
var source = try testSource(alloc, "old\nnew\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelection(1), .cursor = .{ .cursor_row = 4, .cursor_col = 1, .replaceable_row = 4 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &.{ 1, 1 }); const scroll_plan = render_engine.frame_scroll_plan.merge(runtime.layout.rows, 1, 0, 1); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqualStrings("new\r\n", transition.document_append.bytes); try std.testing.expectEqual(@as(u16, 3), transition.document_append.start_row); try std.testing.expectEqual(@as(u16, 1), transition.document_append.start_col);
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = false, .terminal_scroll_rows_committed = 1, .document_append_committed = true, .committed_cursor_row = 4, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual(transcript_runtime.TranscriptCommitDiagnosticState.stable, diagnostic.state); try std.testing.expectEqual(@as(?usize, 1), diagnostic.stable_start_line); try std.testing.expectEqual(@as(u32, 1), diagnostic.visual_offset); const stable = runtime.stableTranscriptProjectionForFlow("old\nnew\n").?; try std.testing.expectEqual(@as(u16, 4), stable.cursor_row); try std.testing.expectEqual(@as(u16, 1), stable.cursor_col);}
test "transcript transition staging preserves prior commit across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkTranscriptTransitionStagingAllocationFailures, .{}, );}
test "committed transcript transition installation performs no allocation" { const backing = std.testing.allocator; var failing = std.testing.FailingAllocator.init(backing, .{}); const alloc = failing.allocator(); var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest(&runtime, alloc, "old\n", testSelection(0), 0, 3, 1, 72);
var source = try testSource(alloc, "old\nnew\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelection(1), .cursor = .{ .cursor_row = 4, .cursor_col = 1, .replaceable_row = 4 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &.{ 1, 1 }); const scroll_plan = render_engine.frame_scroll_plan.merge(runtime.layout.rows, 1, 0, 1); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc);
failing.fail_index = failing.alloc_index; runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = false, .terminal_scroll_rows_committed = 1, .document_append_committed = true, .committed_cursor_row = 4, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
try std.testing.expect(!failing.has_induced_failure); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );}
test "partial transcript transition records exact recovery debt" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest(&runtime, alloc, "stable", testSelection(0), 0, 3, 1, 44);
var source = try testSource(alloc, "stable", runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelection(5), .cursor = .{ .cursor_row = 4, .cursor_col = 1, .replaceable_row = 4 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &([_]u16{1} ** 16)); const scroll_plan = render_engine.frame_scroll_plan.merge(runtime.layout.rows, 1, 0, 5); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc);
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = false, .terminal_scroll_rows_committed = 2, .document_append_committed = false, .committed_cursor_row = 3, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual(transcript_runtime.TranscriptCommitDiagnosticState.recovering, diagnostic.state); try std.testing.expectEqual(@as(u32, 2), diagnostic.visual_offset); try std.testing.expectEqual(@as(u16, 3), diagnostic.remaining_inline_rows); try std.testing.expect(runtime.stableTranscriptProjectionForFlow("stable") == null);}
test "transcript recovery debt does not double count unmaterialized inline rows" { const alloc = std.testing.allocator; const flow = "00\n01\n02\n03\n04\n05\n06\n07\n" ++ "08\n09\n10\n11\n12\n13\n14\n15"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var stable_source = try testSource(alloc, flow, runtime.layout.cols); defer stable_source.deinit(alloc); var stable_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &stable_source, ); defer stable_prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 8), stable_prepared.selection.start_line); try installStableAnchorForTest( &runtime, alloc, flow, stable_prepared.selection, 8, stable_prepared.cursor.cursor_row, stable_prepared.cursor.cursor_col, 44, );
runtime.owned_top_row = 5; var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 12), prepared.selection.start_line); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 4), facts.semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge(runtime.layout.rows, 5, 3, 4); try std.testing.expectEqual(@as(u16, 1), scroll_plan.remaining_inline_advance_rows); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc);
runtime.ackPreservedRowReleaseAssumeValid( scroll_plan, scroll_plan.terminal_scroll_rows, ); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = false, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = prepared.cursor.cursor_row, .committed_cursor_col = prepared.cursor.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual(transcript_runtime.TranscriptCommitDiagnosticState.recovering, diagnostic.state); try std.testing.expectEqual(@as(u16, 1), diagnostic.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 11), diagnostic.visual_offset);
var recovery_source = try testSource(alloc, flow, runtime.layout.cols); defer recovery_source.deinit(alloc); var recovery_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &recovery_source, ); defer recovery_prepared.deinit(alloc); const recovery_facts = runtime.planTranscriptScroll(&recovery_prepared); try std.testing.expectEqual(@as(u16, 1), recovery_facts.planned_rows); const recovery_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, recovery_facts.planned_rows, ); var recovery_plan = testPaintPlan(&runtime, recovery_prepared.selection); const recovery_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(recovery_plan); var recovery_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &recovery_source, &recovery_prepared, recovery_layout, &recovery_plan, recovery_scroll_plan, ); defer recovery_transition.deinit(alloc); try std.testing.expect(recovery_transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &recovery_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 1, .document_append_committed = false, .committed_cursor_row = recovery_transition.cursor_row, .committed_cursor_col = recovery_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); const settled = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual(transcript_runtime.TranscriptCommitDiagnosticState.stable, settled.state); try std.testing.expectEqual(@as(u16, 0), settled.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 12), settled.visual_offset);}
test "recovery area-only endpoint movement preserves semantic debt" { const alloc = std.testing.allocator; const stable_flow = "stable\n"; const attempt_flow = stable_flow ++ "attempt\n"; const attempt_rows = [_]u16{1} ** 10; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 5, }; defer runtime.deinit(alloc); try enterSemanticAppendRecovery( &runtime, alloc, stable_flow, attempt_flow, &attempt_rows, );
var source = try testSource(alloc, attempt_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelectionInArea(7, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &attempt_rows);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u16, 0), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), facts.planned_rows);}
test "recovery source growth plus area movement counts only source visual growth" { const alloc = std.testing.allocator; const stable_flow = "stable\n"; const attempt_flow = stable_flow ++ "attempt\n"; const grown_flow = attempt_flow ++ "growth one\ngrowth two\n"; const attempt_rows = [_]u16{1} ** 10; const grown_rows = [_]u16{1} ** 12; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 5, }; defer runtime.deinit(alloc); try enterSemanticAppendRecovery( &runtime, alloc, stable_flow, attempt_flow, &attempt_rows, );
var source = try testSource(alloc, grown_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = source.bytes, .owns_bytes = false, .selection = testSelectionInArea(9, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer prepared.deinit(alloc); try prepared.line_visual_rows.appendSlice(alloc, &grown_rows);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u32, 3), facts.source_visual_offset); try std.testing.expectEqual(@as(u32, 9), facts.target_visual_offset); try std.testing.expectEqual(@as(u16, 0), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 3), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 3), facts.planned_rows);}
test "recovery consumes resize reflow before semantic debt across partial results" { const alloc = std.testing.allocator; const grown_flow = "stable\nbase\n" ++ "growth one\ngrowth two\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try enterResizeReflowRecovery( &runtime, alloc, null, .terminal_partial_write, );
var source = try testSource(alloc, grown_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u16, 1), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 2), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 3), facts.planned_rows);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 2, .document_append_committed = false, .committed_cursor_row = 2, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u32, 1), recovery.visual_offset); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);
var followup_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer followup_source.deinit(alloc); var followup_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &followup_source, ); defer followup_prepared.deinit(alloc); const followup_facts = runtime.planTranscriptScroll(&followup_prepared); try std.testing.expectEqual(@as(u16, 0), followup_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), followup_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), followup_facts.planned_rows);}
test "committed resize cleanup retains fallback recovery reflow debt" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try enterResizeReflowRecovery( &runtime, alloc, null, .committed, ); const recovery_offset = runtime.transcriptCommitDiagnostic().visual_offset;
runtime.resize_history_row_delta = null; var source = try testSource(alloc, "stable\nbase\n", runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 1), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), facts.planned_rows);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, target_layout, &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 0, .changed_cells = 0, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = 2, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(recovery_offset, recovery.visual_offset); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);
var complete_source = try testSource(alloc, "stable\nbase\n", runtime.layout.cols); defer complete_source.deinit(alloc); var complete_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &complete_source, ); defer complete_prepared.deinit(alloc); const complete_facts = runtime.planTranscriptScroll(&complete_prepared); try std.testing.expect(complete_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 1), complete_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), complete_facts.semantic_rows); const complete_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, complete_facts.planned_rows, ); var complete_plan = testPaintPlan(&runtime, complete_prepared.selection); var complete_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &complete_source, &complete_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(complete_plan), &complete_plan, complete_scroll_plan, ); defer complete_transition.deinit(alloc); try std.testing.expectEqual(recovery_offset, complete_transition.visual_offset); runtime.consumeTranscriptTransition(alloc, &complete_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = complete_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = complete_transition.cursor_row, .committed_cursor_col = complete_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const stable = runtime.stableTranscriptProjectionForFlow("stable\nbase\n") orelse return error.TestUnexpectedResult; try std.testing.expectEqual(recovery_offset, stable.visual_offset);}
test "incompatible recovery source stays on rebase path after partial repaint" { const alloc = std.testing.allocator; const stable_flow = "stable\n"; const attempt_flow = stable_flow ++ "attempt\n"; const replacement_flow = "replacement\n"; const grown_replacement_flow = replacement_flow ++ "growth\n"; const attempt_rows = [_]u16{1} ** 10; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 5, }; defer runtime.deinit(alloc); try enterSemanticAppendRecovery( &runtime, alloc, stable_flow, attempt_flow, &attempt_rows, );
var replacement_source = try testSource( alloc, replacement_flow, runtime.layout.cols, ); defer replacement_source.deinit(alloc); var replacement_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = replacement_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(0, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer replacement_prepared.deinit(alloc); try replacement_prepared.line_visual_rows.appendSlice( alloc, &.{ 1, 1, 1, 1, 1 }, ); const replacement_facts = runtime.planTranscriptScroll(&replacement_prepared); try std.testing.expect(!replacement_facts.source_compatible); try std.testing.expectEqual(@as(u16, 0), replacement_facts.planned_rows);
const replacement_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, replacement_facts.planned_rows, ); var replacement_plan = testPaintPlan(&runtime, replacement_prepared.selection); var replacement_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &replacement_source, &replacement_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( replacement_plan, ), &replacement_plan, replacement_scroll_plan, ); defer replacement_transition.deinit(alloc); try std.testing.expect(replacement_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &replacement_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = 6, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, runtime.transcriptCommitDiagnostic().state, );
var grown_source = try testSource( alloc, grown_replacement_flow, runtime.layout.cols, ); defer grown_source.deinit(alloc); var grown_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = grown_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(1, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer grown_prepared.deinit(alloc); try grown_prepared.line_visual_rows.appendSlice( alloc, &.{ 1, 1, 1, 1, 1, 1 }, ); const grown_facts = runtime.planTranscriptScroll(&grown_prepared); try std.testing.expect(grown_facts.source_compatible); try std.testing.expectEqual(@as(u16, 0), grown_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), grown_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), grown_facts.planned_rows);}
test "structured replacement preserves reflow debt and drops old semantic debt" { const alloc = std.testing.allocator; const stable_flow = "stable\nbase\n"; const old_growth = "old growth\n"; const replacement = "replacement\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntry(alloc, stable_flow); try enterResizeReflowRecoveryWithAcceptedRows( &runtime, alloc, null, .terminal_partial_write, 0, ); const growth_entry_id = try runtime.appendRawTranscriptEntry( alloc, old_growth, );
var old_source = try runtime.prepareTranscriptSource(alloc, null); defer old_source.deinit(alloc); var old_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &old_source, ); defer old_prepared.deinit(alloc); const old_facts = runtime.planTranscriptScroll(&old_prepared); try std.testing.expectEqual(@as(u16, 2), old_facts.resize_reflow_rows); try std.testing.expect(old_facts.semantic_rows > 0); try std.testing.expectEqual( old_facts.resize_reflow_rows + old_facts.semantic_rows, old_facts.planned_rows, );
const old_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, old_facts.planned_rows, ); var old_plan = testPaintPlan(&runtime, old_prepared.selection); var old_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &old_source, &old_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(old_plan), &old_plan, old_scroll_plan, ); defer old_transition.deinit(alloc); try std.testing.expect(old_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &old_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = old_transition.cursor_row, .committed_cursor_col = old_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( old_facts.planned_rows, runtime.transcriptCommitDiagnostic().remaining_inline_rows, );
try std.testing.expect(try runtime.updateRawBytesEntry( alloc, growth_entry_id, replacement, )); var recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 2), recovery.remaining_inline_rows); try std.testing.expect( std.mem.find(u8, runtime.transcript.items, replacement) != null, );
var replacement_source = try runtime.prepareTranscriptSource(alloc, null); defer replacement_source.deinit(alloc); var replacement_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &replacement_source, ); defer replacement_prepared.deinit(alloc); const replacement_facts = runtime.planTranscriptScroll(&replacement_prepared); try std.testing.expect(!replacement_facts.source_compatible); try std.testing.expect(replacement_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 2), replacement_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), replacement_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 2), replacement_facts.planned_rows);
const replacement_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, replacement_facts.planned_rows, ); var replacement_plan = testPaintPlan( &runtime, replacement_prepared.selection, ); var replacement_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &replacement_source, &replacement_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( replacement_plan, ), &replacement_plan, replacement_scroll_plan, ); defer replacement_transition.deinit(alloc); try std.testing.expect(replacement_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &replacement_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 1, .document_append_committed = false, .committed_cursor_row = replacement_transition.cursor_row, .committed_cursor_col = replacement_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);
var repeated_source = try runtime.prepareTranscriptSource(alloc, null); defer repeated_source.deinit(alloc); var repeated_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &repeated_source, ); defer repeated_prepared.deinit(alloc); const repeated_facts = runtime.planTranscriptScroll(&repeated_prepared); try std.testing.expect(repeated_facts.source_compatible); try std.testing.expect(repeated_facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 1), repeated_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.semantic_rows); const repeated_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, repeated_facts.planned_rows, ); var repeated_plan = testPaintPlan(&runtime, repeated_prepared.selection); var repeated_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &repeated_source, &repeated_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( repeated_plan, ), &repeated_plan, repeated_scroll_plan, ); defer repeated_transition.deinit(alloc); try std.testing.expect(repeated_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &repeated_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = repeated_transition.cursor_row, .committed_cursor_col = repeated_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( @as(u16, 1), runtime.transcriptCommitDiagnostic().remaining_inline_rows, );
var complete_source = try runtime.prepareTranscriptSource(alloc, null); defer complete_source.deinit(alloc); var complete_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &complete_source, ); defer complete_prepared.deinit(alloc); const complete_facts = runtime.planTranscriptScroll(&complete_prepared); try std.testing.expectEqual(@as(u16, 1), complete_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), complete_facts.semantic_rows); const complete_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, complete_facts.planned_rows, ); var complete_plan = testPaintPlan(&runtime, complete_prepared.selection); var complete_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &complete_source, &complete_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( complete_plan, ), &complete_plan, complete_scroll_plan, ); defer complete_transition.deinit(alloc); try std.testing.expect(complete_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &complete_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = complete_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = complete_transition.cursor_row, .committed_cursor_col = complete_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); var stable_replacement_source = try runtime.prepareTranscriptSource( alloc, null, ); defer stable_replacement_source.deinit(alloc); try std.testing.expect( runtime.stableTranscriptProjectionForFlow( stable_replacement_source.bytes, ) != null, ); const replacement_flow = try alloc.dupe( u8, stable_replacement_source.bytes, ); defer alloc.free(replacement_flow);
const append = "after\n"; _ = try runtime.appendRawTranscriptEntry(alloc, append); var append_source = try runtime.prepareTranscriptSource(alloc, null); defer append_source.deinit(alloc); var append_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &append_source, ); defer append_prepared.deinit(alloc); const append_facts = runtime.planTranscriptScroll(&append_prepared); try std.testing.expect(!append_facts.recovery_rebase); try std.testing.expect(append_facts.semantic_rows > 0); const append_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, append_facts.planned_rows, ); var append_plan = testPaintPlan(&runtime, append_prepared.selection); var append_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &append_source, &append_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan( append_plan, ), &append_plan, append_scroll_plan, ); defer append_transition.deinit(alloc); try std.testing.expect(append_source.bytes.len == 0); try std.testing.expect(append_transition.target_flow.len > replacement_flow.len); try expectDocumentWireEqualsLogical( alloc, append_transition.target_flow[replacement_flow.len..], append_transition.document_append.bytes, );}
test "structured retention preserves recovery reflow debt" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntry(alloc, "stable\n"); _ = try runtime.appendRawTranscriptEntry(alloc, "base\n"); try enterResizeReflowRecoveryWithAcceptedRows( &runtime, alloc, null, .terminal_partial_write, 0, );
runtime.max_retained_transcript_bytes = "base\n".len; try runtime.enforceStructuredRetention(alloc, null); try std.testing.expectEqualStrings("base\n", runtime.transcript.items); const recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 2), recovery.remaining_inline_rows);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &source, ); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(!facts.source_compatible); try std.testing.expect(facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 2), facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 2), facts.planned_rows);}
test "invalid origin partial recovery rebases until complete repaint then appends" { const alloc = std.testing.allocator; const flow = "0\n1\n2\n3\n4\n5\n6\n7"; const grown_flow = flow ++ "\n8\n9"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var first_source = try testSource(alloc, flow, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &first_source, ); defer first_prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 4), first_prepared.selection.start_line);
const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expect(first_facts.recovery_rebase); try std.testing.expect(!first_facts.recovery_projection_deferred); try std.testing.expectEqual(@as(u16, 0), first_facts.planned_rows); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc); try std.testing.expect(first_transition.recovery_rebase); try std.testing.expect(first_transition.document_append.isEmpty()); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, first_plan, &first_prepared, &first_transition, "4", );
runtime.consumeTranscriptTransition(alloc, &first_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = first_transition.cursor_row, .committed_cursor_col = first_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); var recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 0), recovery.remaining_inline_rows); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null);
var repeated_source = try testSource(alloc, flow, runtime.layout.cols); defer repeated_source.deinit(alloc); var repeated_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &repeated_source, ); defer repeated_prepared.deinit(alloc); const repeated_facts = runtime.planTranscriptScroll(&repeated_prepared); try std.testing.expect(repeated_facts.source_compatible); try std.testing.expect(repeated_facts.recovery_rebase); try std.testing.expect(!repeated_facts.recovery_projection_deferred); try std.testing.expectEqual(@as(u16, 0), repeated_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), repeated_facts.planned_rows);
const repeated_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, repeated_facts.planned_rows, ); var repeated_plan = testPaintPlan(&runtime, repeated_prepared.selection); var repeated_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &repeated_source, &repeated_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(repeated_plan), &repeated_plan, repeated_scroll_plan, ); defer repeated_transition.deinit(alloc); try std.testing.expect(repeated_transition.recovery_rebase); try std.testing.expect(repeated_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &repeated_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = repeated_transition.cursor_row, .committed_cursor_col = repeated_transition.cursor_col, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u16, 0), recovery.remaining_inline_rows); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(flow) == null);
var complete_source = try testSource(alloc, flow, runtime.layout.cols); defer complete_source.deinit(alloc); var complete_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &complete_source, ); defer complete_prepared.deinit(alloc); const complete_facts = runtime.planTranscriptScroll(&complete_prepared); try std.testing.expect(complete_facts.recovery_rebase); try std.testing.expect(!complete_facts.recovery_projection_deferred); const complete_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, complete_facts.planned_rows, ); var complete_plan = testPaintPlan(&runtime, complete_prepared.selection); var complete_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &complete_source, &complete_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(complete_plan), &complete_plan, complete_scroll_plan, ); defer complete_transition.deinit(alloc); try std.testing.expect(complete_transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &complete_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = complete_transition.cursor_row, .committed_cursor_col = complete_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const settled = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, settled.state, ); try std.testing.expectEqual(@as(u16, 0), settled.remaining_inline_rows); const stable = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(@as(usize, 4), stable.selection.start_line); try std.testing.expectEqual(@as(u32, 4), stable.visual_offset);
var append_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer append_source.deinit(alloc); var append_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &append_source, ); defer append_prepared.deinit(alloc); const append_facts = runtime.planTranscriptScroll(&append_prepared); try std.testing.expect(append_facts.source_compatible); try std.testing.expectEqual(@as(u16, 2), append_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 2), append_facts.planned_rows); const append_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, append_facts.planned_rows, ); var append_plan = testPaintPlan(&runtime, append_prepared.selection); var append_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &append_source, &append_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(append_plan), &append_plan, append_scroll_plan, ); defer append_transition.deinit(alloc); try expectDocumentWireEqualsLogical( alloc, grown_flow[flow.len..], append_transition.document_append.bytes, ); try std.testing.expectEqual( stable.cursor_row, append_transition.document_append.start_row, ); try std.testing.expectEqual( stable.cursor_col, append_transition.document_append.start_col, );}
test "recovery projection paints wrapped partial blank tail from acknowledged endpoint" { const alloc = std.testing.allocator; const flow = "abcdefghijklmno\nalpha\n\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(5, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const attempt_offset = try enterRendererDerivedSemanticRecovery( &runtime, alloc, flow, 3, 1, null, ); try std.testing.expectEqual(@as(u32, 2), attempt_offset); runtime.layout = transcriptTestLayout(5, 10, 6);
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 0), prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 0), prepared.selection.partial_skip_rows);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqual(@as(u32, 2), transition.visual_offset); try std.testing.expectEqual(@as(usize, 0), transition.selection.start_line); try std.testing.expectEqual(@as(u16, 2), transition.selection.partial_skip_rows); try std.testing.expectEqual(@as(u16, 3), transition.selection.last_visible_row); try std.testing.expect(transition.selection.last_visible_row_blank); try std.testing.expectEqual(@as(u16, 4), transition.cursor_row); try std.testing.expectEqual(@as(u16, 1), transition.cursor_col); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, plan, &prepared, &transition, "klmno", );}
test "recovery projection moves cursor for zero-row trailing newline growth" { const alloc = std.testing.allocator; const attempt_flow = "a\nb\nc"; const grown_flow = attempt_flow ++ "\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const attempt_offset = try enterRendererDerivedSemanticRecovery( &runtime, alloc, attempt_flow, 2, 0, null, ); try std.testing.expectEqual(@as(u32, 1), attempt_offset); runtime.layout = transcriptTestLayout(20, 8, 3);
var source = try testSource(alloc, grown_flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); try std.testing.expectEqual(@as(u32, 0), facts.target_visual_offset); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqual(@as(u32, 1), transition.visual_offset); try std.testing.expectEqual(@as(usize, 1), transition.selection.start_line); try std.testing.expectEqual(@as(u16, 2), transition.selection.last_visible_row); try std.testing.expectEqual(@as(u16, 3), transition.cursor_row); try std.testing.expectEqual(@as(u16, 1), transition.cursor_col); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, plan, &prepared, &transition, "b", );}
test "recovery projection relocates replaceable row through production painter" { const alloc = std.testing.allocator; const flow = "a\nb\nc\nreplace"; const replaceable_start = std.mem.lastIndexOfScalar(u8, flow, '\n').? + 1; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 5), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const attempt_offset = try enterRendererDerivedSemanticRecovery( &runtime, alloc, flow, 2, 1, replaceable_start, ); try std.testing.expectEqual(@as(u32, 2), attempt_offset); runtime.layout = transcriptTestLayout(20, 8, 6);
var source = try testSourceWithReplaceableTail( alloc, flow, runtime.layout.cols, replaceable_start, ); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(u16, 4), prepared.cursor.replaceable_row);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqual(@as(u32, 2), transition.visual_offset); try std.testing.expectEqual(@as(usize, 2), transition.selection.start_line); try std.testing.expectEqual(@as(u16, 2), transition.selection.replaceable_start_row); try std.testing.expectEqual(@as(u16, 2), transition.replaceable_row); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, plan, &prepared, &transition, "c", );}
test "row-only shrink defers wrapped recovery projection and later converges" { const alloc = std.testing.allocator; const flow = "abcdefghijklmno\nalpha\n\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(5, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const attempt_offset = try enterRendererDerivedSemanticRecovery( &runtime, alloc, flow, 3, 1, null, ); try std.testing.expectEqual(@as(u32, 2), attempt_offset); runtime.layout = transcriptTestLayout(5, 10, 2);
var source = try testSource(alloc, flow, runtime.layout.cols); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 0), prepared.selection.partial_skip_rows); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expectEqual(@as(u16, 1), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), facts.planned_rows); try std.testing.expect(facts.recovery_projection_deferred); const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty()); try std.testing.expect(transition.recovery_projection_deferred); try std.testing.expectEqual(@as(u32, 3), transition.visual_offset); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, plan, &prepared, &transition, "alpha", );
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); var diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, diagnostic.state, ); try std.testing.expectEqual(@as(u16, 1), diagnostic.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 1), diagnostic.visual_offset);
runtime.layout = transcriptTestLayout(5, 10, 3); var recovery_source = try testSource(alloc, flow, runtime.layout.cols); defer recovery_source.deinit(alloc); var recovery_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &recovery_source, ); defer recovery_prepared.deinit(alloc); const recovery_facts = runtime.planTranscriptScroll(&recovery_prepared); try std.testing.expectEqual(@as(u16, 1), recovery_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), recovery_facts.planned_rows); try std.testing.expect(!recovery_facts.recovery_projection_deferred); const recovery_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, recovery_facts.planned_rows, ); var recovery_plan = testPaintPlan(&runtime, recovery_prepared.selection); var recovery_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &recovery_source, &recovery_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(recovery_plan), &recovery_plan, recovery_scroll_plan, ); defer recovery_transition.deinit(alloc); try std.testing.expect(recovery_transition.document_append.isEmpty()); try std.testing.expect(!recovery_transition.recovery_projection_deferred); try std.testing.expectEqual(@as(u32, 2), recovery_transition.visual_offset); try std.testing.expectEqual(@as(usize, 0), recovery_transition.selection.start_line); try std.testing.expectEqual(@as(u16, 2), recovery_transition.selection.partial_skip_rows); try expectFinalizedRecoveryProjectionPaintsCoherently( &runtime, alloc, recovery_plan, &recovery_prepared, &recovery_transition, "klmno", );
runtime.consumeTranscriptTransition(alloc, &recovery_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = recovery_scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = recovery_transition.cursor_row, .committed_cursor_col = recovery_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, diagnostic.state, ); try std.testing.expectEqual(@as(u16, 0), diagnostic.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 2), diagnostic.visual_offset); const projection = runtime.stableTranscriptProjectionForFlow(flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(@as(usize, 0), projection.selection.start_line); try std.testing.expectEqual(@as(u16, 2), projection.selection.partial_skip_rows); try std.testing.expectEqual(@as(u16, 3), projection.cursor_row); try std.testing.expectEqual(@as(u16, 1), projection.cursor_col);}
test "committed deferred shrink installs target geometry before recovery stabilizes" { const alloc = std.testing.allocator; const stable_flow = "0\n1\n2\n3"; const attempt_flow = stable_flow ++ "\n4\n5\n6\n7\n8\n9"; const visual_rows = [_]u16{1} ** 10;
var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile(std.testing.io, "deferred-layout.log", .{ .read = true }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = transcriptTestLayout(5, 10, 8), .owned_top_row = 5, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, stable_flow, testSelectionInArea(0, 5, 8), 0, 8, 1, 401, ); const stable_layout = runtime.committed_frame_layout;
var attempt_source = try testSource(alloc, attempt_flow, runtime.layout.cols); defer attempt_source.deinit(alloc); var attempt_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = attempt_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(6, 5, 8), .cursor = .{ .cursor_row = 8, .cursor_col = 1, .replaceable_row = 8 }, }; defer attempt_prepared.deinit(alloc); try attempt_prepared.line_visual_rows.appendSlice(alloc, &visual_rows); try makeSyntheticPreparedRenderable(&attempt_prepared, alloc);
const attempt_facts = runtime.planTranscriptScroll(&attempt_prepared); try std.testing.expectEqual(@as(u16, 6), attempt_facts.semantic_rows); const attempt_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, attempt_facts.planned_rows, ); var attempt_plan = testPaintPlan(&runtime, attempt_prepared.selection); var attempt_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &attempt_source, &attempt_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(attempt_plan), &attempt_plan, attempt_scroll_plan, ); defer attempt_transition.deinit(alloc);
runtime.ackPreservedRowReleaseAssumeValid(attempt_scroll_plan, 5); runtime.consumeTranscriptTransition(alloc, &attempt_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 5, .document_append_committed = true, .committed_cursor_row = 8, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqualDeep(stable_layout, runtime.committed_frame_layout); try std.testing.expectEqual(@as(u16, 1), runtime.owned_top_row); const partial_recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, partial_recovery.state, ); try std.testing.expectEqual(@as(u16, 5), partial_recovery.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 1), partial_recovery.visual_offset);
runtime.layout = transcriptTestLayout(5, 10, 2); var deferred_source = try testSource(alloc, attempt_flow, runtime.layout.cols); defer deferred_source.deinit(alloc); var deferred_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &deferred_source, ); defer deferred_prepared.deinit(alloc);
const deferred_facts = runtime.planTranscriptScroll(&deferred_prepared); try std.testing.expectEqual(@as(u16, 5), deferred_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), deferred_facts.planned_rows); try std.testing.expect(deferred_facts.recovery_projection_deferred); const deferred_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, deferred_facts.planned_rows, ); var deferred_plan = testPaintPlan(&runtime, deferred_prepared.selection); const target_layout = render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(deferred_plan); var deferred_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &deferred_source, &deferred_prepared, target_layout, &deferred_plan, deferred_scroll_plan, ); defer deferred_transition.deinit(alloc); try std.testing.expect(deferred_transition.document_append.isEmpty());
runtime.consumeTranscriptTransition(alloc, &deferred_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = deferred_transition.cursor_row, .committed_cursor_col = deferred_transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const recovering = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovering.state, ); try std.testing.expectEqual(@as(u16, 5), recovering.remaining_inline_rows); try std.testing.expectEqual(@as(u32, 1), recovering.visual_offset); try std.testing.expectEqualStrings(stable_flow, runtime.transcript.items); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(attempt_flow) == null);
var invalidation_probe = OwnedBandInvalidationProbe{}; var metrics: Metrics = .{}; const next_result = try render_engine.frame_builder.buildAndFlushFrame( alloc, &runtime, &metrics, .{ .plan = deferred_plan, .scroll_plan = render_engine.frame_scroll_plan.FrameScrollPlan.none( runtime.layout.rows, runtime.owned_top_row, ), .body_painter = .{ .ctx = &invalidation_probe, .paint = OwnedBandInvalidationProbe.paint, }, }, ); try std.testing.expectEqual( render_engine.terminal_diff.ShadowCommitState.committed, next_result.shadow_state, ); try std.testing.expectEqualDeep(target_layout, runtime.committed_frame_layout); try std.testing.expect(!invalidation_probe.saw_owned_band_change);}
test "recovery forward area movement stabilizes at acknowledged semantic endpoint" { const alloc = std.testing.allocator; const stable_flow = "stable\n"; const attempt_flow = stable_flow ++ "attempt\n"; const grown_flow = attempt_flow ++ "growth one\ngrowth two\n"; const attempt_rows = [_]u16{1} ** 10; const grown_rows = [_]u16{1} ** 12; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 5, }; defer runtime.deinit(alloc); try enterSemanticAppendRecovery( &runtime, alloc, stable_flow, attempt_flow, &attempt_rows, );
var first_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer first_source.deinit(alloc); var first_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = first_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(6, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer first_prepared.deinit(alloc); try first_prepared.line_visual_rows.appendSlice(alloc, &grown_rows); try makeSyntheticPreparedRenderable(&first_prepared, alloc); const first_facts = runtime.planTranscriptScroll(&first_prepared); try std.testing.expectEqual(@as(u16, 3), first_facts.semantic_rows); const first_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, first_facts.planned_rows, ); var first_plan = testPaintPlan(&runtime, first_prepared.selection); var first_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &first_source, &first_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(first_plan), &first_plan, first_scroll_plan, ); defer first_transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &first_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 1, .document_append_committed = false, .committed_cursor_row = 6, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); var recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u32, 4), recovery.visual_offset); try std.testing.expectEqual(@as(u16, 2), recovery.remaining_inline_rows);
var second_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer second_source.deinit(alloc); var second_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = second_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(8, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 6, .cursor_col = 1, .replaceable_row = 6 }, }; defer second_prepared.deinit(alloc); try second_prepared.line_visual_rows.appendSlice(alloc, &grown_rows); try makeSyntheticPreparedRenderable(&second_prepared, alloc); const second_facts = runtime.planTranscriptScroll(&second_prepared); try std.testing.expectEqual(@as(u16, 2), second_facts.semantic_rows); const second_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, second_facts.planned_rows, ); var second_plan = testPaintPlan(&runtime, second_prepared.selection); var second_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &second_source, &second_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(second_plan), &second_plan, second_scroll_plan, ); defer second_transition.deinit(alloc); runtime.consumeTranscriptTransition(alloc, &second_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = 1, .document_append_committed = false, .committed_cursor_row = 6, .committed_cursor_col = 1, .shadow_state = .terminal_partial_write, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); recovery = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.recovering, recovery.state, ); try std.testing.expectEqual(@as(u32, 5), recovery.visual_offset); try std.testing.expectEqual(@as(u16, 1), recovery.remaining_inline_rows);
var final_source = try testSource(alloc, grown_flow, runtime.layout.cols); defer final_source.deinit(alloc); var final_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = final_source.bytes, .owns_bytes = false, .selection = testSelectionInArea(7, 1, runtime.layout.content_bottom), .cursor = .{ .cursor_row = 5, .cursor_col = 1, .replaceable_row = 5 }, }; defer final_prepared.deinit(alloc); try final_prepared.line_visual_rows.appendSlice(alloc, &grown_rows); try makeSyntheticPreparedRenderable(&final_prepared, alloc); const final_facts = runtime.planTranscriptScroll(&final_prepared); try std.testing.expectEqual(@as(u16, 1), final_facts.semantic_rows); const final_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, final_facts.planned_rows, ); var final_plan = testPaintPlan(&runtime, final_prepared.selection); var final_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &final_source, &final_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(final_plan), &final_plan, final_scroll_plan, ); defer final_transition.deinit(alloc); try std.testing.expectEqual(@as(u32, 6), final_transition.visual_offset); try std.testing.expectEqual(@as(usize, 6), final_transition.selection.start_line); try std.testing.expectEqual(@as(u16, 6), final_transition.selection.last_visible_row); try std.testing.expectEqual(@as(u16, 6), final_transition.cursor_row); try std.testing.expectEqual(@as(u16, 1), final_transition.cursor_col); try std.testing.expectEqual(@as(usize, 6), final_plan.viewport.start_line); try std.testing.expectEqual(@as(u16, 6), final_plan.viewport.last_visible_row); try std.testing.expectEqual(@as(u16, 6), final_plan.cursor_target.?.row); try std.testing.expectEqual(@as(u16, 1), final_plan.cursor_target.?.col); final_prepared.selection = final_transition.selection; runtime.consumeTranscriptTransition(alloc, &final_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = final_scroll_plan.terminal_scroll_rows, .document_append_committed = !final_transition.document_append.isEmpty(), .committed_cursor_row = 6, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const settled = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, settled.state, ); try std.testing.expectEqual(@as(u32, 6), settled.visual_offset); const projection = runtime.stableTranscriptProjectionForFlow(grown_flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(@as(usize, 6), projection.selection.start_line); try std.testing.expectEqual(@as(u16, 6), projection.occupied_last_row); try std.testing.expectEqual(@as(u16, 6), projection.cursor_row); try std.testing.expectEqual(@as(u16, 1), projection.cursor_col); try std.testing.expectEqual( @as(u16, 0), runtime.planTranscriptScroll(&final_prepared).planned_rows, );}
test "recovery backward area movement stabilizes at acknowledged semantic endpoint" { const alloc = std.testing.allocator; const stable_flow = "stable\n"; const attempt_flow = stable_flow ++ "attempt\n"; const attempt_rows = [_]u16{1} ** 10; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 10, 6), .owned_top_row = 5, }; defer runtime.deinit(alloc); try enterSemanticAppendRecovery( &runtime, alloc, stable_flow, attempt_flow, &attempt_rows, );
try consumeUnacceptedSemanticRecoveryRetry( &runtime, alloc, attempt_flow, &attempt_rows, 8, ); try consumeUnacceptedSemanticRecoveryRetry( &runtime, alloc, attempt_flow, &attempt_rows, 2, );
var final_source = try testSource(alloc, attempt_flow, runtime.layout.cols); defer final_source.deinit(alloc); var final_prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = final_source.bytes, .owns_bytes = false, .selection = testSelectionInArea( 2, runtime.owned_top_row, runtime.layout.content_bottom, ), .cursor = .{ .cursor_row = 2, .cursor_col = 9, .replaceable_row = 2, }, }; defer final_prepared.deinit(alloc); try final_prepared.line_visual_rows.appendSlice(alloc, &attempt_rows); try makeSyntheticPreparedRenderable(&final_prepared, alloc); const final_facts = runtime.planTranscriptScroll(&final_prepared); try std.testing.expectEqual(@as(u16, 0), final_facts.resize_reflow_rows); try std.testing.expectEqual(@as(u16, 1), final_facts.semantic_rows); const final_scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, final_facts.planned_rows, ); var final_plan = testPaintPlan(&runtime, final_prepared.selection); var final_transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &final_source, &final_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(final_plan), &final_plan, final_scroll_plan, ); defer final_transition.deinit(alloc); try std.testing.expectEqual(@as(u32, 4), final_transition.visual_offset); try std.testing.expectEqual(@as(usize, 4), final_transition.selection.start_line); try std.testing.expectEqual(@as(u16, 6), final_transition.selection.last_visible_row); try std.testing.expectEqual(@as(u16, 6), final_transition.cursor_row); try std.testing.expectEqual(@as(u16, 1), final_transition.cursor_col); try std.testing.expectEqual(@as(usize, 4), final_plan.viewport.start_line); try std.testing.expectEqual(@as(u16, 6), final_plan.viewport.last_visible_row); try std.testing.expectEqual(@as(u16, 6), final_plan.cursor_target.?.row); try std.testing.expectEqual(@as(u16, 1), final_plan.cursor_target.?.col);
runtime.consumeTranscriptTransition(alloc, &final_transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = final_scroll_plan.terminal_scroll_rows, .document_append_committed = !final_transition.document_append.isEmpty(), .committed_cursor_row = runtime.layout.content_bottom, .committed_cursor_col = 1, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); const settled = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, settled.state, ); try std.testing.expectEqual(@as(u32, 4), settled.visual_offset); const projection = runtime.stableTranscriptProjectionForFlow(attempt_flow) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(@as(usize, 4), projection.selection.start_line); try std.testing.expectEqual(@as(u16, 6), projection.occupied_last_row); try std.testing.expectEqual(@as(u16, 6), projection.cursor_row); try std.testing.expectEqual(@as(u16, 1), projection.cursor_col);}
test "same-width backward footer candidate retains one coherent stable anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(120, 34, 30), .owned_top_row = 1, }; defer runtime.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, "stable-flow", testSelection(88), 368, 19, 120, 1, );
var prepared = transcript_painter.PreparedTranscriptSurfacePaint{ .bytes = try alloc.dupe(u8, "stable-flow"), .selection = testSelection(85), .cursor = .{ .cursor_row = 30, .cursor_col = 120, .replaceable_row = 30, }, }; defer prepared.deinit(alloc); var line_rows = [_]u16{4} ** 100; for (line_rows[0..17]) |*rows| rows.* = 5; line_rows[87] = 3; try prepared.line_visual_rows.appendSlice(alloc, &line_rows);
try std.testing.expectEqual(@as(u16, 0), runtime.planTranscriptScroll(&prepared).planned_rows); var source = TranscriptPreparationSource{ .bytes = try alloc.dupe(u8, "stable-flow"), .folded_summary_indices = &.{}, .preview = .{ .natural_visual_rows = 30 }, .tail_kind = null, .tracked_entry_id = null, .tracked_entry_start_line = null, .replaceable_last_line = false, .replaceable_start = 0, .replaceable_row = 30, .welcome_cut_line = null, .welcome_boundary = null, .cols = 120, }; defer source.deinit(alloc); const layout = render_engine.frame_layout.solve(.{ .terminal = runtime.layout, .owned_top = 1, .footer = .{ .natural_rows = 4, .min_rows = 4, .max_rows = 4 }, .transcript = source.preview, .prior = runtime.committed_frame_layout, }); var plan = layout.toPaintPlan(.{ .footer_rows = .{ .top = 31, .top_divider = 31, .banner = 31, .banner_active = false, .input_base = 32, .picker_divider = 33, .picker_start = 34, .bottom_divider = 33, .hint = 34, .total_rows = 4, }, .viewport = prepared.selection, .cursor_target = .{ .row = 32, .col = 1, .visible = true }, }); const scroll_plan = render_engine.frame_scroll_plan.FrameScrollPlan.none( runtime.layout.rows, 1, ); const scroll_facts = try runtime.prepareTranscriptScrollFactsForFrame( alloc, &source, &prepared, false, false, ); const resolved = try runtime.resolveTranscriptTransitionTargetForFrame( alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromLayout(layout), scroll_plan, scroll_facts, false, false, ); try std.testing.expectEqual(@as(usize, 85), prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 30), prepared.cursor.cursor_row); try std.testing.expectEqual(@as(usize, 88), resolved.selection().start_line); try std.testing.expectEqual(@as(u16, 19), resolved.cursorRow()); try std.testing.expect(resolved.bodyDisposition() == .retain_committed); resolved.applyToPaintPlan(&plan); var transition = try runtime.sealTranscriptTransition( alloc, &source, &prepared, &plan, resolved, ); defer transition.deinit(alloc); try std.testing.expect(transition.body_disposition == .retain_committed); try std.testing.expectEqual(@as(usize, 88), transition.selection.start_line); try std.testing.expectEqual(@as(u32, 368), transition.visual_offset); try std.testing.expectEqual(@as(u16, 19), transition.cursor_row); try std.testing.expectEqual(@as(u16, 120), transition.cursor_col); try std.testing.expectEqual(@as(u16, 30), transition.materialized.cursor_row); try std.testing.expectEqual(@as(u16, 120), transition.materialized.cursor_col); try std.testing.expectEqual(@as(usize, 88), plan.viewport.start_line); try std.testing.expectEqual(@as(u16, 19), plan.cursor_target.?.row); try std.testing.expectEqual(@as(u16, 120), plan.cursor_target.?.col);
runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 0, .changed_cells = 0, .full_repaint = false, .terminal_scroll_rows_committed = 0, .document_append_committed = false, .committed_cursor_row = 19, .committed_cursor_col = 120, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), });
const diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual(transcript_runtime.TranscriptCommitDiagnosticState.stable, diagnostic.state); try std.testing.expectEqual(@as(?usize, 88), diagnostic.stable_start_line); try std.testing.expectEqual(@as(u32, 368), diagnostic.visual_offset); const stable = runtime.stableTranscriptProjectionForFlow("stable-flow").?; try std.testing.expectEqual(@as(u16, 19), stable.cursor_row); try std.testing.expectEqual(@as(u16, 120), stable.cursor_col);}
test "attempt source projections leave transcript runtime and commit state unchanged" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 12, 8), .owned_top_row = 1, .viewport_top_row = 1, .last_rendered_cols = 17, .last_paint_bottom_reserved_rows = 3, .pending_scroll_compact = true, .replaceable_last_line = true, .replaceable_row = 7, .replaceable_start = 2, }; defer runtime.deinit(alloc); var metrics: Metrics = .{}; try runtime.writeTranscript( alloc, &metrics, "alpha\nbeta\ngamma\ndelta\nepsilon\nzeta\neta\ntheta\n", true, ); const entry_id = runtime.entries.items[0].id(); try runtime.folded_command_blocks.append(alloc, .{ .summary_entry_id = entry_id, .summary_transcript_index = 777, }); runtime.paint_trace.transcript_initialized = true; runtime.paint_trace.transcript_top = 9; runtime.paint_trace.transcript_bottom = 10; runtime.paint_trace.transcript_start_line = 42; runtime.paint_trace.transcript_total_lines = 43; runtime.paint_trace.transcript_visible_rows = 2; runtime.paint_trace.transcript_partial_skip_rows = 1; runtime.paint_trace.transcript_entries = 99; runtime.paint_trace.transcript_log_frame = true; try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(2), 2, 6, 1, 9, );
const transcript_ptr = runtime.transcript.items.ptr; const transcript_capacity = runtime.transcript.capacity; const transcript_snapshot = try alloc.dupe(u8, runtime.transcript.items); defer alloc.free(transcript_snapshot); const paint_trace_snapshot = runtime.paint_trace; const commit_snapshot = runtime.transcriptCommitDiagnostic(); const cursor_row = runtime.cursor_row; const cursor_col = runtime.cursor_col; const replaceable_last_line = runtime.replaceable_last_line; const replaceable_row = runtime.replaceable_row; const replaceable_start = runtime.replaceable_start; const last_rendered_cols = runtime.last_rendered_cols; const last_paint_bottom_reserved_rows = runtime.last_paint_bottom_reserved_rows;
var source = try runtime.prepareTranscriptSource(alloc, entry_id); defer source.deinit(alloc); var collapsed = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, &source, .{ .top = 4, .bottom = 3 }, ); collapsed.deinit(alloc); var compact = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, &source, .{ .top = 1, .bottom = 2 }, ); defer compact.deinit(alloc); var expanded = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, &source, .{ .top = 1, .bottom = 8 }, ); defer expanded.deinit(alloc); _ = runtime.planTranscriptScroll(&compact); _ = runtime.planTranscriptScroll(&expanded);
try std.testing.expectEqual(transcript_ptr, runtime.transcript.items.ptr); try std.testing.expectEqual(transcript_capacity, runtime.transcript.capacity); try std.testing.expectEqualStrings(transcript_snapshot, runtime.transcript.items); try std.testing.expectEqual(@as(usize, 777), runtime.folded_command_blocks.items[0].summary_transcript_index); try std.testing.expectEqual(last_rendered_cols, runtime.last_rendered_cols); try std.testing.expectEqual(last_paint_bottom_reserved_rows, runtime.last_paint_bottom_reserved_rows); try std.testing.expect(runtime.pending_scroll_compact); try std.testing.expectEqualDeep(paint_trace_snapshot, runtime.paint_trace); try std.testing.expectEqualDeep(commit_snapshot, runtime.transcriptCommitDiagnostic()); try std.testing.expectEqual(cursor_row, runtime.cursor_row); try std.testing.expectEqual(cursor_col, runtime.cursor_col); try std.testing.expectEqual(replaceable_last_line, runtime.replaceable_last_line); try std.testing.expectEqual(replaceable_row, runtime.replaceable_row); try std.testing.expectEqual(replaceable_start, runtime.replaceable_start);}
fn checkPrepareTranscriptSourceAllocationFailures(alloc: Allocator) !void { const welcome = "Fx welcome banner line one\n" ++ "Fx welcome banner line two\n"; const summary = "● 2 command lines folded\n"; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 10, 6), .owned_top_row = 1, .max_transcript_bytes = 1024, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified(alloc, welcome, .welcome); const summary_entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, summary, .command_output, ); try runtime.folded_command_blocks.append(alloc, .{ .summary_entry_id = summary_entry_id, }); try appendFoldedLineForTest(&runtime, alloc, 0, "command output line");
var uncapped = try runtime.prepareTranscriptSource(alloc, summary_entry_id); defer uncapped.deinit(alloc); try std.testing.expectEqual(@as(usize, 4), uncapped.folded_summary_indices[0]); try std.testing.expectEqual(@as(?usize, 3), uncapped.tracked_entry_start_line); try std.testing.expectEqual(@as(u16, 6), uncapped.preview.natural_visual_rows); try std.testing.expectEqual( transcript_blocks.LeadingWelcomeBoundary{ .full_cut_line = 3, .tail_replay_line = 1, }, uncapped.welcome_boundary.?, ); try std.testing.expectEqual(@as(?usize, 3), uncapped.welcome_cut_line);
runtime.max_transcript_bytes = summary.len; var source = try runtime.prepareTranscriptSource(alloc, summary_entry_id); defer source.deinit(alloc);
try std.testing.expect(welcome.len + summary.len > runtime.max_transcript_bytes); try std.testing.expectEqualStrings(uncapped.bytes, source.bytes); try std.testing.expect(source.bytes.len > runtime.max_transcript_bytes); try std.testing.expectEqual(@as(usize, 1), source.folded_summary_indices.len); try std.testing.expectEqual(@as(usize, 4), source.folded_summary_indices[0]); try std.testing.expectEqual(@as(?usize, 3), source.tracked_entry_start_line); try std.testing.expectEqual(@as(u16, 6), source.preview.natural_visual_rows); try std.testing.expectEqual( transcript_blocks.LeadingWelcomeBoundary{ .full_cut_line = 3, .tail_replay_line = 1, }, source.welcome_boundary.?, ); try std.testing.expectEqual(@as(?usize, 3), source.welcome_cut_line);}
test "structured transcript source frees every partial allocation" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkPrepareTranscriptSourceAllocationFailures, .{}, );}
fn checkPreviewPreparationFailureLeavesRuntimeUnchanged(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 10, 6), .owned_top_row = 1, .max_transcript_bytes = 128, .last_rendered_cols = 17, }; defer runtime.deinit(alloc); try runtime.initBacking(alloc);
const entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, "recorded source\n", .command_output, ); runtime.transcript.clearRetainingCapacity(); try runtime.transcript.appendSlice(alloc, "poisoned cache\n"); runtime.transcript_cache_origin_untrimmed = false; try runtime.folded_command_blocks.append(alloc, .{ .summary_entry_id = entry_id, .summary_transcript_index = 777, }); runtime.transcript_band_dirty = false; runtime.paint_trace.transcript_initialized = true; runtime.paint_trace.transcript_start_line = 41;
const entry_count = runtime.entries.items.len; const next_entry_id = runtime.next_entry_id; const commit_state = runtime.transcriptCommitDiagnostic(); const paint_trace = runtime.paint_trace; const pending_repaints = runtime.render_requests.pendingReasonCount();
_ = runtime.previewTranscriptFlow(alloc) catch |err| { try std.testing.expectEqualStrings("poisoned cache\n", runtime.transcript.items); try std.testing.expectEqual(entry_count, runtime.entries.items.len); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings( "recorded source\n", runtime.entries.items[0].raw_bytes.bytes, ); try std.testing.expectEqual(next_entry_id, runtime.next_entry_id); try std.testing.expectEqual( @as(usize, 777), runtime.folded_command_blocks.items[0].summary_transcript_index, ); try std.testing.expectEqualDeep(commit_state, runtime.transcriptCommitDiagnostic()); try std.testing.expectEqualDeep(paint_trace, runtime.paint_trace); try std.testing.expectEqual( pending_repaints, runtime.render_requests.pendingReasonCount(), ); try std.testing.expect(!runtime.transcript_band_dirty); return err; };}
test "preview preparation failure leaves cache entries anchors and repaint state unchanged" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkPreviewPreparationFailureLeavesRuntimeUnchanged, .{}, );}
test "tail-capped raw fallback rebases retained folded indices and invalidates removed summaries" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, .full_transcript = .{ .depth = .review }, }; defer runtime.deinit(alloc);
try runtime.transcript.appendSlice(alloc, "removed-summary\nretained-summary"); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 1, }); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2, }); try appendFoldedLineForTest(&runtime, alloc, 0, "removed-output"); try appendFoldedLineForTest(&runtime, alloc, 1, "retained-output");
runtime.max_transcript_bytes = "retained-summary".len + 1; var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc);
try std.testing.expectEqualStrings("retained-summary", source.bytes); try std.testing.expectEqualSlices( usize, &.{ 0, 1 }, source.folded_summary_indices, );
var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), prepared.total_lines); try std.testing.expectEqual(@as(usize, 1), prepared.visible_lines.items.len); try std.testing.expect( std.meta.activeTag(prepared.visible_lines.items[0]) == .folded_line, ); try std.testing.expectEqualStrings( "retained-output", resolveVisibleLineForTest( prepared.visible_lines.items[0], .{ .bytes = prepared.bytes }, ), );
runtime.max_transcript_bytes = 4; var partial = try runtime.prepareTranscriptSource(alloc, null); defer partial.deinit(alloc); try std.testing.expectEqualStrings("mary", partial.bytes); try std.testing.expectEqualSlices( usize, &.{ 0, 0 }, partial.folded_summary_indices, );
var partial_paint = try prepareTestSourceForCurrentArea( &runtime, alloc, &partial, ); defer partial_paint.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), partial_paint.total_lines); try std.testing.expect( std.meta.activeTag(partial_paint.visible_lines.items[0]) == .transcript, ); try std.testing.expectEqualStrings( "mary", resolveVisibleLineForTest( partial_paint.visible_lines.items[0], .{ .bytes = partial_paint.bytes }, ), );}
test "structured source keeps tracked entries before the cache tail" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
const removed_id = try runtime.appendRawTranscriptEntryClassified( alloc, "removed\n", .command_output, ); const retained_id = try runtime.appendRawTranscriptEntryClassified( alloc, "tracked\n", .command_output, ); runtime.max_transcript_bytes = "tracked".len + 1;
var retained = try runtime.prepareTranscriptSource(alloc, retained_id); defer retained.deinit(alloc); try std.testing.expectEqualStrings("removed\ntracked", retained.bytes); try std.testing.expectEqual(@as(?usize, 1), retained.tracked_entry_start_line);
var retained_paint = try prepareTestSourceForCurrentArea( &runtime, alloc, &retained, ); defer retained_paint.deinit(alloc); try std.testing.expectEqual(@as(?u16, 2), retained_paint.tracked_entry_row);
var removed = try runtime.prepareTranscriptSource(alloc, removed_id); defer removed.deinit(alloc); try std.testing.expectEqual(@as(?usize, 0), removed.tracked_entry_start_line);
var removed_paint = try prepareTestSourceForCurrentArea( &runtime, alloc, &removed, ); defer removed_paint.deinit(alloc); try std.testing.expectEqual(@as(?u16, 1), removed_paint.tracked_entry_row);
runtime.max_transcript_bytes = 4; var partial = try runtime.prepareTranscriptSource(alloc, retained_id); defer partial.deinit(alloc); try std.testing.expectEqualStrings("removed\ntracked", partial.bytes); try std.testing.expectEqual(@as(?usize, 1), partial.tracked_entry_start_line);
var partial_paint = try prepareTestSourceForCurrentArea( &runtime, alloc, &partial, ); defer partial_paint.deinit(alloc); try std.testing.expectEqual(@as(?u16, 2), partial_paint.tracked_entry_row);}
test "structured source keeps welcome boundary before the cache tail" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "welcome one\nwelcome two\n", .welcome, ); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "tail\n", .subagent_status, );
var uncapped = try runtime.prepareTranscriptSource(alloc, null); defer uncapped.deinit(alloc); try std.testing.expectEqual( transcript_blocks.LeadingWelcomeBoundary{ .full_cut_line = 3, .tail_replay_line = 1, }, uncapped.welcome_boundary.?, ); try std.testing.expectEqual(@as(?usize, 3), uncapped.welcome_cut_line);
runtime.max_transcript_bytes = "tail".len + 1; var capped = try runtime.prepareTranscriptSource(alloc, null); defer capped.deinit(alloc); try std.testing.expectEqualStrings("welcome one\nwelcome two\n\ntail", capped.bytes); try std.testing.expectEqual( transcript_blocks.LeadingWelcomeBoundary{ .full_cut_line = 3, .tail_replay_line = 1, }, capped.welcome_boundary.?, ); try std.testing.expectEqual(@as(?usize, 3), capped.welcome_cut_line);}
test "structured source derives replaceable span from full bytes" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 5), .owned_top_row = 1, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "prefix\n", .command_output, ); _ = try runtime.appendReplaceableTranscriptLineSilentClassified( alloc, "0123456789", .command_output, );
runtime.max_transcript_bytes = "0123456789".len + 1; var whole_tail = try runtime.prepareTranscriptSource(alloc, null); defer whole_tail.deinit(alloc); try std.testing.expectEqualStrings("prefix\n0123456789", whole_tail.bytes); try std.testing.expect(whole_tail.replaceable_last_line); try std.testing.expectEqual(@as(usize, "prefix\n".len), whole_tail.replaceable_start);
runtime.max_transcript_bytes = 4; var partial_tail = try runtime.prepareTranscriptSource(alloc, null); defer partial_tail.deinit(alloc); try std.testing.expectEqualStrings("prefix\n0123456789", partial_tail.bytes); try std.testing.expect(partial_tail.replaceable_last_line); try std.testing.expectEqual(@as(usize, "prefix\n".len), partial_tail.replaceable_start); try std.testing.expect(partial_tail.preview.replaceable_active);
var partial_paint = try prepareTestSourceForCurrentArea( &runtime, alloc, &partial_tail, ); defer partial_paint.deinit(alloc); try std.testing.expect(partial_paint.replaceable_last_line); try std.testing.expectEqual(@as(usize, "prefix\n".len), partial_paint.replaceable_start); try std.testing.expectEqual(@as(u16, 2), partial_paint.selection.replaceable_start_row);
runtime.max_transcript_bytes = 0; var empty = try runtime.prepareTranscriptSource(alloc, null); defer empty.deinit(alloc); try std.testing.expectEqualStrings("prefix\n0123456789", empty.bytes); try std.testing.expect(empty.replaceable_last_line); try std.testing.expectEqual(@as(usize, "prefix\n".len), empty.replaceable_start); try std.testing.expectEqual(@as(u16, 2), empty.preview.natural_visual_rows); try std.testing.expectEqual(@as(u16, 0), empty.preview.trailing_boundary_blank_rows); try std.testing.expectEqual(@as(u16, 0), empty.preview.footer_boundary_gap_rows); try std.testing.expectEqual( @as(?transcript_blocks.TranscriptBlockKind, .command_output), empty.preview.tail_kind, ); try std.testing.expect(empty.preview.replaceable_active);}
test "structured source preview matches full paint geometry" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(4, 8, 5), .owned_top_row = 1, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "removed-long\n", .command_output, ); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "tail\n\n", .tool_status, ); runtime.max_transcript_bytes = "tail".len + 1;
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqualStrings("removed-long\n\ntail", source.bytes); try std.testing.expectEqual(@as(u16, 5), source.preview.natural_visual_rows); try std.testing.expect(source.preview.trailing_boundary_blank_rows >= 1); try std.testing.expect(source.preview.footer_boundary_gap_rows >= 1); try std.testing.expectEqual( @as(?transcript_blocks.TranscriptBlockKind, .tool_status), source.preview.tail_kind, ); try std.testing.expect(!source.preview.replaceable_active);
var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try std.testing.expect(prepared.total_lines >= 1); try std.testing.expect(prepared.sourceVisualRows().len > 0);
const solved = render_engine.frame_layout.solve(.{ .terminal = runtime.layout, .owned_top = runtime.owned_top_row, .footer = .{ .natural_rows = 2, .min_rows = 2, .max_rows = 2 }, .transcript = source.preview, }); try std.testing.expect(!solved.transcript_area.isEmpty());}
test "hidden context notices do not change compact footer or activity tail policy" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); var metrics = Metrics{}; _ = try runtime.streamAssistantChunk(alloc, &metrics, "visible response"); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "context", .tone = .warning, .body = "hidden trailing context", .visibility = .full_only, }); runtime.last_paint_bottom_reserved_rows = 2;
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expect(std.mem.find(u8, source.bytes, "hidden trailing context") == null); try std.testing.expectEqual( @as(?transcript_blocks.TranscriptBlockKind, .assistant_turn), source.preview.tail_kind, ); try std.testing.expectEqual(@as(u16, 1), source.preview.footer_boundary_gap_rows); try std.testing.expectEqual(@as(u16, 1), runtime.transientAssistantGapRows()); try std.testing.expectEqual(@as(u16, 2), runtime.preservedBottomReservationRows());
var only_context = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .owned_top_row = 1, }; defer only_context.deinit(alloc); _ = try only_context.appendSemanticNotice(alloc, .{ .topic = "context", .tone = .warning, .body = "only hidden context", .visibility = .full_only, }); only_context.last_paint_bottom_reserved_rows = 2; var empty_source = try only_context.prepareTranscriptSource(alloc, null); defer empty_source.deinit(alloc); try std.testing.expectEqualStrings("", empty_source.bytes); try std.testing.expectEqual(@as(?transcript_blocks.TranscriptBlockKind, null), empty_source.preview.tail_kind); try std.testing.expectEqual(@as(u16, 0), empty_source.preview.footer_boundary_gap_rows); try std.testing.expectEqual(@as(u16, 0), only_context.transientAssistantGapRows()); try std.testing.expectEqual(@as(u16, 0), only_context.preservedBottomReservationRows());}
test "recorded projection ignores a poisoned cache without rebuilding it" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 12, 8), .owned_top_row = 1, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "recorded first\n", .subagent_status, ); const tracked_id = try runtime.appendRawTranscriptEntryClassified( alloc, "recorded tracked\n", .tool_status, ); runtime.transcript.clearRetainingCapacity(); try runtime.transcript.appendSlice(alloc, "poisoned cache\n"); runtime.transcript_cache_origin_untrimmed = false;
const preview = try runtime.previewTranscriptFlow(alloc); try std.testing.expectEqual(@as(u16, 3), preview.natural_visual_rows);
var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintForAreaTrackingEntry( alloc, &metrics, .{ .top = 1, .bottom = 4 }, tracked_id, ); defer prepared.deinit(alloc);
try std.testing.expect(std.mem.find(u8, prepared.bytes, "recorded first") != null); try std.testing.expect(std.mem.find(u8, prepared.bytes, "recorded tracked") != null); try std.testing.expect(std.mem.find(u8, prepared.bytes, "poisoned cache") == null); try std.testing.expectEqual(@as(?u16, 3), prepared.tracked_entry_row);
var shadow = try vt_emulator.Grid.init( alloc, runtime.layout.cols, runtime.layout.rows, ); defer shadow.deinit(); const plan = testPaintPlan(&runtime, prepared.selection); var surface = try render_engine.frame_surface.FrameSurface.initFromShadow( alloc, plan, shadow, ); defer surface.deinit(); _ = try runtime.paintPreparedTranscriptIntoSurface( alloc, &surface, &prepared, ); var target = try surface.copyToTargetGrid(alloc); defer target.deinit(); var row_text: std.ArrayList(u8) = .empty; defer row_text.deinit(alloc); try target.rowTextTrimmed(1, &row_text); try std.testing.expectEqualStrings("recorded first", row_text.items); row_text.clearRetainingCapacity(); try target.rowTextTrimmed(3, &row_text); try std.testing.expectEqualStrings("recorded tracked", row_text.items);
try std.testing.expectEqualStrings("poisoned cache\n", runtime.transcript.items);}
test "cache-only paint excludes record false transient bytes" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.transcript.appendSlice(alloc, "cache only\n");
var metrics: Metrics = .{}; try runtime.writeTranscript(alloc, &metrics, "transient only\n", false); try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len); try std.testing.expectEqualStrings("cache only\n", runtime.transcript.items);
const preview = try runtime.previewTranscriptFlow(alloc); try std.testing.expectEqual(@as(u16, 1), preview.natural_visual_rows); var prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = 1, .bottom = 3 }, ); defer prepared.deinit(alloc); try std.testing.expectEqualStrings("cache only\n", prepared.bytes);}
test "zero-column preparation uses cache fallback even when entries exist" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "recorded source\n", .subagent_status, ); runtime.transcript.clearRetainingCapacity(); try runtime.transcript.appendSlice(alloc, "bootstrap cache\n"); runtime.layout.cols = 0;
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqualStrings("bootstrap cache\n", source.bytes);}
test "reconstructive paint repairs a poisoned cache from entries" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "recorded reconstruction\n", .subagent_status, ); runtime.transcript.clearRetainingCapacity(); try runtime.transcript.appendSlice(alloc, "poisoned cache\n");
var metrics: Metrics = .{}; try runtime.reconstructivePaint(alloc, &metrics);
try std.testing.expect( std.mem.find(u8, runtime.transcript.items, "recorded reconstruction") != null, ); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "poisoned cache") == null); try std.testing.expect(runtime.viewport_clear_pending); try std.testing.expect(runtime.render_requests.hasReason(.transcript));}
test "append-only source remains compatible while tail replacement invalidates anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
var metrics: Metrics = .{}; try runtime.writeTranscript(alloc, &metrics, "stable", true); try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 1, 7, 19, );
try runtime.writeTranscript(alloc, &metrics, " append", true); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expect(runtime.stableTranscriptProjectionForFlow(runtime.transcript.items) != null);
const tail_id = runtime.entries.items[runtime.entries.items.len - 1].id(); try std.testing.expect(try runtime.updateRawBytesEntry( alloc, tail_id, " append extended", )); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.invalid, runtime.transcriptCommitDiagnostic().state, );}
test "prepared wrapped line delta creates visual-row inline scroll rows" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 8, .cols = 10, .content_bottom = 4, .divider_top_row = 5, .input_row = 6, .divider_bottom_row = 7, .hint_row = 8, }, .viewport_top_row = 1, .owned_top_row = 1, .cursor_row = 4, .cursor_col = 1, .has_painted_transcript = true, .has_committed_frame = true, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, "abcdefghijklmnopqrstuvwxyz\nshort\nend", testSelection(0), 0, 4, 1, 11, );
var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = 1, .bottom = 2 }, ); defer prepared.deinit(alloc);
try std.testing.expectEqual(@as(usize, 1), prepared.selection.start_line); try std.testing.expectEqual(@as(u16, 3), prepared.sourceVisualRows()[0]);
const planned = runtime.planTranscriptScroll(&prepared).planned_rows;
try std.testing.expectEqual(@as(u16, 3), planned);}
test "prepareTranscriptSurfacePaintForArea keeps rows inside solved transcript rect" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .viewport_top_row = 1, .owned_top_row = 1, .cursor_row = 8, .cursor_col = 1, .has_painted_transcript = true, .last_paint_bottom_reserved_rows = 3, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try runtime.transcript.appendSlice(alloc, "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\n");
var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = 3, .bottom = 5 }, ); defer prepared.deinit(alloc);
try std.testing.expect(prepared.selection.top_row >= 3); try std.testing.expect(prepared.selection.bottom_row <= 5); try std.testing.expect(prepared.selection.last_visible_row <= 5); try std.testing.expectEqual(@as(u16, 0), prepared.bottom_reserved_rows); try std.testing.expectEqual(@as(u16, 3), runtime.last_paint_bottom_reserved_rows);}
test "prepared transcript tracks an entry row without rerendering the selection" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .viewport_top_row = 1, .owned_top_row = 1, .cursor_row = 8, .cursor_col = 1, .has_painted_transcript = true, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "first\n\n", .unknown_raw); const tracked_id = try runtime.appendRawTranscriptEntryClassified( alloc, "● Running command\x1b[0m\n", .tool_status, );
var metrics: Metrics = .{}; var visible = try runtime.prepareTranscriptSurfacePaintForAreaTrackingEntry( alloc, &metrics, .{ .top = 1, .bottom = 4 }, tracked_id, ); defer visible.deinit(alloc); try std.testing.expectEqual(@as(?u32, tracked_id), visible.tracked_entry_id); try std.testing.expectEqual(@as(?u16, 3), visible.tracked_entry_row);
var i: usize = 0; while (i < 6) : (i += 1) { _ = try runtime.appendRawTranscriptEntryClassified(alloc, "later\n", .unknown_raw); }
var clipped = try runtime.prepareTranscriptSurfacePaintForAreaTrackingEntry( alloc, &metrics, .{ .top = 1, .bottom = 2 }, tracked_id, ); defer clipped.deinit(alloc); try std.testing.expectEqual(@as(?u32, tracked_id), clipped.tracked_entry_id); try std.testing.expectEqual(@as(?u16, null), clipped.tracked_entry_row);}
test "prepared transcript source can omit one active entry without changing durable entries" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "before\n", .subagent_status); const active_id = try runtime.appendRawTranscriptEntryClassified(alloc, "running\n", .tool_status); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "after\n", .subagent_status);
var active = try runtime.prepareTranscriptSourceOmittingEntry(alloc, active_id); defer active.deinit(alloc); try std.testing.expect(std.mem.find(u8, active.bytes, "running") == null); try std.testing.expect(std.mem.find(u8, active.bytes, "before") != null); try std.testing.expect(std.mem.find(u8, active.bytes, "after") != null); try std.testing.expect(!active.cache_origin_untrimmed);
var terminal = try runtime.prepareTranscriptSource(alloc, null); defer terminal.deinit(alloc); try std.testing.expect(std.mem.find(u8, terminal.bytes, "running") != null); try std.testing.expect(terminal.cache_origin_untrimmed);}
test "prepareTranscriptSurfacePaintForArea does not update committed inline scroll baseline" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = .{ .rows = 12, .cols = 40, .content_bottom = 8, .divider_top_row = 9, .input_row = 10, .divider_bottom_row = 11, .hint_row = 12, }, .viewport_top_row = 4, .owned_top_row = 4, .cursor_row = 8, .cursor_col = 1, .has_painted_transcript = true, .has_committed_frame = true, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, "line 1\nline 2\nline 3\nline 4\nline 5\nline 6\n", testSelection(1), 1, 8, 1, 12, ); const commit_before = runtime.transcriptCommitDiagnostic();
var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = 1, .bottom = 3 }, ); defer prepared.deinit(alloc);
try std.testing.expectEqualDeep(commit_before, runtime.transcriptCommitDiagnostic()); try std.testing.expectEqual(@as(u16, 4), runtime.owned_top_row); try std.testing.expectEqual(@as(u16, 4), runtime.viewport_top_row);}
test "full transcript paint replaces the fold summary with captured lines" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), }; defer runtime.deinit(alloc);
try runtime.transcript.appendSlice(alloc, "a\nsummary\nb\n"); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2 }); try runtime.folded_command_blocks.items[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "hidden-1") }); try runtime.folded_command_blocks.items[0].lines.append(alloc, .{ .stream = .stderr, .text = try alloc.dupe(u8, "hidden-2") }); runtime.full_transcript.depth = .review;
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, &source, .{ .top = 1, .bottom = 8 }, ); defer prepared.deinit(alloc);
const source_buf = TranscriptBuffer{ .bytes = source.bytes }; try std.testing.expectEqual(@as(usize, 4), prepared.visible_lines.items.len); try std.testing.expectEqualStrings("a", resolveVisibleLineForTest(prepared.visible_lines.items[0], source_buf)); try std.testing.expect(std.meta.activeTag(prepared.visible_lines.items[1]) == .folded_line); try std.testing.expectEqualStrings("hidden-1", resolveVisibleLineForTest(prepared.visible_lines.items[1], source_buf)); try std.testing.expect(std.meta.activeTag(prepared.visible_lines.items[2]) == .folded_line); try std.testing.expectEqualStrings("hidden-2", resolveVisibleLineForTest(prepared.visible_lines.items[2], source_buf)); try std.testing.expectEqualStrings("b", resolveVisibleLineForTest(prepared.visible_lines.items[3], source_buf));}
test "collapsed state still shows the fold summary" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), }; defer runtime.deinit(alloc);
try runtime.transcript.appendSlice(alloc, "a\nsummary\nb\n"); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2 }); try runtime.folded_command_blocks.items[0].lines.append(alloc, .{ .stream = .stdout, .text = try alloc.dupe(u8, "hidden-1") });
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintFromSourceForArea( alloc, &metrics, &source, .{ .top = 1, .bottom = 8 }, ); defer prepared.deinit(alloc);
const source_buf = TranscriptBuffer{ .bytes = source.bytes }; try std.testing.expectEqual(@as(usize, 3), prepared.visible_lines.items.len); try std.testing.expect(std.meta.activeTag(prepared.visible_lines.items[1]) == .transcript); try std.testing.expectEqualStrings("summary", resolveVisibleLineForTest(prepared.visible_lines.items[1], source_buf));}
test "source-less surface paint keeps transcript lines one to one under full transcript" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
try runtime.transcript.appendSlice(alloc, "a\nsummary\nb\n"); try runtime.folded_command_blocks.append(alloc, .{ .summary_transcript_index = 2 }); runtime.full_transcript.depth = .review;
var metrics: Metrics = .{}; var prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = 1, .bottom = 3 }, ); defer prepared.deinit(alloc);
try std.testing.expectEqual(@as(usize, 3), prepared.visible_lines.items.len); for (prepared.visible_lines.items) |line| { try std.testing.expect(std.meta.activeTag(line) == .transcript); }}
test "record false command output remains transient" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8) }; defer runtime.deinit(alloc); var metrics = Metrics{};
try runtime.writeCommandOutputChunk( alloc, &metrics, commandOutputTestStyles(), .stdout, "transient\n", false, ); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expectEqualStrings("transient", runtime.command_output_blocks.items[0].lines.items[0].text); try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len); try std.testing.expectEqual(@as(usize, 0), runtime.transcript.items.len);
try runtime.flushCommandOutputSummary( alloc, &metrics, commandOutputTestStyles(), false, ); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items.len); try std.testing.expect(runtime.command_output_display.open_command_block == null);}
test "command output consolidation preserves committed prompt scrollback anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const prompt = try alloc.dupe(u8, "give me a table of my system information"); _ = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{}, });
var live_entry_ids: [18]u32 = undefined; for (0..18) |index| { var line: [48]u8 = undefined; const text = try std.fmt.bufPrint(&line, "SYSTEM OUTPUT {d:0>2}\\n", .{index + 1}); const bytes = try alloc.dupe(u8, text); live_entry_ids[index] = try runtime.appendRawBytesEntryClassified( alloc, bytes, .unknown_raw, ); }
const first_assistant_id = try runtime.appendAssistantTurnEntry(alloc); const first_assistant = runtime.lookupAssistantSegments(first_assistant_id) orelse return error.TestExpectedAssistantSegments; for (0..24) |index| { var line: [48]u8 = undefined; const text = try std.fmt.bufPrint(&line, "assistant table row {d}\n", .{index + 1}); try first_assistant.text.appendSlice(alloc, text); } // The assistant content above is complete; report producer closure so // the finality floor does not hold the tail. runtime.transcript_release = runtime.transcript_release.with_assistant_tail_writable(false);
var live_source = try runtime.prepareTranscriptSource(alloc, null); defer live_source.deinit(alloc); try std.testing.expect(std.mem.find(u8, live_source.bytes, "give me a table") != null); try std.testing.expect(std.mem.find(u8, live_source.bytes, "SYSTEM OUTPUT 01") != null); try std.testing.expect(std.mem.find(u8, live_source.bytes, "assistant table row 24") != null); var live_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &live_source, ); defer live_prepared.deinit(alloc); try commitPreparedForTest(&runtime, alloc, &live_source, &live_prepared); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
try removeRawEntriesForTest(&runtime, alloc, &live_entry_ids); const compact_bytes = try alloc.dupe( u8, "SYSTEM OUTPUT 01\n... 16 command lines folded\nSYSTEM OUTPUT 18\n", ); _ = try runtime.appendRawBytesEntryClassified( alloc, compact_bytes, .unknown_raw, ); try runtime.rebuildTranscriptCacheAfterStructuredRewrite( alloc, "command output consolidation", ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
var metrics = Metrics{}; try runtime.writeTranscriptClassified( alloc, &metrics, "permission accepted\n", true, .subagent_status, ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
const second_assistant_id = try runtime.appendAssistantTurnEntry(alloc); const second_assistant = runtime.lookupAssistantSegments(second_assistant_id) orelse return error.TestExpectedAssistantSegments; for (0..60) |index| { var line: [40]u8 = undefined; const text = try std.fmt.bufPrint(&line, "follow-up table row {d}\n", .{index + 1}); try second_assistant.text.appendSlice(alloc, text); }
var compact_source = try runtime.prepareTranscriptSource(alloc, null); defer compact_source.deinit(alloc); try std.testing.expect(std.mem.find(u8, compact_source.bytes, "give me a table") != null); try std.testing.expect(std.mem.find(u8, compact_source.bytes, "follow-up table row 60") != null); var compact_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &compact_source, ); defer compact_prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&compact_prepared); try std.testing.expect(facts.target_visual_offset > facts.source_visual_offset); // The consolidation changed committed rows in place, so this frame has // no ability to materialize the held range: zero release, re-anchor on // the rewritten flow, and mark the finality debt. try std.testing.expect(!facts.source_compatible); try std.testing.expect(facts.recovery_rebase); try std.testing.expectEqual(@as(u32, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), facts.planned_rows); try std.testing.expect(facts.finality_hold); try commitPreparedForTest(&runtime, alloc, &compact_source, &compact_prepared);
// The following compatible frame settles the debt with final bytes. var settle_source = try runtime.prepareTranscriptSource(alloc, null); defer settle_source.deinit(alloc); var settle_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &settle_source, ); defer settle_prepared.deinit(alloc); const settle_facts = runtime.planTranscriptScroll(&settle_prepared); try std.testing.expect(settle_facts.source_compatible); try std.testing.expect(settle_facts.semantic_rows > 0); try std.testing.expect(settle_facts.planned_rows > 0);}
fn removeRawEntriesForTest( runtime: *TranscriptRuntime, alloc: Allocator, ids: []const u32,) !void { for (ids) |id| { var index: usize = 0; while (index < runtime.entries.items.len) : (index += 1) { const entry = runtime.entries.items[index]; if (entry == .raw_bytes and entry.raw_bytes.id == id) { var removed = runtime.entries.orderedRemove(index); removed.deinit(alloc); break; } } else return error.TestExpectedRawEntry; }}
test "command output stores terminal-safe text for live consolidated and full transcript views" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); const raw = "\x1b[2JCSI_CLEAR_TOKEN\x1b[31mCSI_SGR_TOKEN\x1b[0m\r\x08\x07\x7f\n"; const safe = "\\x08\\x07\\x7f";
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, raw, true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stderr, "unterminated-final", true);
try std.testing.expectEqualStrings(safe, runtime.command_output_blocks.items[0].lines.items[0].text); try std.testing.expectEqualStrings("unterminated-final", runtime.command_output_blocks.items[0].lines.items[1].text);
const live = try renderEntriesToBytes(alloc, runtime.entries.items, 80); defer alloc.free(live); try std.testing.expect(std.mem.find(u8, live, safe) != null); try std.testing.expect(std.mem.find(u8, live, "\x1b[2JCSI_CLEAR_TOKEN") == null);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); const consolidated = try renderEntriesToBytes(alloc, runtime.entries.items, 80); defer alloc.free(consolidated); try std.testing.expect(std.mem.find(u8, consolidated, safe) != null); try std.testing.expect(std.mem.find(u8, consolidated, "\x1b[2JCSI_CLEAR_TOKEN") == null);
runtime.has_committed_frame = true; runtime.owned_top_row = 5; try std.testing.expect(try runtime.setTranscriptPresentationDepth(alloc, .review)); var projection = try full_transcript_screen.buildProjection( alloc, runtime.entries.items, runtime.tool_details.items, runtime.command_output_blocks.items, runtime.command_output_render.styles, runtime.layout.cols, runtime.fullTranscriptAnchorEntryId(), ); defer projection.deinit(alloc); const source_bytes = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 16, 0, null, ); var source = try runtime.prepareFullTranscriptViewportSource(alloc, source_bytes); defer source.deinit(alloc); try std.testing.expect(std.mem.find(u8, source.bytes, safe) != null); try std.testing.expect(std.mem.find(u8, source.bytes, "\x1b[2JCSI_CLEAR_TOKEN") == null);}
test "command output keeps capped and folded transcript behavior" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-one\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stderr, "line-two\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-three\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-four\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-five\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-six\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-seven\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "line-one") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "line-two") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "line-five") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "line-six") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "│ … 2 lines more (ctrl o to view)") != null); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expectEqual(@as(usize, 7), runtime.command_output_blocks.items[0].lines.items.len);}
test "prepared command output paint clears stale hint before projecting newest hint" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc); var metrics = Metrics{}; const styles = commandOutputTestStyles();
try runtime.writeCommandOutputChunk( alloc, &metrics, styles, .stdout, "fast-1\nfast-2\nfast-3\nfast-4\nfast-5\nfast-6\n", true, ); const old_hint_entry_id = runtime.command_output_blocks.items[0].lines.items[5].entry_id.?; try expectRawEntryBytes( &runtime, old_hint_entry_id, "│ … 1 line more (ctrl o to view)", );
try runtime.writeCommandOutputChunk( alloc, &metrics, styles, .stdout, "fast-7\nfast-8\n", true, ); const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(@as(usize, 8), block.total_lines); try std.testing.expectEqual(@as(usize, 8), block.lines.items.len); const newest_entry_id = block.lines.items[7].entry_id.?; try expectRawEntryBytes( &runtime, old_hint_entry_id, "│ … 1 line more (ctrl o to view)", ); try expectRawEntryBytes(&runtime, newest_entry_id, "");
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, source.bytes, "(ctrl o to view)"), ); try std.testing.expect(std.mem.find( u8, source.bytes, "│ … 3 lines more (ctrl o to view)", ) != null); try std.testing.expect(std.mem.find( u8, source.bytes, "│ … 1 line more (ctrl o to view)", ) == null);}
test "command output consolidation replaces live row before following transcript rows" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "before\n", .subagent_status); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "middle\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "after\n", .subagent_status);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc);
const before_pos = std.mem.indexOf(u8, source.bytes, "before") orelse return error.MissingBeforeRow; const middle_pos = std.mem.indexOf(u8, source.bytes, "middle") orelse return error.MissingCommandOutputRow; const after_pos = std.mem.indexOf(u8, source.bytes, "after") orelse return error.MissingAfterRow;
try std.testing.expect(before_pos < middle_pos); try std.testing.expect(middle_pos < after_pos);}
test "command output consolidation preserves rows between noncontiguous live rows" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "before\n", .subagent_status); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "command-one\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "intervening\n", .subagent_status); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "command-two\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "after\n", .subagent_status);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc);
const before_pos = std.mem.indexOf(u8, source.bytes, "before") orelse return error.MissingBeforeRow; const first_output_pos = std.mem.indexOf(u8, source.bytes, "command-one") orelse return error.MissingFirstCommandOutputRow; const intervening_pos = std.mem.indexOf(u8, source.bytes, "intervening") orelse return error.MissingInterveningRow; const second_output_pos = std.mem.indexOf(u8, source.bytes, "command-two") orelse return error.MissingSecondCommandOutputRow; const after_pos = std.mem.indexOf(u8, source.bytes, "after") orelse return error.MissingAfterRow;
try std.testing.expect(before_pos < first_output_pos); try std.testing.expect(first_output_pos < intervening_pos); try std.testing.expect(intervening_pos < second_output_pos); try std.testing.expect(second_output_pos < after_pos);}
test "command output folding preserves rows between noncontiguous live rows" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "before\n", .subagent_status); for (0..5) |index| { var line: [32]u8 = undefined; const text = try std.fmt.bufPrint(&line, "command-visible-{d}\n", .{index + 1}); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, text, true); } _ = try runtime.appendRawTranscriptEntryClassified(alloc, "intervening\n", .subagent_status); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "command-two\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "after\n", .subagent_status);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc);
const before_pos = std.mem.indexOf(u8, source.bytes, "before") orelse return error.MissingBeforeRow; const first_output_pos = std.mem.indexOf(u8, source.bytes, "command-visible-1") orelse return error.MissingFirstCommandOutputRow; const intervening_pos = std.mem.indexOf(u8, source.bytes, "intervening") orelse return error.MissingInterveningRow; const folded_pos = std.mem.indexOf(u8, source.bytes, "│ … 1 line more (ctrl o to view)") orelse return error.MissingFoldedCommandOutputRow; const after_pos = std.mem.indexOf(u8, source.bytes, "after") orelse return error.MissingAfterRow;
try std.testing.expect(before_pos < first_output_pos); try std.testing.expect(first_output_pos < intervening_pos); try std.testing.expect(intervening_pos < folded_pos); try std.testing.expect(folded_pos < after_pos);}
test "partial first command record keeps its hint after an intervening notice" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc); runtime.layout.cols = 16;
var metrics = Metrics{}; const styles = commandOutputTestStyles(); try runtime.writeCommandOutputChunk( alloc, &metrics, styles, .stdout, "first record wraps across many physical rows and remains intentionally long", true, ); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "intervening-notice\n", .subagent_status); try runtime.writeCommandOutputChunk( alloc, &metrics, styles, .stdout, "\nlater-hidden-record\n", true, );
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); const first_pos = std.mem.find(u8, source.bytes, "first record") orelse return error.MissingFirstCommandOutputRow; const notice_pos = std.mem.find(u8, source.bytes, "intervening-notice") orelse return error.MissingInterveningRow; const hint_pos = std.mem.find(u8, source.bytes, "│ … 2") orelse return error.MissingFoldedCommandOutputRow; try std.testing.expect(first_pos < notice_pos); try std.testing.expect(notice_pos < hint_pos); try std.testing.expect(std.mem.find(u8, source.bytes, "later-hidden-record") == null);}
test "production command pruning preserves deferred replay around a notice" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc); var metrics = Metrics{}; const styles = commandOutputTestStyles();
const status_entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "● Ran printf ordered-output\n", ); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "output-0\n", true); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "intervening-notice\n", .subagent_status, ); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "output-1\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); try runtime.attachHistoricalToolDetailAfterCommandOutput( alloc, status_entry_id, .{ .id = "ordered-output", .name = "run_command", .arguments_json = "{\"command\":\"printf ordered-output\"}", }, .command, .{ .tool_call_id = @constCast("ordered-output"), .tool_name = @constCast("run_command"), .status = .success, .output = @constCast("exit_code=0\n<stdout>\noutput-0\noutput-1\n</stdout>\n"), .output_bytes = "exit_code=0\n<stdout>\noutput-0\noutput-1\n</stdout>\n".len, .stored_output_bytes = "exit_code=0\n<stdout>\noutput-0\noutput-1\n</stdout>\n".len, }, ); const pruned_source_entry_id = runtime.command_output_blocks.items[0].lines.items[1].entry_id.?;
try std.testing.expect(try command_output_runtime.trimRetainedCommandOutputLine( &runtime, alloc, 0, 1, )); _ = try command_output_runtime.syncCommandOutputBlockEntries(&runtime, alloc); try runtime.rebuildTranscriptCacheAfterStructuredRewrite(alloc, "test command prune"); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].pruned_ranges.items.len); try std.testing.expectEqual( pruned_source_entry_id, runtime.command_output_blocks.items[0].pruned_ranges.items[0].anchor_entry_id, );
var compact = try runtime.prepareTranscriptSource(alloc, null); defer compact.deinit(alloc); const compact_output_0_pos = std.mem.find(u8, compact.bytes, "output-0") orelse return error.MissingFirstCommandOutputRow; const compact_notice_pos = std.mem.find(u8, compact.bytes, "intervening-notice") orelse return error.MissingInterveningRow; const compact_hint_pos = std.mem.find(u8, compact.bytes, "│ … 1 line more") orelse return error.MissingFoldedCommandOutputRow; try std.testing.expect(compact_output_0_pos < compact_notice_pos); try std.testing.expect(compact_notice_pos < compact_hint_pos); try std.testing.expect(std.mem.find(u8, compact.bytes, "output-1") == null);
runtime.full_transcript.depth = .full; var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const source = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 64, 0, null, ); defer alloc.free(source); const output_0_pos = std.mem.find(u8, source, "output-0") orelse return error.MissingFirstCommandOutputRow; const notice_pos = std.mem.find(u8, source, "intervening-notice") orelse return error.MissingInterveningRow; const output_1_pos = std.mem.find(u8, source, "output-1") orelse return error.MissingSecondCommandOutputRow; try std.testing.expect(output_0_pos < notice_pos); try std.testing.expect(notice_pos < output_1_pos);}
test "production all-pruned command keeps process and hint at final anchor" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc); var metrics = Metrics{}; const styles = commandOutputTestStyles();
const status_entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "● Ran printf all-pruned\n", ); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "pruned-0\n", true); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "pruned-separator\n", .subagent_status, ); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "pruned-1\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); try runtime.attachHistoricalToolDetailAfterCommandOutput( alloc, status_entry_id, .{ .id = "all-pruned", .name = "run_command", .arguments_json = "{\"command\":\"printf all-pruned\"}", }, .command, .{ .tool_call_id = @constCast("all-pruned"), .tool_name = @constCast("run_command"), .status = .success, .output = @constCast("exit_code=7\n<stdout>\npruned-0\npruned-1\n</stdout>\n"), .output_bytes = "exit_code=7\n<stdout>\npruned-0\npruned-1\n</stdout>\n".len, .stored_output_bytes = "exit_code=7\n<stdout>\npruned-0\npruned-1\n</stdout>\n".len, .command_process_presentation = .{ .exit_code = 7 }, }, ); const final_anchor = runtime.command_output_blocks.items[0].lines.items[1].entry_id.?;
try std.testing.expect(try command_output_runtime.trimRetainedCommandOutputLine( &runtime, alloc, 0, 0, )); try std.testing.expect(try command_output_runtime.trimRetainedCommandOutputLine( &runtime, alloc, 0, 0, )); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqual(@as(usize, 2), runtime.command_output_blocks.items[0].pruned_ranges.items.len); _ = try command_output_runtime.syncCommandOutputBlockEntries(&runtime, alloc); try runtime.rebuildTranscriptCacheAfterStructuredRewrite(alloc, "test all-pruned command");
var final_anchor_bytes: ?[]const u8 = null; for (runtime.entries.items) |entry| { if (entry.id() != final_anchor or entry != .raw_bytes) continue; final_anchor_bytes = entry.raw_bytes.bytes; break; } const final = final_anchor_bytes orelse return error.MissingFinalCommandAnchor; try std.testing.expect(std.mem.find(u8, final, "│ exit code 7") != null); try std.testing.expect(std.mem.find(u8, final, "│ … 2 lines more") != null);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); const notice_pos = std.mem.find(u8, source.bytes, "pruned-separator") orelse return error.MissingInterveningRow; const process_pos = std.mem.find(u8, source.bytes, "│ exit code 7") orelse return error.MissingCommandProcessRow; const hint_pos = std.mem.find(u8, source.bytes, "│ … 2 lines more") orelse return error.MissingFoldedCommandOutputRow; try std.testing.expect(notice_pos < process_pos); try std.testing.expect(process_pos < hint_pos); try std.testing.expect(std.mem.find(u8, source.bytes, "pruned-0") == null); try std.testing.expect(std.mem.find(u8, source.bytes, "pruned-1") == null);}
test "pruned command ranges bridge after their separator is retained then removed" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc); var metrics = Metrics{}; const styles = commandOutputTestStyles();
const status_entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "● Ran printf ranges\n", ); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "range-0\nrange-1\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "range-separator\n", .subagent_status); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "range-2\nrange-3\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); try runtime.attachHistoricalToolDetailAfterCommandOutput( alloc, status_entry_id, .{ .id = "ranges", .name = "run_command", .arguments_json = "{\"command\":\"printf ranges\"}" }, .command, .{ .tool_call_id = @constCast("ranges"), .tool_name = @constCast("run_command"), .status = .success, .output = @constCast("exit_code=0\n<stdout>\nrange-0\nrange-1\nrange-2\nrange-3\n</stdout>\n"), .output_bytes = "exit_code=0\n<stdout>\nrange-0\nrange-1\nrange-2\nrange-3\n</stdout>\n".len, .stored_output_bytes = "exit_code=0\n<stdout>\nrange-0\nrange-1\nrange-2\nrange-3\n</stdout>\n".len, }, );
while (runtime.command_output_blocks.items[0].lines.items.len > 0) { try std.testing.expect(try command_output_runtime.trimRetainedCommandOutputLine( &runtime, alloc, 0, 0, )); } try std.testing.expectEqual(@as(usize, 2), runtime.command_output_blocks.items[0].pruned_ranges.items.len);
const retained_before = transcript_store.retainedStructuredBytes(&runtime); runtime.max_retained_transcript_bytes = retained_before - 1; try runtime.enforceStructuredRetention(alloc, null); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].pruned_ranges.items.len); const range = runtime.command_output_blocks.items[0].pruned_ranges.items[0]; try std.testing.expectEqual(@as(usize, 0), range.start_record); try std.testing.expectEqual(@as(usize, 4), range.end_record); try std.testing.expect( transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes, );}
test "command output detail retargets when first split source row is pruned" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); const lifecycle_id = types.ToolLifecycleId{ .turn_id = 3, .call_id = "split-prune" };
_ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycle_id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"printf split\"}", } }); try runtime.writeCommandOutputChunkForLifecycle(alloc, &metrics, styles, lifecycle_id, .stdout, "command-one\n", true); _ = try runtime.appendRawTranscriptEntryClassified(alloc, "intervening\n", .subagent_status); try runtime.writeCommandOutputChunkForLifecycle(alloc, &metrics, styles, lifecycle_id, .stdout, "command-two\n", true); try runtime.flushCommandOutputSummaryForLifecycle(alloc, &metrics, styles, lifecycle_id, true); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycle_id, .outcome = .{ .kind = .completed, .summary = "Ran printf split" }, } });
const status_entry_id = runtime.toolActivityRecord(lifecycle_id).?.entry_id; const first_source_id = runtime.command_output_blocks.items[0].source_entry_ids.items[0]; const second_source_id = runtime.command_output_blocks.items[0].source_entry_ids.items[1]; try std.testing.expectEqual(first_source_id, runtime.toolDetailForEntry(status_entry_id).?.command_output_entry_id.?);
for (runtime.entries.items, 0..) |entry, entry_index| { if (entry.id() != first_source_id) continue; var removed = runtime.entries.orderedRemove(entry_index); removed.deinit(alloc); break; }
try runtime.enforceStructuredRetention(alloc, second_source_id);
try std.testing.expectEqual(second_source_id, runtime.command_output_blocks.items[0].entry_id.?); try std.testing.expectEqual(second_source_id, runtime.toolDetailForEntry(status_entry_id).?.command_output_entry_id.?); try std.testing.expectEqual(status_entry_id, runtime.detailEntryIdForCommandOutputSource(second_source_id).?);}
test "command output shows retained records within the compact limit" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "retained-one\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stderr, "retained-two\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "retained-three\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "retained-one") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "retained-two") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "retained-three") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "command lines folded") == null); try std.testing.expectEqual(@as(usize, 0), runtime.folded_command_blocks.items.len); try std.testing.expectEqual(@as(usize, 3), runtime.entries.items.len);}
test "command output entries are classified" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line one\n", true); try std.testing.expect(runtime.entries.items.len > 0); try std.testing.expectEqual(RawEntryClass.command_output, runtime.entries.items[runtime.entries.items.len - 1].raw_bytes.class);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expect(runtime.entries.items.len > 0); try std.testing.expectEqual(RawEntryClass.command_output, runtime.entries.items[runtime.entries.items.len - 1].raw_bytes.class);}
test "pre-flush live command output chunks match consolidated row geometry" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputAnsiTestStyles();
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "one\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stderr, "two\n", true);
const live = try renderEntriesToBytes(alloc, runtime.entries.items, 80); defer alloc.free(live);
try std.testing.expect(std.mem.find(u8, live, "\x1b[2m│ one\x1b[0m") != null); try std.testing.expect(std.mem.find(u8, live, "\x1b[2m│ two\x1b[0m") != null); try std.testing.expect(std.mem.find(u8, live, "\x1b[31m") == null);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); const consolidated = try renderEntriesToBytes(alloc, runtime.entries.items, 80); defer alloc.free(consolidated);
try std.testing.expectEqualStrings(live, consolidated);}
test "command output lifecycle mismatch cannot append to or complete the active block" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = commandOutputTestRuntime(sink); defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); const active_id = types.ToolLifecycleId{ .turn_id = 7, .call_id = "active-command" }; const foreign_id = types.ToolLifecycleId{ .turn_id = 7, .call_id = "foreign-command" };
try runtime.writeCommandOutputChunkForLifecycle(alloc, &metrics, styles, active_id, .stdout, "active-one\n", true); try std.testing.expectError( error.CommandOutputLifecycleMismatch, runtime.writeCommandOutputChunkForLifecycle(alloc, &metrics, styles, foreign_id, .stderr, "foreign\n", true), ); try runtime.flushCommandOutputSummaryForLifecycle(alloc, &metrics, styles, foreign_id, true);
try std.testing.expectEqual(@as(?usize, 0), runtime.command_output_display.open_command_block); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqualStrings("active-one", runtime.command_output_blocks.items[0].lines.items[0].text); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "foreign") == null);
try runtime.writeCommandOutputChunkForLifecycle(alloc, &metrics, styles, active_id, .stderr, "active-two\n", true); try runtime.flushCommandOutputSummaryForLifecycle(alloc, &metrics, styles, active_id, true);
try std.testing.expect(runtime.command_output_display.open_command_block == null); try std.testing.expectEqual(@as(usize, 2), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqual(command_output_content.Stream.stdout, runtime.command_output_blocks.items[0].lines.items[0].stream); try std.testing.expectEqual(command_output_content.Stream.stderr, runtime.command_output_blocks.items[0].lines.items[1].stream); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, runtime.transcript.items, "active-one")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, runtime.transcript.items, "active-two")); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "foreign") == null);}
test "command output display caps at five physical rows" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .maxxing_mode = .legacy, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; const styles: Styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", };
var line_index: usize = 0; while (line_index < 26) : (line_index += 1) { const line = try std.fmt.allocPrint(std.testing.allocator, "line-{d}\n", .{line_index}); defer std.testing.allocator.free(line); try runtime.writeCommandOutputChunk(std.testing.allocator, &metrics, styles, .stdout, line, true); } try runtime.flushCommandOutputSummary(std.testing.allocator, &metrics, styles, true);
try std.testing.expectEqual(@as(usize, 5), std.mem.count(u8, runtime.transcript.items, "│ line-")); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "│ line-4") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "│ line-5") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "│ … 21 lines more (ctrl o to view)") != null); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, runtime.transcript.items, "ctrl o to view")); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expectEqual(@as(usize, 26), runtime.command_output_blocks.items[0].lines.items.len);}
test "structured retention prunes old raw transcript entries past cap" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 128, .max_retained_transcript_bytes = 32, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 1); try runtime.writeTranscript(alloc, &metrics, "raw-one-12345\n", true); try runtime.writeTranscript(alloc, &metrics, "raw-two-12345\n", true); try runtime.writeTranscript(alloc, &metrics, "raw-three-123\n", true);
try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes); try std.testing.expect(runtime.entries.items.len < 3); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "raw-one") == null); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "raw-three") != null);}
test "structured retention compacts a large pruning pass in entry order" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 4096, .max_retained_transcript_bytes = std.math.maxInt(usize), }; defer runtime.deinit(alloc);
for (0..2048) |index| { const line = try std.fmt.allocPrint(alloc, "retained-entry-{d:0>4}\n", .{index}); _ = runtime.appendRawBytesEntryClassified(alloc, line, .unknown_raw) catch |err| { alloc.free(line); return err; }; }
runtime.max_retained_transcript_bytes = 1024; try runtime.enforceStructuredRetention(alloc, null);
try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= 1024); try std.testing.expect(runtime.entries.items.len < 2048); try std.testing.expect(runtime.entries.items.len > 0); for (runtime.entries.items[1..], runtime.entries.items[0 .. runtime.entries.items.len - 1]) |entry, previous| { try std.testing.expect(previous.id() < entry.id()); } try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "retained-entry-0000") == null); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "retained-entry-2047") != null);}
test "assistant streaming retention trims active segment text" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 128, .max_retained_transcript_bytes = 32, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 1); _ = try runtime.streamAssistantChunk(alloc, &metrics, "aaaaaaaaaaaaaaaa\n"); _ = try runtime.streamAssistantChunk(alloc, &metrics, "bbbbbbbbbbbbbbbb\n"); _ = try runtime.streamAssistantChunk(alloc, &metrics, "cccccccccccccccc\n");
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); const text = runtime.entries.items[0].assistant_turn.segments.text.items; try std.testing.expect(text.len <= runtime.max_retained_transcript_bytes); try std.testing.expect(std.mem.indexOf(u8, text, "cccccccc") != null); try std.testing.expect(std.mem.indexOf(u8, text, "aaaaaaaa") == null); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);}
test "hidden command output becomes count-only at the hard cap" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .maxxing_mode = .legacy, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 512, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); const retained_lines = [_][]const u8{ "line-00\n", "line-01\n", "line-02\n", "line-03\n", "line-04\n", "line-05\n", }; for (retained_lines, 0..) |line, index| { const stream: command_output_content.Stream = if (index % 2 == 0) .stdout else .stderr; try runtime.writeCommandOutputChunk(alloc, &metrics, styles, stream, line, true); }
runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-06\n", true);
try std.testing.expectEqual(@as(usize, 6), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqualStrings("line-00", runtime.command_output_blocks.items[0].lines.items[0].text); try std.testing.expect(std.mem.find(u8, runtime.command_output_blocks.items[0].lines.items[5].text, "line-06") == null); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);
var failing = std.testing.FailingAllocator.init(alloc, .{ .fail_index = 0 }); try runtime.writeCommandOutputChunk( failing.allocator(), &metrics, styles, .stderr, "line-07\n", true, ); try std.testing.expectEqual(@as(usize, 0), failing.allocations);
try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(@as(usize, 8), block.total_lines); const expected_summary = try std.fmt.allocPrint( alloc, "│ … {d} lines more (ctrl o to view)", .{block.total_lines - @min(@as(usize, 5), block.lines.items.len)}, ); defer alloc.free(expected_summary); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, expected_summary) != null); var retained_text_bytes: usize = 0; for (block.lines.items) |line| retained_text_bytes += line.text.len; try std.testing.expectEqual(retained_text_bytes, block.retained_text_bytes);
_ = try runtime.streamAssistantChunk(alloc, &metrics, "assistant after cap"); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "assistant after cap") != null);}
test "command output becomes count-only at the hard cap" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 512, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-00\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stderr, "line-01\n", true);
runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "line-02\n", true);
var failing = std.testing.FailingAllocator.init(alloc, .{ .fail_index = 0 }); try runtime.writeCommandOutputChunk( failing.allocator(), &metrics, styles, .stderr, "line-03\n", true, );
try std.testing.expectEqual(@as(usize, 0), failing.allocations); const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(@as(usize, 4), block.total_lines); try std.testing.expect(block.lines.items.len < block.total_lines); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);}
test "blank hidden command output becomes count-only at the hard cap" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 256, .max_retained_transcript_bytes = 64, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles(); for (0..8) |_| { try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "\n", true); }
const block = &runtime.command_output_blocks.items[0]; try std.testing.expect(block.lines.items.len < block.total_lines); try std.testing.expectEqual(@as(usize, 8), block.total_lines); try std.testing.expectEqual(@as(usize, 0), block.retained_text_bytes); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);
var failing = std.testing.FailingAllocator.init(alloc, .{ .fail_index = 0 }); try runtime.writeCommandOutputChunk( failing.allocator(), &metrics, styles, .stderr, "\n", true, ); try std.testing.expectEqual(@as(usize, 0), failing.allocations); try std.testing.expectEqual(@as(usize, 9), block.total_lines);}
test "command output lines count toward structured retention" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 256, .max_retained_transcript_bytes = 512, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles: Styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", };
var i: usize = 0; while (i < 6) : (i += 1) { try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "hidden-command-line\n", true); } try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expect(runtime.command_output_blocks.items[0].entry_id != null); try std.testing.expect(runtime.command_output_blocks.items[0].lines.items.len < 6); try std.testing.expectEqual(@as(usize, 6), runtime.command_output_blocks.items[0].total_lines); var retained_text_bytes: usize = 0; for (runtime.command_output_blocks.items[0].lines.items) |line| retained_text_bytes += line.text.len; try std.testing.expectEqual(retained_text_bytes, runtime.command_output_blocks.items[0].retained_text_bytes); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);}
test "structured retention prunes old command output block state" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 256, .max_retained_transcript_bytes = 260, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles = commandOutputTestStyles();
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "old-command-output-line-that-should-prune\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len);
try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "new-command-output-line-that-should-remain\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expect(std.mem.find(u8, runtime.command_output_blocks.items[0].lines.items[0].text, "new-command-output") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "old-command-output") == null); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);}
test "resize preparation uses retained entries after pruning without rewriting cache" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 128, .max_retained_transcript_bytes = 40, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 1); try runtime.writeTranscript(alloc, &metrics, "old-entry-that-will-prune\n", true); try runtime.writeTranscript(alloc, &metrics, "latest-entry-stays\n", true);
const cache_before = try alloc.dupe(u8, runtime.transcript.items); defer alloc.free(cache_before); const rendered_cols_before = runtime.last_rendered_cols;
runtime.layout.cols = 20; var prepared = try runtime.prepareTranscriptSurfacePaint(alloc, &metrics, 0); defer prepared.deinit(alloc);
try std.testing.expectEqual(rendered_cols_before, runtime.last_rendered_cols); try std.testing.expectEqualStrings(cache_before, runtime.transcript.items); try std.testing.expect(std.mem.indexOf(u8, prepared.bytes, "latest-entry-stays") != null); try std.testing.expect(std.mem.indexOf(u8, prepared.bytes, "old-entry") == null);}
test "clearTranscript after retention pruning frees retained entries and command output blocks" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22 }, .max_transcript_bytes = 128, .max_retained_transcript_bytes = 64, }; defer runtime.deinit(alloc);
var metrics = Metrics{}; const styles: Styles = .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", };
try runtime.writeTranscript(alloc, &metrics, "first-entry-to-prune\n", true); try runtime.writeTranscript(alloc, &metrics, "second-entry-to-keep\n", true); try runtime.writeCommandOutputChunk(alloc, &metrics, styles, .stdout, "hidden-command-line\n", true); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);
runtime.clearTranscript(alloc);
try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len); try std.testing.expectEqual(@as(usize, 0), runtime.folded_command_blocks.items.len); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items.len); try std.testing.expectEqual(@as(usize, 0), transcript_store.retainedStructuredBytes(&runtime));
const after = try alloc.dupe(u8, "after-clear\n"); const id = try runtime.appendRawBytesEntry(alloc, after); try std.testing.expect(id > 0);}
test "recomputeCursorFromTranscript respects resized width" { var runtime = TranscriptRuntime{ .layout = .{ .rows = 24, .cols = 6, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, }; defer runtime.deinit(std.testing.allocator);
try runtime.transcript.appendSlice(std.testing.allocator, "hello world\nabc"); runtime.cursor_row = 99; runtime.cursor_col = 99;
runtime.recomputeCursorFromTranscript();
try std.testing.expectEqual(@as(u16, 3), runtime.cursor_row); try std.testing.expectEqual(@as(u16, 4), runtime.cursor_col);}
test "recomputeCursorFromTranscript skips ANSI in styled rows" { var runtime = TranscriptRuntime{ .layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, }; defer runtime.deinit(std.testing.allocator);
const bar_row = "\x1b[48;5;235m\x1b[39m❯ hello\x1b[0m"; try runtime.transcript.appendSlice(std.testing.allocator, bar_row);
runtime.cursor_row = 99; runtime.cursor_col = 99; runtime.recomputeCursorFromTranscript();
try std.testing.expectEqual(@as(u16, 8), runtime.cursor_col);}
test "replaceTrailingTranscriptLine updates latest replaceable line" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; try runtime.writeTranscript(std.testing.allocator, &metrics, "started\n", true); _ = try runtime.appendReplaceableTranscriptLine(std.testing.allocator, &metrics, "progress one\n"); try std.testing.expect(try runtime.replaceTrailingTranscriptLine(std.testing.allocator, &metrics, "progress two\n")); try std.testing.expectEqualStrings("started\nprogress two\n", runtime.transcript.items);}
test "replaceable line with ansi wrapper does not accumulate historical entries" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; try runtime.writeTranscript(std.testing.allocator, &metrics, "start\n", true); _ = try runtime.appendReplaceableTranscriptLine(std.testing.allocator, &metrics, "\x1b[38;5;245mline one\n\x1b[0m"); try std.testing.expect(try runtime.replaceTrailingTranscriptLine(std.testing.allocator, &metrics, "\x1b[38;5;245mline two\n\x1b[0m")); try std.testing.expectEqualStrings("start\n\x1b[38;5;245mline two\n\x1b[0m", runtime.transcript.items);}
test "updateExtraInputRows shrink preserves pre-fx scrollback" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 40, .cols = 120, .content_bottom = 36, .divider_top_row = 37, .input_row = 38, .divider_bottom_row = 39, .hint_row = 40, }, }; defer runtime.deinit(std.testing.allocator); try runtime.enableShadowVt(std.testing.allocator);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 12);
try runtime.updateExtraInputRows(std.testing.allocator, &metrics, 7); try runtime.updateExtraInputRows(std.testing.allocator, &metrics, 0);
try std.testing.expectEqual(@as(u16, 12), runtime.viewport_top_row);}
test "updateExtraInputRows after committed frame only records invalidation" { var tmp = std.testing.tmpDir(.{}); defer tmp.cleanup(); var sink = try tmp.dir.createFile(std.testing.io, "post-frame-extra-rows.log", .{ .read = true }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 20, .divider_top_row = 21, .input_row = 22, .divider_bottom_row = 23, .hint_row = 24, }, .owned_top_row = 5, .viewport_top_row = 5, .has_committed_frame = true, }; defer runtime.deinit(std.testing.allocator); runtime.footer_viewport.has_frame = true; runtime.footer_viewport.geometry = .{ .top = 21, .top_divider = 21, .input_base = 22, .bottom_divider = 23, .hint = 24, };
var metrics = Metrics{}; try runtime.updateExtraInputRows(std.testing.allocator, &metrics, 3);
try std.testing.expectEqual(@as(u16, 3), runtime.extra_input_rows); try std.testing.expect(runtime.transcript_band_dirty); try std.testing.expect(runtime.footer_viewport.externally_invalidated); try std.testing.expectEqual(@as(u64, 0), try sink.length(io_mod.getIo()));
const pending = runtime.render_requests.pendingInvalidations(); try std.testing.expectEqual(@as(u8, 1), pending.len); try std.testing.expectEqual(render_engine.paint_plan.FrameInvalidationReason.external_clear, pending.ranges()[0].reason); try std.testing.expectEqual(@as(u16, 5), pending.ranges()[0].top); try std.testing.expectEqual(@as(u16, 24), pending.ranges()[0].bottom);}
test "resize reservation never moves viewport above launch-owned row" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 46, .cols = 131, .content_bottom = 42, .divider_top_row = 43, .input_row = 44, .divider_bottom_row = 45, .hint_row = 46, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; try runtime.initViewportWithReservedRows(&metrics, 45, 11);
try std.testing.expectEqual(@as(u16, 32), runtime.viewport_top_row);
runtime.layout = .{ .rows = 44, .cols = 132, .content_bottom = 40, .divider_top_row = 41, .input_row = 42, .divider_bottom_row = 43, .hint_row = 44, }; runtime.reserveVisibleViewportRows(11);
try std.testing.expectEqual(@as(u16, 32), runtime.viewport_top_row);}
test "clearTranscript preserves launch-owned row" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 24, .cols = 80, .content_bottom = 21, .divider_top_row = 22, .input_row = 23, .divider_bottom_row = 24, .hint_row = 22, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 7); try runtime.writeTranscript(std.testing.allocator, &metrics, "hello\n", true);
runtime.clearTranscript(std.testing.allocator);
try std.testing.expectEqual(@as(u16, 7), runtime.owned_top_row); try std.testing.expectEqual(@as(u16, 7), runtime.viewport_top_row); try std.testing.expectEqual(@as(u16, 7), runtime.cursor_row);}
test "writeTranscript overflow defers terminal scroll to frame selection delta" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10, }, }; defer runtime.deinit(std.testing.allocator);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5); runtime.has_painted_transcript = true; try std.testing.expectEqual(@as(u16, 5), runtime.viewport_top_row);
try runtime.writeTranscript(std.testing.allocator, &metrics, "a\nb\nc\nd\ne\nf\ng\nh\n", true); try std.testing.expectEqual(@as(u16, 5), runtime.viewport_top_row); try std.testing.expectEqual(@as(u16, 5), runtime.owned_top_row); try std.testing.expectEqual(@as(u16, 7), runtime.cursor_row);}
test "appendRawBytesEntry stamps monotonic ids from 1" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const a = try alloc.dupe(u8, "first"); const id_a = try runtime.appendRawBytesEntry(alloc, a); const b = try alloc.dupe(u8, "second"); const id_b = try runtime.appendRawBytesEntry(alloc, b);
try std.testing.expectEqual(@as(u32, 1), id_a); try std.testing.expectEqual(@as(u32, 2), id_b); try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expectEqual(@as(u32, 1), runtime.entries.items[0].id()); try std.testing.expectEqualStrings("first", runtime.entries.items[0].raw_bytes.bytes);}
test "append helpers cover all three variants with unique ids" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const raw = try alloc.dupe(u8, "banner"); const raw_id = try runtime.appendRawBytesEntry(alloc, raw);
const prompt = try alloc.dupe(u8, "hello"); const user_id = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{} });
const assistant_id = try runtime.appendAssistantTurnEntry(alloc); const segs = runtime.lookupAssistantSegments(assistant_id) orelse unreachable; try segs.text.appendSlice(alloc, "streaming");
try std.testing.expectEqual(@as(u32, 1), raw_id); try std.testing.expectEqual(@as(u32, 2), user_id); try std.testing.expectEqual(@as(u32, 3), assistant_id); try std.testing.expectEqualStrings("streaming", runtime.entries.items[2].assistant_turn.segments.text.items);}
test "appendRawTranscriptEntryClassified stores raw entry class" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const entry_id = try runtime.appendRawTranscriptEntryClassified(alloc, "running tests\n", .tool_status);
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .raw_bytes); try std.testing.expectEqual(entry_id, runtime.entries.items[0].raw_bytes.id); try std.testing.expectEqual(RawEntryClass.tool_status, runtime.entries.items[0].raw_bytes.class); try std.testing.expectEqual(RawEntryClass.tool_status, runtime.rawEntryClass(entry_id).?);}
test "appendRawTranscriptEntry defaults to unknown_raw class" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const entry_id = try runtime.appendRawTranscriptEntry(alloc, "raw entry\n");
try std.testing.expectEqual(RawEntryClass.unknown_raw, runtime.rawEntryClass(entry_id).?);}
test "updateRawBytesEntry preserves raw entry class" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const entry_id = try runtime.appendRawTranscriptEntryClassified(alloc, "running\n", .tool_status); try std.testing.expect(try runtime.updateRawBytesEntry(alloc, entry_id, "done\n"));
try std.testing.expectEqual(RawEntryClass.tool_status, runtime.rawEntryClass(entry_id).?); try std.testing.expectEqualStrings("done\n", runtime.entries.items[0].raw_bytes.bytes);}
test "setRawEntryClass updates only matching raw entry" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const raw_id = try runtime.appendRawTranscriptEntry(alloc, "raw entry\n"); _ = try runtime.appendAssistantTurnEntry(alloc);
try std.testing.expect(runtime.setRawEntryClass(raw_id, .subagent_status)); try std.testing.expectEqual(RawEntryClass.subagent_status, runtime.rawEntryClass(raw_id).?); try std.testing.expect(!runtime.setRawEntryClass(999_999, .tool_status));}
test "streamAssistantChunk opens a new assistant_turn when there is no trailing one" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo()); const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10 } }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5);
const id = try runtime.streamAssistantChunk(alloc, &metrics, "first chunk");
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); try std.testing.expectEqual(id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings("first chunk", runtime.entries.items[0].assistant_turn.segments.text.items); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "first chunk") != null);}
test "streamAssistantChunk extends the trailing assistant_turn on subsequent chunks" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo()); const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10 } }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5);
const id_a = try runtime.streamAssistantChunk(alloc, &metrics, "alpha "); const id_b = try runtime.streamAssistantChunk(alloc, &metrics, "beta");
try std.testing.expectEqual(id_a, id_b); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); try std.testing.expectEqualStrings("alpha beta", runtime.entries.items[0].assistant_turn.segments.text.items);}
test "recorded assistant stream slow path preserves a canonical anchor when retention rewrites its source" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const old_prefix = "old retained prefix\n"; _ = try runtime.appendRawTranscriptEntryClassified( alloc, old_prefix, .subagent_status, ); const long_prompt = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_prompt); var metrics: Metrics = .{}; const user_id = try runtime.writeUserPromptCard( alloc, &metrics, .{ .text = long_prompt, .images = &.{} }, false, &.{}, );
var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime);
const chunk = "trimmed assistant tail"; runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime) + chunk.len - old_prefix.len; const assistant_id = try runtime.streamAssistantChunk(alloc, &metrics, chunk);
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); try std.testing.expect( transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes, ); try std.testing.expect(runtime.lookupAssistantSegments(assistant_id) != null); var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expect(!std.mem.startsWith( u8, appended_source.bytes, committed_source.bytes, )); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, appended_source.bytes, old_prefix), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "LONG_PASTE_LAST_MARKER"), ); try std.testing.expect(runtime.entries.items[0].id() == user_id);}
const AssistantStreamFastPathCase = enum { opening, continuation,};
const AssistantStreamFastPathFailureWitness = struct { target_failures: usize = 0,};
fn checkOrdinaryAssistantStreamAllocationFailures( alloc: Allocator, test_case: AssistantStreamFastPathCase, witness: *AssistantStreamFastPathFailureWitness,) !void { const continuation = [_]u8{'b'} ** 4096; const chunk: []const u8 = switch (test_case) { .opening => "first chunk", .continuation => &continuation, };
var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8) }; defer runtime.deinit(alloc); var metrics = Metrics{};
const existing_entry_id: ?u32 = switch (test_case) { .opening => null, .continuation => try runtime.streamAssistantChunk(alloc, &metrics, "a"), }; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const assistant_before = if (existing_entry_id) |entry_id| try std.testing.allocator.dupe( u8, runtime.lookupAssistantSegments(entry_id).?.text.items, ) else null; defer if (assistant_before) |text| std.testing.allocator.free(text); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const cache_origin_before = runtime.transcript_cache_origin_untrimmed; const repaint_count_before = runtime.render_requests.pendingReasonCount();
try std.testing.expect(retained_before <= runtime.max_retained_transcript_bytes); try std.testing.expect( chunk.len <= runtime.max_retained_transcript_bytes - retained_before, ); try std.testing.expect( chunk.len > runtime.transcript.capacity - runtime.transcript.items.len, ); if (existing_entry_id) |entry_id| { const segments = runtime.lookupAssistantSegments(entry_id).?; try std.testing.expect( chunk.len > segments.text.capacity - segments.text.items.len, ); } else { try std.testing.expectEqual(@as(usize, 0), runtime.entries.capacity); }
const entry_id = runtime.streamAssistantChunk(alloc, &metrics, chunk) catch |err| { witness.target_failures += 1; try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); if (existing_entry_id) |prior_entry_id| { try std.testing.expectEqualStrings( assistant_before.?, runtime.lookupAssistantSegments(prior_entry_id).?.text.items, ); } try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(cache_origin_before, runtime.transcript_cache_origin_untrimmed); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
const opened_new_turn = test_case == .opening; const expected_entry_id = existing_entry_id orelse next_entry_id_before; try std.testing.expectEqual(expected_entry_id, entry_id); try std.testing.expectEqual( next_entry_id_before +% @intFromBool(opened_new_turn), runtime.next_entry_id, ); try std.testing.expectEqual( entry_count_before + @intFromBool(opened_new_turn), runtime.entries.items.len, ); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id());
const assistant_text = runtime.entries.items[0].assistant_turn.segments.text.items; switch (test_case) { .opening => try std.testing.expectEqualStrings(chunk, assistant_text), .continuation => { try std.testing.expectEqual(@as(usize, 1) + chunk.len, assistant_text.len); try std.testing.expectEqualStrings("a", assistant_text[0..1]); try std.testing.expectEqualStrings(chunk, assistant_text[1..]); }, } try std.testing.expectEqualStrings(assistant_text, runtime.transcript.items); try std.testing.expectEqual( assistant_text.len, transcript_store.retainedStructuredBytes(&runtime), ); try std.testing.expectEqual(repaint_count_before + 1, runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "ordinary assistant stream admission is atomic across allocation failures" { var opening_witness = AssistantStreamFastPathFailureWitness{}; try std.testing.checkAllAllocationFailures( std.testing.allocator, checkOrdinaryAssistantStreamAllocationFailures, .{ .opening, &opening_witness }, ); try std.testing.expectEqual(@as(usize, 3), opening_witness.target_failures);
var continuation_witness = AssistantStreamFastPathFailureWitness{}; try std.testing.checkAllAllocationFailures( std.testing.allocator, checkOrdinaryAssistantStreamAllocationFailures, .{ .continuation, &continuation_witness }, ); try std.testing.expectEqual(@as(usize, 2), continuation_witness.target_failures);}
fn checkOpeningAssistantStreamAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8) }; defer runtime.deinit(alloc); var metrics = Metrics{};
try runtime.writeTranscript(alloc, &metrics, "older transcript row\n", true); const prompt = try alloc.dupe(u8, "prompt"); _ = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{} }); runtime.max_retained_transcript_bytes = "prompt".len + "first chunk".len; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const cache_origin_before = runtime.transcript_cache_origin_untrimmed; const repaint_count_before = runtime.render_requests.pendingReasonCount();
const entry_id = runtime.streamAssistantChunk( alloc, &metrics, "first chunk", ) catch |err| { try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(cache_origin_before, runtime.transcript_cache_origin_untrimmed); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
try std.testing.expectEqual(next_entry_id_before, entry_id); try std.testing.expectEqual(next_entry_id_before +% 1, runtime.next_entry_id); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .user_turn); try std.testing.expect(runtime.entries.items[1] == .assistant_turn); try std.testing.expectEqual(entry_id, runtime.entries.items[1].id()); try std.testing.expectEqualStrings( "first chunk", runtime.entries.items[1].assistant_turn.segments.text.items, ); try std.testing.expectEqual( runtime.max_retained_transcript_bytes, transcript_store.retainedStructuredBytes(&runtime), ); const rendered = try renderEntriesToBytes( std.testing.allocator, runtime.entries.items, runtime.layout.cols, ); defer std.testing.allocator.free(rendered); try std.testing.expectEqualStrings(rendered, runtime.transcript.items); try std.testing.expectEqual(repaint_count_before + 1, runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "opening a recorded assistant stream is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkOpeningAssistantStreamAllocationFailures, .{}, );}
fn checkExtendingAssistantStreamAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 12, 8) }; defer runtime.deinit(alloc); var metrics = Metrics{};
try runtime.writeTranscript(alloc, &metrics, "older transcript row\n", true); const entry_id = try runtime.streamAssistantChunk(alloc, &metrics, "alpha "); runtime.max_retained_transcript_bytes = "alpha beta".len; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const assistant_before = try std.testing.allocator.dupe( u8, runtime.lookupAssistantSegments(entry_id).?.text.items, ); defer std.testing.allocator.free(assistant_before); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const cache_origin_before = runtime.transcript_cache_origin_untrimmed; const repaint_count_before = runtime.render_requests.pendingReasonCount();
const continued_id = runtime.streamAssistantChunk( alloc, &metrics, "beta", ) catch |err| { try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); try std.testing.expectEqualStrings( assistant_before, runtime.lookupAssistantSegments(entry_id).?.text.items, ); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(cache_origin_before, runtime.transcript_cache_origin_untrimmed); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
try std.testing.expectEqual(entry_id, continued_id); try std.testing.expectEqual(entry_count_before - 1, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); try std.testing.expectEqual(entry_id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings( "alpha beta", runtime.entries.items[0].assistant_turn.segments.text.items, ); try std.testing.expectEqual( runtime.max_retained_transcript_bytes, transcript_store.retainedStructuredBytes(&runtime), ); const rendered = try renderEntriesToBytes( std.testing.allocator, runtime.entries.items, runtime.layout.cols, ); defer std.testing.allocator.free(rendered); try std.testing.expectEqualStrings(rendered, runtime.transcript.items); try std.testing.expectEqual(repaint_count_before + 1, runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "extending a recorded assistant stream is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkExtendingAssistantStreamAllocationFailures, .{}, );}
test "paced assistant continuations do not clone retained history per chunk" { const backing = std.testing.allocator; var counted = std.testing.FailingAllocator.init(backing, .{}); const alloc = counted.allocator(); var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 24, 20), .max_transcript_bytes = 4096, }; defer runtime.deinit(alloc); try runtime.initBacking(alloc);
for (0..48) |_| { _ = try runtime.appendRawTranscriptEntryClassified( alloc, "retained transcript history row\n", .subagent_status, ); }
var metrics = Metrics{}; const entry_id = try runtime.streamAssistantChunk(alloc, &metrics, "a"); const allocations_before = counted.allocations; for (0..256) |_| { try std.testing.expectEqual( entry_id, try runtime.streamAssistantChunk(alloc, &metrics, "b"), ); }
try std.testing.expect(counted.allocations - allocations_before <= 8); try std.testing.expectEqual(@as(usize, 49), runtime.entries.items.len); try std.testing.expectEqual(@as(usize, 257), runtime.lookupAssistantSegments(entry_id).?.text.items.len);}
test "streamAssistantChunk opens a new assistant_turn after a user_turn" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo()); const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10 } }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5);
_ = try runtime.streamAssistantChunk(alloc, &metrics, "assistant A"); const user_text = try alloc.dupe(u8, "next user prompt"); _ = try runtime.appendUserTurnOwned(alloc, .{ .text = user_text, .images = &.{} }); const id_after = try runtime.streamAssistantChunk(alloc, &metrics, "assistant B");
try std.testing.expectEqual(@as(usize, 3), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .assistant_turn); try std.testing.expect(runtime.entries.items[1] == .user_turn); try std.testing.expect(runtime.entries.items[2] == .assistant_turn); try std.testing.expectEqual(id_after, runtime.entries.items[2].id()); try std.testing.expectEqualStrings("assistant B", runtime.entries.items[2].assistant_turn.segments.text.items);}
test "appendUserTurnOwned frees text, images, and image slices when entries.append OOMs" { const base = std.testing.allocator; // Fail after all transferred slices exist, when the entries list first grows. var failing = std.testing.FailingAllocator.init(base, .{ .fail_index = 4 }); const alloc = failing.allocator();
var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const text = try alloc.dupe(u8, "prompt"); const images = try alloc.alloc(types.ImageAttachment, 1); images[0] = .{ .path = try alloc.dupe(u8, "/tmp/image.png"), .media_type = try alloc.dupe(u8, "image/png"), };
try std.testing.expectError( error.OutOfMemory, runtime.appendUserTurnOwned(alloc, .{ .text = text, .images = images }), );
try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len); try std.testing.expectEqual(failing.allocated_bytes, failing.freed_bytes);}
test "appendUserTurnOwnedWithSkillTokens stores selected skill metadata for reflow" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const prompt_text = "raw $review then $review"; const prompt = try alloc.dupe(u8, prompt_text); var handed_off = false; errdefer if (!handed_off) alloc.free(prompt);
const tokens = [_]input_visual_layout.SkillTokenSpan{.{ .raw_start = "raw $review then ".len, .raw_end = prompt_text.len, .name = "review", .path = "/tmp/review", }};
_ = try runtime.appendUserTurnOwnedWithSkillTokens(alloc, .{ .text = prompt, .images = &.{} }, &tokens); handed_off = true;
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items[0].user_turn.skill_tokens.len); try std.testing.expectEqualStrings("review", runtime.entries.items[0].user_turn.skill_tokens[0].name); try std.testing.expectEqual( @as(usize, prompt_text.len + "review".len + "/tmp/review".len), transcript_store.retainedStructuredBytes(&runtime), );
const rendered = try renderEntriesToBytes(alloc, runtime.entries.items, 80); defer alloc.free(rendered); try std.testing.expect(std.mem.find(u8, rendered, "$review then ") != null); try std.testing.expect(std.mem.find(u8, rendered, "\x1b[38;5;252mreview") != null); try std.testing.expect(std.mem.find(u8, rendered, "$review then $review") == null);}
const UserPromptCardAdmissionCase = enum { text_with_separator, image_with_skill_token,};
const prompt_card_skill_tokens = [_]input_visual_layout.SkillTokenSpan{.{ .raw_start = "inspect ".len, .raw_end = "inspect $review".len, .name = "review", .path = "/tmp/review",}};
fn setup_user_prompt_card_admission_runtime( runtime: *TranscriptRuntime, alloc: Allocator, test_case: UserPromptCardAdmissionCase,) !u32 { const seed_id = try runtime.appendRawTranscriptEntryClassified( alloc, "seed", .subagent_status, ); runtime.cursor_row = 2; runtime.cursor_col = switch (test_case) { .text_with_separator => 5, .image_with_skill_token => 1, }; runtime.replaceable_last_line = true; runtime.replaceable_start = 1; runtime.replaceable_row = 2; runtime.transcript_cache_origin_untrimmed = true; runtime.full_transcript.depth = .review; runtime.full_transcript.scroll_rows = 3; runtime.full_transcript.follow_tail = false; runtime.full_transcript.anchor_entry_id = seed_id; runtime.full_transcript.anchor_pending = true; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false; return seed_id;}
fn user_prompt_card_admission_input( test_case: UserPromptCardAdmissionCase, images: []types.ImageAttachment,) struct { user: types.UserTurn, skill_tokens: []const input_visual_layout.SkillTokenSpan, has_prior_turns: bool,} { return switch (test_case) { .text_with_separator => .{ .user = .{ .text = @constCast("plain prompt"), .images = &.{} }, .skill_tokens = &.{}, .has_prior_turns = false, }, .image_with_skill_token => .{ .user = .{ .text = @constCast("inspect $review"), .images = images }, .skill_tokens = &prompt_card_skill_tokens, .has_prior_turns = true, }, };}
fn check_user_prompt_card_admission_success( test_case: UserPromptCardAdmissionCase,) !void { const alloc = std.testing.allocator; const layout = transcriptTestLayout(48, 12, 8); var actual = TranscriptRuntime{ .layout = layout }; defer actual.deinit(alloc); const seed_id = try setup_user_prompt_card_admission_runtime(&actual, alloc, test_case);
var images = [_]types.ImageAttachment{.{ .id = 7, .path = @constCast("/tmp/prompt-card.png"), .media_type = @constCast("image/png"), }}; const input = user_prompt_card_admission_input(test_case, &images); const input_images_ptr = input.user.images.ptr; const card = try user_message_card.buildUserPromptCardWithSkillTokens( alloc, input.user.text, input.user.images, actual.layout.cols, input.skill_tokens, ); defer alloc.free(card); const separator = if (input.has_prior_turns) "" else "\n"; const expected_transcript = try std.fmt.allocPrint( alloc, "seed{s}{s}", .{ separator, card }, ); defer alloc.free(expected_transcript); const expected_reconstructed = try std.fmt.allocPrint( alloc, "seed\n\n{s}", .{card}, ); defer alloc.free(expected_reconstructed);
var actual_metrics = Metrics{}; const actual_id = try actual.writeUserPromptCard( alloc, &actual_metrics, input.user, input.has_prior_turns, input.skill_tokens, );
const expected_id = seed_id + @as(u32, if (input.has_prior_turns) 1 else 2); try std.testing.expectEqual(expected_id, actual_id); try std.testing.expectEqualStrings(expected_transcript, actual.transcript.items); try std.testing.expectEqual( @as(usize, if (input.has_prior_turns) 2 else 3), actual.entries.items.len, ); try std.testing.expectEqual(expected_id +% 1, actual.next_entry_id); var expected_cursor = TranscriptRuntime{ .layout = layout, .cursor_row = 2, .cursor_col = switch (test_case) { .text_with_separator => 5, .image_with_skill_token => 1, }, }; _ = expected_cursor.advanceCursor(expected_transcript["seed".len..]); try std.testing.expectEqual(expected_cursor.cursor_row, actual.cursor_row); try std.testing.expectEqual(expected_cursor.cursor_col, actual.cursor_col); try std.testing.expect(!actual.replaceable_last_line); try std.testing.expectEqual(@as(usize, 0), actual.replaceable_start); try std.testing.expectEqual(@as(u16, 2), actual.replaceable_row); try std.testing.expect(!actual.transcript_cache_origin_untrimmed); try std.testing.expect(actual.render_requests.hasReason(.transcript)); try std.testing.expectEqual(@as(usize, 1), actual.render_requests.pendingReasonCount()); try std.testing.expectEqual(@as(u32, 3), actual.full_transcript.scroll_rows); try std.testing.expect(!actual.full_transcript.follow_tail); try std.testing.expectEqual(@as(?u32, seed_id), actual.full_transcript.anchor_entry_id); try std.testing.expect(actual.full_transcript.anchor_pending);
const actual_reconstructed = try renderEntriesToBytes( alloc, actual.entries.items, actual.layout.cols, ); defer alloc.free(actual_reconstructed); try std.testing.expectEqualStrings(expected_reconstructed, actual_reconstructed); var expected_retained_bytes = "seed".len + separator.len + input.user.text.len; for (input.user.images) |image| { expected_retained_bytes += image.path.len + image.media_type.len; } for (input.skill_tokens) |token| { expected_retained_bytes += token.name.len + token.path.len; } try std.testing.expectEqual( expected_retained_bytes, transcript_store.retainedStructuredBytes(&actual), ); try std.testing.expectEqualStrings(input.user.text, actual.entries.items[actual.entries.items.len - 1].user_turn.turn.text); try std.testing.expectEqual(input_images_ptr, input.user.images.ptr);}
test "recorded user prompt card admission preserves immediate and reconstructive rendering" { try check_user_prompt_card_admission_success(.text_with_separator); try check_user_prompt_card_admission_success(.image_with_skill_token);}
test "recorded user prompt card admission preserves an authoritative committed anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 256, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 80); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, ); try std.testing.expect(!runtime.transcript_cache_origin_untrimmed);
var metrics = Metrics{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); const committed_offset = preparedVisualOffsetForTest(&committed_prepared); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, committed_offset, committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, committed_diagnostic.state, );
_ = try runtime.writeUserPromptCard( alloc, &metrics, .{ .text = @constCast("run the prepared two commands"), .images = &.{} }, true, &.{}, );
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expect(std.mem.startsWith( u8, appended_source.bytes, committed_source.bytes, )); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "LONG_PASTE_LAST_MARKER"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "run the prepared two commands"), ); const appended_flow = try alloc.dupe(u8, appended_source.bytes); defer alloc.free(appended_flow);
var appended_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer appended_prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&appended_prepared); try std.testing.expect(facts.source_compatible); try std.testing.expect(facts.semantic_rows > 0); try std.testing.expectEqual(committed_offset, facts.source_visual_offset);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, appended_prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &appended_source, &appended_prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); const settled_offset = transition.visual_offset; runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = !transition.document_append.isEmpty(), .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); const settled = runtime.transcriptCommitDiagnostic(); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, settled.state, ); try std.testing.expectEqual(settled_offset, settled.visual_offset); const projection = runtime.stableTranscriptProjectionForFlow( appended_flow, ) orelse return error.TestUnexpectedResult; try std.testing.expectEqual(settled_offset, projection.visual_offset);}
test "recorded user prompt card preserves a committed anchor after a non-prefix rewrite" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 10, 6), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
var metrics = Metrics{}; _ = try runtime.streamAssistantChunk( alloc, &metrics, "alpha beta gamma delta epsilon zeta eta theta", ); const committed_flow = try alloc.dupe(u8, runtime.transcript.items); defer alloc.free(committed_flow); try installStableAnchorForTest( &runtime, alloc, committed_flow, testSelection(0), 0, runtime.cursor_row, runtime.cursor_col, 1, );
_ = try runtime.appendSemanticNotice(alloc, .{ .topic = "response", .tone = .cancelled, .body = "Interrupted by user", }); var notice_source = try runtime.prepareTranscriptSource(alloc, null); defer notice_source.deinit(alloc); try std.testing.expect(!std.mem.startsWith( u8, notice_source.bytes, committed_flow, )); switch (runtime.transcript_commit_state) { .stable => |anchor| try std.testing.expect(anchor.normal_buffer_recovery_pending), .invalid, .recovering => return error.TestExpectedStableTranscript, }
_ = try runtime.writeUserPromptCard( alloc, &metrics, .{ .text = @constCast("queued prompt"), .images = &.{} }, true, &.{}, );
switch (runtime.transcript_commit_state) { .stable => |anchor| try std.testing.expect(anchor.normal_buffer_recovery_pending), .invalid, .recovering => return error.TestExpectedStableTranscript, } var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "queued prompt"), );}
test "recorded user prompt card preserves an anchor when retention prunes its source" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "anchored transcript\n", .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime);
const prompt = "retained prompt"; runtime.max_retained_transcript_bytes = prompt.len; var metrics = Metrics{}; _ = try runtime.writeUserPromptCard( alloc, &metrics, .{ .text = @constCast(prompt), .images = &.{} }, true, &.{}, );
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); var retained_source = try runtime.prepareTranscriptSource(alloc, null); defer retained_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, retained_source.bytes, "anchored transcript"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, retained_source.bytes, prompt), );}
test "recorded transcript append preserves an authoritative committed anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, );
var metrics = Metrics{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); const committed_offset = preparedVisualOffsetForTest(&committed_prepared); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, committed_offset, committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
const notice = "permission accepted\ncommand starting\n"; try runtime.writeTranscriptClassified( alloc, &metrics, notice, true, .subagent_status, );
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expect(std.mem.startsWith( u8, appended_source.bytes, committed_source.bytes, )); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "LONG_PASTE_FIRST_MARKER"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "LONG_PASTE_LAST_MARKER"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "permission accepted"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "command starting"), );
var appended_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer appended_prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&appended_prepared); try std.testing.expect(facts.source_compatible); try std.testing.expect(facts.semantic_rows > 0); try std.testing.expectEqual(committed_offset, facts.source_visual_offset);}
test "theme retint preserves a capped canonical anchor and visual geometry" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, ); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "\x1b[38;5;252mRETINT_THEME_MARKER\x1b[39m\n", .subagent_status, );
var metrics: Metrics = .{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
try runtime.retintEntriesForTheme(alloc, false, true);
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); var retinted_source = try runtime.prepareTranscriptSource(alloc, null); defer retinted_source.deinit(alloc); const first_marker = std.mem.find( u8, retinted_source.bytes, "LONG_PASTE_FIRST_MARKER", ) orelse return error.TestUnexpectedResult; const last_marker = std.mem.find( u8, retinted_source.bytes, "LONG_PASTE_LAST_MARKER", ) orelse return error.TestUnexpectedResult; const theme_marker = std.mem.find( u8, retinted_source.bytes, "RETINT_THEME_MARKER", ) orelse return error.TestUnexpectedResult; try std.testing.expect(first_marker < last_marker); try std.testing.expect(last_marker < theme_marker); try std.testing.expect(std.mem.find( u8, retinted_source.bytes, "\x1b[38;5;238mRETINT_THEME_MARKER", ) != null);
var retinted_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer retinted_prepared.deinit(alloc); try std.testing.expectEqualDeep( committed_prepared.selection, retinted_prepared.selection, ); try std.testing.expectEqualSlices( u16, committed_prepared.sourceVisualRows(), retinted_prepared.sourceVisualRows(), ); try std.testing.expectEqual( committed_prepared.cursor.cursor_row, retinted_prepared.cursor.cursor_row, ); try std.testing.expectEqual( committed_prepared.cursor.cursor_col, retinted_prepared.cursor.cursor_col, );
const retinted_diagnostic = runtime.transcriptCommitDiagnostic(); const retinted_bytes = try alloc.dupe(u8, retinted_source.bytes); defer alloc.free(retinted_bytes); try runtime.retintEntriesForTheme(alloc, true, true); var unchanged_source = try runtime.prepareTranscriptSource(alloc, null); defer unchanged_source.deinit(alloc); try std.testing.expectEqualStrings(retinted_bytes, unchanged_source.bytes); try std.testing.expectEqualDeep( retinted_diagnostic, runtime.transcriptCommitDiagnostic(), );}
test "light to dark theme retint preserves retention with equal-width tokens" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "OLDER_RETINT_ENTRY\n", .subagent_status, ); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "\x1b[38;5;238mRETINT_GROWTH_MARKER\x1b[39m\n", .subagent_status, ); runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, );
try runtime.retintEntriesForTheme(alloc, true, false);
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expect( transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes, ); var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expect(std.mem.find( u8, source.bytes, "\x1b[38;5;252mRETINT_GROWTH_MARKER", ) != null); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, source.bytes, "OLDER_RETINT_ENTRY"), );}
fn checkThemeRetintAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "ALLOCATION TRANSCRIPT 01\n" ++ "ALLOCATION TRANSCRIPT 02\n" ++ "ALLOCATION TRANSCRIPT 03\n" ++ "\x1b[38;5;252mRETINT ALLOCATION MARKER\x1b[39m\n", .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, );
var source_before = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_before.deinit(std.testing.allocator); const cache_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(cache_before); const diagnostic_before = runtime.transcriptCommitDiagnostic(); const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const pending_repaints_before = runtime.render_requests.pendingReasonCount(); const cache_origin_before = runtime.transcript_cache_origin_untrimmed;
runtime.retintEntriesForTheme(alloc, false, true) catch |err| { var source_after = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_after.deinit(std.testing.allocator); try std.testing.expectEqualStrings(source_before.bytes, source_after.bytes); try std.testing.expectEqualStrings(cache_before, runtime.transcript.items); try std.testing.expectEqualDeep( diagnostic_before, runtime.transcriptCommitDiagnostic(), ); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual( pending_repaints_before, runtime.render_requests.pendingReasonCount(), ); try std.testing.expectEqual( cache_origin_before, runtime.transcript_cache_origin_untrimmed, ); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
try std.testing.expectEqualDeep( diagnostic_before, runtime.transcriptCommitDiagnostic(), ); var retinted_source = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer retinted_source.deinit(std.testing.allocator); try std.testing.expect(std.mem.find( u8, retinted_source.bytes, "\x1b[38;5;238mRETINT ALLOCATION MARKER", ) != null);}
test "theme retint is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkThemeRetintAllocationFailures, .{}, );}
test "recorded transcript append preserves an anchor when retention prunes its source" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "anchored transcript\n", .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime);
const notice = "permission accepted\n"; runtime.max_retained_transcript_bytes = notice.len; var metrics = Metrics{}; try runtime.writeTranscriptClassified( alloc, &metrics, notice, true, .subagent_status, );
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); var retained_source = try runtime.prepareTranscriptSource(alloc, null); defer retained_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, retained_source.bytes, "anchored transcript"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, retained_source.bytes, "permission accepted"), );}
fn check_user_prompt_card_admission_allocation_failures( alloc: Allocator, test_case: UserPromptCardAdmissionCase,) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8) }; defer runtime.deinit(alloc); const seed_id = try setup_user_prompt_card_admission_runtime(&runtime, alloc, test_case);
var images = [_]types.ImageAttachment{.{ .id = 7, .path = @constCast("/tmp/prompt-card.png"), .media_type = @constCast("image/png"), }}; const input = user_prompt_card_admission_input(test_case, &images); const input_images_ptr = input.user.images.ptr; const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const reconstructed_before = try renderEntriesToBytes( std.testing.allocator, runtime.entries.items, runtime.layout.cols, ); defer std.testing.allocator.free(reconstructed_before); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const replaceable_before = runtime.replaceable_last_line; const replaceable_start_before = runtime.replaceable_start; const replaceable_row_before = runtime.replaceable_row; const cache_origin_before = runtime.transcript_cache_origin_untrimmed; const repaint_count_before = runtime.render_requests.pendingReasonCount(); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, runtime.cursor_row, runtime.cursor_col, 1, ); const commit_before = runtime.transcriptCommitDiagnostic(); const projection_before = runtime.stableTranscriptProjectionForFlow( committed_source.bytes, ) orelse return error.TestUnexpectedResult; const full_transcript_before = runtime.full_transcript; var metrics = Metrics{};
_ = runtime.writeUserPromptCard( alloc, &metrics, input.user, input.has_prior_turns, input.skill_tokens, ) catch |err| { try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(seed_id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); const reconstructed_after = try renderEntriesToBytes( std.testing.allocator, runtime.entries.items, runtime.layout.cols, ); defer std.testing.allocator.free(reconstructed_after); try std.testing.expectEqualStrings(reconstructed_before, reconstructed_after); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(replaceable_before, runtime.replaceable_last_line); try std.testing.expectEqual(replaceable_start_before, runtime.replaceable_start); try std.testing.expectEqual(replaceable_row_before, runtime.replaceable_row); try std.testing.expectEqual(cache_origin_before, runtime.transcript_cache_origin_untrimmed); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); try std.testing.expectEqualDeep(commit_before, runtime.transcriptCommitDiagnostic()); const projection_after = runtime.stableTranscriptProjectionForFlow( committed_source.bytes, ) orelse return error.TestUnexpectedResult; try std.testing.expectEqualDeep(projection_before, projection_after); try std.testing.expectEqual(full_transcript_before.scroll_rows, runtime.full_transcript.scroll_rows); try std.testing.expectEqual(full_transcript_before.follow_tail, runtime.full_transcript.follow_tail); try std.testing.expectEqual(full_transcript_before.anchor_entry_id, runtime.full_transcript.anchor_entry_id); try std.testing.expectEqual(full_transcript_before.anchor_pending, runtime.full_transcript.anchor_pending); try std.testing.expectEqualStrings(input.user.text, switch (test_case) { .text_with_separator => "plain prompt", .image_with_skill_token => "inspect $review", }); try std.testing.expectEqual(input_images_ptr, input.user.images.ptr); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expectEqual(repaint_count_before + 1, runtime.render_requests.pendingReasonCount()); try std.testing.expectEqualStrings(input.user.text, runtime.entries.items[runtime.entries.items.len - 1].user_turn.turn.text); try std.testing.expectEqual(input_images_ptr, input.user.images.ptr);}
test "recorded user prompt card admission is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, check_user_prompt_card_admission_allocation_failures, .{UserPromptCardAdmissionCase.text_with_separator}, ); try std.testing.checkAllAllocationFailures( std.testing.allocator, check_user_prompt_card_admission_allocation_failures, .{UserPromptCardAdmissionCase.image_with_skill_token}, );}
test "tailAssistantSegments returns trailing assistant or null" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
try std.testing.expect(runtime.tailAssistantSegments() == null);
const bytes = try alloc.dupe(u8, "banner"); _ = try runtime.appendRawBytesEntry(alloc, bytes); try std.testing.expect(runtime.tailAssistantSegments() == null);
const assistant_id = try runtime.appendAssistantTurnEntry(alloc); const segs = runtime.lookupAssistantSegments(assistant_id) orelse unreachable; try segs.text.appendSlice(alloc, "tok1"); const tail = runtime.tailAssistantSegments(); try std.testing.expect(tail != null); try std.testing.expectEqualStrings("tok1", tail.?.text.items);
const trailing = try alloc.dupe(u8, "later"); _ = try runtime.appendRawBytesEntry(alloc, trailing); try std.testing.expect(runtime.tailAssistantSegments() == null);}
test "lookupAssistantSegments resolves assistant ids and rejects others" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const prompt = try alloc.dupe(u8, "hello"); const user_id = try runtime.appendUserTurnOwned(alloc, .{ .text = prompt, .images = &.{} });
const assistant_id = try runtime.appendAssistantTurnEntry(alloc); const segs = runtime.lookupAssistantSegments(assistant_id) orelse unreachable; try segs.text.appendSlice(alloc, "tok");
const looked_up = runtime.lookupAssistantSegments(assistant_id); try std.testing.expect(looked_up != null); try std.testing.expectEqualStrings("tok", looked_up.?.text.items);
const raw = try alloc.dupe(u8, "banner"); const raw_id = try runtime.appendRawBytesEntry(alloc, raw); try std.testing.expect(runtime.lookupAssistantSegments(raw_id) == null);
try std.testing.expect(runtime.lookupAssistantSegments(user_id) == null);
try std.testing.expect(runtime.lookupAssistantSegments(std.math.maxInt(u32)) == null);}
test "clearTranscript drops entries but preserves next_entry_id" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const first = try alloc.dupe(u8, "first"); _ = try runtime.appendRawBytesEntry(alloc, first); const second = try alloc.dupe(u8, "second"); _ = try runtime.appendRawBytesEntry(alloc, second);
runtime.clearTranscript(alloc); try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len);
const after = try alloc.dupe(u8, "after-clear"); const id_after = try runtime.appendRawBytesEntry(alloc, after); try std.testing.expectEqual(@as(u32, 3), id_after);}
test "writeTranscript auto-mirrors a raw_bytes entry" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo()); const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10 } }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5); try runtime.writeTranscript(alloc, &metrics, "banner line\n", true);
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .raw_bytes); try std.testing.expectEqualStrings("banner line\n", runtime.entries.items[0].raw_bytes.bytes);}
test "writeTranscriptClassified records raw entry class" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc); var metrics = Metrics{};
try runtime.writeTranscriptClassified(alloc, &metrics, "cancelled\n", true, .question_resolution);
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(RawEntryClass.question_resolution, runtime.entries.items[0].raw_bytes.class);}
const RecordedWriteToolDetailFixture = struct { entry_id: u32, tool_name: []const u8, arguments_json: []const u8, result: []const u8, result_handle: []const u8, turn_id: u64, call_id: []const u8, command_output_entry_id: u32,};
fn appendRecordedWriteToolDetailFixture( runtime: *TranscriptRuntime, alloc: Allocator, fixture: RecordedWriteToolDetailFixture,) !void { var detail: ToolDetailRecord = .{ .entry_id = fixture.entry_id, .tool_name = try alloc.dupe(u8, fixture.tool_name), }; errdefer detail.deinit(alloc); detail.arguments_json = try alloc.dupe(u8, fixture.arguments_json); detail.result = try alloc.dupe(u8, fixture.result); detail.result_handle = try alloc.dupe(u8, fixture.result_handle); detail.outcome = .completed; const lifecycle_call_id = try alloc.dupe(u8, fixture.call_id); detail.lifecycle_id = .{ .turn_id = fixture.turn_id, .call_id = lifecycle_call_id, }; detail.command_output_entry_id = fixture.command_output_entry_id; try runtime.tool_details.append(alloc, detail);}
fn expectRecordedWriteToolDetailFixture( runtime: *const TranscriptRuntime, fixture: RecordedWriteToolDetailFixture,) !void { const detail = runtime.toolDetailForEntry(fixture.entry_id); try std.testing.expect(detail != null); try std.testing.expectEqualStrings(fixture.tool_name, detail.?.tool_name); try std.testing.expectEqualStrings(fixture.arguments_json, detail.?.arguments_json.?); try std.testing.expectEqualStrings(fixture.result, detail.?.result.?); try std.testing.expectEqualStrings(fixture.result_handle, detail.?.result_handle.?); try std.testing.expectEqual(types.ToolOutcomeKind.completed, detail.?.outcome.?); try std.testing.expectEqual(fixture.turn_id, detail.?.lifecycle_id.?.turn_id); try std.testing.expectEqualStrings(fixture.call_id, detail.?.lifecycle_id.?.call_id); try std.testing.expectEqual(fixture.command_output_entry_id, detail.?.command_output_entry_id.?);}
fn appendOwnedToolDetail( runtime: *TranscriptRuntime, alloc: Allocator, entry_id: u32, tool_name: []const u8,) !void { var detail: ToolDetailRecord = .{ .entry_id = entry_id, .tool_name = try alloc.dupe(u8, tool_name), }; errdefer detail.deinit(alloc); try runtime.tool_details.append(alloc, detail);}
test "historical tool detail insertion preserves entry id order" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
for ([_]u32{ 30, 10, 20 }) |entry_id| { try runtime.attachHistoricalToolDetail( alloc, entry_id, .{ .id = "call", .name = "read_file", .arguments_json = "{}", }, .read, .{ .tool_call_id = @constCast("call"), .tool_name = @constCast("read_file"), .status = .success, .output = @constCast("result"), .output_bytes = 6, .stored_output_bytes = 6, }, ); }
try std.testing.expectEqual(@as(usize, 3), runtime.tool_details.items.len); try std.testing.expectEqual(@as(u32, 10), runtime.tool_details.items[0].entry_id); try std.testing.expectEqual(@as(u32, 20), runtime.tool_details.items[1].entry_id); try std.testing.expectEqual(@as(u32, 30), runtime.tool_details.items[2].entry_id); try std.testing.expect(runtime.toolDetailForEntry(9) == null); try std.testing.expectEqual(@as(u32, 10), runtime.toolDetailForEntry(10).?.entry_id); try std.testing.expectEqual(@as(u32, 20), runtime.toolDetailForEntry(20).?.entry_id); try std.testing.expectEqual(@as(u32, 30), runtime.toolDetailForEntry(30).?.entry_id); try std.testing.expect(runtime.toolDetailForEntry(31) == null);
try runtime.attachHistoricalToolDetail( alloc, 20, .{ .id = "updated-call", .name = "list_files", .arguments_json = "{\"path\":\"src\"}", }, .list, .{ .tool_call_id = @constCast("updated-call"), .tool_name = @constCast("list_files"), .status = .success, .output = @constCast("updated result"), .output_bytes = 14, .stored_output_bytes = 14, }, ); try std.testing.expectEqual(@as(usize, 3), runtime.tool_details.items.len); const updated = runtime.toolDetailForEntry(20).?; try std.testing.expectEqualStrings("list_files", updated.tool_name); try std.testing.expectEqualStrings("{\"path\":\"src\"}", updated.arguments_json.?); try std.testing.expectEqualStrings("updated result", updated.result.?);}
test "tool detail pruning preserves retained payload order and capacity" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
try appendOwnedToolDetail(&runtime, alloc, 1, "first"); try appendOwnedToolDetail(&runtime, alloc, 2, "second"); try appendOwnedToolDetail(&runtime, alloc, 3, "third"); try appendOwnedToolDetail(&runtime, alloc, 4, "fourth"); try appendOwnedToolDetail(&runtime, alloc, 5, "fifth"); const initial_capacity = runtime.tool_details.capacity;
var retained_entry_ids: transcript_store.EntryIdSet = .empty; defer retained_entry_ids.deinit(alloc); try retained_entry_ids.put(alloc, 2, {}); try retained_entry_ids.put(alloc, 4, {});
runtime.pruneToolDetailsForRetainedEntries(alloc, &retained_entry_ids);
try std.testing.expectEqual(@as(usize, 2), runtime.tool_details.items.len); try std.testing.expectEqual(initial_capacity, runtime.tool_details.capacity); try std.testing.expectEqual(@as(u32, 2), runtime.tool_details.items[0].entry_id); try std.testing.expectEqualStrings("second", runtime.tool_details.items[0].tool_name); try std.testing.expectEqual(@as(u32, 4), runtime.tool_details.items[1].entry_id); try std.testing.expectEqualStrings("fourth", runtime.tool_details.items[1].tool_name);}
test "tool detail pruning stays bounded at fifty thousand records" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const detail_count = 50_000; try runtime.tool_details.ensureTotalCapacity(alloc, detail_count);
var retained_entry_ids: transcript_store.EntryIdSet = .empty; defer retained_entry_ids.deinit(alloc); try retained_entry_ids.ensureTotalCapacity(alloc, detail_count / 2);
for (0..detail_count) |index| { const entry_id: u32 = @intCast(index + 1); try appendOwnedToolDetail(&runtime, alloc, entry_id, "read_file"); if (index % 2 == 0) { retained_entry_ids.putAssumeCapacity(entry_id, {}); } }
const lookup_started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); for (0..detail_count) |index| { const entry_id: u32 = @intCast(index + 1); try std.testing.expect(runtime.toolDetailForEntry(entry_id) != null); } try std.testing.expect(runtime.toolDetailForEntry( @as(u32, @intCast(detail_count + 1)), ) == null); const lookup_elapsed_ms = lookup_started.durationTo( std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), ).raw.toMilliseconds(); try std.testing.expect(lookup_elapsed_ms < 1_000);
const started = std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake); runtime.pruneToolDetailsForRetainedEntries(alloc, &retained_entry_ids); const elapsed_ms = started.durationTo( std.Io.Clock.Timestamp.now(io_mod.getIo(), .awake), ).raw.toMilliseconds();
try std.testing.expect(elapsed_ms < 1_000); try std.testing.expectEqual(detail_count / 2, runtime.tool_details.items.len); for (runtime.tool_details.items, 0..) |detail, index| { try std.testing.expectEqual(@as(u32, @intCast(index * 2 + 1)), detail.entry_id); try std.testing.expectEqualStrings("read_file", detail.tool_name); }}
const RecordedWriteCommandOutputFixture = struct { entry_id: u32, turn_id: u64, call_id: []const u8, line: []const u8,};
fn appendRecordedWriteCommandOutputFixture( runtime: *TranscriptRuntime, alloc: Allocator, fixture: RecordedWriteCommandOutputFixture,) !void { const Block = @TypeOf(runtime.command_output_blocks.items[0]); var block: Block = .{ .entry_id = fixture.entry_id, .lifecycle_id = .{ .turn_id = fixture.turn_id, .call_id = try alloc.dupe(u8, fixture.call_id), }, }; errdefer block.deinit(alloc); const line = try alloc.dupe(u8, fixture.line); block.lines.append(alloc, .{ .stream = .stdout, .text = line, }) catch |err| { alloc.free(line); return err; }; block.total_lines = 1; block.retained_text_bytes = line.len; try runtime.command_output_blocks.append(alloc, block);}
fn expectRecordedWriteCommandOutputFixture( runtime: *const TranscriptRuntime, fixture: RecordedWriteCommandOutputFixture,) !void { try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(fixture.entry_id, block.entry_id.?); try std.testing.expect(block.lifecycle_id != null); try std.testing.expectEqual(fixture.turn_id, block.lifecycle_id.?.turn_id); try std.testing.expectEqualStrings(fixture.call_id, block.lifecycle_id.?.call_id); try std.testing.expectEqual(@as(usize, 1), block.lines.items.len); try std.testing.expectEqual(command_output_content.Stream.stdout, block.lines.items[0].stream); try std.testing.expectEqualStrings(fixture.line, block.lines.items[0].text);}
test "command output retention preserves its artifact detail owner" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .max_retained_transcript_bytes = 128 }; defer runtime.deinit(alloc);
const detail_entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, "● Ran command\n", .tool_status, ); const command_entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, "│ ... command lines folded\n", .command_output, ); const detail: RecordedWriteToolDetailFixture = .{ .entry_id = detail_entry_id, .tool_name = "run_command", .arguments_json = "{\"command\":\"generate output\"}", .result = "output_file=/tmp/fx-command-retained.log\n", .result_handle = "result-run-command.txt", .turn_id = 1, .call_id = "retained-command", .command_output_entry_id = command_entry_id, }; try appendRecordedWriteToolDetailFixture(&runtime, alloc, detail); try appendRecordedWriteCommandOutputFixture(&runtime, alloc, .{ .entry_id = command_entry_id, .turn_id = 1, .call_id = "retained-command", .line = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", }); runtime.command_output_blocks.items[0].total_lines = 2;
try transcript_store.enforceStructuredRetention(&runtime, alloc, command_entry_id);
try std.testing.expect(runtime.toolDetailForEntry(detail_entry_id) != null); try std.testing.expect(runtime.rawEntryClass(detail_entry_id) == .tool_status); try std.testing.expect(runtime.rawEntryClass(command_entry_id) == .command_output); try std.testing.expectEqual(@as(usize, 2), runtime.command_output_blocks.items[0].total_lines); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items[0].retained_text_bytes); try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes);}
fn checkRecordedTranscriptWriteAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, .viewport_top_row = 1, .cursor_row = 2, .cursor_col = 4, .max_transcript_bytes = 8, .max_retained_transcript_bytes = 19 + @sizeOf(command_output_runtime.CommandOutputLine), .command_output_render = .{}, }; defer runtime.deinit(alloc);
const existing_id = try runtime.appendRawTranscriptEntryClassified( alloc, "old\n", .subagent_status, ); const replaceable_id = try runtime.appendRawTranscriptEntryClassified( alloc, "tail\n", .subagent_status, ); const pruned_detail: RecordedWriteToolDetailFixture = .{ .entry_id = existing_id, .tool_name = "read_file", .arguments_json = "{\"path\":\"old\"}", .result = "old result", .result_handle = "old-result.txt", .turn_id = 1, .call_id = "call-old", .command_output_entry_id = existing_id, }; const retained_detail: RecordedWriteToolDetailFixture = .{ .entry_id = replaceable_id, .tool_name = "write_file", .arguments_json = "{\"path\":\"tail\"}", .result = "tail result", .result_handle = "tail-result.txt", .turn_id = 2, .call_id = "call-tail", .command_output_entry_id = replaceable_id, }; const retained_command_output: RecordedWriteCommandOutputFixture = .{ .entry_id = replaceable_id, .turn_id = 3, .call_id = "call-command-tail", .line = "x", }; try appendRecordedWriteToolDetailFixture(&runtime, alloc, pruned_detail); try appendRecordedWriteToolDetailFixture(&runtime, alloc, retained_detail); try appendRecordedWriteCommandOutputFixture(&runtime, alloc, retained_command_output); runtime.cursor_row = 2; runtime.cursor_col = 4; runtime.replaceable_last_line = true; runtime.replaceable_start = 0; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const replaceable_before = runtime.replaceable_last_line; const replaceable_start_before = runtime.replaceable_start; const repaint_count_before = runtime.render_requests.pendingReasonCount(); const transcript_before = "tail\n"; try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items);
var metrics = Metrics{}; const entry_id = transcript_writer.writeTranscriptReturningEntryIdClassified( &runtime, alloc, &metrics, "first\nsecond\n", true, .question_resolution, ) catch |err| { try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(existing_id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings("old\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expectEqual(replaceable_id, runtime.entries.items[1].id()); try std.testing.expectEqualStrings("tail\n", runtime.entries.items[1].raw_bytes.bytes); try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(replaceable_before, runtime.replaceable_last_line); try std.testing.expectEqual(replaceable_start_before, runtime.replaceable_start); try std.testing.expectEqual(@as(usize, 2), runtime.tool_details.items.len); try expectRecordedWriteToolDetailFixture(&runtime, pruned_detail); try expectRecordedWriteToolDetailFixture(&runtime, retained_detail); try expectRecordedWriteCommandOutputFixture(&runtime, retained_command_output); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return err; };
try std.testing.expectEqual(@as(u32, 3), entry_id); try std.testing.expectEqual(@as(u32, 4), runtime.next_entry_id); try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expectEqual(replaceable_id, runtime.entries.items[0].id()); try std.testing.expectEqual(entry_id, runtime.entries.items[1].id()); try std.testing.expectEqual(RawEntryClass.question_resolution, runtime.entries.items[1].raw_bytes.class); try std.testing.expectEqualStrings("first\nsecond\n", runtime.entries.items[1].raw_bytes.bytes); try std.testing.expectEqualStrings("second\n", runtime.transcript.items); try std.testing.expect(!runtime.replaceable_last_line); try std.testing.expectEqual(@as(usize, 0), runtime.replaceable_start); try std.testing.expectEqual(@as(usize, 1), runtime.tool_details.items.len); try std.testing.expect(runtime.toolDetailForEntry(existing_id) == null); try expectRecordedWriteToolDetailFixture(&runtime, retained_detail); try expectRecordedWriteCommandOutputFixture(&runtime, retained_command_output); try std.testing.expectEqual(@as(usize, 1), runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "recorded transcript write is atomic across entry cache and retention allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkRecordedTranscriptWriteAllocationFailures, .{}, );}
test "context notices stay canonical and ordered across compact and full projections" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 24, 20) }; defer runtime.deinit(alloc); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "context", .tone = .warning, .body = "context-first", .visibility = .full_only, }); try std.testing.expectEqualStrings("", runtime.transcript.items); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "system", .tone = .information, .body = "ordinary-system", }); const compact_before_open = try alloc.dupe(u8, runtime.transcript.items); defer alloc.free(compact_before_open); try std.testing.expect(std.mem.find(u8, compact_before_open, "context-first") == null); try std.testing.expect(std.mem.find(u8, compact_before_open, "ordinary-system") != null);
try std.testing.expect(try runtime.setTranscriptPresentationDepth(alloc, .review)); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "context", .tone = .warning, .body = "context-second", .visibility = .full_only, }); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "system", .tone = .@"error", .body = "ordinary-error", }); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "context-first") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "context-second") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "ordinary-system") != null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "ordinary-error") != null); const compact_while_open = try alloc.dupe(u8, runtime.transcript.items); defer alloc.free(compact_while_open);
try std.testing.expectEqual(@as(usize, 4), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .semantic_notice); try std.testing.expectEqual(types.NoticeVisibility.full_only, runtime.entries.items[0].semantic_notice.visibility); try std.testing.expectEqualStrings("context-first", runtime.entries.items[0].semantic_notice.body); try std.testing.expect(runtime.entries.items[1] == .semantic_notice); try std.testing.expectEqual(types.NoticeVisibility.compact_and_full, runtime.entries.items[1].semantic_notice.visibility); try std.testing.expectEqualStrings("ordinary-system", runtime.entries.items[1].semantic_notice.body); try std.testing.expect(runtime.entries.items[2] == .semantic_notice); try std.testing.expectEqual(types.NoticeVisibility.full_only, runtime.entries.items[2].semantic_notice.visibility); try std.testing.expectEqualStrings("context-second", runtime.entries.items[2].semantic_notice.body); try std.testing.expect(runtime.entries.items[3] == .semantic_notice); try std.testing.expectEqual(types.NoticeTone.@"error", runtime.entries.items[3].semantic_notice.tone);
var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const full = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 64, 0, null, ); defer alloc.free(full); const first_pos = std.mem.find(u8, full, "context-first") orelse return error.MissingFirstContextNotice; const system_pos = std.mem.find(u8, full, "ordinary-system") orelse return error.MissingOrdinarySystemNotice; const second_pos = std.mem.find(u8, full, "context-second") orelse return error.MissingSecondContextNotice; const error_pos = std.mem.find(u8, full, "ordinary-error") orelse return error.MissingOrdinaryErrorNotice; try std.testing.expect(first_pos < system_pos); try std.testing.expect(system_pos < second_pos); try std.testing.expect(second_pos < error_pos);
try std.testing.expect(try runtime.setTranscriptPresentationDepth(alloc, .inline_mode)); try std.testing.expect(!runtime.fullTranscriptActive()); try std.testing.expectEqualStrings(compact_while_open, runtime.transcript.items); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "context-first") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "context-second") == null);}
fn checkContextNoticeAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 12, 8) }; defer runtime.deinit(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "visible-before\n", .subagent_status, ); runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false;
const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; _ = transcript_store.appendSemanticNoticeAtomic( &runtime, alloc, .{ .topic = "context", .tone = .warning, .body = "hidden-context", .visibility = .full_only, }, ) catch |err| { try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(RawEntryClass.subagent_status, runtime.entries.items[0].raw_bytes.class); try std.testing.expectEqualStrings("visible-before\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expectEqualStrings("visible-before\n", runtime.transcript.items); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return err; };
try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[1] == .semantic_notice); try std.testing.expectEqualStrings("context", runtime.entries.items[1].semantic_notice.topic); try std.testing.expectEqualStrings("hidden-context", runtime.entries.items[1].semantic_notice.body); try std.testing.expectEqual(types.NoticeVisibility.full_only, runtime.entries.items[1].semantic_notice.visibility); try std.testing.expectEqualStrings("visible-before\n", runtime.transcript.items); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "context notice admission is atomic across entry cache and retention allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkContextNoticeAllocationFailures, .{}, );}
test "repeated recorded mutations keep tool detail capacity bounded" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8) }; defer runtime.deinit(alloc);
const fixture: RecordedWriteToolDetailFixture = .{ .entry_id = 1, .tool_name = "run_command", .arguments_json = "{\"command\":\"pwd\"}", .result = "workspace", .result_handle = "command-output.txt", .turn_id = 1, .call_id = "bounded-tool-detail", .command_output_entry_id = 1, }; try appendRecordedWriteToolDetailFixture(&runtime, alloc, fixture); const initial_capacity = runtime.tool_details.capacity; var metrics = Metrics{};
for (0..4) |_| { try runtime.writeTranscriptClassified( alloc, &metrics, "recorded\n", true, .subagent_status, ); }
try std.testing.expect(runtime.tool_details.capacity <= initial_capacity); try expectRecordedWriteToolDetailFixture(&runtime, fixture);}
const RecordedCommandOutputAtomicFixture = struct { lifecycle_id: types.ToolLifecycleId, status_entry_id: u32,};
fn setupRecordedCommandOutputAtomicFixture( runtime: *TranscriptRuntime, alloc: Allocator,) !RecordedCommandOutputAtomicFixture { const lifecycle_id = types.ToolLifecycleId{ .turn_id = 71, .call_id = "atomic-command-output", }; _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycle_id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"printf atomic\"}", } }); const status_entry_id = runtime.toolActivityRecord(lifecycle_id).?.entry_id; runtime.full_transcript.depth = .review; runtime.full_transcript.scroll_rows = 3; runtime.full_transcript.follow_tail = false; runtime.full_transcript.anchor_entry_id = status_entry_id; runtime.full_transcript.anchor_pending = true; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false; return .{ .lifecycle_id = lifecycle_id, .status_entry_id = status_entry_id, };}
fn expectRecordedCommandOutputAnchor( runtime: *const TranscriptRuntime, entry_id: u32,) !void { try std.testing.expect(runtime.full_transcript.depth.active()); try std.testing.expectEqual(@as(u32, 3), runtime.full_transcript.scroll_rows); try std.testing.expect(!runtime.full_transcript.follow_tail); try std.testing.expectEqual(entry_id, runtime.full_transcript.anchor_entry_id.?); try std.testing.expect(runtime.full_transcript.anchor_pending);}
test "visible recorded command output preserves a capped canonical anchor without pruning" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const status_entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "canonical command status prefix extends beyond the capped cache\nretained status tail\n", ); var metrics: Metrics = .{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
const styles = commandOutputAnsiTestStyles(); const retained_before = transcript_store.retainedStructuredBytes(&runtime); runtime.max_retained_transcript_bytes = retained_before + 512;
try runtime.writeCommandOutputChunk( alloc, &metrics, styles, .stdout, "visible\n", true, );
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expectEqual(status_entry_id, runtime.entries.items[0].id()); try std.testing.expect(runtime.entries.items[0].raw_bytes.lifecycle_pinned); try std.testing.expectEqual(RawEntryClass.command_output, runtime.entries.items[1].raw_bytes.class); try std.testing.expectEqualStrings( "\x1b[2m│ visible\x1b[0m", runtime.entries.items[1].raw_bytes.bytes, ); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(@as(usize, 1), block.total_lines); try std.testing.expectEqual(@as(usize, 1), block.lines.items.len); try std.testing.expectEqual(@as(usize, 1), block.live_entry_ids.items.len); try std.testing.expectEqual(runtime.entries.items[1].id(), block.live_entry_ids.items[0]); try std.testing.expect( transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes, ); var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expect(std.mem.startsWith( u8, appended_source.bytes, committed_source.bytes, ));}
test "visible recorded command output survives consolidation" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc);
const fixture = try setupRecordedCommandOutputAtomicFixture(&runtime, alloc); var metrics: Metrics = .{}; const styles = commandOutputAnsiTestStyles(); const retained_before = transcript_store.retainedStructuredBytes(&runtime); runtime.max_retained_transcript_bytes = retained_before + 512;
try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "visible\n", true, ); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].lines.items.len); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items[0].live_entry_ids.items.len); const live_entry_id = runtime.command_output_blocks.items[0].live_entry_ids.items[0]; runtime.full_transcript.anchor_entry_id = live_entry_id;
try runtime.flushCommandOutputSummaryForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, true, );
const block = runtime.command_output_blocks.items[0]; try std.testing.expectEqual(@as(usize, 0), block.live_entry_ids.items.len); try std.testing.expectEqualSlices(u32, &.{live_entry_id}, block.source_entry_ids.items); try std.testing.expectEqual(live_entry_id, block.entry_id.?); try std.testing.expectEqual( live_entry_id, runtime.toolDetailForEntry(fixture.status_entry_id).?.command_output_entry_id.?, ); try std.testing.expectEqual(live_entry_id, runtime.fullTranscriptAnchorEntryId().?);
var consolidated_source = try runtime.prepareTranscriptSource(alloc, null); defer consolidated_source.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, consolidated_source.bytes, "visible"));
runtime.setCommandOutputRenderPolicy(styles); _ = try command_output_runtime.syncCommandOutputBlockEntries(&runtime, alloc); var synchronized_source = try runtime.prepareTranscriptSource(alloc, null); defer synchronized_source.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, synchronized_source.bytes, "visible"));
var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const projected = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 32, 0, null, ); defer alloc.free(projected); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, projected, "visible")); try std.testing.expect((try full_transcript_screen.measureProjectionInterruptible( alloc, &projection, null, runtime.layout.cols, null, )).anchor_row != null);}
test "retention capped command output retargets a missing source anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const missing_entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, "│ pruned\n", .command_output, ); const retained_entry_id = try runtime.appendRawTranscriptEntryClassified( alloc, "│ retained\n", .command_output, ); try runtime.command_output_blocks.append(alloc, .{ .total_lines = 2 }); try runtime.command_output_blocks.items[0].live_entry_ids.append(alloc, missing_entry_id); try runtime.command_output_blocks.items[0].live_entry_ids.append(alloc, retained_entry_id); runtime.command_output_display.open_command_block = 0; runtime.full_transcript.depth = .review; runtime.full_transcript.anchor_entry_id = missing_entry_id; try removeRawEntriesForTest(&runtime, alloc, &.{missing_entry_id});
var metrics: Metrics = .{}; const styles = commandOutputAnsiTestStyles(); try runtime.flushCommandOutputSummary(alloc, &metrics, styles, true);
try std.testing.expectEqual(retained_entry_id, runtime.command_output_blocks.items[0].entry_id.?); try std.testing.expectEqual(retained_entry_id, runtime.fullTranscriptAnchorEntryId().?); var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const measurement = try full_transcript_screen.measureProjectionInterruptible( alloc, &projection, null, runtime.layout.cols, null, ); try std.testing.expect(measurement.anchor_row != null);}
fn checkVisibleRecordedCommandOutputAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); const fixture = try setupRecordedCommandOutputAtomicFixture(&runtime, alloc);
const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const repaint_count_before = runtime.render_requests.pendingReasonCount(); var metrics = Metrics{}; const styles = commandOutputAnsiTestStyles();
runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "visible\n", true, ) catch |err| { try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(@as(usize, 0), runtime.command_output_blocks.items.len); try std.testing.expect(runtime.command_output_display.open_command_block == null); try std.testing.expectEqualDeep(command_output_runtime.CommandOutputRenderPolicy{}, runtime.command_output_render); try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expect(runtime.toolDetailForEntry(fixture.status_entry_id).?.command_output_entry_id == null); try expectRecordedCommandOutputAnchor(&runtime, fixture.status_entry_id); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
try std.testing.expectEqual(entry_count_before + 1, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before +% 1, runtime.next_entry_id); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); const block = runtime.command_output_blocks.items[0]; try std.testing.expect(command_output_runtime.sameLifecycleId(block.lifecycle_id, fixture.lifecycle_id)); try std.testing.expectEqual(@as(usize, 1), block.lines.items.len); try std.testing.expectEqual(command_output_content.Stream.stdout, block.lines.items[0].stream); try std.testing.expectEqualStrings("visible", block.lines.items[0].text); try std.testing.expectEqual(@as(usize, 1), block.live_entry_ids.items.len); try std.testing.expectEqual(runtime.entries.items[entry_count_before].id(), block.live_entry_ids.items[0]); try std.testing.expectEqual(RawEntryClass.command_output, runtime.entries.items[entry_count_before].raw_bytes.class); try std.testing.expectEqualStrings("\x1b[2m│ visible\x1b[0m", runtime.entries.items[entry_count_before].raw_bytes.bytes); try std.testing.expectEqualDeep(styles, runtime.command_output_render.styles); try std.testing.expectEqual(@as(?usize, 0), runtime.command_output_display.open_command_block); try std.testing.expect(runtime.toolDetailForEntry(fixture.status_entry_id).?.command_output_entry_id == null); try expectRecordedCommandOutputAnchor(&runtime, fixture.status_entry_id); try std.testing.expectEqual(@as(usize, 1), runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "visible recorded command output admission is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkVisibleRecordedCommandOutputAllocationFailures, .{}, );}
fn checkRecordedCommandOutputConsolidationAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8), .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); const fixture = try setupRecordedCommandOutputAtomicFixture(&runtime, alloc); var metrics = Metrics{}; const styles = commandOutputAnsiTestStyles();
runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "one\n", true, ) catch |err| return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stderr, "two\n", true, ) catch |err| return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, };
const first_live_entry_id = runtime.command_output_blocks.items[0].live_entry_ids.items[0]; runtime.full_transcript.anchor_entry_id = first_live_entry_id; runtime.render_requests.clearReason(.transcript); runtime.transcript_band_dirty = false; const rendered_before = try renderEntriesToBytes(std.testing.allocator, runtime.entries.items, 80); defer std.testing.allocator.free(rendered_before); const transcript_before = try std.testing.allocator.dupe(u8, runtime.transcript.items); defer std.testing.allocator.free(transcript_before); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const cursor_row_before = runtime.cursor_row; const cursor_col_before = runtime.cursor_col; const retained_before = transcript_store.retainedStructuredBytes(&runtime); const repaint_count_before = runtime.render_requests.pendingReasonCount();
runtime.flushCommandOutputSummaryForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, true, ) catch |err| { const rendered_after_failure = try renderEntriesToBytes( std.testing.allocator, runtime.entries.items, 80, ); defer std.testing.allocator.free(rendered_after_failure); try std.testing.expectEqualStrings(rendered_before, rendered_after_failure); try std.testing.expectEqualStrings(transcript_before, runtime.transcript.items); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(cursor_row_before, runtime.cursor_row); try std.testing.expectEqual(cursor_col_before, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); const block = runtime.command_output_blocks.items[0]; try std.testing.expect(block.entry_id == null); try std.testing.expectEqual(@as(usize, 2), block.live_entry_ids.items.len); try std.testing.expectEqual(@as(usize, 0), block.source_entry_ids.items.len); try std.testing.expectEqual(@as(?usize, 0), runtime.command_output_display.open_command_block); try std.testing.expect(runtime.toolDetailForEntry(fixture.status_entry_id).?.command_output_entry_id == null); try expectRecordedCommandOutputAnchor(&runtime, first_live_entry_id); try std.testing.expectEqual(repaint_count_before, runtime.render_requests.pendingReasonCount()); try std.testing.expect(!runtime.render_requests.hasReason(.transcript)); try std.testing.expect(!runtime.transcript_band_dirty); return switch (err) { error.WriteFailed => error.OutOfMemory, else => err, }; };
const rendered_after = try renderEntriesToBytes(std.testing.allocator, runtime.entries.items, 80); defer std.testing.allocator.free(rendered_after); try std.testing.expectEqualStrings(rendered_before, rendered_after); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, runtime.transcript.items, "one")); try std.testing.expectEqual(@as(usize, 1), std.mem.count(u8, runtime.transcript.items, "two")); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); const cursor_row_after = runtime.cursor_row; const cursor_col_after = runtime.cursor_col; runtime.recomputeCursorFromTranscript(); try std.testing.expectEqual(cursor_row_after, runtime.cursor_row); try std.testing.expectEqual(cursor_col_after, runtime.cursor_col); try std.testing.expectEqual(retained_before, transcript_store.retainedStructuredBytes(&runtime)); try std.testing.expectEqual(@as(usize, 1), runtime.command_output_blocks.items.len); const block = runtime.command_output_blocks.items[0]; try std.testing.expect(block.entry_id != null); try std.testing.expectEqual(@as(usize, 0), block.live_entry_ids.items.len); try std.testing.expectEqual(@as(usize, 2), block.source_entry_ids.items.len); try std.testing.expect(runtime.command_output_display.open_command_block == null); try std.testing.expectEqual(block.entry_id, runtime.toolDetailForEntry(fixture.status_entry_id).?.command_output_entry_id); try expectRecordedCommandOutputAnchor(&runtime, first_live_entry_id); try std.testing.expectEqual(@as(usize, 1), runtime.render_requests.pendingReasonCount()); try std.testing.expect(runtime.render_requests.hasReason(.transcript)); try std.testing.expect(runtime.transcript_band_dirty);}
test "recorded command output consolidation is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkRecordedCommandOutputConsolidationAllocationFailures, .{}, );}
test "recorded command output consolidation preserves a capped canonical anchor without recovery fallback" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
var metrics: Metrics = .{}; try runtime.writeTranscript( alloc, &metrics, "canonical command output prefix extends beyond the capped cache\nretained command output prefix tail\n", true, ); const fixture = try setupRecordedCommandOutputAtomicFixture(&runtime, alloc); const styles = commandOutputAnsiTestStyles(); try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "one\n", true, ); try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stderr, "two\n", true, );
var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic(); const retained_before = transcript_store.retainedStructuredBytes(&runtime);
try runtime.flushCommandOutputSummaryForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, true, );
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); try std.testing.expectEqual( retained_before, transcript_store.retainedStructuredBytes(&runtime), ); try std.testing.expectEqual(@as(usize, 2), runtime.command_output_blocks.items[0].lines.items.len); var consolidated_source = try runtime.prepareTranscriptSource(alloc, null); defer consolidated_source.deinit(alloc); try std.testing.expectEqualStrings(committed_source.bytes, consolidated_source.bytes); switch (runtime.transcript_commit_state) { .stable => |anchor| try std.testing.expect(!anchor.normal_buffer_recovery_pending), .invalid, .recovering => return error.TestExpectedStableTranscript, }}
test "recorded command output completion does not allocate without a matching block" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8) }; defer runtime.deinit(alloc); var metrics = Metrics{}; const styles = commandOutputAnsiTestStyles();
try runtime.writeTranscript(alloc, &metrics, "existing\n", true); var no_open_failing = std.testing.FailingAllocator.init( alloc, .{ .fail_index = 0 }, ); try runtime.flushCommandOutputSummaryForLifecycle( no_open_failing.allocator(), &metrics, styles, null, true, ); try std.testing.expectEqualDeep(styles, runtime.command_output_render.styles); try std.testing.expect(runtime.command_output_display.open_command_block == null);
const open_id = types.ToolLifecycleId{ .turn_id = 81, .call_id = "open-command" }; try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, open_id, .stdout, "open\n", true, ); const entry_count_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id; const display_before = runtime.command_output_display; const mismatch_id = types.ToolLifecycleId{ .turn_id = 82, .call_id = "other-command" }; var mismatch_failing = std.testing.FailingAllocator.init( alloc, .{ .fail_index = 0 }, ); try runtime.flushCommandOutputSummaryForLifecycle( mismatch_failing.allocator(), &metrics, styles, mismatch_id, true, );
try std.testing.expectEqualDeep(styles, runtime.command_output_render.styles); try std.testing.expectEqual(entry_count_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); try std.testing.expectEqual(display_before.open_command_block, runtime.command_output_display.open_command_block);}
test "recorded command output consolidation preserves its anchor when retention changes" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 12, 8) }; defer runtime.deinit(alloc); const fixture = try setupRecordedCommandOutputAtomicFixture(&runtime, alloc); var metrics = Metrics{}; const styles = commandOutputAnsiTestStyles();
try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "one\n", true, ); try runtime.writeCommandOutputChunkForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, .stdout, "two\n", true, ); const retained_before = transcript_store.retainedStructuredBytes(&runtime); runtime.max_retained_transcript_bytes = retained_before - 1; try runtime.enableShadowVt(alloc); try installStableAnchorForTest( &runtime, alloc, "pre-retention source\n", testSelection(0), 0, 3, 1, 91, ); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime);
try runtime.flushCommandOutputSummaryForLifecycle( alloc, &metrics, styles, fixture.lifecycle_id, true, );
try std.testing.expect(transcript_store.retainedStructuredBytes(&runtime) <= runtime.max_retained_transcript_bytes); try std.testing.expect(runtime.command_output_blocks.items[0].lines.items.len < 2); try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, );}
test "writeTranscriptBytes does NOT append an entry" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo()); const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 10, .cols = 80, .content_bottom = 7, .divider_top_row = 8, .input_row = 9, .divider_bottom_row = 10, .hint_row = 10 } }; defer runtime.deinit(alloc);
var metrics = Metrics{}; try runtime.initViewport(&metrics, 5); try runtime.writeTranscriptBytes(alloc, &metrics, "structured writer bytes\n", true);
try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "structured writer bytes") != null);}
test "appendReplaceableTranscriptLineSilent mirrors a raw_bytes entry" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
_ = try runtime.appendReplaceableTranscriptLineSilent(alloc, "Thinking...\n"); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expect(runtime.entries.items[0] == .raw_bytes); try std.testing.expectEqualStrings("Thinking...\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expect(runtime.replaceable_last_line);}
test "classified replaceable append stores raw entry class" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const entry_id = try runtime.appendReplaceableTranscriptLineSilentClassified(alloc, "Thinking...\n", .subagent_status);
try std.testing.expectEqual(RawEntryClass.subagent_status, runtime.rawEntryClass(entry_id).?);}
test "replaceTrailingTranscriptLineSilent swaps the trailing entry's bytes in place" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
_ = try runtime.appendReplaceableTranscriptLineSilent(alloc, "Thinking...\n"); const initial_id = runtime.entries.items[0].id();
const replaced = try runtime.replaceTrailingTranscriptLineSilent(alloc, "Thinking... done\n"); try std.testing.expect(replaced); try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(initial_id, runtime.entries.items[0].id()); try std.testing.expectEqualStrings("Thinking... done\n", runtime.entries.items[0].raw_bytes.bytes);}
test "updateRawBytesEntry swaps bytes when entry is trailing" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const entry_id = try runtime.appendReplaceableTranscriptLineSilent(alloc, "modal v1\n"); try std.testing.expect(entry_id != 0); try std.testing.expectEqualStrings("modal v1\n", runtime.entries.items[0].raw_bytes.bytes);
const ok = try runtime.updateRawBytesEntry(alloc, entry_id, "modal v2\n"); try std.testing.expect(ok); try std.testing.expectEqualStrings("modal v2\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expectEqualStrings("modal v2\n", runtime.transcript.items); try std.testing.expect(runtime.replaceable_last_line); try std.testing.expectEqual(runtime.transcript.items.len - "modal v2\n".len, runtime.replaceable_start);}
test "updateRawBytesEntry swaps bytes when entry is in middle" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const id_a = try runtime.appendReplaceableTranscriptLineSilent(alloc, "block A\n"); const dup_b = try alloc.dupe(u8, "block B\n"); _ = try runtime.appendRawBytesEntry(alloc, dup_b); try runtime.transcript.appendSlice(alloc, "block B\n");
const ok = try runtime.updateRawBytesEntry(alloc, id_a, "block A updated\n"); try std.testing.expect(ok); try std.testing.expectEqualStrings("block A updated\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expect(runtime.entries.items[1] == .raw_bytes); try std.testing.expectEqualStrings("block B\n", runtime.entries.items[1].raw_bytes.bytes); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "block A updated\n") != null); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "block B\n") != null); try std.testing.expect(!runtime.replaceable_last_line);}
test "updateRawBytesEntry returns false for unknown id" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
_ = try runtime.appendReplaceableTranscriptLineSilent(alloc, "existing\n"); const ok = try runtime.updateRawBytesEntry(alloc, 9999, "nope\n"); try std.testing.expect(!ok); try std.testing.expectEqualStrings("existing\n", runtime.entries.items[0].raw_bytes.bytes);}
test "updateRawBytesEntry returns false for non-raw_bytes entry" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const text = try alloc.dupe(u8, "hello user"); const user_id = try runtime.appendUserTurnOwned(alloc, .{ .text = text, .images = &.{} }); const ok = try runtime.updateRawBytesEntry(alloc, user_id, "hijack\n"); try std.testing.expect(!ok);}
test "updateRawBytesEntry updates modal entry in place after intervening append" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{}; defer runtime.deinit(alloc);
const modal_id = try runtime.appendReplaceableTranscriptLineSilent(alloc, "modal v1\n"); const stream_dup = try alloc.dupe(u8, "stream chunk\n"); _ = try runtime.appendRawBytesEntry(alloc, stream_dup); try runtime.transcript.appendSlice(alloc, "stream chunk\n");
const ok = try runtime.updateRawBytesEntry(alloc, modal_id, "modal v2\n"); try std.testing.expect(ok); try std.testing.expectEqual(@as(usize, 2), runtime.entries.items.len); try std.testing.expectEqualStrings("modal v2\n", runtime.entries.items[0].raw_bytes.bytes); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "modal v2\n") != null); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "stream chunk\n") != null); try std.testing.expect(std.mem.indexOf(u8, runtime.transcript.items, "modal v1") == null);}
test "tool status raw entry updates after command output appends" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .maxxing_mode = .legacy }; defer runtime.deinit(alloc); var metrics = Metrics{};
const status_id = try runtime.appendRawTranscriptEntry(alloc, "Running npm test\n"); try runtime.writeCommandOutputChunk(alloc, &metrics, .{ .system_notice_label_style = "", .system_notice_text_style = "", .reset_style = "", .dim_style = "", .red_style = "", }, .stdout, "ok\n", true);
const updated = try runtime.updateRawBytesEntry(alloc, status_id, "Ran npm test\n"); try std.testing.expect(updated); var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "Ran npm test") != null); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "│ ok") != null); try std.testing.expect(std.mem.indexOf(u8, source.bytes, "Running npm test") == null);}
test "advanceCursor row advance matches visualRowsForLine - 1 for wrap-exact content" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 40, .cols = 3, .content_bottom = 37, .divider_top_row = 38, .input_row = 39, .divider_bottom_row = 40, .hint_row = 40, }, }; defer runtime.deinit(std.testing.allocator);
const text = "abcdef"; try std.testing.expectEqual(@as(u16, 2), visualRowsForLine(text, 3));
runtime.cursor_row = 1; runtime.cursor_col = 1; _ = runtime.advanceCursor(text); try std.testing.expectEqual(@as(u16, 2), runtime.cursor_row);}
test "advanceCursor row advance matches visualRowsForLine - 1 across hard newlines" { var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 40, .cols = 3, .content_bottom = 37, .divider_top_row = 38, .input_row = 39, .divider_bottom_row = 40, .hint_row = 40, }, }; defer runtime.deinit(std.testing.allocator);
const text = "abcdef\nghijkl"; try std.testing.expectEqual(@as(u16, 4), visualRowsForLine(text, 3));
runtime.cursor_row = 1; runtime.cursor_col = 1; _ = runtime.advanceCursor(text); try std.testing.expectEqual(@as(u16, 4), runtime.cursor_row);}
test "writeTranscriptBytes mid-row continuation defers scroll after first paint" { const alloc = std.testing.allocator; var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 40, .cols = 80, .content_bottom = 35, .divider_top_row = 36, .input_row = 37, .divider_bottom_row = 38, .hint_row = 39, }, }; defer runtime.deinit(alloc); runtime.cursor_row = 35; runtime.cursor_col = 40; runtime.viewport_top_row = 35; runtime.has_painted_transcript = true;
var bytes: std.ArrayList(u8) = .empty; defer bytes.deinit(alloc); var i: usize = 0; while (i < 1000) : (i += 1) try bytes.append(alloc, 'X');
var metrics: Metrics = .{}; try runtime.writeTranscriptBytes(alloc, &metrics, bytes.items, true);
try std.testing.expectEqual(@as(u16, 35), runtime.viewport_top_row); try std.testing.expectEqual(@as(u16, 35), runtime.cursor_row);}
test "appendReplaceableTranscriptLine does not emit scroll (buffer-only)" { const alloc = std.testing.allocator; var sink = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink.close(io_mod.getIo());
var runtime = TranscriptRuntime{ .stdout_file = sink, .layout = .{ .rows = 40, .cols = 10, .content_bottom = 35, .divider_top_row = 36, .input_row = 37, .divider_bottom_row = 38, .hint_row = 39, }, }; defer runtime.deinit(alloc); runtime.cursor_row = 35; runtime.cursor_col = 1; runtime.viewport_top_row = 35;
var bytes: std.ArrayList(u8) = .empty; defer bytes.deinit(alloc); try bytes.appendSlice(alloc, "XXXXXXXXXX"); var ln: u16 = 0; while (ln < 9) : (ln += 1) { try bytes.append(alloc, '\n'); try bytes.appendSlice(alloc, "XXXXXXXXXX"); }
var metrics: Metrics = .{}; _ = try runtime.appendReplaceableTranscriptLine(alloc, &metrics, bytes.items);
try std.testing.expectEqual(@as(u16, 35), runtime.viewport_top_row); try std.testing.expectEqual(@as(u16, 40), runtime.cursor_row);}
test "streamed chunk-split produces same viewport as single emission" { const alloc = std.testing.allocator;
var sink1 = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink1.close(io_mod.getIo()); var sink2 = try std.Io.Dir.openFileAbsolute(io_mod.getIo(), "/dev/null", .{ .mode = .write_only }); defer sink2.close(io_mod.getIo());
const layout: Layout = .{ .rows = 40, .cols = 80, .content_bottom = 35, .divider_top_row = 36, .input_row = 37, .divider_bottom_row = 38, .hint_row = 39, };
var single = TranscriptRuntime{ .stdout_file = sink1, .layout = layout }; defer single.deinit(alloc); single.cursor_row = 35; single.cursor_col = 1; single.viewport_top_row = 35;
var split = TranscriptRuntime{ .stdout_file = sink2, .layout = layout }; defer split.deinit(alloc); split.cursor_row = 35; split.cursor_col = 1; split.viewport_top_row = 35;
var full: std.ArrayList(u8) = .empty; defer full.deinit(alloc); var i: usize = 0; while (i < 2000) : (i += 1) try full.append(alloc, 'X');
var half: std.ArrayList(u8) = .empty; defer half.deinit(alloc); i = 0; while (i < 1000) : (i += 1) try half.append(alloc, 'X');
var m1: Metrics = .{}; var m2: Metrics = .{}; try single.writeTranscriptBytes(alloc, &m1, full.items, true); try split.writeTranscriptBytes(alloc, &m2, half.items, true); try split.writeTranscriptBytes(alloc, &m2, half.items, true);
try std.testing.expectEqual(single.viewport_top_row, split.viewport_top_row); try std.testing.expectEqual(single.cursor_row, split.cursor_row); try std.testing.expectEqual(single.cursor_col, split.cursor_col);}
fn lifecycleTestRuntime(max_retained_bytes: ?usize) TranscriptRuntime { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 24, 20), }; if (max_retained_bytes) |value| runtime.max_retained_transcript_bytes = value; return runtime;}
fn lifecycleId(turn_id: u64, call_id: []const u8) types.ToolLifecycleId { return .{ .turn_id = turn_id, .call_id = call_id };}
fn startLifecycle( runtime: *TranscriptRuntime, alloc: Allocator, turn_id: u64, call_id: []const u8,) !u32 { _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycleId(turn_id, call_id), .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); return runtime.toolActivityRecord(lifecycleId(turn_id, call_id)).?.entry_id;}
test "minimal maxxing groups tool rows without mutating the legacy transcript" { const alloc = std.testing.allocator; defer user_message_card.setStyle(false, null); user_message_card.setStyle(false, null); var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); runtime.maxxing_mode = .legacy;
const read_id = lifecycleId(1, "read"); _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = read_id, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = read_id, .outcome = .{ .kind = .completed, .summary = "Read file" }, } });
const edit_id = lifecycleId(1, "edit"); _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = edit_id, .reconciles_provisional_call_id = null, .tool_name = "edit_file", .activity_kind = .edit, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = edit_id, .outcome = .{ .kind = .failed, .summary = "Edit failed" }, } });
const entry_count = runtime.entries.items.len; var normal = try runtime.prepareTranscriptSource(alloc, null); defer normal.deinit(alloc); try std.testing.expect(std.mem.find(u8, normal.bytes, "● 2 tool calls") == null);
runtime.maxxing_mode = .minimal; var minimal = try runtime.prepareTranscriptSource(alloc, null); defer minimal.deinit(alloc); try std.testing.expect(std.mem.find( u8, minimal.bytes, "\x1b[38;5;255m●\x1b[0m \x1b[38;5;245m2 tool calls · 1 read · 1 edit · 1 failed\x1b[0m\n" ++ "\x1b[38;5;245m├ Read file\x1b[0m\n" ++ "\x1b[38;5;245m└ Edit failed\x1b[0m", ) != null); try std.testing.expectEqual(entry_count, runtime.entries.items.len);
runtime.maxxing_mode = .legacy; var restored = try runtime.prepareTranscriptSource(alloc, null); defer restored.deinit(alloc); try std.testing.expectEqualStrings(normal.bytes, restored.bytes);}
test "minimal maxxing finalizes tool groups from turn finished fallbacks" { const alloc = std.testing.allocator; const cases = [_]struct { call_id: []const u8, provisional: bool, turn_outcome: types.TurnPresentationOutcome, detail_outcome: types.ToolOutcomeKind, fallback_disposition: ?transcript_blocks.ToolFallbackDisposition, summary_text: []const u8, }{ .{ .call_id = "unreported", .provisional = false, .turn_outcome = .completed, .detail_outcome = .completed, .fallback_disposition = .completion_unreported, .summary_text = "1 tool call · 1 read · 1 unreported" }, .{ .call_id = "not-executed", .provisional = true, .turn_outcome = .completed, .detail_outcome = .completed, .fallback_disposition = .not_executed, .summary_text = "1 tool call · 1 read · 1 not executed" }, .{ .call_id = "interrupted", .provisional = false, .turn_outcome = .interrupted, .detail_outcome = .cancelled, .fallback_disposition = null, .summary_text = "1 cancelled" }, .{ .call_id = "failed", .provisional = false, .turn_outcome = .failed, .detail_outcome = .failed, .fallback_disposition = null, .summary_text = "Tool failed" }, };
for (cases) |case| { var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
const id = lifecycleId(1, case.call_id); if (case.provisional) { _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "read_file", .activity_kind = .read, } }); } else { _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); } const entry_id = runtime.toolActivityRecord(id).?.entry_id;
_ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = case.turn_outcome, } });
runtime.maxxing_mode = .minimal; var rendered = try runtime.prepareTranscriptSource(alloc, null); defer rendered.deinit(alloc); try std.testing.expect(std.mem.find(u8, rendered.bytes, case.summary_text) != null); try std.testing.expect(std.mem.find(u8, rendered.bytes, "running") == null); try std.testing.expectEqual( case.detail_outcome, runtime.toolDetailForEntry(entry_id).?.outcome.?, ); try std.testing.expectEqual( case.fallback_disposition, runtime.toolDetailForEntry(entry_id).?.fallback_disposition, ); }}
fn checkMinimalMaxxingParallelFallbackAllocationFailuresImpl(alloc: Allocator) !void { var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); const ids = [_]types.ToolLifecycleId{ lifecycleId(1, "provisional-a"), lifecycleId(1, "provisional-b"), }; var entry_ids: [ids.len]u32 = undefined; for (ids, 0..) |id, index| { _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "read_file", .activity_kind = .read, } }); entry_ids[index] = runtime.toolActivityRecord(id).?.entry_id; }
var source_before = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_before.deinit(std.testing.allocator); _ = runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .completed, } }) catch |err| { var source_after = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_after.deinit(std.testing.allocator); try std.testing.expectEqualStrings(source_before.bytes, source_after.bytes); for (ids) |id| { try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .provisional); } return err; };
runtime.maxxing_mode = .minimal; var rendered = try runtime.prepareTranscriptSource(alloc, null); defer rendered.deinit(alloc); try std.testing.expect(std.mem.find( u8, rendered.bytes, "2 tool calls · 2 read · 2 not executed", ) != null); try std.testing.expect(std.mem.find(u8, rendered.bytes, "running") == null); for (entry_ids) |entry_id| { try std.testing.expectEqual( types.ToolOutcomeKind.completed, runtime.toolDetailForEntry(entry_id).?.outcome.?, ); try std.testing.expectEqual( transcript_blocks.ToolFallbackDisposition.not_executed, runtime.toolDetailForEntry(entry_id).?.fallback_disposition.?, ); }}
fn checkMinimalMaxxingParallelFallbackAllocationFailures(alloc: Allocator) !void { return checkMinimalMaxxingParallelFallbackAllocationFailuresImpl(alloc) catch |err| switch (err) { error.WriteFailed => error.OutOfMemory, else => err, };}
test "minimal maxxing parallel fallbacks are atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkMinimalMaxxingParallelFallbackAllocationFailures, .{}, );}
fn prepareTurnFinishedAnchor(runtime: *TranscriptRuntime, alloc: Allocator) !void { try runtime.enableShadowVt(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "pre 0\npre 1\npre 2\npre 3\npre 4\npre 5\n", .subagent_status, ); _ = try startLifecycle(runtime, alloc, 1, "unfinished"); try installStableAnchorForTest( runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, );}
test "preserving lifecycle policy keeps anchor for turn finished fallback rewrite" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try prepareTurnFinishedAnchor(&runtime, alloc);
_ = try runtime.applyToolLifecyclePreservingNormalBufferAnchor(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .interrupted, }, });
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );}
test "preserving batch lifecycle rewrite keeps a capped canonical anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, ); const first_entry_id = try startLifecycle(&runtime, alloc, 1, "first"); const second_entry_id = try startLifecycle(&runtime, alloc, 1, "second");
var metrics: Metrics = .{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
_ = try runtime.applyToolLifecyclePreservingNormalBufferAnchor(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .interrupted, }, });
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); try std.testing.expect(std.mem.find( u8, runtime.toolStatusEntryLabel(first_entry_id).?, "Tool cancelled", ) != null); try std.testing.expect(std.mem.find( u8, runtime.toolStatusEntryLabel(second_entry_id).?, "Tool cancelled", ) != null);}
test "turn finished anchor preservation keeps a same-epoch retention rewrite" { const alloc = std.testing.allocator;
var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try prepareTurnFinishedAnchor(&runtime, alloc); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime); runtime.max_retained_transcript_bytes = 0;
_ = try runtime.applyToolLifecyclePreservingNormalBufferAnchor(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .interrupted }, });
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, );}
test "turn finished anchor preservation falls back for strict mode or geometry blocker" { const alloc = std.testing.allocator;
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try prepareTurnFinishedAnchor(&runtime, alloc); runtime.max_transcript_bytes = 1;
_ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .interrupted }, });
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.invalid, runtime.transcriptCommitDiagnostic().state, ); }
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try prepareTurnFinishedAnchor(&runtime, alloc); runtime.layout.cols = 39;
_ = try runtime.applyToolLifecyclePreservingNormalBufferAnchor(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .interrupted }, });
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.invalid, runtime.transcriptCommitDiagnostic().state, ); }}
test "untrimmed pinned status replacement preserves anchor through scroll transition" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "pre 0\npre 1\npre 2\npre 3\npre 4\npre 5\n", .subagent_status, ); const entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", ); try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, );
try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, entry_id, "running\n", )); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); try setPreparedVisualOffsetForTest(&prepared, 2);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(!facts.source_compatible); try std.testing.expect(facts.recovery_rebase); try std.testing.expectEqual(@as(u16, 2), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), facts.semantic_progress_rows); try std.testing.expectEqual(@as(u16, 2), facts.planned_rows);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); try std.testing.expectEqual(@as(u16, 2), scroll_plan.terminal_scroll_rows); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc); try std.testing.expect(transition.document_append.isEmpty()); runtime.consumeTranscriptTransition(alloc, &transition, .{ .bytes_written = 1, .changed_cells = 1, .full_repaint = true, .terminal_scroll_rows_committed = scroll_plan.terminal_scroll_rows, .document_append_committed = false, .committed_cursor_row = transition.cursor_row, .committed_cursor_col = transition.cursor_col, .shadow_state = .committed, .next_invalidation = render_engine.paint_plan.FrameInvalidationSet.empty(), }); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); try std.testing.expect(runtime.transcript_cache_origin_untrimmed);
var next_source = try runtime.prepareTranscriptSource(alloc, null); defer next_source.deinit(alloc); try std.testing.expect( runtime.stableTranscriptProjectionForFlow(next_source.bytes) != null, );}
test "command terminal replacement preserves committed scrollback anchor" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "pre 0\npre 1\npre 2\npre 3\npre 4\npre 5\n", .subagent_status, ); const id = lifecycleId(1, "cancelled-command"); _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"sleep 30\"}", } }); try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, );
_ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .cancelled, .summary = "Command cancelled" }, .result_memory = .{ .command_process_presentation = .{ .exit_code = 130 } }, } });
try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, ); const entry_id = runtime.toolActivityRecord(id).?.entry_id; try std.testing.expect(std.mem.find( u8, runtime.toolStatusEntryLabel(entry_id).?, "Command cancelled", ) != null); try std.testing.expect(runtime.toolDetailForEntry(entry_id).?.command_output_entry_id != null);}
test "pinned status admission preserves an authoritative committed anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, .max_transcript_bytes = 64, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, ); const first_status_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_before = runtime.transcriptCommitDiagnostic();
try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, first_status_id, "running\n", )); try std.testing.expectEqualDeep( committed_before, runtime.transcriptCommitDiagnostic(), );
_ = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", );
try std.testing.expectEqualDeep( committed_before, runtime.transcriptCommitDiagnostic(), ); var appended_source = try runtime.prepareTranscriptSource(alloc, null); defer appended_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "LONG_PASTE_LAST_MARKER"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "running"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, appended_source.bytes, "pending"), );}
test "pinned status admission preserves an anchor when retention prunes its source" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "anchored transcript\n", .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime); runtime.max_retained_transcript_bytes = "pending\n".len;
_ = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", );
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); var retained_source = try runtime.prepareTranscriptSource(alloc, null); defer retained_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, retained_source.bytes, "anchored transcript"), ); try std.testing.expectEqual( @as(usize, 1), std.mem.count(u8, retained_source.bytes, "pending"), );}
test "pinned status replacement preserves authoritative cache changes and rebases retention or geometry" { const alloc = std.testing.allocator;
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "ordinary retained entry\n", .subagent_status, ); const entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", ); runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime); try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, ); try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, entry_id, "replacement that requires structured retention\n", )); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.invalid, runtime.transcriptCommitDiagnostic().state, ); }
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); const entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "old\n", ); runtime.max_transcript_bytes = runtime.transcript.items.len; try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, ); const committed_before = runtime.transcriptCommitDiagnostic();
try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, entry_id, "replacement that crosses the visible cache cap\n", )); try std.testing.expectEqualDeep( committed_before, runtime.transcriptCommitDiagnostic(), ); }
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, .max_transcript_bytes = 5, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); const entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "old\npinned\nstatus", ); try std.testing.expect(runtime.transcript.items.len <= runtime.max_transcript_bytes); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_before = runtime.transcriptCommitDiagnostic();
try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, entry_id, "ok", )); try std.testing.expectEqualDeep( committed_before, runtime.transcriptCommitDiagnostic(), ); }
{ var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(40, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc); const entry_id = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "pending\n", ); try installStableAnchorForTest( &runtime, alloc, runtime.transcript.items, testSelection(0), 0, 4, 1, 1, );
runtime.layout.cols = 20; try std.testing.expect(try transcript_store.replacePinnedToolStatusAtomic( &runtime, alloc, entry_id, "running\n", )); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.invalid, runtime.transcriptCommitDiagnostic().state, ); }}
test "visual epoch replaces ordinary entries and preserves live tool identities" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified(alloc, "old transcript\n", .subagent_status); const entry_id = try startLifecycle(&runtime, alloc, 7, "call-7");
try runtime.resetVisualEpoch(alloc, "welcome\n");
try std.testing.expect(std.mem.startsWith(u8, runtime.transcript.items, "welcome\n")); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "old transcript") == null); try std.testing.expectEqual(entry_id, runtime.toolActivityRecord(lifecycleId(7, "call-7")).?.entry_id); try std.testing.expect(runtime.isLifecyclePinned(entry_id));
_ = try runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = lifecycleId(7, "call-7"), .text = "still running", } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(7, "call-7"), .outcome = .{ .kind = .completed, .summary = "finished" }, } }); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "finished") != null);}
test "transcript lifecycle identity updates are idempotent and atomic" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
for ([_]?[]const u8{ null, "read_file", "read_file" }) |tool_name| { _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = lifecycleId(1, "call"), .presentation_group_id = .{ .turn_id = 1, .anchor_step_id = 11 }, .tool_name = tool_name, .activity_kind = .read, } }); } const provisional_id = lifecycleId(1, "call"); const entry_id = runtime.toolActivityRecord(provisional_id).?.entry_id; try std.testing.expectEqualStrings( "read_file", runtime.toolActivityRecord(provisional_id).?.tool_name.?, ); // Force record-map growth so stale pointers fail deterministically. inline for ([_][]const u8{ "alias", "target", "fill-1", "fill-2", "fill-3" }) |call_id| { _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = lifecycleId(1, call_id), .tool_name = "read_file", .activity_kind = .read, } }); } const authoritative_id = lifecycleId(1, "authoritative-" ++ ("x" ** 800)); const record_capacity_before = runtime.lifecycle_state.records.capacity(); _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = authoritative_id, .presentation_group_id = .{ .turn_id = 1, .anchor_step_id = 12 }, .reconciles_provisional_call_id = "call", .tool_name = "read_file", .activity_kind = .read, } }); try std.testing.expect(runtime.lifecycle_state.records.capacity() > record_capacity_before); try std.testing.expect(runtime.toolActivityRecord(provisional_id) == null); try std.testing.expectEqual( entry_id, runtime.toolActivityRecord(authoritative_id).?.entry_id, ); try std.testing.expectEqual( types.ToolPresentationGroupId{ .turn_id = 1, .anchor_step_id = 11 }, runtime.toolDetailForEntry(entry_id).?.presentation_group_id.?, ); const alias_before = runtime.toolActivityRecord(lifecycleId(1, "alias")).?.entry_id; const target_before = runtime.toolActivityRecord(lifecycleId(1, "target")).?.entry_id; try std.testing.expectError( error.LifecycleReconciliationCollision, runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycleId(1, "target"), .reconciles_provisional_call_id = "alias", .tool_name = "list_files", .activity_kind = .list, } }), ); try std.testing.expectEqual(alias_before, runtime.toolActivityRecord(lifecycleId(1, "alias")).?.entry_id); try std.testing.expectEqual(target_before, runtime.toolActivityRecord(lifecycleId(1, "target")).?.entry_id); const records_before = runtime.toolActivityRecordCount(); try std.testing.expectError( error.UnknownToolLifecycleIdentity, runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = lifecycleId(1, "missing"), .text = "progress", } }), ); try std.testing.expectError( error.UnknownToolLifecycleIdentity, runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(1, "missing"), .outcome = .{ .kind = .failed, .summary = "failed" }, } }), ); try std.testing.expectEqual(records_before, runtime.toolActivityRecordCount()); runtime.clearTranscript(alloc); try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount()); try std.testing.expectEqual(@as(usize, 0), runtime.lifecyclePinCount()); try std.testing.expectEqual(@as(usize, 0), runtime.entries.items.len);}
test "authoritative lifecycle can place a provisional row after the latest transcript entry" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
const id = lifecycleId(1, "command"); _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "run_command", .activity_kind = .command, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = id, .text = "Preparing command", } }); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "permissions", .tone = .success, .body = "Auto agent approved this request: Running command.", .visibility = .full_only, });
_ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"printf approved\"}", .place_after_current_transcript = true, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = id, .text = "Running printf approved", } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Ran printf approved" }, } });
try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "Auto agent approved") == null); try std.testing.expect(std.mem.find(u8, runtime.transcript.items, "Ran printf approved") != null);
var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const full = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 64, 0, null, ); defer alloc.free(full); const notice_index = std.mem.find(u8, full, "Auto agent approved").?; const completed_index = std.mem.find(u8, full, "Ran printf approved").?; try std.testing.expect(notice_index < completed_index);}
test "coalesced approval lifecycle reposition preserves an authoritative committed anchor" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, );
var metrics = Metrics{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); const committed_offset = preparedVisualOffsetForTest(&committed_prepared); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, committed_offset, committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
const id = lifecycleId(91, "coalesced-command"); _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "run_command", .activity_kind = .command, } }); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "permissions", .tone = .success, .body = "Auto agent approved this request: Running command.", .visibility = .full_only, }); _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"seq 1 1\"}", .place_after_current_transcript = true, } });
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); var repositioned_source = try runtime.prepareTranscriptSource(alloc, null); defer repositioned_source.deinit(alloc); try std.testing.expect(std.mem.find(u8, repositioned_source.bytes, "Auto agent approved") == null); try std.testing.expect(std.mem.find( u8, repositioned_source.bytes, "run_command", ) != null); var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const full = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 64, 0, null, ); defer alloc.free(full); const notice_index = std.mem.find(u8, full, "Auto agent approved") orelse return error.TestExpectedEqual; const full_status_index = std.mem.find(u8, full, "run_command") orelse return error.TestExpectedEqual; try std.testing.expect(notice_index < full_status_index);
var repositioned_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer repositioned_prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&repositioned_prepared); try std.testing.expect(facts.source_compatible); try std.testing.expect(facts.semantic_rows > 0); try std.testing.expectEqual(committed_offset, facts.source_visual_offset);}
test "coalesced approval lifecycle reposition preserves its anchor when retention prunes its source" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const anchored = "anchored transcript\n"; _ = try runtime.appendRawTranscriptEntryClassified( alloc, anchored, .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime);
const id = lifecycleId(92, "retained-command"); _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "run_command", .activity_kind = .command, } }); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "permissions", .tone = .success, .body = "Auto agent approved this request: Running command.", .visibility = .full_only, }); runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime) - anchored.len;
_ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"seq 1 1\"}", .place_after_current_transcript = true, } });
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); var retained_source = try runtime.prepareTranscriptSource(alloc, null); defer retained_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, retained_source.bytes, "anchored transcript"), ); try std.testing.expect(std.mem.find(u8, retained_source.bytes, "Auto agent approved") == null); try std.testing.expect(std.mem.find( u8, retained_source.bytes, "run_command", ) != null); var projection = try runtime.buildFullTranscriptProjection(alloc, null); defer projection.deinit(alloc); const full = try full_transcript_screen.renderProjectionViewportSourceInterruptible( alloc, &projection, null, runtime.layout.cols, 64, 0, null, ); defer alloc.free(full); const notice_index = std.mem.find(u8, full, "Auto agent approved") orelse return error.TestExpectedEqual; const status_index = std.mem.find(u8, full, "run_command") orelse return error.TestExpectedEqual; try std.testing.expect(notice_index < status_index);}
test "transcript lifecycle preserves caller resolved activity metadata" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
const id = lifecycleId(1, "custom-browser"); const started_kind = (try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "custom_probe_tool", .activity_kind = .open, } })) orelse return error.TestExpectedEqual;
try std.testing.expectEqual(types.ToolActivityKind.open, started_kind); try std.testing.expectEqual(types.ToolActivityKind.open, runtime.toolActivityRecord(id).?.activity_kind); try std.testing.expectEqual(types.ToolActivityKind.open, runtime.focusedToolActivityKind().?); switch (runtime.activityProjection()) { .tool_slot => |slot| try std.testing.expectEqual(types.ToolActivityKind.open, slot.kind), else => return error.TestExpectedEqual, }}
test "transcript lifecycle terminal and finalization transitions stay batch safe" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
const cases = [_]struct { call_id: []const u8, kind: types.ToolOutcomeKind, summary: []const u8, marker_style: []const u8, marker: []const u8, }{ .{ .call_id = "completed", .kind = .completed, .summary = "completed", .marker_style = ui_render.system_notice_text_style, .marker = "●" }, .{ .call_id = "denied", .kind = .denied, .summary = "denied", .marker_style = ui_render.red_style, .marker = "⊘" }, .{ .call_id = "cancelled", .kind = .cancelled, .summary = "cancelled", .marker_style = ui_render.warning_style, .marker = "■" }, .{ .call_id = "failed", .kind = .failed, .summary = "failed", .marker_style = ui_render.red_style, .marker = "●" }, }; for (cases) |case| { const id = lifecycleId(1, case.call_id); const entry_id = try startLifecycle(&runtime, alloc, 1, case.call_id); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = case.kind, .summary = case.summary }, } }); var expected: [128]u8 = undefined; const expected_line = if (case.kind == .cancelled) try std.fmt.bufPrint( &expected, "{s}{s}{s} {s}{s}{s} · What can fx do differently?\n", .{ case.marker_style, case.marker, ui_render.reset_style, ui_render.hint_style, case.summary, ui_render.reset_style, }, ) else try std.fmt.bufPrint( &expected, "{s}{s}{s} {s}\n", .{ case.marker_style, case.marker, ui_render.reset_style, case.summary }, ); try expectRawEntryBytes(&runtime, entry_id, expected_line); } try std.testing.expect(runtime.activityProjection() == .none);
_ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = lifecycleId(2, "old"), .tool_name = "read_file", .activity_kind = .read, } }); const old_entry_id = runtime.toolActivityRecord(lifecycleId(2, "old")).?.entry_id; _ = try startLifecycle(&runtime, alloc, 3, "new");
for ([_]types.ToolLifecycleEvent{ .{ .turn_finished = .{ .turn_id = 2, .outcome = .completed } }, .{ .turn_finished = .{ .turn_id = 2, .outcome = .interrupted } }, .{ .turn_finished = .{ .turn_id = 1, .outcome = .failed } }, }) |event| _ = try runtime.applyToolLifecycle(alloc, event); try expectRawEntryBytes(&runtime, old_entry_id, "● Tool was not executed\n");
_ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(2, "old"), .outcome = .{ .kind = .completed, .summary = "● Late completion" }, } }); var late_completion_expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, old_entry_id, try std.fmt.bufPrint( &late_completion_expected, "{s}●{s} Late completion\n", .{ ui_render.system_notice_text_style, ui_render.reset_style }, )); try std.testing.expectEqual( null, runtime.toolDetailForEntry(old_entry_id).?.fallback_disposition, ); try std.testing.expect(runtime.isLifecyclePinned(old_entry_id));
try runtime.finishLifecycleBatch(alloc); try std.testing.expectEqual(@as(u64, 2), runtime.finalizedToolTurnWatermark()); try std.testing.expect(runtime.toolActivityRecord(lifecycleId(2, "old")) == null); try std.testing.expect(runtime.toolActivityRecord(lifecycleId(3, "new")) != null); try std.testing.expect(!runtime.isLifecyclePinned(old_entry_id));
_ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = lifecycleId(2, "late-start"), .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); try std.testing.expect(runtime.toolActivityRecord(lifecycleId(2, "late-start")) == null);}
test "completed tool status projection keeps lifecycle styling without activity state" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); var metrics: Metrics = .{};
try runtime.writeCompletedToolStatus( alloc, &metrics, .completed, "● Ran pwd\x1b[0m \x1b[38;5;245mpwd\x1b[0m", true, );
try std.testing.expectEqual(@as(usize, 1), runtime.entries.items.len); try std.testing.expectEqual(RawEntryClass.tool_status, runtime.entries.items[0].raw_bytes.class); try expectRawEntryBytes( &runtime, runtime.entries.items[0].raw_bytes.id, "\x1b[38;5;250m●\x1b[0m Ran pwd\x1b[0m \x1b[38;5;245mpwd\x1b[0m\n", ); try std.testing.expect(runtime.activityProjection() == .none); try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount());}
test "transcript lifecycle terminal markers preserve ANSI summaries and normalize markerless failures" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc);
const styled_entry_id = try startLifecycle(&runtime, alloc, 1, "styled"); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(1, "styled"), .outcome = .{ .kind = .completed, .summary = "● Ran command\x1b[0m", }, } }); var styled_expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, styled_entry_id, try std.fmt.bufPrint( &styled_expected, "{s}●{s} Ran command\x1b[0m\n", .{ ui_render.system_notice_text_style, ui_render.reset_style }, ));
const styled_cancelled_entry_id = try startLifecycle(&runtime, alloc, 1, "styled-cancelled"); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(1, "styled-cancelled"), .outcome = .{ .kind = .cancelled, .summary = "● Cancelled\x1b[0m \x1b[38;5;245msleep 30\x1b[0m", }, } }); var styled_cancelled_expected: [256]u8 = undefined; try expectRawEntryBytes(&runtime, styled_cancelled_entry_id, try std.fmt.bufPrint( &styled_cancelled_expected, "{s}■{s}{s} Cancelled\x1b[0m \x1b[38;5;245msleep 30\x1b[0m{s}" ++ " · What can fx do differently?\n", .{ ui_render.warning_style, ui_render.reset_style, ui_render.hint_style, ui_render.reset_style, }, ));
const malformed_entry_id = try startLifecycle(&runtime, alloc, 1, "malformed"); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(1, "malformed"), .outcome = .{ .kind = .failed, .summary = "write_file failed: invalid JSON arguments", }, } }); var malformed_expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, malformed_entry_id, try std.fmt.bufPrint( &malformed_expected, "{s}●{s} write_file failed: invalid JSON arguments\n", .{ ui_render.red_style, ui_render.reset_style }, ));
const cancelled_entry_id = try startLifecycle(&runtime, alloc, 2, "cancelled"); _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 2, .outcome = .interrupted, } }); var cancelled_expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, cancelled_entry_id, try std.fmt.bufPrint( &cancelled_expected, "{s}■{s} {s}Tool cancelled{s} · What can fx do differently?\n", .{ ui_render.warning_style, ui_render.reset_style, ui_render.hint_style, ui_render.reset_style, }, ));
const failed_entry_id = try startLifecycle(&runtime, alloc, 3, "failed"); _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 3, .outcome = .failed, } }); var failed_expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, failed_entry_id, try std.fmt.bufPrint( &failed_expected, "{s}●{s} Tool failed\n", .{ ui_render.red_style, ui_render.reset_style }, ));}
fn expectRawEntryBytes( runtime: *const TranscriptRuntime, entry_id: u32, expected: []const u8,) !void { for (runtime.entries.items) |entry| { if (entry == .raw_bytes and entry.raw_bytes.id == entry_id) { try std.testing.expectEqualStrings(expected, entry.raw_bytes.bytes); return; } } return error.TestExpectedEqual;}
fn transcriptContainsEntry(runtime: *const TranscriptRuntime, entry_id: u32) bool { for (runtime.entries.items) |entry| { if (entry.id() == entry_id) return true; } return false;}
fn checkLifecycleRepositionAllocationFailures(alloc: Allocator) !void { var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, .maxxing_mode = .legacy, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "ALLOCATION TRANSCRIPT 01\n" ++ "ALLOCATION TRANSCRIPT 02\n" ++ "ALLOCATION TRANSCRIPT 03\n" ++ "ALLOCATION TRANSCRIPT 04\n" ++ "ALLOCATION TRANSCRIPT 05\n" ++ "ALLOCATION TRANSCRIPT 06\n", .subagent_status, ); var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, );
const id = lifecycleId(93, "allocation-command"); _ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "run_command", .activity_kind = .command, } }); _ = try runtime.appendSemanticNotice(alloc, .{ .topic = "permissions", .tone = .success, .body = "Auto agent approved this request: Running command.", .visibility = .full_only, });
var source_before = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_before.deinit(std.testing.allocator); const diagnostic_before = runtime.transcriptCommitDiagnostic(); _ = runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"seq 1 1\"}", .place_after_current_transcript = true, } }) catch |err| { var source_after = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer source_after.deinit(std.testing.allocator); try std.testing.expectEqualStrings(source_before.bytes, source_after.bytes); try std.testing.expectEqualDeep( diagnostic_before, runtime.transcriptCommitDiagnostic(), ); try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .provisional); return err; };
try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .authoritative); try std.testing.expectEqual( transcript_runtime.TranscriptCommitDiagnosticState.stable, runtime.transcriptCommitDiagnostic().state, );}
test "coalesced approval lifecycle reposition is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkLifecycleRepositionAllocationFailures, .{}, );}
test "lifecycle pin cleanup preserves a capped canonical anchor without pruning" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, .max_transcript_bytes = 64, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const long_tail = try makeLongPastePrompt(alloc, 40); defer alloc.free(long_tail); _ = try runtime.appendRawTranscriptEntryClassified( alloc, long_tail, .subagent_status, ); const id = lifecycleId(94, "cleanup-command"); _ = try startLifecycle(&runtime, alloc, id.turn_id, id.call_id); _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = id.turn_id, .outcome = .completed, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Cleanup complete" }, } });
var metrics = Metrics{}; var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try std.testing.expect(committed_source.recorded_entries_authoritative); try std.testing.expect(committed_source.bytes.len > runtime.transcript.items.len); var committed_prepared = try runtime.prepareTranscriptSurfacePaintForArea( alloc, &metrics, .{ .top = runtime.owned_top_row, .bottom = runtime.layout.content_bottom }, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); const committed_diagnostic = runtime.transcriptCommitDiagnostic();
try runtime.finishLifecycleBatch(alloc);
try std.testing.expectEqualDeep( committed_diagnostic, runtime.transcriptCommitDiagnostic(), ); try std.testing.expectEqual(@as(usize, 0), runtime.lifecyclePinCount()); try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount()); var cleaned_source = try runtime.prepareTranscriptSource(alloc, null); defer cleaned_source.deinit(alloc); try std.testing.expectEqualStrings(committed_source.bytes, cleaned_source.bytes);}
test "lifecycle pin cleanup preserves a canonical anchor when retention prunes" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(48, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc); try runtime.enableShadowVt(alloc);
const anchored = "anchored lifecycle cleanup transcript\n"; _ = try runtime.appendRawTranscriptEntryClassified( alloc, anchored, .subagent_status, ); const id = lifecycleId(95, "pruning-cleanup-command"); _ = try startLifecycle(&runtime, alloc, id.turn_id, id.call_id); _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = id.turn_id, .outcome = .completed, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Cleanup complete" }, } });
var committed_source = try runtime.prepareTranscriptSource(alloc, null); defer committed_source.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_source.bytes, testSelection(0), 0, 4, 1, 1, ); const committed_history_visual_offset = try stableHistoryVisualOffsetForTest(&runtime); runtime.max_retained_transcript_bytes = transcript_store.retainedStructuredBytes(&runtime) - anchored.len;
try runtime.finishLifecycleBatch(alloc);
try expectStableNormalBufferRecoveryForTest( &runtime, committed_history_visual_offset, ); try std.testing.expectEqual(@as(usize, 0), runtime.lifecyclePinCount()); try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount()); var retained_source = try runtime.prepareTranscriptSource(alloc, null); defer retained_source.deinit(alloc); try std.testing.expectEqual( @as(usize, 0), std.mem.count(u8, retained_source.bytes, anchored), );}
fn checkLifecycleAllocationFailures(alloc: Allocator) !void { var runtime = lifecycleTestRuntime(64); defer runtime.deinit(alloc); runtime.maxxing_mode = .legacy; const existing = try runtime.appendRawTranscriptEntryClassified( alloc, "existing transcript state\n", .subagent_status, ); const entry_id = startLifecycle(&runtime, alloc, 1, "transaction") catch |err| { try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount()); try std.testing.expectEqual(@as(usize, 0), runtime.lifecyclePinCount()); try expectRawEntryBytes(&runtime, existing, "existing transcript state\n"); return err; }; _ = runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = lifecycleId(1, "transaction"), .text = "● Reading updated", } }) catch |err| { try std.testing.expect(runtime.isLifecyclePinned(entry_id)); try std.testing.expect(std.mem.find( u8, runtime.toolStatusEntryLabel(entry_id).?, "updated", ) == null); return err; }; _ = runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .completed }, }) catch |err| { try expectRawEntryBytes(&runtime, entry_id, "● Reading updated\n"); try std.testing.expect(runtime.isLifecyclePinned(entry_id)); return err; }; runtime.finishLifecycleBatch(alloc) catch |err| { try std.testing.expect(runtime.toolActivityRecord(lifecycleId(1, "transaction")) != null); try std.testing.expect(runtime.isLifecyclePinned(entry_id)); return err; }; try std.testing.expect(runtime.toolActivityRecord(lifecycleId(1, "transaction")) == null); try std.testing.expect(!runtime.isLifecyclePinned(entry_id));}
test "transcript lifecycle transactions are atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkLifecycleAllocationFailures, .{}, );}
fn checkLateTerminalFallbackAllocationFailures(alloc: Allocator) !void { var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); runtime.maxxing_mode = .legacy; const id = lifecycleId(1, "late-terminal");
_ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "read_file", .activity_kind = .read, } }); const entry_id = runtime.toolActivityRecord(id).?.entry_id; _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .completed, } });
_ = runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Late completion" }, .result = "late result", } }) catch |err| { try expectRawEntryBytes(&runtime, entry_id, "● Tool was not executed\n"); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expect(detail.result == null); try std.testing.expectEqual( transcript_blocks.ToolFallbackDisposition.not_executed, detail.fallback_disposition.?, ); runtime.maxxing_mode = .minimal; var compact = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer compact.deinit(std.testing.allocator); try std.testing.expect(std.mem.find(u8, compact.bytes, "1 not executed") != null); return err; };
var expected: [128]u8 = undefined; try expectRawEntryBytes(&runtime, entry_id, try std.fmt.bufPrint( &expected, "{s}●{s} Late completion\n", .{ ui_render.system_notice_text_style, ui_render.reset_style }, )); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expectEqualStrings("late result", detail.result.?); try std.testing.expect(detail.fallback_disposition == null); runtime.maxxing_mode = .minimal; var compact = try runtime.prepareTranscriptSource(std.testing.allocator, null); defer compact.deinit(std.testing.allocator); try std.testing.expect(std.mem.find(u8, compact.bytes, "1 not executed") == null); try std.testing.expect(std.mem.find(u8, compact.bytes, "Late completion") != null);}
test "late terminal fallback replacement is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkLateTerminalFallbackAllocationFailures, .{}, );}
fn checkProvisionalTerminalAllocationFailures(alloc: Allocator) !void { var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); runtime.maxxing_mode = .legacy; const id = lifecycleId(1, "provisional-terminal");
_ = try runtime.applyToolLifecycle(alloc, .{ .provisional = .{ .id = id, .tool_name = "read_file", .activity_kind = .read, } }); const entry_id = runtime.toolActivityRecord(id).?.entry_id; const entries_before = runtime.entries.items.len; const next_entry_id_before = runtime.next_entry_id;
_ = runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Read provisional file" }, .result = "provisional result", } }) catch |err| { try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .provisional); try std.testing.expectEqual(entries_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expectEqualStrings("read_file", detail.tool_name); try std.testing.expectEqual(types.ToolActivityKind.read, detail.activity_kind.?); try std.testing.expect(detail.result == null); try std.testing.expect(detail.outcome == null); const status = runtime.toolStatusEntryLabel(entry_id).?; try std.testing.expect(std.mem.find(u8, status, "read_file") != null); try std.testing.expect(std.mem.find(u8, status, "Read provisional file") == null); return err; };
try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .terminal); try std.testing.expectEqual(entries_before, runtime.entries.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expectEqualStrings("read_file", detail.tool_name); try std.testing.expectEqualStrings("provisional result", detail.result.?); try std.testing.expectEqual(types.ToolOutcomeKind.completed, detail.outcome.?);}
test "provisional terminal admission is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkProvisionalTerminalAllocationFailures, .{}, );}
fn checkCommandProcessTerminalAllocationFailures(alloc: Allocator) !void { var runtime = lifecycleTestRuntime(null); defer runtime.deinit(alloc); runtime.maxxing_mode = .legacy; const id = lifecycleId(1, "command-process-terminal");
_ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .reconciles_provisional_call_id = null, .tool_name = "run_command", .activity_kind = .command, .arguments_json = "{\"command\":\"true\"}", } }); const entry_id = runtime.toolActivityRecord(id).?.entry_id; const entries_before = runtime.entries.items.len; const blocks_before = runtime.command_output_blocks.items.len; const next_entry_id_before = runtime.next_entry_id;
_ = runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Ran true" }, .result_memory = .{ .command_process_presentation = .{ .exit_code = 0 } }, } }) catch |err| { try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .authoritative); try std.testing.expectEqual(entries_before, runtime.entries.items.len); try std.testing.expectEqual(blocks_before, runtime.command_output_blocks.items.len); try std.testing.expectEqual(next_entry_id_before, runtime.next_entry_id); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expect(detail.command_process_presentation == null); try std.testing.expect(detail.command_output_entry_id == null); const status = runtime.toolStatusEntryLabel(entry_id).?; try std.testing.expect(std.mem.find(u8, status, "run_command") != null); try std.testing.expect(std.mem.find(u8, status, "Ran true") == null); return err; };
try std.testing.expect(runtime.toolActivityRecord(id).?.phase == .terminal); try std.testing.expectEqual(entries_before + 1, runtime.entries.items.len); try std.testing.expectEqual(blocks_before + 1, runtime.command_output_blocks.items.len); try std.testing.expectEqual(next_entry_id_before + 1, runtime.next_entry_id); const detail = runtime.toolDetailForEntry(entry_id).?; try std.testing.expectEqual( types.CommandProcessPresentation{ .exit_code = 0 }, detail.command_process_presentation.?, ); try std.testing.expectEqual(next_entry_id_before, detail.command_output_entry_id.?); try std.testing.expectEqual(next_entry_id_before, runtime.command_output_blocks.items[0].entry_id.?);}
test "command process terminal admission is atomic across allocation failures" { try std.testing.checkAllAllocationFailures( std.testing.allocator, checkCommandProcessTerminalAllocationFailures, .{}, );}
test "capped parallel lifecycle progress keeps bounded allocations and pins" { const backing = std.testing.allocator; var counted = std.testing.FailingAllocator.init(backing, .{}); const alloc = counted.allocator(); var runtime = lifecycleTestRuntime(256); defer runtime.deinit(alloc);
_ = try runtime.appendRawTranscriptEntryClassified( alloc, "unrelated output retained near the configured transcript cap\n", .subagent_status, ); const first_entry_id = try startLifecycle(&runtime, alloc, 1, call_ids[0]); const second_entry_id = try startLifecycle(&runtime, alloc, 1, call_ids[1]); try std.testing.expectEqual(@as(usize, 2), runtime.tool_details.items.len); try std.testing.expect(runtime.toolDetailForEntry(first_entry_id) != null); try std.testing.expect(runtime.toolDetailForEntry(second_entry_id) != null); const capacity_after_start = runtime.tool_details.capacity; const progress_text = "● Reading progress " ++ ("x" ** 256); _ = try runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = lifecycleId(1, call_ids[0]), .text = progress_text, } }); try std.testing.expectEqual(@as(usize, 2), runtime.tool_details.items.len); try std.testing.expectEqual(capacity_after_start, runtime.tool_details.capacity);
var allocations_before_progress = counted.allocations; for (0..120) |index| { if (index == 20) allocations_before_progress = counted.allocations; _ = try runtime.applyToolLifecycle(alloc, .{ .progress = .{ .id = lifecycleId(1, call_ids[index % call_ids.len]), .text = "● Reading progress", } }); try std.testing.expectEqual(capacity_after_start, runtime.tool_details.capacity); } try std.testing.expectEqual(@as(usize, 2), runtime.tool_details.items.len); try std.testing.expect(runtime.toolDetailForEntry(first_entry_id) != null); try std.testing.expect(runtime.toolDetailForEntry(second_entry_id) != null); try std.testing.expect(counted.allocations - allocations_before_progress <= 600); try std.testing.expectEqual(@as(usize, 2), runtime.lifecyclePinCount());}
const call_ids = [_][]const u8{ "first", "second" };
test "lifecycle pins survive low cap until batch cleanup restores prune eligibility" { const alloc = std.testing.allocator; var runtime = lifecycleTestRuntime(48); defer runtime.deinit(alloc);
const first = try startLifecycle(&runtime, alloc, 1, call_ids[0]); const second = try startLifecycle(&runtime, alloc, 1, call_ids[1]); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "ordinary output that creates retention pressure\n", .subagent_status, );
try std.testing.expectEqual(@as(usize, 2), runtime.lifecyclePinCount()); try std.testing.expect(transcriptContainsEntry(&runtime, first)); try std.testing.expect(transcriptContainsEntry(&runtime, second));
_ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 1, .outcome = .completed, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = lifecycleId(1, "first"), .outcome = .{ .kind = .completed, .summary = "● First complete" }, } }); try std.testing.expectEqual(@as(usize, 2), runtime.lifecyclePinCount()); var first_complete_expected: [128]u8 = undefined; try std.testing.expectEqualStrings( try std.fmt.bufPrint( &first_complete_expected, "{s}●{s} First complete\n", .{ ui_render.system_notice_text_style, ui_render.reset_style }, ), runtime.entries.items[0].raw_bytes.bytes, );
try runtime.finishLifecycleBatch(alloc); _ = try runtime.appendRawTranscriptEntryClassified( alloc, "next ordinary retention pass\n", .subagent_status, );
try std.testing.expectEqual(@as(usize, 0), runtime.lifecyclePinCount()); try std.testing.expectEqual(@as(usize, 0), runtime.toolActivityRecordCount()); try std.testing.expect( !transcriptContainsEntry(&runtime, first) or !transcriptContainsEntry(&runtime, second), );}
test "finality floor holds unfenced tool turn across quiet ticks and settles after the fence" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(60, 10, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
for (0..6) |index| { var line: [32]u8 = undefined; const text = try std.fmt.bufPrint(&line, "final context {d:0>2}\n", .{index}); _ = try runtime.appendRawTranscriptEntry(alloc, text); } var base_source = try runtime.prepareTranscriptSource(alloc, null); defer base_source.deinit(alloc); var base_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &base_source); defer base_prepared.deinit(alloc); try commitPreparedForTest(&runtime, alloc, &base_source, &base_prepared);
var turn_call_ids: [8][12]u8 = undefined; for (0..8) |index| { const call_id = try std.fmt.bufPrint(&turn_call_ids[index], "t2-call-{d:0>2}", .{index}); const id = types.ToolLifecycleId{ .turn_id = 2, .call_id = call_id }; _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .presentation_group_id = .{ .turn_id = 2, .anchor_step_id = 1 }, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Read one file" }, } }); } try runtime.finishLifecycleBatch(alloc); try std.testing.expectEqual(@as(u64, 0), runtime.finalizedToolTurnWatermark());
var live_source = try runtime.prepareTranscriptSource(alloc, null); defer live_source.deinit(alloc); var live_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &live_source); defer live_prepared.deinit(alloc); try commitPreparedForTest(&runtime, alloc, &live_source, &live_prepared);
const held = runtime.transcript_commit_state.stable; try std.testing.expect(held.visual_offset > held.history_visual_offset);
// Quiet ticks over the unchanged flow release nothing: byte stability // is not finality while the turn is unfenced. var quiet_source = try runtime.prepareTranscriptSource(alloc, null); defer quiet_source.deinit(alloc); var quiet_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &quiet_source); defer quiet_prepared.deinit(alloc); const quiet_facts = runtime.planTranscriptScroll(&quiet_prepared); try std.testing.expect(quiet_facts.source_compatible); try std.testing.expectEqual(@as(u32, 0), quiet_facts.semantic_rows); try std.testing.expect(quiet_facts.finality_hold);
// A later mutation of the same group still releases nothing. const late_call = types.ToolLifecycleId{ .turn_id = 2, .call_id = "t2-late" }; _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = late_call, .presentation_group_id = .{ .turn_id = 2, .anchor_step_id = 1 }, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = late_call, .outcome = .{ .kind = .completed, .summary = "Read late file" }, } }); try runtime.finishLifecycleBatch(alloc); var mutated_source = try runtime.prepareTranscriptSource(alloc, null); defer mutated_source.deinit(alloc); var mutated_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &mutated_source); defer mutated_prepared.deinit(alloc); const mutated_facts = runtime.planTranscriptScroll(&mutated_prepared); try std.testing.expectEqual(@as(u32, 0), mutated_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), mutated_facts.planned_rows); try commitPreparedForTest(&runtime, alloc, &mutated_source, &mutated_prepared);
// The fence and the final mutation arrive in one batch: the first // post-fence frame is byte-incompatible and must hold (zero release), // re-anchoring on the final flow. _ = try runtime.applyToolLifecycle(alloc, .{ .turn_finished = .{ .turn_id = 2, .outcome = .completed, } }); try runtime.finishLifecycleBatch(alloc); try std.testing.expectEqual(@as(u64, 2), runtime.finalizedToolTurnWatermark());
// The debt settles on the first eligible frame after the fence: the // same frame when the fence publication changed no bytes, or the frame // after a byte-incompatible publication re-anchors (Phase A then B). var released: u32 = 0; for (0..2) |frame_index| { var frame_source = try runtime.prepareTranscriptSource(alloc, null); defer frame_source.deinit(alloc); var frame_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &frame_source); defer frame_prepared.deinit(alloc); const frame_facts = runtime.planTranscriptScroll(&frame_prepared); if (!frame_facts.source_compatible) { // Phase A: zero release while the anchor is stale. try std.testing.expectEqual(@as(u32, 0), frame_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), frame_facts.planned_rows); try std.testing.expect(frame_facts.finality_hold); try std.testing.expectEqual(@as(usize, 0), frame_index); } released += frame_facts.semantic_rows; try commitPreparedForTest(&runtime, alloc, &frame_source, &frame_prepared); } try std.testing.expect(released > 0); const settled = runtime.transcript_commit_state.stable; try std.testing.expectEqual(settled.visual_offset, settled.history_visual_offset);}
test "catch-up release materializes history before staging a larger finality hold" { const alloc = std.testing.allocator; const committed_flow = "row-00\nrow-01\nrow-02\nrow-03\n" ++ "row-04\nrow-05\nrow-06\nrow-07\n"; const target_flow = committed_flow ++ "row-08\nrow-09\nrow-10\nrow-11\nrow-12\nrow-13\n"; const finality_floor = "row-00\nrow-01\nrow-02\n".len; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var committed_source = try testSource(alloc, committed_flow, runtime.layout.cols); defer committed_source.deinit(alloc); var committed_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &committed_source, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_flow, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); switch (runtime.transcript_commit_state) { .stable => |*anchor| { anchor.history_visual_offset = 0; anchor.history_catchup_pending = true; }, .invalid, .recovering => return error.TestExpectedStableTranscript, }
var source = try testSource(alloc, target_flow, runtime.layout.cols); defer source.deinit(alloc); source.finality.mutation_pin_start = finality_floor; var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u32, 3), facts.semantic_rows); try std.testing.expect(facts.semantic_rows > 0); try std.testing.expect( facts.target_visual_offset - facts.source_visual_offset > facts.semantic_rows, ); try std.testing.expect(facts.finality_hold);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqualStrings( "row-00\r\nrow-01\r\nrow-02\r\n", transition.document_append.bytes, ); switch (transition.document_append.clear) { .rows => |rows| try std.testing.expectEqual(@as(u16, 3), rows), .remainder => return error.TestExpectedHistoryReplay, }}
test "partial finality release bounds append before staging withheld viewport" { const alloc = std.testing.allocator; const committed_flow = "row-00\nrow-01\nrow-02\nrow-03\n" ++ "row-04\nrow-05\nrow-06\nrow-07\n"; const target_flow = committed_flow ++ "row-08\nrow-09\nrow-10\nrow-11\nrow-12\nrow-13\n"; const finality_floor = "row-00\nrow-01\nrow-02\nrow-03\nrow-04\n".len; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
var committed_source = try testSource(alloc, committed_flow, runtime.layout.cols); defer committed_source.deinit(alloc); var committed_prepared = try prepareTestSourceForCurrentArea( &runtime, alloc, &committed_source, ); defer committed_prepared.deinit(alloc); try installStableAnchorForTest( &runtime, alloc, committed_flow, committed_prepared.selection, preparedVisualOffsetForTest(&committed_prepared), committed_prepared.cursor.cursor_row, committed_prepared.cursor.cursor_col, 1, ); switch (runtime.transcript_commit_state) { .stable => |*anchor| anchor.total_visual_rows = 8, .invalid, .recovering => return error.TestExpectedStableTranscript, }
var source = try testSource(alloc, target_flow, runtime.layout.cols); defer source.deinit(alloc); source.finality.mutation_pin_start = finality_floor; var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc); const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expectEqual(@as(u32, 4), facts.source_visual_offset); try std.testing.expectEqual(@as(u32, 10), facts.target_visual_offset); try std.testing.expectEqual(@as(u32, 1), facts.semantic_rows); try std.testing.expectEqual(@as(u16, 1), facts.planned_rows); try std.testing.expect(facts.finality_hold);
const scroll_plan = render_engine.frame_scroll_plan.merge( runtime.layout.rows, runtime.owned_top_row, 0, facts.planned_rows, ); var plan = testPaintPlan(&runtime, prepared.selection); var transition = try resolveAndSealTranscriptTransitionForTest( &runtime, alloc, &source, &prepared, render_engine.frame_layout.CommittedLayoutSnapshot.fromPaintPlan(plan), &plan, scroll_plan, ); defer transition.deinit(alloc);
try std.testing.expectEqualStrings( "row-08\r\n", transition.document_append.bytes, ); try std.testing.expectEqual(@as(u32, 10), transition.visual_offset); try std.testing.expectEqual(@as(u32, 5), transition.history_visual_offset);}
test "recovery growth does not release rows past the finality floor" { const alloc = std.testing.allocator; const attempt_flow = "row-00\nrow-01\nrow-02\nrow-03\n" ++ "row-04\nrow-05\nrow-06\nrow-07\n"; const grown_flow = attempt_flow ++ "row-08\nrow-09\nrow-10\nrow-11\n"; const finality_floor = "row-00\nrow-01\nrow-02\nrow-03\n".len; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(20, 8, 4), .owned_top_row = 1, .transcript_commit_state = .{ .recovering = .{ .accepted_visual_offset = 4, .accepted_history_visual_offset = 4, .attempt_visual_offset = 4, .attempt_total_visual_rows = 8, .materialized_visual_offset = 4, .materialized_visual_rows = 4, .materialized_flow_len = attempt_flow.len, .attempt_cols = 20, .tracks_semantic_progress = true, .flow = try alloc.dupe(u8, attempt_flow), .cursor_row = 4, .cursor_col = 1, } }, }; defer runtime.deinit(alloc);
var source = try testSource(alloc, grown_flow, runtime.layout.cols); defer source.deinit(alloc); source.finality.mutation_pin_start = finality_floor; var prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &source); defer prepared.deinit(alloc);
const facts = runtime.planTranscriptScroll(&prepared); try std.testing.expect(facts.source_compatible); try std.testing.expect(facts.recovery_progress_compatible); try std.testing.expectEqual(@as(u32, 8), facts.target_visual_offset); try std.testing.expectEqual(@as(u32, 0), facts.semantic_rows); try std.testing.expectEqual(@as(u32, 0), facts.semantic_progress_rows); try std.testing.expectEqual(@as(u16, 0), facts.planned_rows);}
test "pending replacement notice holds release until the finished replacement settles" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(24, 10, 4), .owned_top_row = 1, }; defer runtime.deinit(alloc);
for (0..4) |index| { var line: [24]u8 = undefined; const text = try std.fmt.bufPrint(&line, "history {d:0>2}\n", .{index}); _ = try runtime.appendRawTranscriptEntry(alloc, text); } var base_source = try runtime.prepareTranscriptSource(alloc, null); defer base_source.deinit(alloc); var base_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &base_source); defer base_prepared.deinit(alloc); try commitPreparedForTest(&runtime, alloc, &base_source, &base_prepared); const notice_id = try runtime.appendReplaceableSemanticNotice(alloc, .{ .topic = "feedback", .tone = .neutral, .body = "Preparing feedback report while external work is blocking", }); for (0..6) |index| { var line: [24]u8 = undefined; const text = try std.fmt.bufPrint(&line, "later {d:0>2}\n", .{index}); _ = try runtime.appendRawTranscriptEntry(alloc, text); }
var live_source = try runtime.prepareTranscriptSource(alloc, null); defer live_source.deinit(alloc); var live_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &live_source); defer live_prepared.deinit(alloc); try commitPreparedForTest(&runtime, alloc, &live_source, &live_prepared); const held = runtime.transcript_commit_state.stable; try std.testing.expect(held.visual_offset > held.history_visual_offset);
// Quiet frames while the producer blocks release nothing. var quiet_source = try runtime.prepareTranscriptSource(alloc, null); defer quiet_source.deinit(alloc); var quiet_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &quiet_source); defer quiet_prepared.deinit(alloc); const quiet_facts = runtime.planTranscriptScroll(&quiet_prepared); try std.testing.expect(quiet_facts.source_compatible); try std.testing.expectEqual(@as(u32, 0), quiet_facts.semantic_rows); try std.testing.expect(quiet_facts.finality_hold);
// The finished replacement clears the pin; the incompatible frame // re-anchors with zero release and the next frame settles everything. try std.testing.expect(try runtime.replaceSemanticNotice(alloc, notice_id, .{ .topic = "feedback", .tone = .success, .body = "Feedback report ready", })); var replaced_source = try runtime.prepareTranscriptSource(alloc, null); defer replaced_source.deinit(alloc); var replaced_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &replaced_source); defer replaced_prepared.deinit(alloc); const replaced_facts = runtime.planTranscriptScroll(&replaced_prepared); try std.testing.expect(!replaced_facts.source_compatible); try std.testing.expectEqual(@as(u32, 0), replaced_facts.semantic_rows); try std.testing.expectEqual(@as(u16, 0), replaced_facts.planned_rows); try commitPreparedForTest(&runtime, alloc, &replaced_source, &replaced_prepared);
var settle_source = try runtime.prepareTranscriptSource(alloc, null); defer settle_source.deinit(alloc); try std.testing.expect( std.mem.find(u8, settle_source.bytes, "report ready") != null, ); var settle_prepared = try prepareTestSourceForCurrentArea(&runtime, alloc, &settle_source); defer settle_prepared.deinit(alloc); const settle_facts = runtime.planTranscriptScroll(&settle_prepared); try std.testing.expect(settle_facts.source_compatible); try std.testing.expect(settle_facts.semantic_rows > 0); try commitPreparedForTest(&runtime, alloc, &settle_source, &settle_prepared); const settled = runtime.transcript_commit_state.stable; try std.testing.expectEqual(settled.visual_offset, settled.history_visual_offset);}
test "finality candidates keep tool turn and replaceable tail offsets independent" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(60, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
const id = types.ToolLifecycleId{ .turn_id = 5, .call_id = "boundary-call" }; _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .presentation_group_id = .{ .turn_id = 5, .anchor_step_id = 1 }, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Read boundary file" }, } }); try runtime.finishLifecycleBatch(alloc); _ = try runtime.appendRawTranscriptEntry(alloc, "settled context line\n"); _ = try transcript_store.appendReplaceableTranscriptLineSilent( &runtime, alloc, "working status line", );
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), source.finality.tool_turn_floors.len); const group_floor = source.finality.tool_turn_floors[0]; try std.testing.expectEqual(@as(u64, 5), group_floor.turn_id); try std.testing.expect(group_floor.start_byte < source.bytes.len); // The replaceable-tail contract keeps its own offset; the finality // boundary does not repurpose it. try std.testing.expect(source.replaceable_last_line); try std.testing.expect(source.replaceable_start > group_floor.start_byte); try std.testing.expect(source.replaceable_start < source.bytes.len);}
fn applyCompletedReadForFinalityTest( runtime: *TranscriptRuntime, alloc: Allocator, turn_id: u64, call_id: []const u8, presentation_group_id: ?types.ToolPresentationGroupId,) !void { const id = types.ToolLifecycleId{ .turn_id = turn_id, .call_id = call_id }; _ = try runtime.applyToolLifecycle(alloc, .{ .authoritative_started = .{ .id = id, .presentation_group_id = presentation_group_id, .reconciles_provisional_call_id = null, .tool_name = "read_file", .activity_kind = .read, } }); _ = try runtime.applyToolLifecycle(alloc, .{ .terminal = .{ .id = id, .outcome = .{ .kind = .completed, .summary = "Read finality fixture" }, } });}
test "finality candidates anchor a fully grouped turn at its newest rendered group" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 14, 10), .owned_top_row = 1, }; defer runtime.deinit(alloc); runtime.maxxing_mode = .minimal;
const group_a = types.ToolPresentationGroupId{ .turn_id = 9, .anchor_step_id = 1 }; for ([_][]const u8{ "group-a-1", "group-a-2", "group-a-3" }) |call_id| { try applyCompletedReadForFinalityTest(&runtime, alloc, 9, call_id, group_a); } _ = try runtime.appendRawTranscriptEntry(alloc, "SECOND_GROUP_INTRO\n"); const group_b = types.ToolPresentationGroupId{ .turn_id = 9, .anchor_step_id = 2 }; try applyCompletedReadForFinalityTest(&runtime, alloc, 9, "group-b-1", group_b);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), source.finality.tool_turn_floors.len); try std.testing.expect(source.finality.mutation_pin_start == null);
const group_a_header = try std.fmt.allocPrint( alloc, "{s}●\x1b[0m {s}3 tool calls · 3 read\x1b[0m", .{ user_message_card.minimalMarkerStyle(), ui_render.statusline_style }, ); defer alloc.free(group_a_header); const group_b_header = try std.fmt.allocPrint( alloc, "{s}●\x1b[0m {s}1 tool call · 1 read\x1b[0m", .{ user_message_card.minimalMarkerStyle(), ui_render.statusline_style }, ); defer alloc.free(group_b_header); const group_a_start = std.mem.find(u8, source.bytes, group_a_header) orelse return error.TestExpectedGroupAHeader; const group_b_start = std.mem.find(u8, source.bytes, group_b_header) orelse return error.TestExpectedGroupBHeader; try std.testing.expect(group_a_start < group_b_start);
const floor = source.finality.tool_turn_floors[0]; try std.testing.expectEqual(@as(u64, 9), floor.turn_id); try std.testing.expectEqual(group_b_start, floor.start_byte);}
test "finality candidates keep a mixed legacy turn at its earliest rendered tool row" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(80, 14, 10), .owned_top_row = 1, }; defer runtime.deinit(alloc); runtime.maxxing_mode = .minimal;
const group_a = types.ToolPresentationGroupId{ .turn_id = 10, .anchor_step_id = 1 }; try applyCompletedReadForFinalityTest(&runtime, alloc, 10, "mixed-group-a", group_a); try applyCompletedReadForFinalityTest(&runtime, alloc, 10, "mixed-legacy", null); _ = try runtime.appendRawTranscriptEntry(alloc, "LATEST_GROUP_INTRO\n"); const group_b = types.ToolPresentationGroupId{ .turn_id = 10, .anchor_step_id = 2 }; try applyCompletedReadForFinalityTest(&runtime, alloc, 10, "mixed-group-b", group_b);
var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual(@as(usize, 1), source.finality.tool_turn_floors.len); try std.testing.expect(source.finality.mutation_pin_start == null);
const group_a_header = try std.fmt.allocPrint( alloc, "{s}●\x1b[0m {s}1 tool call · 1 read\x1b[0m", .{ user_message_card.minimalMarkerStyle(), ui_render.statusline_style }, ); defer alloc.free(group_a_header); const earliest_tool_start = std.mem.find(u8, source.bytes, group_a_header) orelse return error.TestExpectedGroupAHeader; const floor = source.finality.tool_turn_floors[0]; try std.testing.expectEqual(@as(u64, 10), floor.turn_id); try std.testing.expectEqual(earliest_tool_start, floor.start_byte);}
test "finality candidates retain the global pin for an unidentified tool row" { const alloc = std.testing.allocator; var runtime = TranscriptRuntime{ .layout = transcriptTestLayout(60, 12, 8), .owned_top_row = 1, }; defer runtime.deinit(alloc);
_ = try transcript_store.appendPinnedToolStatusAtomic( &runtime, alloc, "● Running unidentified tool\n", ); var source = try runtime.prepareTranscriptSource(alloc, null); defer source.deinit(alloc); try std.testing.expectEqual(@as(usize, 0), source.finality.tool_turn_floors.len); try std.testing.expect(source.finality.mutation_pin_start != null);}