import test from 'node:test';import assert from 'node:assert/strict';import {mkdtempSync,rmSync,readFileSync,writeFileSync} from 'node:fs';import {join} from 'node:path';import {tmpdir} from 'node:os';import {RuntimeFeedback,readRuntimeFeedback,runtimeFeedbackContext} from '../src/runtime-feedback.mjs'; test('runtime errors are bounded, redacted, revision-scoped and cleared on piece changes',t=>{const cwd=mkdtempSync(join(tmpdir(),'easel-runtime-'));t.after(()=>rmSync(cwd,{recursive:true,force:true}));const f=new RuntimeFeedback(cwd);f.select({channel:'tester/demo',revision:'hash-one',version:1,piece:'demo.mjs'});f.log({level:'error',text:'TypeError: circle is not a function; Bearer private-token',source:'demo.mjs',line:5});f.frame({width:100,height:80,colors:1,blank:true});const result=readRuntimeFeedback(cwd,{channel:'tester/demo',revision:'hash-one'});assert.equal(result.logs.length,1);assert(!result.logs[0].text.includes('private-token'));assert(result.frame.blank);assert.match(runtimeFeedbackContext(result),/untrusted diagnostic data/);assert.equal(readRuntimeFeedback(cwd,{revision:'old'}),null);for(let i=0;i<80;i++)f.log({level:'warn',text:'warning '+i});assert.equal(readRuntimeFeedback(cwd).logs.length,50);f.select({channel:'tester/next',revision:'hash-two',version:1});assert.equal(readRuntimeFeedback(cwd).logs.length,0);assert.equal(readRuntimeFeedback(cwd).frame,null);const path=join(cwd,'.easel/preview-feedback.json');const old=JSON.parse(readFileSync(path));old.updatedAt='2000-01-01T00:00:00Z';writeFileSync(path,JSON.stringify(old));assert.equal(readRuntimeFeedback(cwd),null);});