Probe rendering and modal focus boundaries in pinned browser fixture
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
This commit is contained in:
parent
50c68575f1
commit
3eecd74b0d
18 changed files with 2067 additions and 0 deletions
63
research/experiments/boundary-recovery/README.md
Normal file
63
research/experiments/boundary-recovery/README.md
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Rendering and focus boundary experiment
|
||||
|
||||
Executed 2026-09-26. Real React 19.3.0 / Radix Dialog 1.1.23 in a synthetic browser
|
||||
fixture; no deployed application, provider inference or production requests.
|
||||
[Review and interpretation](../../reviews/BoundaryRecoveryExperiment.md).
|
||||
|
||||
## Reproduce
|
||||
|
||||
From this directory:
|
||||
|
||||
```bash
|
||||
npm ci --ignore-scripts --cache /tmp/fep-npm-cache
|
||||
FEP_CHROMIUM_PATH=/path/to/chrome FEP_RESULT_PATH=/tmp/immediate.json npm test
|
||||
FEP_CHROMIUM_PATH=/path/to/chrome FEP_NESTED_SETTLE_MS=100 FEP_RESULT_PATH=/tmp/settled.json npm test
|
||||
```
|
||||
|
||||
Use a locally available Chromium executable, or omit `FEP_CHROMIUM_PATH` to use
|
||||
Playwright's installed browser. The recorded runs used preinstalled Chromium
|
||||
151.0.7922.34, not an assertion of compatibility with every browser. Version and
|
||||
executable hash are in [provenance](provenance.json); the lockfile pins all packages
|
||||
with archive integrity. Installation does not download a browser automatically here.
|
||||
The runner binds an ephemeral loopback port, bundles the fixture in memory, and
|
||||
closes browser/server in `finally`. No external network is used by the cases.
|
||||
|
||||
Output defaults to `/tmp/fep-boundary-result.json`; reviewed receipts are not
|
||||
overwritten automatically. A failed obligation makes the runner exit nonzero.
|
||||
The immediate nested-dialog case is known to be timing-sensitive; do not hide it
|
||||
with retries or interpret a later pass as its resolution. `FEP_NESTED_SETTLE_MS`
|
||||
changes only the pause after nested activation before the first Escape. It is an
|
||||
experimental variable, not a proposed product fix. The browser uses React's development
|
||||
build, without StrictMode. Production builds and other browsers remain untested.
|
||||
|
||||
## Recorded cases
|
||||
|
||||
| Case | Observation | Immediate / 100 ms settled |
|
||||
| --- | --- | --- |
|
||||
| X01 | Render fault uses inner fallback; sibling stays interactive | pass / pass |
|
||||
| X02 | Event-handler exception reaches browser error reporting, not boundary | pass / pass |
|
||||
| X03 | Synthetic GET returns 503; explicit catch sets request-failure state | pass / pass |
|
||||
| X04 | Fault in inner fallback reaches outer boundary | pass / pass |
|
||||
| X05 | Closing modal returns focus to surviving invoker | pass / pass |
|
||||
| X06 | Removing invoker leaves BODY focused with default behavior | pass / pass (negative control) |
|
||||
| X07 | Application close policy selects surviving next-record button | pass / pass |
|
||||
| X08 | Nested close should return to parent trigger, then outer trigger | fail / pass |
|
||||
|
||||
[result-immediate.json](result-immediate.json) records 7/8; [result-settled.json](result-settled.json)
|
||||
records 8/8 with identical code/input hashes, except the declared timing parameter.
|
||||
“Pass” means an observation matched its assertion, not that the UX is acceptable:
|
||||
X06 deliberately expects the missing workflow target.
|
||||
|
||||
[development-results.json](development-results.json) preserves three earlier runs
|
||||
in order: 7/8, 8/8, 7/8. They preceded final diagnostic instrumentation; their old
|
||||
runner bytes are not archived, so they are development history, not exact reproducible
|
||||
snapshots. Current-code receipts above retain their matching SHA-256 input hashes.
|
||||
All five runs are reported; no estimate of failure frequency is justified.
|
||||
|
||||
## Scope
|
||||
|
||||
Focus checks inspect activeElement and keyboard behavior, not screen-reader output
|
||||
or full accessibility conformance. X03 handles a response error explicitly; it does
|
||||
not test unhandled promises, timeouts, mutation idempotency or remote rollback.
|
||||
Nested dismissal remains unresolved. Dependency/version compatibility and fixture
|
||||
lifecycle effects must be separated before attributing a library defect.
|
||||
333
research/experiments/boundary-recovery/development-results.json
Normal file
333
research/experiments/boundary-recovery/development-results.json
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
[
|
||||
{
|
||||
"date": "2026-09-26T19:57:23.882Z",
|
||||
"evidence": "synthetic-browser-fixture-real-libraries",
|
||||
"node": "v24.11.1",
|
||||
"browser": "151.0.7922.34",
|
||||
"browserSelection": "explicit executable override",
|
||||
"packages": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
},
|
||||
"files": {
|
||||
"fixture.jsx": "d01a78f533a8ac4c086fc93845ce5b86a5b676aee86a22ee53ac91ad2a77f936",
|
||||
"experiment.mjs": "981d39a45d22503077817cb032145f1e05221821c157be18ca7a509667a5e384",
|
||||
"package.json": "a0ad37e8518b0c561d6b4a091ee51f5bca90e0ce329b2be7ba75347f6dc26ae7",
|
||||
"package-lock.json": "ec4b544d441f89d9c512bc9931c1818473327105d5ef9047dc04d6a721e68463"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"id": "X01-render-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "inner",
|
||||
"message": "render fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"siblingUsable": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X02-event-not-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [
|
||||
"Uncaught Error: event fault"
|
||||
],
|
||||
"requests": []
|
||||
},
|
||||
"panelPresent": true,
|
||||
"browserErrors": [
|
||||
"event fault"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "X03-request-explicit-state",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [
|
||||
503
|
||||
]
|
||||
},
|
||||
"state": "request failed",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X04-fallback-escapes-inner",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "outer",
|
||||
"message": "fallback fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"enclosingFallback": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X05-focus-existing-invoker",
|
||||
"status": "pass",
|
||||
"activeId": "invoker",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X06-focus-removed-default",
|
||||
"status": "pass",
|
||||
"activeTag": "BODY",
|
||||
"workflowTargetSelected": false,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X07-focus-removed-explicit",
|
||||
"status": "pass",
|
||||
"activeId": "next",
|
||||
"applicationPolicy": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X08-nested-return",
|
||||
"status": "fail",
|
||||
"error": "page.waitForFunction: Timeout 5000ms exceeded.",
|
||||
"browserErrors": []
|
||||
}
|
||||
],
|
||||
"passed": 7,
|
||||
"total": 8
|
||||
},
|
||||
{
|
||||
"date": "2026-09-26T19:57:42.875Z",
|
||||
"evidence": "synthetic-browser-fixture-real-libraries",
|
||||
"node": "v24.11.1",
|
||||
"browser": "151.0.7922.34",
|
||||
"browserSelection": "explicit executable override",
|
||||
"packages": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
},
|
||||
"files": {
|
||||
"fixture.jsx": "d01a78f533a8ac4c086fc93845ce5b86a5b676aee86a22ee53ac91ad2a77f936",
|
||||
"experiment.mjs": "5268d5cfefedb6186333bcc014080757821f2bb4820f70397b22474bd3264414",
|
||||
"package.json": "a0ad37e8518b0c561d6b4a091ee51f5bca90e0ce329b2be7ba75347f6dc26ae7",
|
||||
"package-lock.json": "ec4b544d441f89d9c512bc9931c1818473327105d5ef9047dc04d6a721e68463"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"id": "X01-render-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "inner",
|
||||
"message": "render fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"siblingUsable": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X02-event-not-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [
|
||||
"Uncaught Error: event fault"
|
||||
],
|
||||
"requests": []
|
||||
},
|
||||
"panelPresent": true,
|
||||
"browserErrors": [
|
||||
"event fault"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "X03-request-explicit-state",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [
|
||||
503
|
||||
]
|
||||
},
|
||||
"state": "request failed",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X04-fallback-escapes-inner",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "outer",
|
||||
"message": "fallback fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"enclosingFallback": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X05-focus-existing-invoker",
|
||||
"status": "pass",
|
||||
"activeId": "invoker",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X06-focus-removed-default",
|
||||
"status": "pass",
|
||||
"activeTag": "BODY",
|
||||
"workflowTargetSelected": false,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X07-focus-removed-explicit",
|
||||
"status": "pass",
|
||||
"activeId": "next",
|
||||
"applicationPolicy": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X08-nested-return",
|
||||
"status": "pass",
|
||||
"innerReturn": "nested-invoker",
|
||||
"outerReturn": "invoker",
|
||||
"browserErrors": []
|
||||
}
|
||||
],
|
||||
"passed": 8,
|
||||
"total": 8
|
||||
},
|
||||
{
|
||||
"date": "2026-09-26T19:58:16.005Z",
|
||||
"evidence": "synthetic-browser-fixture-real-libraries",
|
||||
"node": "v24.11.1",
|
||||
"browser": "151.0.7922.34",
|
||||
"browserSelection": "explicit executable override",
|
||||
"packages": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
},
|
||||
"files": {
|
||||
"fixture.jsx": "d01a78f533a8ac4c086fc93845ce5b86a5b676aee86a22ee53ac91ad2a77f936",
|
||||
"experiment.mjs": "df9912cacd5b01b10fdc70a45d50b36d91202c44c0f57358334a1d3c41b4c88d",
|
||||
"package.json": "a0ad37e8518b0c561d6b4a091ee51f5bca90e0ce329b2be7ba75347f6dc26ae7",
|
||||
"package-lock.json": "ec4b544d441f89d9c512bc9931c1818473327105d5ef9047dc04d6a721e68463"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"id": "X01-render-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "inner",
|
||||
"message": "render fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"siblingUsable": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X02-event-not-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [
|
||||
"Uncaught Error: event fault"
|
||||
],
|
||||
"requests": []
|
||||
},
|
||||
"panelPresent": true,
|
||||
"browserErrors": [
|
||||
"event fault"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "X03-request-explicit-state",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [
|
||||
503
|
||||
]
|
||||
},
|
||||
"state": "request failed",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X04-fallback-escapes-inner",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "outer",
|
||||
"message": "fallback fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": []
|
||||
},
|
||||
"enclosingFallback": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X05-focus-existing-invoker",
|
||||
"status": "pass",
|
||||
"activeId": "invoker",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X06-focus-removed-default",
|
||||
"status": "pass",
|
||||
"activeTag": "BODY",
|
||||
"workflowTargetSelected": false,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X07-focus-removed-explicit",
|
||||
"status": "pass",
|
||||
"activeId": "next",
|
||||
"applicationPolicy": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X08-nested-return",
|
||||
"status": "fail",
|
||||
"error": "Expected focus nested-invoker; got {\"id\":\"invoker\",\"tag\":\"BUTTON\",\"dialogs\":0}: page.waitForFunction: Timeout 5000ms exceeded.",
|
||||
"browserErrors": []
|
||||
}
|
||||
],
|
||||
"passed": 7,
|
||||
"total": 8
|
||||
}
|
||||
]
|
||||
124
research/experiments/boundary-recovery/experiment.mjs
Normal file
124
research/experiments/boundary-recovery/experiment.mjs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import {build} from 'esbuild';
|
||||
import {chromium} from 'playwright';
|
||||
import {createServer} from 'node:http';
|
||||
import {once} from 'node:events';
|
||||
import {readFile, writeFile} from 'node:fs/promises';
|
||||
import {createHash} from 'node:crypto';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
const dir = fileURLToPath(new URL('.', import.meta.url));
|
||||
const bundle = await build({entryPoints: [dir + 'fixture.jsx'], bundle: true, write: false,
|
||||
define: {'process.env.NODE_ENV': '"development"'}, format: 'iife'});
|
||||
const server = createServer((req, res) => {
|
||||
if (req.url === '/bundle.js') {
|
||||
res.writeHead(200, {'Content-Type': 'application/javascript'}); res.end(bundle.outputFiles[0].contents);
|
||||
} else if (req.url === '/failure') {
|
||||
res.writeHead(503, {'Content-Type': 'text/plain'}); res.end('synthetic unavailable');
|
||||
} else {
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.end('<!doctype html><html lang="en"><head><title>Boundary probe</title></head><body><div id="root"></div><script src="/bundle.js"></script></body></html>');
|
||||
}
|
||||
});
|
||||
server.listen(0, '127.0.0.1'); await once(server, 'listening');
|
||||
const url = `http://127.0.0.1:${server.address().port}`;
|
||||
let browser;
|
||||
const cases = [];
|
||||
async function probe(id, query, action) {
|
||||
const page = await browser.newPage();
|
||||
page.setDefaultTimeout(5000);
|
||||
const browserErrors = [];
|
||||
page.on('pageerror', e => browserErrors.push(e.message));
|
||||
try {
|
||||
await page.goto(url + query);
|
||||
await page.getByRole('button').first().waitFor();
|
||||
const observed = await action(page);
|
||||
cases.push({id, status: 'pass', ...observed, browserErrors});
|
||||
} catch (error) {
|
||||
cases.push({id, status: 'fail', error: error.message, observed: await page.evaluate(() => window.observed).catch(() => null), browserErrors});
|
||||
} finally {await page.close();}
|
||||
}
|
||||
async function active(page, id) {
|
||||
try { await page.waitForFunction(id => document.activeElement?.id === id, id, {timeout: 5000}); }
|
||||
catch (error) { throw new Error(`Expected focus ${id}; got ${await page.evaluate(() => ({id: document.activeElement?.id, tag: document.activeElement?.tagName, dialogs: document.querySelectorAll('[role=dialog]').length})).then(JSON.stringify)}: ${error.message}`); }
|
||||
}
|
||||
try {
|
||||
browser = await chromium.launch({headless: true,
|
||||
...(process.env.FEP_CHROMIUM_PATH ? {executablePath: process.env.FEP_CHROMIUM_PATH} : {})});
|
||||
await probe('X01-render-contained', '/', async page => {
|
||||
await page.getByText('Break render', {exact: true}).click();
|
||||
await page.getByTestId('inner').waitFor();
|
||||
await page.getByText('Sibling 0', {exact: true}).click();
|
||||
await page.getByText('Sibling 1', {exact: true}).waitFor();
|
||||
const o = await page.evaluate(() => window.observed);
|
||||
assert(o.caught.some(x => x.boundary === 'inner' && x.message === 'render fault'));
|
||||
assert.equal(await page.getByTestId('outer').count(), 0);
|
||||
return {observed: o, siblingUsable: true};
|
||||
});
|
||||
await probe('X02-event-not-contained', '/', async page => {
|
||||
await page.getByText('Break event', {exact: true}).click();
|
||||
await page.waitForFunction(() => window.observed.globalErrors.some(x => x.includes('event fault')));
|
||||
const o = await page.evaluate(() => window.observed);
|
||||
assert.equal(o.caught.length, 0); assert.equal(await page.getByTestId('panel').count(), 1);
|
||||
return {observed: o, panelPresent: true};
|
||||
});
|
||||
await probe('X03-request-explicit-state', '/', async page => {
|
||||
await page.getByText('Fail request', {exact: true}).click();
|
||||
await page.getByRole('status').filter({hasText: 'request failed'}).waitFor();
|
||||
const o = await page.evaluate(() => window.observed);
|
||||
assert.deepEqual(o.requests, [503]); assert.equal(o.caught.length, 0);
|
||||
return {observed: o, state: 'request failed'};
|
||||
});
|
||||
await probe('X04-fallback-escapes-inner', '/?brokenFallback=1', async page => {
|
||||
await page.getByText('Break render', {exact: true}).click();
|
||||
await page.getByTestId('outer').waitFor();
|
||||
const o = await page.evaluate(() => window.observed);
|
||||
assert(o.caught.some(x => x.boundary === 'outer' && x.message === 'fallback fault'));
|
||||
return {observed: o, enclosingFallback: true};
|
||||
});
|
||||
await probe('X05-focus-existing-invoker', '/?mode=focus', async page => {
|
||||
await page.locator('#invoker').focus(); await page.keyboard.press('Enter');
|
||||
await active(page, 'remove'); await page.keyboard.press('Escape'); await active(page, 'invoker');
|
||||
return {activeId: await page.evaluate(() => document.activeElement.id)};
|
||||
});
|
||||
await probe('X06-focus-removed-default', '/?mode=focus', async page => {
|
||||
await page.locator('#invoker').focus(); await page.keyboard.press('Enter'); await active(page, 'remove');
|
||||
await page.keyboard.press('Enter'); await page.getByRole('dialog').waitFor({state: 'detached'});
|
||||
await page.waitForFunction(() => document.activeElement === document.body);
|
||||
// Negative control: default restoration cannot choose a workflow target for the removed trigger.
|
||||
assert.equal(await page.locator('#invoker').count(), 0);
|
||||
return {activeTag: await page.evaluate(() => document.activeElement.tagName), workflowTargetSelected: false};
|
||||
});
|
||||
await probe('X07-focus-removed-explicit', '/?mode=focus&explicit=1', async page => {
|
||||
await page.locator('#invoker').focus(); await page.keyboard.press('Enter'); await active(page, 'remove');
|
||||
await page.keyboard.press('Enter'); await active(page, 'next');
|
||||
return {activeId: await page.evaluate(() => document.activeElement.id), applicationPolicy: true};
|
||||
});
|
||||
await probe('X08-nested-return', '/?mode=focus', async page => {
|
||||
await page.locator('#invoker').focus(); await page.keyboard.press('Enter'); await active(page, 'remove');
|
||||
await page.keyboard.press('Tab'); await active(page, 'nested-invoker');
|
||||
await page.keyboard.press('Enter'); await active(page, 'nested-close');
|
||||
// Experimental timing variable, not a hidden retry: compare immediate versus settled Escape.
|
||||
if (Number(process.env.FEP_NESTED_SETTLE_MS)) await page.waitForTimeout(Number(process.env.FEP_NESTED_SETTLE_MS));
|
||||
await page.keyboard.press('Escape'); await active(page, 'nested-invoker');
|
||||
assert.equal(await page.getByRole('dialog').count(), 1);
|
||||
await page.keyboard.press('Escape'); await active(page, 'invoker');
|
||||
return {innerReturn: 'nested-invoker', outerReturn: 'invoker', observed: await page.evaluate(() => window.observed)};
|
||||
});
|
||||
const files = {};
|
||||
for (const name of ['fixture.jsx', 'experiment.mjs', 'package.json', 'package-lock.json']) {
|
||||
files[name] = createHash('sha256').update(await readFile(dir + name)).digest('hex');
|
||||
}
|
||||
const result = {date: new Date().toISOString(), evidence: 'synthetic-browser-fixture-real-libraries',
|
||||
node: process.version, browser: browser.version(), nestedSettleMs: Number(process.env.FEP_NESTED_SETTLE_MS || 0),
|
||||
browserSelection: process.env.FEP_CHROMIUM_PATH ? 'explicit executable override' : 'playwright bundled',
|
||||
packages: JSON.parse(await readFile(dir + 'package.json')).dependencies,
|
||||
files, cases, passed: cases.filter(x => x.status === 'pass').length, total: cases.length};
|
||||
const output = process.env.FEP_RESULT_PATH || '/tmp/fep-boundary-result.json';
|
||||
await writeFile(output, JSON.stringify(result, null, 2) + '\n');
|
||||
console.log(JSON.stringify({output, passed: result.passed, total: result.total, cases}, null, 2));
|
||||
if (result.passed !== result.total) process.exitCode = 1;
|
||||
} finally {
|
||||
if (browser) await browser.close();
|
||||
await new Promise(resolve => server.close(resolve));
|
||||
}
|
||||
81
research/experiments/boundary-recovery/fixture.jsx
Normal file
81
research/experiments/boundary-recovery/fixture.jsx
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import React, {useState, useRef} from 'react';
|
||||
import {createRoot} from 'react-dom/client';
|
||||
import * as Dialog from '@radix-ui/react-dialog';
|
||||
|
||||
window.observed = {caught: [], globalErrors: [], requests: [], dialogTransitions: []};
|
||||
window.addEventListener('error', e => window.observed.globalErrors.push(e.message));
|
||||
class Boundary extends React.Component {
|
||||
state = {failed: false};
|
||||
static getDerivedStateFromError() { return {failed: true}; }
|
||||
componentDidCatch(error) { window.observed.caught.push({boundary: this.props.name, message: error.message}); }
|
||||
render() {
|
||||
if (this.state.failed) return this.props.brokenFallback
|
||||
? <BrokenFallback /> : <p role="alert" data-testid={this.props.name}>Region unavailable</p>;
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
function BrokenFallback() { throw new Error('fallback fault'); }
|
||||
function Panel() {
|
||||
const [broken, setBroken] = useState(false);
|
||||
const [request, setRequest] = useState('idle');
|
||||
if (broken) throw new Error('render fault');
|
||||
return <section data-testid="panel">
|
||||
<button onClick={() => setBroken(true)}>Break render</button>
|
||||
<button onClick={() => {throw new Error('event fault');}}>Break event</button>
|
||||
<button onClick={async () => {
|
||||
setRequest('pending');
|
||||
try {
|
||||
const r = await fetch('/failure');
|
||||
window.observed.requests.push(r.status);
|
||||
if (!r.ok) throw new Error('request rejected');
|
||||
setRequest('accepted');
|
||||
} catch {setRequest('request failed');}
|
||||
}}>Fail request</button>
|
||||
<p role="status">{request}</p>
|
||||
</section>;
|
||||
}
|
||||
function FailureFixture() {
|
||||
const [clicks, setClicks] = useState(0);
|
||||
const brokenFallback = new URLSearchParams(location.search).has('brokenFallback');
|
||||
return <main>
|
||||
<button onClick={() => setClicks(clicks + 1)}>Sibling {clicks}</button>
|
||||
<Boundary name="outer"><Boundary name="inner" brokenFallback={brokenFallback}>
|
||||
<Panel />
|
||||
</Boundary></Boundary>
|
||||
</main>;
|
||||
}
|
||||
function Modal({children, title}) {
|
||||
return <Dialog.Portal><Dialog.Overlay />
|
||||
<Dialog.Content aria-describedby={undefined}>
|
||||
<Dialog.Title>{title}</Dialog.Title>{children}
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>;
|
||||
}
|
||||
function FocusFixture() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [present, setPresent] = useState(true);
|
||||
const next = useRef(null);
|
||||
const explicit = new URLSearchParams(location.search).has('explicit');
|
||||
return <main>
|
||||
<button id="next" ref={next}>Next record</button>
|
||||
<Dialog.Root open={open} onOpenChange={value => {window.observed.dialogTransitions.push({dialog: "outer", open: value}); setOpen(value);}}>
|
||||
{present && <Dialog.Trigger id="invoker">Open task</Dialog.Trigger>}
|
||||
<Dialog.Portal><Dialog.Overlay />
|
||||
<Dialog.Content aria-describedby={undefined} onCloseAutoFocus={event => {
|
||||
if (explicit && !present) {event.preventDefault(); next.current?.focus();}
|
||||
}}>
|
||||
<Dialog.Title>Record task</Dialog.Title>
|
||||
<button id="remove" onClick={() => {setPresent(false); setOpen(false);}}>Remove invoking record</button>
|
||||
<Dialog.Root onOpenChange={value => window.observed.dialogTransitions.push({dialog: "inner", open: value})}>
|
||||
<Dialog.Trigger id="nested-invoker">Nested task</Dialog.Trigger>
|
||||
<Modal title="Nested task"><Dialog.Close id="nested-close">Close nested</Dialog.Close></Modal>
|
||||
</Dialog.Root>
|
||||
<Dialog.Close id="close">Close task</Dialog.Close>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog.Root>
|
||||
</main>;
|
||||
}
|
||||
createRoot(document.getElementById('root')).render(
|
||||
new URLSearchParams(location.search).get('mode') === 'focus' ? <FocusFixture /> : <FailureFixture />
|
||||
);
|
||||
989
research/experiments/boundary-recovery/package-lock.json
generated
Normal file
989
research/experiments/boundary-recovery/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
{
|
||||
"name": "fep-boundary-recovery",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fep-boundary-recovery",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"esbuild": "0.28.2",
|
||||
"playwright": "1.63.0",
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz",
|
||||
"integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz",
|
||||
"integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz",
|
||||
"integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz",
|
||||
"integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz",
|
||||
"integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz",
|
||||
"integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz",
|
||||
"integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz",
|
||||
"integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz",
|
||||
"integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz",
|
||||
"integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz",
|
||||
"integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz",
|
||||
"integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz",
|
||||
"integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz",
|
||||
"integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-context": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz",
|
||||
"integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog": {
|
||||
"version": "1.1.23",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz",
|
||||
"integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
"@radix-ui/react-context": "1.2.2",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.19",
|
||||
"@radix-ui/react-focus-guards": "1.1.6",
|
||||
"@radix-ui/react-focus-scope": "1.1.16",
|
||||
"@radix-ui/react-id": "1.1.4",
|
||||
"@radix-ui/react-portal": "1.1.17",
|
||||
"@radix-ui/react-presence": "1.1.10",
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
"@radix-ui/react-slot": "1.3.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.6",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz",
|
||||
"integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.4",
|
||||
"@radix-ui/react-use-effect-event": "0.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-guards": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz",
|
||||
"integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz",
|
||||
"integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-id": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz",
|
||||
"integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz",
|
||||
"integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz",
|
||||
"integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz",
|
||||
"integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz",
|
||||
"integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-callback-ref": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz",
|
||||
"integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-controllable-state": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz",
|
||||
"integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
"@radix-ui/react-use-effect-event": "0.0.5",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-effect-event": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz",
|
||||
"integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-layout-effect": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz",
|
||||
"integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
|
||||
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.28.2",
|
||||
"@esbuild/android-arm": "0.28.2",
|
||||
"@esbuild/android-arm64": "0.28.2",
|
||||
"@esbuild/android-x64": "0.28.2",
|
||||
"@esbuild/darwin-arm64": "0.28.2",
|
||||
"@esbuild/darwin-x64": "0.28.2",
|
||||
"@esbuild/freebsd-arm64": "0.28.2",
|
||||
"@esbuild/freebsd-x64": "0.28.2",
|
||||
"@esbuild/linux-arm": "0.28.2",
|
||||
"@esbuild/linux-arm64": "0.28.2",
|
||||
"@esbuild/linux-ia32": "0.28.2",
|
||||
"@esbuild/linux-loong64": "0.28.2",
|
||||
"@esbuild/linux-mips64el": "0.28.2",
|
||||
"@esbuild/linux-ppc64": "0.28.2",
|
||||
"@esbuild/linux-riscv64": "0.28.2",
|
||||
"@esbuild/linux-s390x": "0.28.2",
|
||||
"@esbuild/linux-x64": "0.28.2",
|
||||
"@esbuild/netbsd-arm64": "0.28.2",
|
||||
"@esbuild/netbsd-x64": "0.28.2",
|
||||
"@esbuild/openbsd-arm64": "0.28.2",
|
||||
"@esbuild/openbsd-x64": "0.28.2",
|
||||
"@esbuild/openharmony-arm64": "0.28.2",
|
||||
"@esbuild/sunos-x64": "0.28.2",
|
||||
"@esbuild/win32-arm64": "0.28.2",
|
||||
"@esbuild/win32-ia32": "0.28.2",
|
||||
"@esbuild/win32-x64": "0.28.2"
|
||||
}
|
||||
},
|
||||
"node_modules/get-nonce": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
|
||||
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.63.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
|
||||
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz",
|
||||
"integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz",
|
||||
"integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
|
||||
"integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.7",
|
||||
"react-style-singleton": "^2.2.3",
|
||||
"tslib": "^2.1.0",
|
||||
"use-callback-ref": "^1.3.3",
|
||||
"use-sidecar": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll-bar": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-style-singleton": "^2.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-nonce": "^1.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.28.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz",
|
||||
"integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sidecar": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
||||
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-node-es": "^1.1.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
research/experiments/boundary-recovery/package.json
Normal file
13
research/experiments/boundary-recovery/package.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "fep-boundary-recovery",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {"test": "node experiment.mjs"},
|
||||
"dependencies": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
}
|
||||
}
|
||||
57
research/experiments/boundary-recovery/provenance.json
Normal file
57
research/experiments/boundary-recovery/provenance.json
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"date": "2026-09-26",
|
||||
"source_id": "SRC-0029",
|
||||
"packages": {
|
||||
"node_modules/react": {
|
||||
"version": "19.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz",
|
||||
"integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog=="
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz",
|
||||
"integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog": {
|
||||
"version": "1.1.23",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz",
|
||||
"integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA=="
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz",
|
||||
"integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ=="
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
|
||||
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg=="
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.2",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz",
|
||||
"integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz",
|
||||
"integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w=="
|
||||
}
|
||||
},
|
||||
"inspected_files": {
|
||||
"@radix-ui/react-dialog/dist/index.mjs": {
|
||||
"sha256": "a37daaef3f67c502500404ee93f60a04fdf05d2b0ce4783c858b1027c7f54792"
|
||||
},
|
||||
"@radix-ui/react-focus-scope/dist/index.mjs": {
|
||||
"sha256": "798184fbe00268a6c4a539fd2073b85b6dfef6d89bd2cd547d9a66ae1024e55d"
|
||||
},
|
||||
"@radix-ui/react-dismissable-layer/dist/index.mjs": {
|
||||
"sha256": "01df449a23d65bab1f2f2215a953cba74741419496ebd9a7932533f267cc873d"
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"version": "151.0.7922.34",
|
||||
"executable_sha256": "0b20b130e7edd9dd51873be867761295fe0cfad490c2b9a64f95bd3cfc08fa71",
|
||||
"selection": "preinstalled Chromium build 1234, explicit executable override; not claimed to be Playwright 1.63 bundled revision"
|
||||
}
|
||||
}
|
||||
134
research/experiments/boundary-recovery/result-immediate.json
Normal file
134
research/experiments/boundary-recovery/result-immediate.json
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
{
|
||||
"date": "2026-09-26T19:58:51.268Z",
|
||||
"evidence": "synthetic-browser-fixture-real-libraries",
|
||||
"node": "v24.11.1",
|
||||
"browser": "151.0.7922.34",
|
||||
"nestedSettleMs": 0,
|
||||
"browserSelection": "explicit executable override",
|
||||
"packages": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
},
|
||||
"files": {
|
||||
"fixture.jsx": "3dd538006affc9bcdb69c8b5cd1bb06ac335499f1143b91f06f1d455a127c525",
|
||||
"experiment.mjs": "33ea08bcbd8fda533dc4bb44d5369b5453fd8e23940116597658435296d834fb",
|
||||
"package.json": "a0ad37e8518b0c561d6b4a091ee51f5bca90e0ce329b2be7ba75347f6dc26ae7",
|
||||
"package-lock.json": "ec4b544d441f89d9c512bc9931c1818473327105d5ef9047dc04d6a721e68463"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"id": "X01-render-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "inner",
|
||||
"message": "render fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"siblingUsable": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X02-event-not-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [
|
||||
"Uncaught Error: event fault"
|
||||
],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"panelPresent": true,
|
||||
"browserErrors": [
|
||||
"event fault"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "X03-request-explicit-state",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [
|
||||
503
|
||||
],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"state": "request failed",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X04-fallback-escapes-inner",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "outer",
|
||||
"message": "fallback fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"enclosingFallback": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X05-focus-existing-invoker",
|
||||
"status": "pass",
|
||||
"activeId": "invoker",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X06-focus-removed-default",
|
||||
"status": "pass",
|
||||
"activeTag": "BODY",
|
||||
"workflowTargetSelected": false,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X07-focus-removed-explicit",
|
||||
"status": "pass",
|
||||
"activeId": "next",
|
||||
"applicationPolicy": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X08-nested-return",
|
||||
"status": "fail",
|
||||
"error": "Expected focus nested-invoker; got {\"id\":\"invoker\",\"tag\":\"BUTTON\",\"dialogs\":0}: page.waitForFunction: Timeout 5000ms exceeded.",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": [
|
||||
{
|
||||
"dialog": "outer",
|
||||
"open": true
|
||||
},
|
||||
{
|
||||
"dialog": "inner",
|
||||
"open": true
|
||||
},
|
||||
{
|
||||
"dialog": "outer",
|
||||
"open": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserErrors": []
|
||||
}
|
||||
],
|
||||
"passed": 7,
|
||||
"total": 8
|
||||
}
|
||||
139
research/experiments/boundary-recovery/result-settled.json
Normal file
139
research/experiments/boundary-recovery/result-settled.json
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"date": "2026-09-26T19:58:59.954Z",
|
||||
"evidence": "synthetic-browser-fixture-real-libraries",
|
||||
"node": "v24.11.1",
|
||||
"browser": "151.0.7922.34",
|
||||
"nestedSettleMs": 100,
|
||||
"browserSelection": "explicit executable override",
|
||||
"packages": {
|
||||
"react": "19.3.0",
|
||||
"react-dom": "19.3.0",
|
||||
"@radix-ui/react-dialog": "1.1.23",
|
||||
"playwright": "1.63.0",
|
||||
"esbuild": "0.28.2"
|
||||
},
|
||||
"files": {
|
||||
"fixture.jsx": "3dd538006affc9bcdb69c8b5cd1bb06ac335499f1143b91f06f1d455a127c525",
|
||||
"experiment.mjs": "33ea08bcbd8fda533dc4bb44d5369b5453fd8e23940116597658435296d834fb",
|
||||
"package.json": "a0ad37e8518b0c561d6b4a091ee51f5bca90e0ce329b2be7ba75347f6dc26ae7",
|
||||
"package-lock.json": "ec4b544d441f89d9c512bc9931c1818473327105d5ef9047dc04d6a721e68463"
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"id": "X01-render-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "inner",
|
||||
"message": "render fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"siblingUsable": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X02-event-not-contained",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [
|
||||
"Uncaught Error: event fault"
|
||||
],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"panelPresent": true,
|
||||
"browserErrors": [
|
||||
"event fault"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "X03-request-explicit-state",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [
|
||||
503
|
||||
],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"state": "request failed",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X04-fallback-escapes-inner",
|
||||
"status": "pass",
|
||||
"observed": {
|
||||
"caught": [
|
||||
{
|
||||
"boundary": "outer",
|
||||
"message": "fallback fault"
|
||||
}
|
||||
],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": []
|
||||
},
|
||||
"enclosingFallback": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X05-focus-existing-invoker",
|
||||
"status": "pass",
|
||||
"activeId": "invoker",
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X06-focus-removed-default",
|
||||
"status": "pass",
|
||||
"activeTag": "BODY",
|
||||
"workflowTargetSelected": false,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X07-focus-removed-explicit",
|
||||
"status": "pass",
|
||||
"activeId": "next",
|
||||
"applicationPolicy": true,
|
||||
"browserErrors": []
|
||||
},
|
||||
{
|
||||
"id": "X08-nested-return",
|
||||
"status": "pass",
|
||||
"innerReturn": "nested-invoker",
|
||||
"outerReturn": "invoker",
|
||||
"observed": {
|
||||
"caught": [],
|
||||
"globalErrors": [],
|
||||
"requests": [],
|
||||
"dialogTransitions": [
|
||||
{
|
||||
"dialog": "outer",
|
||||
"open": true
|
||||
},
|
||||
{
|
||||
"dialog": "inner",
|
||||
"open": true
|
||||
},
|
||||
{
|
||||
"dialog": "inner",
|
||||
"open": false
|
||||
},
|
||||
{
|
||||
"dialog": "outer",
|
||||
"open": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserErrors": []
|
||||
}
|
||||
],
|
||||
"passed": 8,
|
||||
"total": 8
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue