land: area/playback-qa 17163984f7 (playback-qa)

This commit is contained in:
thePR0M3TH3AN committed 2026-10-20 12:29:45 -04:00
commit 06e920e77e
19 files changed
+3998 -8

No files matched your search

+8 -8
View File
@@ -1,10 +1,10 @@
{ {
"id": "playback-qa-2", "id": "playback-qa-2",
"area": "playback-qa", "area": "playback-qa",
"status": "blocked", "status": "blocked",
"title": "Capture actual-app local core-flow/mobile baseline before UI changes", "title": "Capture actual-app local core-flow/mobile baseline before UI changes",
"blockedOn": "Client7 routed cold-feed subscription refresh fix; await durable landing + rebuilt integrated artifact + dispatch browser clearance to finish original mobile/UI baseline.", "blockedOn": "Original strict Upload overflow finding remains open:360 document362,390 document394; minor/usable geometry measured. Separate original3viewport/core/Home/focus coverage completed; await dispatch disposition, no optional CSS fix.",
"addedOn": "2026-10-20", "addedOn": "2026-10-20",
"filedAt": "1bb3a4fc452969f060c09a286b72b8cd7ac4123e", "filedAt": "1bb3a4fc452969f060c09a286b72b8cd7ac4123e",
"notes": "Measured hard localreviewblocker16:06:34.174→16:06:51.787:transport3EVENT+EOSE/client+appmaps3/actualfiltered3,all3allow/serviceInclude=true,notprivate/nsfw/blocked;whitelistfalse/lockdownfalse/bodynotinert/docvisible/containerconnected. Passivecache0→subscriptionupdate3;viewcurrent0/rendered0/signature__EMPTY__/lastmetadata.reasoncache/DOM0after15s. SourceNostrService.loadVideos livecallback caches/emitswithoutonVideos usedbyfeedrefresh. Dispatch16:08:41 routedclient7method-onlyactualservicefix,QAproductread-only/browserHOLD. Originalschema s mismatch disclosed(notpreventingingest/eligibility),observerrelativeimportpageerrorseparatefromproduct;allinterventionsretained. Ownedresourcesreleased,noUIflowsorother2viewportsverified. Rendergaptrace/screenshot docs/testing/playback-qa-2-render-gap.md;finishdocs-onlyevidencequeue thenwaitfix/artifact/clearance,notbaselineclosure." "notes": "Final granted run16:25:30.066\u219216:25:33.901UTC,Chromium154,b1174163/build6da89895,frozen830files/pinsverified.9stepsPASS/1FAIL:realcrypto/startup/cold3cards/login/360feed/nav/Profile;Uploadtitle/missingsource/no-publish/6Tab checks reached,then documentoverflowfail (PNG362 vs360).No remainingHome/390/1280/Uploadclose. Allownedresourcesclosed/RELEASE,no productwrites. Exact report/driver/screenshots docs/testing/playback-qa-2-final-evidence.md. Evidenceclosure only,NOT baselinepass/close. Separate dispatch-authorized16:27:44.416\u219216:28:10.112 follow-on25steps/0hardfail:all3viewportTrending/Explore/ForYou/Home3cards/Profile+Uploadvalidation/focus/close completed. Exactmobileoverflow2px/4px,panelsfit,controlsusable;originalfailureopen,notallpass. Browser/serversclosed/RELEASE;docs-onlynormalqueue thenIDLE perdispatch."
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

+102
View File
@@ -0,0 +1,102 @@
# QA2 granted final attempt: exact scratch driver
Unretained diagnostic/browser runner, not an added regression test. SHA256 a420415d0b4e0da1713386458e83c26db4db0d089470c441d043e72920f0967d.
```js
import {createServer} from 'node:http';
import {createHash} from 'node:crypto';
import {mediaResponse} from './media-fixture.mjs';
import {readFile,writeFile} from 'node:fs/promises';
import {resolve,extname} from 'node:path';
import {createInterface} from 'node:readline';
import {createRequire} from 'node:module';
import {chromium} from '/home/user/Documents/GitHub/bitvid/node_modules/playwright/index.mjs';
import {startRelay} from '/home/user/Documents/GitHub/bitvid-playback-qa/scripts/agent/simple-relay.mjs';
const require=createRequire('/home/user/Documents/GitHub/bitvid/package.json');
const {finalizeEvent,verifyEvent}=require('nostr-tools');
import {NOTE_TYPES,validateEventStructure} from '/home/user/Documents/GitHub/bitvid-playback-qa/js/nostrEventSchemas.js';
const base='/tmp/bitvid-playback-qa-2-final',root=base+'/dist';
const evidence='/home/user/Documents/GitHub/bitvid-playback-qa/docs/testing';
const report={driver:'noninteractive bounded actions',started:new Date().toISOString(),mirrorHits:[],blockedHttp:[],blockedWs:[],failedLocal:[],pageErrors:[],consoleErrors:[],actions:[]};
const sk=new Uint8Array(32).fill(0x7b);
const fixtureBytes=await readFile(base+'/fixtures/qa2-unplayed.webm');
if(createHash('sha256').update(fixtureBytes).digest('hex')!=='d911005a5bca7fb1f3e5aa2fbee701b6476c9baf93460264c2aa5105dd0b3c69')throw Error('local genuine fixture hash changed');
const frozenManifest=await readFile(base+'/dist-manifest.json');
if(createHash('sha256').update(frozenManifest).digest('hex')!=='2747d37916362971a5abe05db4018adf31b5c7031b48d8e4bd6eb1e19b9fa927')throw Error('integrated artifact manifest changed');
for(const [name,hash] of Object.entries(JSON.parse(frozenManifest)))if(createHash('sha256').update(await readFile(root+'/'+name)).digest('hex')!==hash)throw Error('integrated artifact byte changed: '+name);
const server=createServer(async(req,res)=>{
let path=decodeURIComponent(new URL(req.url,'http://127.0.0.1:31847').pathname);if(path==='/qa2-unplayed.webm'){const r=mediaResponse(req.method,req.headers.range,fixtureBytes);res.writeHead(r.status,r.headers);res.end(r.body);return;}if(path==='/')path='/index.html';const f=resolve(root,'.'+path);
if(!f.startsWith(root+'/')||path.includes('/.')){res.writeHead(404);res.end();return;}
try{const b=await readFile(f);res.setHeader('Content-Type',({'.html':'text/html','.js':'text/javascript','.mjs':'text/javascript','.css':'text/css','.json':'application/json','.svg':'image/svg+xml','.wasm':'application/wasm','.png':'image/png','.webmanifest':'application/manifest+json'})[extname(f)]||'application/octet-stream');res.end(b);}catch{res.writeHead(404);res.end();}
});
let browser,relay,context,page,closed=false,hardDeadline;
async function finish(){if(closed)return;closed=true;clearTimeout(hardDeadline);if(context)await context.close();if(browser)await browser.close();if(relay)await relay.close();await new Promise(ok=>server.close(ok));report.ended=new Date().toISOString();report.resourcesClosed=true;await writeFile(base+'/result.json',JSON.stringify(report,null,2));console.log(JSON.stringify({type:'CLOSED',ended:report.ended,mirrorHits:report.mirrorHits.length,blockedHttp:report.blockedHttp,blockedWs:report.blockedWs,failedLocal:report.failedLocal,pageErrors:report.pageErrors}));}
hardDeadline=setTimeout(()=>{report.deadlineFailure='120s bounded runner deadline';void finish().finally(()=>process.exit(1));},120000);
try{
await new Promise((ok,no)=>{server.once('error',no);server.listen(31847,'127.0.0.1',ok);});
relay=startRelay(31848,{httpPort:31849});
for(let i=0;i<3;i++){const title=i===0?'QA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls':'QA local synthetic video '+i;const event=finalizeEvent({kind:30078,created_at:Math.floor(Date.now()/1000)-i,tags:[['d','qa2-'+i],['t','video'],['s','nostr:qa2-'+i],['title',title],['url','http://127.0.0.1:31847/qa2-unplayed.webm']],content:JSON.stringify({version:3,title,url:'http://127.0.0.1:31847/qa2-unplayed.webm',videoRootId:'qa2-'+i,mode:'dev',isPrivate:false,deleted:false})},sk);if(!validateEventStructure(NOTE_TYPES.VIDEO_POST,event).valid||!verifyEvent(JSON.parse(JSON.stringify(event))))throw Error('canonical real signed fixture invalid');relay.seedEvent(event);}
const fixtureUrl='http://127.0.0.1:31847/qa2-unplayed.webm';
const head=await fetch(fixtureUrl,{method:'HEAD'}),whole=await fetch(fixtureUrl),part=await fetch(fixtureUrl,{headers:{Range:'bytes=0-31'}});
const wholeBytes=Buffer.from(await whole.arrayBuffer()),partBytes=Buffer.from(await part.arrayBuffer());
if(head.status!==200||head.headers.get('content-type')!=='video/webm'||Number(head.headers.get('content-length'))!==fixtureBytes.length||whole.status!==200||!wholeBytes.equals(fixtureBytes)||part.status!==206||!partBytes.equals(fixtureBytes.subarray(0,32)))throw Error('genuine local media HTTP preflight failed');
report.fixtureHttp={head:head.status,get:whole.status,range:part.status,bytes:fixtureBytes.length,contentType:head.headers.get('content-type')};
browser=await chromium.launch({headless:true,executablePath:'/usr/bin/google-chrome',args:['--no-sandbox']});report.browserVersion=browser.version();
context=await browser.newContext({viewport:{width:360,height:800},serviceWorkers:'block'});
const mirror=await readFile(base+'/buffer-6.0.3-local.mjs');
await context.route('**/*',r=>{const url=r.request().url();if(url==='https://cdn.jsdelivr.net/npm/[email protected]/+esm'){report.mirrorHits.push(url);return r.fulfill({body:mirror,contentType:'text/javascript',headers:{'Access-Control-Allow-Origin':'*'}});}const u=new URL(url);if(['127.0.0.1','localhost','[::1]'].includes(u.hostname))return r.continue();report.blockedHttp.push(url);return r.abort('blockedbyclient');});
await context.routeWebSocket('**/*',ws=>{const u=new URL(ws.url());if(['127.0.0.1','localhost','[::1]'].includes(u.hostname))ws.connectToServer();else{report.blockedWs.push(ws.url());ws.close();}});
await context.addInitScript(()=>{localStorage.setItem('hasSeenDisclaimer','true');localStorage.setItem('__bitvidTestMode__','1');localStorage.setItem('__bitvidTestRelays__',JSON.stringify(['ws://127.0.0.1:31848']));window.__bitvidTestRelays__=['ws://127.0.0.1:31848'];localStorage.setItem('bitvid_admin_whitelist_mode','false');});
page=await context.newPage();page.setDefaultTimeout(10000);
page.on('pageerror',e=>report.pageErrors.push(e.message));page.on('console',m=>{if(m.type()==='error')report.consoleErrors.push(m.text().slice(0,700));});page.on('response',r=>{if(r.status()>=400&&new URL(r.url()).hostname==='127.0.0.1')report.failedLocal.push({url:r.url(),status:r.status()});});
await page.goto('http://127.0.0.1:31847/?__test__=1&__testRelays__=ws%3A%2F%2F127.0.0.1%3A31848',{waitUntil:'domcontentloaded'});
try{await page.waitForFunction(()=>typeof window.__bitvidTest__==='object',null,{timeout:15000});await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');return !!m.getApplication();},null,{timeout:15000});await page.locator('[data-testid="video-list"]').waitFor({state:'visible',timeout:15000});report.boot='passed';console.log(JSON.stringify({type:'BOOTED',viewport:{width:360,height:800},body:(await page.locator('body').innerText()).slice(0,3000)}));}
catch(e){report.boot='blocked';report.bootError=e.message;await page.screenshot({path:evidence+'/playback-qa-2-second-boot-blocker.png',fullPage:true});console.log(JSON.stringify({type:'BLOCKED',error:e.message,body:(await page.locator('body').innerText()).slice(0,1500)}));await finish();process.exit(0);}
// Noninteractive: no stdin/readline loop; each action is awaited exactly once.
const check=(condition,message)=>{if(!condition)throw new Error(message);};
const step=async(name,action)=>{const item={name,at:new Date().toISOString()};report.actions.push(item);try{item.result=await action();item.ok=true;console.log(JSON.stringify({type:'STEP',name,ok:true,result:item.result}));return item.result;}catch(e){item.ok=false;item.error=e.message;console.log(JSON.stringify({type:'STEP',name,ok:false,error:e.message}));throw e;}};
const capture=async(name)=>{await page.screenshot({path:evidence+'/'+name,fullPage:true});report.actions.push({screenshot:name});};
const layout=async()=>page.evaluate(()=>({width:innerWidth,documentWidth:document.documentElement.scrollWidth,cardBounds:[...document.querySelectorAll('[data-testid="video-card"]')].map(e=>{const r=e.getBoundingClientRect();return {x:r.x,right:r.right,width:r.width};}),smallControls:[...document.querySelectorAll('button,a,input')].filter(e=>e.getClientRects().length&&getComputedStyle(e).visibility!=='hidden').map(e=>{const r=e.getBoundingClientRect();return {id:e.id,label:(e.getAttribute('aria-label')||e.textContent||'').trim().slice(0,80),width:r.width,height:r.height};}).filter(x=>x.width>0&&x.height>0&&(x.width<44||x.height<44))}));
const modalFocus=async(root)=>{const samples=[];for(let i=0;i<6;i++){await page.keyboard.press('Tab');samples.push(await page.evaluate(selector=>{const el=document.activeElement;return {inside:!!document.querySelector(selector)?.contains(el),id:el?.id,tag:el?.tagName,outline:getComputedStyle(el).outlineStyle,shadow:getComputedStyle(el).boxShadow};},root));}check(samples.every(x=>x.inside),'keyboard focus escaped '+root);return samples;};
try{
await step('actual toolkit ready',async()=>{
const event=[...relay.getEvents().values()].find(e=>e.kind===30078);
const ready=await page.evaluate(async(seed)=>{
const m=await import('/js/nostrToolsBootstrap.js'),t=await m.nostrToolsReady;
const callable=['getPublicKey','finalizeEvent','verifyEvent'].every(k=>typeof t?.[k]==='function');
const state={callable,canonicalIdentity:t===window.__BITVID_CANONICAL_NOSTR_TOOLS__,frozen:Object.isFrozen(t),mockFlag:!!window.__TEST_MODE__||window.process?.env?.NODE_ENV==='test'};
if(!callable)return state;
const sk=new Uint8Array(32).fill(0x7b),clean=JSON.parse(JSON.stringify(seed));
state.validSeed=t.verifyEvent(clean)===true;state.tamperedRejected=t.verifyEvent({...JSON.parse(JSON.stringify(seed)),content:'tampered local challenge'})===false;state.pubkeyMatches=t.getPublicKey(sk)===seed.pubkey;
state.signed=t.finalizeEvent({kind:1,created_at:seed.created_at,tags:[],content:'QA real toolkit sanity'},sk);
return state;
},event);
const {signed,...status}=ready;
check(status.callable&&status.canonicalIdentity&&status.frozen&&!status.mockFlag&&status.validSeed&&status.tamperedRejected&&status.pubkeyMatches,'real toolkit contract unavailable: '+JSON.stringify(status));
const {verifyEvent}=require('nostr-tools');check(verifyEvent(JSON.parse(JSON.stringify(signed)))===true,'actual toolkit signature failed independent Node verification');
return {...status,independentSignatureVerified:true};
});
await step('actual application startup completes',async()=>{
await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');await m.getApplicationReady();return !!m.getApplication();},null,{timeout:15000});
const relayState=await page.evaluate(()=>window.__bitvidTest__.setTestRelays(['ws://127.0.0.1:31848'],{persist:false}));
check(relayState.ok===true,'documented fixture relay alignment failed');
return {readyPromiseCompleted:true,relays:relayState.relays};
});
await step('three synthetic relay cards hydrate',async()=>{await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const items=await page.evaluate(()=>window.__bitvidTest__.getFeedItems());check(items.length===3,'expected exactly3 local cards,got'+items.length);return items.map(x=>({title:x.title,dTag:x.dTag}));});
await step('local test identity login',async()=>{await page.evaluate(()=>window.__bitvidTest__.loginWithNsec('7b'.repeat(32)));await page.locator('[data-testid="profile-button"]').waitFor({state:'visible'});await page.locator('[data-testid="upload-button"]').waitFor({state:'visible'});return {profileVisible:true,uploadVisible:true};});
for(const viewport of [{width:360,height:800},{width:390,height:844},{width:1280,height:720}]){
await page.setViewportSize(viewport);const prefix=String(viewport.width);
await step(prefix+' trending navigation/feed',async()=>{await page.locator('#trendingLink').click();await page.waitForFunction(()=>location.hash.includes('view=trending'));await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const r=await layout();check(r.documentWidth<=r.width,'horizontal document overflow');check(r.cardBounds.every(x=>x.x>=0&&x.right<=r.width),'card extends beyond viewport');return r;});
await capture('playback-qa-2-'+prefix+'-feed.png');
for(const [id,view] of [['#exploreLink','explore'],['#forYouLink','for-you'],['#trendingLink','trending']])await step(prefix+' navigation '+view,async()=>{await page.locator(id).click();await page.waitForFunction(v=>location.hash.includes('view='+v),view);return {hash:await page.evaluate(()=>location.hash),headings:await page.locator('h1,h2').allTextContents()};});
await step(prefix+' Profile open/focus/close',async()=>{await page.locator('[data-testid="profile-button"]').click();await page.locator('#profileModal').waitFor({state:'visible'});const focus=await modalFocus('#profileModal');await capture('playback-qa-2-'+prefix+'-profile.png');await page.locator('#closeProfileModal').click();await page.locator('#profileModal').waitFor({state:'hidden'});await page.waitForFunction(()=>document.activeElement?.id==='profileButton');const restored=await page.evaluate(()=>document.activeElement?.id);check(restored==='profileButton','Profile close did not restore trigger focus');return {focus,restored};});
await step(prefix+' Upload required fields/focus/close',async()=>{const videoCount=()=>[...relay.getEvents().values()].filter(e=>e.kind===30078).length;const before=videoCount();await page.locator('[data-testid="upload-button"]').click();await page.locator('#uploadModal').waitFor({state:'visible'});await page.locator('#btn-mode-external').click();const focus=await modalFocus('#uploadModal');await page.locator('#input-title').fill('');await page.locator('#input-url').fill('');await page.locator('#input-magnet').fill('');await page.locator('#btn-submit').click();const missingTitle=await page.locator('#input-title').evaluate(e=>e.validity.valueMissing);check(missingTitle,'empty title not rejected by native validation');await page.locator('#input-title').fill('QA invalid local form');await page.locator('#btn-submit').click();await page.waitForFunction(()=>document.querySelector('#errorContainer')?.textContent.includes('Please provide at least a Video URL or Magnet Link.'));check(videoCount()===before,'invalid form published video event');await capture('playback-qa-2-'+prefix+'-upload-validation.png');const l=await layout();check(l.documentWidth<=l.width,'Upload horizontal document overflow');await page.locator('#closeUploadModal').click();await page.locator('#uploadModal').waitFor({state:'hidden'});const restored=await page.evaluate(()=>document.activeElement?.id);check(restored==='uploadButton','Upload close did not restore trigger focus');return {focus,missingTitle,noSourceRejected:true,noRelayPublish:true,restored,layout:l};});
await step(prefix+' Home navigation',async()=>{await page.getByRole('link',{name:'Return to the bitvid home page',exact:true}).click();await page.waitForURL('**/index.html');await page.waitForFunction(()=>!!window.__bitvidTest__);await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');await m.getApplicationReady();return !!m.getApplication();},null,{timeout:15000});await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const items=await page.evaluate(()=>window.__bitvidTest__.getFeedItems());check(items.length===3,'Home expected exactly3 local cards');return {url:page.url(),cards:items.length};});
}
report.baseline='completed';
}catch(e){report.baseline='blocked-or-failed';report.failedStep=report.actions.findLast(x=>x.ok===false)?.name;report.failure=e.message;try{report.failureDiagnostics=await page.evaluate(async()=>{const m=await import('/js/applicationContext.js');return {appPresent:!!m.getApplication(),relayHealth:window.__bitvidTest__?.getRelayHealth(),feedItems:window.__bitvidTest__?.getFeedItems(),body:document.body.innerText.slice(0,2000)};});}catch{}await capture('playback-qa-2-resumed-stop.png');}
await finish();
}catch(e){report.runError=e.stack;console.log(JSON.stringify({type:'ERROR',error:e.stack}));await finish();process.exitCode=1;}
```
@@ -0,0 +1,71 @@
# QA2: cold-feed fixed; original overflow failure and separate completed coverage
Actual app tested: unstable b1174163556e2705ba85868e21adcaf51b44bd5f, dispatch build6da89895.
Dispatch supplied explicit exclusive browser grant16:22:06; QA START16:25:27, runner16:25:30.066→16:25:33.901 UTC (3.835s).
All owned context/browser/app+relay servers closed at end; RELEASE16:25:47; dependency symlink removed.
No browser, server or build was run during the prior client7 gate hold. Blocked on fix/artifact from16:08:41 to grant16:22:06 (13m25s).
Original failure below is preserved. Dispatch subsequently authorized one geometry check plus independent remaining coverage; see follow-on below.
## Original run result and limits
`node /tmp/bitvid-playback-qa-2-final/noninteractive.mjs` process exit0 means controlled cleanup, **not baseline success**.
JSON baseline is blocked-or-failed:9 completed steps and1 failed step. Chromium154.0.8037.97, fresh360×800 context:
- Genuine canonical browser toolkit/signature/tamper/independent-Node checks passed; application readiness and existing fixture relay alignment passed.
- Original cold-feed assertion passed: exactly3 genuine signed synthetic events became actual cards within15s, without manual refresh/render/cache/card injection. This verifies the former measured cold-feed symptom on the fixed build, with canonical fixtures.
- Test identity login and360 Trending fit passed: documentWidth360, all3 cards x76.796875/right347.203125/width270.40625.
- Actual Explore, For You and Trending clicks/hash transitions passed. Headings captured; no claim of complete feed content correctness for those views.
- Profile open,6 keyboard tabs contained within modal, close and exact profileButton focus restoration passed.
- Upload opened in External Link mode;6 tabs contained, native empty-title rejection, exact missing-source error and unchanged relay video-event count all passed before the subsequent layout assertion failed.
- First failure: **Upload horizontal document overflow**. Full-page screenshots are362px wide at a360px viewport; feed/Profile screenshots are360px. Exact failed DOM scrollWidth and offending element bounds were not persisted because the assertion threw before returning layout. Do not invent a culprit or precise CSS fix from this evidence.
- Screenshot also shows Upload title/error-banner overlap; captured visual observation, no separately isolated cause.
- Remaining Upload close/focus restoration, Home navigation,390×844 and1280×720 checks were NOT EXECUTED. QA2 remains blocked/incomplete, not closed as successful. No product/CSS/helper/config/test changes.
Visible controls below44px are observations, not an invented failure threshold: e.g. sidebar35.1875, theme32, profile/upload38.390625, card buttons32.
[Feed](playback-qa-2-360-feed.png), [Profile](playback-qa-2-360-profile.png), [Upload failure](playback-qa-2-360-upload-validation.png), [stop](playback-qa-2-final-stop.png).
[Exact report](playback-qa-2-final-result.json), [exact driver](playback-qa-2-final-driver.md).
Report SHA2568434598bc187e203c313c2378e94d3beec853293471de987853af87dbe9eb31f.
## Provenance and fidelity
Fresh private frozen snapshot830files; full manifest SHA2562747d37916362971a5abe05db4018adf31b5c7031b48d8e4bd6eb1e19b9fa927.
All830file bytes verified before server start; supplied index78f8bb3d5ed2a92b5ab388eb9e9c3afd2a475e4525fa6ea23c454ffb0ac8cf40,
CSS283d04642d201edba1e9bd5cbc3ede8d74fbd11b50ff0cd2732d463847d2adf3,
nostrService d23884c8ec46d51ca602de9548e17b417975d6de08fa30d6a6fae76070c573ae all match dispatch pins.
First preparation selected nonexistent css/tailwind.css and ambiguously found duplicate equal-hash generated copies; assertion failed before copying/browser. Corrected to actual index-linked css/tailwind.generated.283d04642d201edb.css; no product change.
Canonical established fixture s=nostr:dTag was added explicitly per dispatch; original failed no-s inputs remain in prior evidence/source/commits. Cheap actual-runner seed-loop preflight:3 unique events,3 schema-valid,3 genuine signatures,3 tampered rejected,3 canonical s tags; exit0. This changes input fidelity, so not a same-input before/after claim. Client7 owns controlled service regression/mutants; QA observed actual DOM after fix.
Profile source uses requestAnimationFrame for restoration; exact bounded focus wait was added before unchanged expected-trigger assertion. Actual Home anchor is index.html with accessible name Return to the bitvid home page; added original required Home action to runner, but not reached.
Runner syntax check exit0. No new retained test/assertion changes, retries or sleeps; no mutant required for these evidence-only files.
Existing genuine VP8 fixture d911005a5bca7fb1f3e5aa2fbee701b6476c9baf93460264c2aa5105dd0b3c69 (1019bytes): actual local HEAD200/GET200/Range206 passed. Fixture not played; no actual playback/decoding/WebTorrent/live-service claim here.
Only exact Buffer CDN URL fulfilled once with previously pinned genuine cached bundle (not CDN-byte equivalence).15 nonlocal HTTP and4 nonlocal WebSocket attempts blocked, including auth fallback/robohash/relay attempts;0 external requests allowed.0 pageerrors,0 failed local HTTP. Private ports31847/31848/31849; preview3000 untouched. No real signer/wallet/cloud/peers.
## Follow-up routing
Dispatch notified first failure plus release; client-reliability notified actual cold3card pass. Possible next owner scope is upload modal/CSS layout, requiring dispatch routing and bounded exact DOM measurements before a fix. QA did not reopen browser or patch product. Original baseline remains required after resolution; stop-milestone review cannot claim these unexecuted checks passed.
Historical evidence: [cold render gap](playback-qa-2-render-gap.md), [prior interventions](playback-qa-2-second-pass.md).
## Separately authorized geometry and remaining coverage
Dispatch16:26:39 authorized exact Upload geometry; if minor and usable, continue independent remaining checks while preserving original failure. START16:27:42, runner16:27:44.416→16:28:10.112 UTC (25.696s); RELEASE16:28:25; all owned resources closed and dependency link removed. No product/CSS edits or build/full-suite run.
`node /tmp/bitvid-playback-qa-2-final/follow-on.mjs` exit0, report explicitly says follow-on coverage completed; original360overflow remains failed/open.25 completed steps,0 hard failures. This is separate diagnostic coverage, **not a passing original baseline**.
| Viewport | Document client/scroll width | Body client/scroll width | Panel client/scroll width | Outcome |
|---|---|---|---|---|
|360×800|360/362|360/362|360/360|2px document overflow, usable controls|
|390×844|390/394|390/394|390/390|4px document overflow, usable controls|
|1280×720|1280/1280|1280/1280|502/502|No document overflow|
ScrollX/Y=0/0 for all samples. Modal root fits viewport.360 control bounds:inputs/publish x38.375→321.625, close283.21875→315.21875,y41.578125→73.578125; successful actual close and uploadButton focus restoration.390 close313.21875→345.21875; successful real close/focus. Inputs were actually filled, native required validation and missing-source message observed, invalid submission did not add relay video events. At desktop the scrolled form URL has negative y; actual prior fill/tab and close work, not all controls claimed simultaneously visible.
All3 viewports completed Trending feed exactly3/cards within viewport, Explore/ForYou/Trending navigation, Profile6Tab containment+close+trigger focus, Upload6Tab containment/title+source validation/no publication/close+trigger focus, and actual Home anchor navigation returning exactly3 cards. Home reload uses real app startup and persisted existing test-mode flag; no manual refreshFeed/render/card injection. Feed widths360/390/1280 fit. Touch-control size observations retained in JSON; no invented44px acceptance change.
Raw offender list includes unlabelled SPANs with large bounds even at desktop (where no document overflow), likely clipped/animated descendants. It does not isolate the cause; no culprit or CSS fix inferred. The diagnostic heuristic >16px or critical horizontal control outside viewport only decides whether to stop follow-on, not a new tolerance for original strict overflow assertion. Original2px failure and mobile4px finding remain open. Header/error overlap is visual observation, not independently isolated severity.
[Full follow-on report](playback-qa-2-follow-on-result.json), SHA2560c8b8eff287e06d47dc830425b258d969bc71eba1f07870b6b9dc88bc5819200; [exact separate driver](playback-qa-2-follow-on-driver.md).
Screenshots for each viewport use playback-qa-2-follow-on-{360,390,1280}-{feed,profile,upload-validation}.png.
4 exact genuine Buffer mirror fulfillments (initial plus3 Home reloads),53 externalHTTP/16 externalWS attempts denied,0 allowed external traffic,0 pageerrors,0 failed localHTTP. Real cloud/signers/peers/deployed CDN/full offline operation remain unverified; no actual media playback/decoding in QA2. Browser closed; dispatch to integrate open minor finding and local-review coverage. No optional CSS work started.
@@ -0,0 +1,459 @@
{
"driver": "noninteractive bounded actions",
"started": "2026-10-20T16:25:30.066Z",
"mirrorHits": [
"https://cdn.jsdelivr.net/npm/[email protected]/+esm"
],
"blockedHttp": [
"https://esm.sh/@aws-sdk/[email protected]?bundle",
"https://cdn.jsdelivr.net/npm/[email protected]/+esm",
"https://esm.sh/[email protected]",
"https://esm.sh/[email protected]?target=es2022&exports=nip04",
"https://esm.sh/[email protected]/nip44?target=es2022",
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js",
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js",
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js",
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js",
"https://cdn.jsdelivr.net/npm/[email protected]/lib/nostr.bundle.min.js",
"https://robohash.org/032ee87ce307cbf86f3eeecea732f73a19698cd07d13394a0c14b52d35798304",
"https://cdn.jsdelivr.net/npm/[email protected]/+esm",
"https://esm.sh/[email protected]",
"https://esm.sh/[email protected]?target=es2022&exports=nip04",
"https://esm.sh/[email protected]/nip44?target=es2022"
],
"blockedWs": [
"wss://relay.damus.io/",
"wss://nos.lol/",
"wss://relay.snort.social/",
"wss://relay.primal.net/"
],
"failedLocal": [],
"pageErrors": [],
"consoleErrors": [
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector",
"[bitvid] Submission failed Error: Please provide at least a Video URL or Magnet Link.\n at UploadModal.handleExternalFlow (http://127.0.0.1:31847/js/ui/components/UploadModal.js:1342:17)\n at UploadModal.handleSubmit (http://127.0.0.1:31847/js/ui/components/UploadModal.js:1280:25)\n at HTMLFormElement.<anonymous> (http://127.0.0.1:31847/js/ui/components/UploadModal.js:360:14)",
"[bitvid] Please provide at least a Video URL or Magnet Link."
],
"actions": [
{
"name": "actual toolkit ready",
"at": "2026-10-20T16:25:32.215Z",
"result": {
"callable": true,
"canonicalIdentity": true,
"frozen": true,
"mockFlag": false,
"validSeed": true,
"tamperedRejected": true,
"pubkeyMatches": true,
"independentSignatureVerified": true
},
"ok": true
},
{
"name": "actual application startup completes",
"at": "2026-10-20T16:25:32.252Z",
"result": {
"readyPromiseCompleted": true,
"relays": [
"ws://127.0.0.1:31848"
]
},
"ok": true
},
{
"name": "three synthetic relay cards hydrate",
"at": "2026-10-20T16:25:32.266Z",
"result": [
{
"title": "QA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls",
"dTag": "qa2-0"
},
{
"title": "QA local synthetic video 1",
"dTag": "qa2-1"
},
{
"title": "QA local synthetic video 2",
"dTag": "qa2-2"
}
],
"ok": true
},
{
"name": "local test identity login",
"at": "2026-10-20T16:25:32.273Z",
"result": {
"profileVisible": true,
"uploadVisible": true
},
"ok": true
},
{
"name": "360 trending navigation/feed",
"at": "2026-10-20T16:25:32.366Z",
"result": {
"width": 360,
"documentWidth": 360,
"cardBounds": [
{
"x": 76.796875,
"right": 347.203125,
"width": 270.40625
},
{
"x": 76.796875,
"right": 347.203125,
"width": 270.40625
},
{
"x": 76.796875,
"right": 347.203125,
"width": 270.40625
}
],
"smallControls": [
{
"id": "sidebarCollapseToggle",
"label": "Expand sidebar",
"width": 35.1875,
"height": 35.1875
},
{
"id": "forYouLink",
"label": "For You",
"width": 35.1875,
"height": 35.1875
},
{
"id": "trendingLink",
"label": "Trending",
"width": 35.1875,
"height": 35.1875
},
{
"id": "mostZappedLink",
"label": "Most Zapped",
"width": 35.1875,
"height": 35.1875
},
{
"id": "",
"label": "Recently Added",
"width": 35.1875,
"height": 35.1875
},
{
"id": "",
"label": "For Kids",
"width": 35.1875,
"height": 35.1875
},
{
"id": "exploreLink",
"label": "Explore",
"width": 35.1875,
"height": 35.1875
},
{
"id": "subscriptionsLink",
"label": "Subscriptions",
"width": 35.1875,
"height": 35.1875
},
{
"id": "",
"label": "History",
"width": 35.1875,
"height": 35.1875
},
{
"id": "footerDropdownButton",
"label": "Show more sidebar links",
"width": 35.1875,
"height": 35.1875
},
{
"id": "themeToggle",
"label": "Switch to dark theme",
"width": 32,
"height": 32
},
{
"id": "uploadButton",
"label": "+",
"width": 38.390625,
"height": 38.390625
},
{
"id": "profileButton",
"label": "",
"width": 38.390625,
"height": 38.390625
},
{
"id": "trendingInfoTrigger",
"label": "How is this feed sorted?",
"width": 16,
"height": 16
},
{
"id": "",
"label": "#video",
"width": 49.8125,
"height": 18.21875
},
{
"id": "",
"label": "More options",
"width": 32,
"height": 32
},
{
"id": "",
"label": "Video settings",
"width": 32,
"height": 32
},
{
"id": "",
"label": "More options",
"width": 32,
"height": 32
},
{
"id": "",
"label": "Video settings",
"width": 32,
"height": 32
},
{
"id": "",
"label": "More options",
"width": 32,
"height": 32
},
{
"id": "",
"label": "Video settings",
"width": 32,
"height": 32
}
]
},
"ok": true
},
{
"screenshot": "playback-qa-2-360-feed.png"
},
{
"name": "360 navigation explore",
"at": "2026-10-20T16:25:32.590Z",
"result": {
"hash": "#view=explore",
"headings": [
"Explore",
"\n Login Options\n ",
"\n Application Form\n ",
"\n Content Appeals Form\n ",
"\n General Feedback Form\n ",
"\n Feature Request Form\n ",
"\n Bug Fix Form\n ",
"\n Search Filters\n ",
"\n Share a Video\n ",
"",
"\n Comments\n ",
"\n Similar Content\n ",
"Edit Video Note",
"Profile",
"Conversations",
"\n Allow browser uploads (bucket CORS)\n ",
"\n Welcome to bitvid\n ",
"\n seed. zap. subscribe.\n "
]
},
"ok": true
},
{
"name": "360 navigation for-you",
"at": "2026-10-20T16:25:32.705Z",
"result": {
"hash": "#view=for-you",
"headings": [
"For You",
"\n Login Options\n ",
"\n Application Form\n ",
"\n Content Appeals Form\n ",
"\n General Feedback Form\n ",
"\n Feature Request Form\n ",
"\n Bug Fix Form\n ",
"\n Search Filters\n ",
"\n Share a Video\n ",
"",
"\n Comments\n ",
"\n Similar Content\n ",
"Edit Video Note",
"Profile",
"Conversations",
"\n Allow browser uploads (bucket CORS)\n ",
"\n Welcome to bitvid\n ",
"\n seed. zap. subscribe.\n "
]
},
"ok": true
},
{
"name": "360 navigation trending",
"at": "2026-10-20T16:25:32.815Z",
"result": {
"hash": "#view=trending",
"headings": [
"Trending",
"\n Login Options\n ",
"\n Application Form\n ",
"\n Content Appeals Form\n ",
"\n General Feedback Form\n ",
"\n Feature Request Form\n ",
"\n Bug Fix Form\n ",
"\n Search Filters\n ",
"\n Share a Video\n ",
"",
"\n Comments\n ",
"\n Similar Content\n ",
"Edit Video Note",
"Profile",
"Conversations",
"\n Allow browser uploads (bucket CORS)\n ",
"\n Welcome to bitvid\n ",
"\n seed. zap. subscribe.\n "
]
},
"ok": true
},
{
"name": "360 Profile open/focus/close",
"at": "2026-10-20T16:25:32.905Z",
"result": {
"focus": [
{
"inside": true,
"id": "profileModalIdentityCard",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgba(15, 23, 42, 0.18) 0px 3.2px 4.8px -0.8px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px"
},
{
"inside": true,
"id": "profileNavAccount",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgb(84, 0, 17) 3px 0px 0px 0px inset, rgba(15, 23, 42, 0.18) 0px 3.2px 4.8px -0.8px"
},
{
"inside": true,
"id": "profileNavRelays",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgba(15, 23, 42, 0.18) 0px 0.8px 1.6px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px"
},
{
"inside": true,
"id": "profileNavWallet",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgba(15, 23, 42, 0.18) 0px 0.8px 1.6px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px"
},
{
"inside": true,
"id": "profileNavStorage",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgba(15, 23, 42, 0.18) 0px 0.8px 1.6px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px"
},
{
"inside": true,
"id": "profileNavMyVideos",
"tag": "BUTTON",
"outline": "solid",
"shadow": "rgba(15, 23, 42, 0.18) 0px 0.8px 1.6px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px"
}
],
"restored": "profileButton"
},
"ok": true
},
{
"screenshot": "playback-qa-2-360-profile.png"
},
{
"name": "360 Upload required fields/focus/close",
"at": "2026-10-20T16:25:33.252Z",
"ok": false,
"error": "Upload horizontal document overflow"
},
{
"screenshot": "playback-qa-2-360-upload-validation.png"
},
{
"screenshot": "playback-qa-2-resumed-stop.png"
}
],
"fixtureHttp": {
"head": 200,
"get": 200,
"range": 206,
"bytes": 1019,
"contentType": "video/webm"
},
"browserVersion": "154.0.8037.97",
"boot": "passed",
"baseline": "blocked-or-failed",
"failedStep": "360 Upload required fields/focus/close",
"failure": "Upload horizontal document overflow",
"failureDiagnostics": {
"appPresent": true,
"relayHealth": {
"relays": [
"ws://127.0.0.1:31848"
],
"unreachable": [],
"backoff": {}
},
"feedItems": [
{
"title": "QA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls",
"pubkey": "032ee87ce307cbf86f3eeecea732f73a19698cd07d13394a0c14b52d35798304",
"dTag": "qa2-0",
"hasUrl": true,
"hasMagnet": false
},
{
"title": "QA local synthetic video 1",
"pubkey": "032ee87ce307cbf86f3eeecea732f73a19698cd07d13394a0c14b52d35798304",
"dTag": "qa2-1",
"hasUrl": true,
"hasMagnet": false
},
{
"title": "QA local synthetic video 2",
"pubkey": "032ee87ce307cbf86f3eeecea732f73a19698cd07d13394a0c14b52d35798304",
"dTag": "qa2-2",
"hasUrl": true,
"hasMagnet": false
}
],
"body": "Switch to dark theme\n+\nPlease provide at least a Video URL or Magnet Link.\nTrending\n#video\nQA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls\nQA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls\nQA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls\n\nUnknown\n\njust now\n✅ CDN\n0 views\n0 sats\nQA local synthetic video 1\nQA local synthetic video 1\nQA local synthetic video 1\n\nUnknown\n\njust now\n✅ CDN\n0 views\n0 sats\nQA local synthetic video 2\nQA local synthetic video 2\nQA local synthetic video 2\n\nUnknown\n\njust now\n✅ CDN\n0 views\n0 sats\nShare a Video\nUpload File\nExternal Link\nVideo URL\n\nPrimary hosted video source (URL-first playback).\n\nMagnet Link\n\nOptional WebTorrent fallback when the URL is unavailable.\n\nTitle\nDescription\nThumbnail URL\nHashtags\n+ Add Tag\nEnable Comments\nNSFW\nFor Kids\nDo not share this video to other Nostr apps\nAdvanced Options\nPublish Video\n\nseed. zap. subscribe.\nv: 6da89895 • 2026-10-20"
},
"ended": "2026-10-20T16:25:33.901Z",
"resourcesClosed": true
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

@@ -0,0 +1,102 @@
# QA2 separately authorized follow-on driver
Diagnostic-only scratch, SHA25652cb54c6f327affa4a95dc3e2f5ba8b65892c3f42b2bb39f868775d974c4aff7. Original failed baseline and strict assertion preserved separately. Overflow conditional is diagnostic routing, not regression acceptance policy.
```js
import {createServer} from 'node:http';
import {createHash} from 'node:crypto';
import {mediaResponse} from './media-fixture.mjs';
import {readFile,writeFile} from 'node:fs/promises';
import {resolve,extname} from 'node:path';
import {createInterface} from 'node:readline';
import {createRequire} from 'node:module';
import {chromium} from '/home/user/Documents/GitHub/bitvid/node_modules/playwright/index.mjs';
import {startRelay} from '/home/user/Documents/GitHub/bitvid-playback-qa/scripts/agent/simple-relay.mjs';
const require=createRequire('/home/user/Documents/GitHub/bitvid/package.json');
const {finalizeEvent,verifyEvent}=require('nostr-tools');
import {NOTE_TYPES,validateEventStructure} from '/home/user/Documents/GitHub/bitvid-playback-qa/js/nostrEventSchemas.js';
const base='/tmp/bitvid-playback-qa-2-final',root=base+'/dist';
const evidence='/home/user/Documents/GitHub/bitvid-playback-qa/docs/testing';
const report={driver:'noninteractive bounded actions',started:new Date().toISOString(),mirrorHits:[],blockedHttp:[],blockedWs:[],failedLocal:[],pageErrors:[],consoleErrors:[],actions:[]};
const sk=new Uint8Array(32).fill(0x7b);
const fixtureBytes=await readFile(base+'/fixtures/qa2-unplayed.webm');
if(createHash('sha256').update(fixtureBytes).digest('hex')!=='d911005a5bca7fb1f3e5aa2fbee701b6476c9baf93460264c2aa5105dd0b3c69')throw Error('local genuine fixture hash changed');
const frozenManifest=await readFile(base+'/dist-manifest.json');
if(createHash('sha256').update(frozenManifest).digest('hex')!=='2747d37916362971a5abe05db4018adf31b5c7031b48d8e4bd6eb1e19b9fa927')throw Error('integrated artifact manifest changed');
for(const [name,hash] of Object.entries(JSON.parse(frozenManifest)))if(createHash('sha256').update(await readFile(root+'/'+name)).digest('hex')!==hash)throw Error('integrated artifact byte changed: '+name);
const server=createServer(async(req,res)=>{
let path=decodeURIComponent(new URL(req.url,'http://127.0.0.1:31847').pathname);if(path==='/qa2-unplayed.webm'){const r=mediaResponse(req.method,req.headers.range,fixtureBytes);res.writeHead(r.status,r.headers);res.end(r.body);return;}if(path==='/')path='/index.html';const f=resolve(root,'.'+path);
if(!f.startsWith(root+'/')||path.includes('/.')){res.writeHead(404);res.end();return;}
try{const b=await readFile(f);res.setHeader('Content-Type',({'.html':'text/html','.js':'text/javascript','.mjs':'text/javascript','.css':'text/css','.json':'application/json','.svg':'image/svg+xml','.wasm':'application/wasm','.png':'image/png','.webmanifest':'application/manifest+json'})[extname(f)]||'application/octet-stream');res.end(b);}catch{res.writeHead(404);res.end();}
});
let browser,relay,context,page,closed=false,hardDeadline;
async function finish(){if(closed)return;closed=true;clearTimeout(hardDeadline);if(context)await context.close();if(browser)await browser.close();if(relay)await relay.close();await new Promise(ok=>server.close(ok));report.ended=new Date().toISOString();report.resourcesClosed=true;await writeFile(base+'/follow-on-result.json',JSON.stringify(report,null,2));console.log(JSON.stringify({type:'CLOSED',ended:report.ended,mirrorHits:report.mirrorHits.length,blockedHttp:report.blockedHttp,blockedWs:report.blockedWs,failedLocal:report.failedLocal,pageErrors:report.pageErrors}));}
hardDeadline=setTimeout(()=>{report.deadlineFailure='120s bounded runner deadline';void finish().finally(()=>process.exit(1));},120000);
try{
await new Promise((ok,no)=>{server.once('error',no);server.listen(31847,'127.0.0.1',ok);});
relay=startRelay(31848,{httpPort:31849});
for(let i=0;i<3;i++){const title=i===0?'QA local synthetic video with a deliberately long title to inspect narrow-card wrapping and controls':'QA local synthetic video '+i;const event=finalizeEvent({kind:30078,created_at:Math.floor(Date.now()/1000)-i,tags:[['d','qa2-'+i],['t','video'],['s','nostr:qa2-'+i],['title',title],['url','http://127.0.0.1:31847/qa2-unplayed.webm']],content:JSON.stringify({version:3,title,url:'http://127.0.0.1:31847/qa2-unplayed.webm',videoRootId:'qa2-'+i,mode:'dev',isPrivate:false,deleted:false})},sk);if(!validateEventStructure(NOTE_TYPES.VIDEO_POST,event).valid||!verifyEvent(JSON.parse(JSON.stringify(event))))throw Error('canonical real signed fixture invalid');relay.seedEvent(event);}
const fixtureUrl='http://127.0.0.1:31847/qa2-unplayed.webm';
const head=await fetch(fixtureUrl,{method:'HEAD'}),whole=await fetch(fixtureUrl),part=await fetch(fixtureUrl,{headers:{Range:'bytes=0-31'}});
const wholeBytes=Buffer.from(await whole.arrayBuffer()),partBytes=Buffer.from(await part.arrayBuffer());
if(head.status!==200||head.headers.get('content-type')!=='video/webm'||Number(head.headers.get('content-length'))!==fixtureBytes.length||whole.status!==200||!wholeBytes.equals(fixtureBytes)||part.status!==206||!partBytes.equals(fixtureBytes.subarray(0,32)))throw Error('genuine local media HTTP preflight failed');
report.fixtureHttp={head:head.status,get:whole.status,range:part.status,bytes:fixtureBytes.length,contentType:head.headers.get('content-type')};
browser=await chromium.launch({headless:true,executablePath:'/usr/bin/google-chrome',args:['--no-sandbox']});report.browserVersion=browser.version();
context=await browser.newContext({viewport:{width:360,height:800},serviceWorkers:'block'});
const mirror=await readFile(base+'/buffer-6.0.3-local.mjs');
await context.route('**/*',r=>{const url=r.request().url();if(url==='https://cdn.jsdelivr.net/npm/[email protected]/+esm'){report.mirrorHits.push(url);return r.fulfill({body:mirror,contentType:'text/javascript',headers:{'Access-Control-Allow-Origin':'*'}});}const u=new URL(url);if(['127.0.0.1','localhost','[::1]'].includes(u.hostname))return r.continue();report.blockedHttp.push(url);return r.abort('blockedbyclient');});
await context.routeWebSocket('**/*',ws=>{const u=new URL(ws.url());if(['127.0.0.1','localhost','[::1]'].includes(u.hostname))ws.connectToServer();else{report.blockedWs.push(ws.url());ws.close();}});
await context.addInitScript(()=>{localStorage.setItem('hasSeenDisclaimer','true');localStorage.setItem('__bitvidTestMode__','1');localStorage.setItem('__bitvidTestRelays__',JSON.stringify(['ws://127.0.0.1:31848']));window.__bitvidTestRelays__=['ws://127.0.0.1:31848'];localStorage.setItem('bitvid_admin_whitelist_mode','false');});
page=await context.newPage();page.setDefaultTimeout(10000);
page.on('pageerror',e=>report.pageErrors.push(e.message));page.on('console',m=>{if(m.type()==='error')report.consoleErrors.push(m.text().slice(0,700));});page.on('response',r=>{if(r.status()>=400&&new URL(r.url()).hostname==='127.0.0.1')report.failedLocal.push({url:r.url(),status:r.status()});});
await page.goto('http://127.0.0.1:31847/?__test__=1&__testRelays__=ws%3A%2F%2F127.0.0.1%3A31848',{waitUntil:'domcontentloaded'});
try{await page.waitForFunction(()=>typeof window.__bitvidTest__==='object',null,{timeout:15000});await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');return !!m.getApplication();},null,{timeout:15000});await page.locator('[data-testid="video-list"]').waitFor({state:'visible',timeout:15000});report.boot='passed';console.log(JSON.stringify({type:'BOOTED',viewport:{width:360,height:800},body:(await page.locator('body').innerText()).slice(0,3000)}));}
catch(e){report.boot='blocked';report.bootError=e.message;await page.screenshot({path:evidence+'/playback-qa-2-second-boot-blocker.png',fullPage:true});console.log(JSON.stringify({type:'BLOCKED',error:e.message,body:(await page.locator('body').innerText()).slice(0,1500)}));await finish();process.exit(0);}
// Noninteractive: no stdin/readline loop; each action is awaited exactly once.
const check=(condition,message)=>{if(!condition)throw new Error(message);};
const step=async(name,action)=>{const item={name,at:new Date().toISOString()};report.actions.push(item);try{item.result=await action();item.ok=true;console.log(JSON.stringify({type:'STEP',name,ok:true,result:item.result}));return item.result;}catch(e){item.ok=false;item.error=e.message;console.log(JSON.stringify({type:'STEP',name,ok:false,error:e.message}));throw e;}};
const capture=async(name)=>{name=name.replace('playback-qa-2-','playback-qa-2-follow-on-');await page.screenshot({path:evidence+'/'+name,fullPage:true});report.actions.push({screenshot:name});};
const layout=async()=>page.evaluate(()=>({width:innerWidth,documentWidth:document.documentElement.scrollWidth,cardBounds:[...document.querySelectorAll('[data-testid="video-card"]')].map(e=>{const r=e.getBoundingClientRect();return {x:r.x,right:r.right,width:r.width};}),smallControls:[...document.querySelectorAll('button,a,input')].filter(e=>e.getClientRects().length&&getComputedStyle(e).visibility!=='hidden').map(e=>{const r=e.getBoundingClientRect();return {id:e.id,label:(e.getAttribute('aria-label')||e.textContent||'').trim().slice(0,80),width:r.width,height:r.height};}).filter(x=>x.width>0&&x.height>0&&(x.width<44||x.height<44))}));
const modalFocus=async(root)=>{const samples=[];for(let i=0;i<6;i++){await page.keyboard.press('Tab');samples.push(await page.evaluate(selector=>{const el=document.activeElement;return {inside:!!document.querySelector(selector)?.contains(el),id:el?.id,tag:el?.tagName,outline:getComputedStyle(el).outlineStyle,shadow:getComputedStyle(el).boxShadow};},root));}check(samples.every(x=>x.inside),'keyboard focus escaped '+root);return samples;};
try{
await step('actual toolkit ready',async()=>{
const event=[...relay.getEvents().values()].find(e=>e.kind===30078);
const ready=await page.evaluate(async(seed)=>{
const m=await import('/js/nostrToolsBootstrap.js'),t=await m.nostrToolsReady;
const callable=['getPublicKey','finalizeEvent','verifyEvent'].every(k=>typeof t?.[k]==='function');
const state={callable,canonicalIdentity:t===window.__BITVID_CANONICAL_NOSTR_TOOLS__,frozen:Object.isFrozen(t),mockFlag:!!window.__TEST_MODE__||window.process?.env?.NODE_ENV==='test'};
if(!callable)return state;
const sk=new Uint8Array(32).fill(0x7b),clean=JSON.parse(JSON.stringify(seed));
state.validSeed=t.verifyEvent(clean)===true;state.tamperedRejected=t.verifyEvent({...JSON.parse(JSON.stringify(seed)),content:'tampered local challenge'})===false;state.pubkeyMatches=t.getPublicKey(sk)===seed.pubkey;
state.signed=t.finalizeEvent({kind:1,created_at:seed.created_at,tags:[],content:'QA real toolkit sanity'},sk);
return state;
},event);
const {signed,...status}=ready;
check(status.callable&&status.canonicalIdentity&&status.frozen&&!status.mockFlag&&status.validSeed&&status.tamperedRejected&&status.pubkeyMatches,'real toolkit contract unavailable: '+JSON.stringify(status));
const {verifyEvent}=require('nostr-tools');check(verifyEvent(JSON.parse(JSON.stringify(signed)))===true,'actual toolkit signature failed independent Node verification');
return {...status,independentSignatureVerified:true};
});
await step('actual application startup completes',async()=>{
await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');await m.getApplicationReady();return !!m.getApplication();},null,{timeout:15000});
const relayState=await page.evaluate(()=>window.__bitvidTest__.setTestRelays(['ws://127.0.0.1:31848'],{persist:false}));
check(relayState.ok===true,'documented fixture relay alignment failed');
return {readyPromiseCompleted:true,relays:relayState.relays};
});
await step('three synthetic relay cards hydrate',async()=>{await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const items=await page.evaluate(()=>window.__bitvidTest__.getFeedItems());check(items.length===3,'expected exactly3 local cards,got'+items.length);return items.map(x=>({title:x.title,dTag:x.dTag}));});
await step('local test identity login',async()=>{await page.evaluate(()=>window.__bitvidTest__.loginWithNsec('7b'.repeat(32)));await page.locator('[data-testid="profile-button"]').waitFor({state:'visible'});await page.locator('[data-testid="upload-button"]').waitFor({state:'visible'});return {profileVisible:true,uploadVisible:true};});
for(const viewport of [{width:360,height:800},{width:390,height:844},{width:1280,height:720}]){
await page.setViewportSize(viewport);const prefix=String(viewport.width);
await step(prefix+' trending navigation/feed',async()=>{await page.locator('#trendingLink').click();await page.waitForFunction(()=>location.hash.includes('view=trending'));await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const r=await layout();check(r.documentWidth<=r.width,'horizontal document overflow');check(r.cardBounds.every(x=>x.x>=0&&x.right<=r.width),'card extends beyond viewport');return r;});
await capture('playback-qa-2-'+prefix+'-feed.png');
for(const [id,view] of [['#exploreLink','explore'],['#forYouLink','for-you'],['#trendingLink','trending']])await step(prefix+' navigation '+view,async()=>{await page.locator(id).click();await page.waitForFunction(v=>location.hash.includes('view='+v),view);return {hash:await page.evaluate(()=>location.hash),headings:await page.locator('h1,h2').allTextContents()};});
await step(prefix+' Profile open/focus/close',async()=>{await page.locator('[data-testid="profile-button"]').click();await page.locator('#profileModal').waitFor({state:'visible'});const focus=await modalFocus('#profileModal');await capture('playback-qa-2-'+prefix+'-profile.png');await page.locator('#closeProfileModal').click();await page.locator('#profileModal').waitFor({state:'hidden'});await page.waitForFunction(()=>document.activeElement?.id==='profileButton');const restored=await page.evaluate(()=>document.activeElement?.id);check(restored==='profileButton','Profile close did not restore trigger focus');return {focus,restored};});
await step(prefix+' Upload required fields/focus/close',async()=>{const videoCount=()=>[...relay.getEvents().values()].filter(e=>e.kind===30078).length;const before=videoCount();await page.locator('[data-testid="upload-button"]').click();await page.locator('#uploadModal').waitFor({state:'visible'});await page.locator('#btn-mode-external').click();const focus=await modalFocus('#uploadModal');await page.locator('#input-title').fill('');await page.locator('#input-url').fill('');await page.locator('#input-magnet').fill('');await page.locator('#btn-submit').click();const missingTitle=await page.locator('#input-title').evaluate(e=>e.validity.valueMissing);check(missingTitle,'empty title not rejected by native validation');await page.locator('#input-title').fill('QA invalid local form');await page.locator('#btn-submit').click();await page.waitForFunction(()=>document.querySelector('#errorContainer')?.textContent.includes('Please provide at least a Video URL or Magnet Link.'));check(videoCount()===before,'invalid form published video event');await capture('playback-qa-2-'+prefix+'-upload-validation.png');const l=await layout();const geometry=await page.evaluate(()=>{const box=e=>{if(!e)return null;const r=e.getBoundingClientRect();return {id:e.id,tag:e.tagName,x:r.x,y:r.y,right:r.right,bottom:r.bottom,width:r.width,height:r.height,clientWidth:e.clientWidth,scrollWidth:e.scrollWidth,overflowX:getComputedStyle(e).overflowX,position:getComputedStyle(e).position};};const panel=document.querySelector('#uploadModal .modal-sheet');return {viewport:{width:innerWidth,height:innerHeight,scrollX,scrollY},document:box(document.documentElement),body:box(document.body),panel:box(panel),root:box(document.querySelector('#uploadModal')),active:box(document.activeElement),controls:['#input-title','#input-url','#input-magnet','#btn-submit','#closeUploadModal'].map(s=>({selector:s,...box(document.querySelector(s))})),offenders:[...document.querySelectorAll('body *')].filter(e=>e.getClientRects().length&&getComputedStyle(e).visibility!=='hidden').map(box).filter(r=>r.x<0||r.right>innerWidth).slice(0,40)};});report.uploadGeometry??=[];report.uploadGeometry.push({viewport:prefix,geometry});if(l.documentWidth>l.width){const critical=geometry.controls;const hard=l.documentWidth-l.width>16||critical.some(r=>r.width<=0||r.x<0||r.right>l.width);report.uploadOverflowFindings??=[];report.uploadOverflowFindings.push({viewport:prefix,documentWidth:l.documentWidth,width:l.width,severity:hard?'hard usability candidate':'minor horizontal overflow; controls horizontally in viewport',geometry});if(hard)throw Error('hard Upload overflow/accessibility candidate; stop for routing');}await page.locator('#closeUploadModal').click();await page.locator('#uploadModal').waitFor({state:'hidden'});const restored=await page.evaluate(()=>document.activeElement?.id);check(restored==='uploadButton','Upload close did not restore trigger focus');return {focus,missingTitle,noSourceRejected:true,noRelayPublish:true,restored,layout:l};});
await step(prefix+' Home navigation',async()=>{await page.getByRole('link',{name:'Return to the bitvid home page',exact:true}).click();await page.waitForURL('**/index.html');await page.waitForFunction(()=>!!window.__bitvidTest__);await page.waitForFunction(async()=>{const m=await import('/js/applicationContext.js');await m.getApplicationReady();return !!m.getApplication();},null,{timeout:15000});await page.evaluate(()=>window.__bitvidTest__.waitForFeedItems(3,15000));const items=await page.evaluate(()=>window.__bitvidTest__.getFeedItems());check(items.length===3,'Home expected exactly3 local cards');return {url:page.url(),cards:items.length};});
}
report.baseline='follow-on coverage completed; original360overflow remains failed/open';
}catch(e){report.baseline='blocked-or-failed';report.failedStep=report.actions.findLast(x=>x.ok===false)?.name;report.failure=e.message;try{report.failureDiagnostics=await page.evaluate(async()=>{const m=await import('/js/applicationContext.js');return {appPresent:!!m.getApplication(),relayHealth:window.__bitvidTest__?.getRelayHealth(),feedItems:window.__bitvidTest__?.getFeedItems(),body:document.body.innerText.slice(0,2000)};});}catch{}await capture('playback-qa-2-resumed-stop.png');}
await finish();
}catch(e){report.runError=e.stack;console.log(JSON.stringify({type:'ERROR',error:e.stack}));await finish();process.exitCode=1;}
```
File diff suppressed because it is too large. Load diff