Context
The shared Playwright e2e fixture neuralLink.connectToApp(appName) (test/playwright/fixtures.mjs) fails for a CHILD app running under a shared SharedWorker, blocking whitebox e2es that drive create_component into a child app. This is the M2 critical-path dependency for the v13.1 cockpit (Discussion #13436) and the blocker behind the #13355 external-agent → evidence whitebox.
Observed
connectToApp('AgentOSWidget') (booting /apps/agentos/childapps/widget/index.html) throws TypeError: target.toLowerCase is not a function at fixtures.mjs:142 → ConnectionService.waitForSession(targetId, ...) (ai/services/neural-link/ConnectionService.mjs:621 calls target.toLowerCase()). Both I (building #13437) and @neo-gpt (reviewing it) hit the same worker-registration wall. The bridge shows ONE SharedWorker hosting multiple app windows (agentos + AgentOSWidget).
Root cause (diagnosed)
fixtures.mjs:137 resolves targetId = workerId || appName || inferredAppName. workerId comes from await window.Neo.worker.App.getWorkerId() (src/worker/App.mjs:370 returns this.id). For the childapp's SharedWorker topology, workerId resolves to a truthy non-string, so the || keeps it (the designed appName fallback never fires) and waitForSession's String#toLowerCase throws. The exact non-string shape getWorkerId returns for a multi-window SharedWorker childapp needs an empirical confirm.
The Fix
- Fixture (
fixtures.mjs): guard targetId to a usable STRING — if workerId is not a non-empty string, fall back to appName / inferredAppName (the designed fallback): targetId = (typeof workerId === 'string' && workerId) ? workerId : (appName || inferredAppName).
- Defense (
ConnectionService.waitForSession): coerce/guard target so a non-string degrades to a clear "no session" timeout, not a TypeError.
- Empirical confirm: log
typeof/value of await Neo.worker.App.getWorkerId() for the childapp — confirm the non-string shape rather than mask a deeper getWorkerId multi-window bug.
Acceptance Criteria
Unblocks
- #13355 external-agent
create_component → evidence whitebox (the residual after PR #13437).
- The M2 first-widget agent-driven demo (Discussion #13436).
Duplicate sweep
Checked open testing + ai labels + the recent backlog — no existing connectToApp / neuralLink-fixture ticket. Tracked locally as a session task chip before this.
Context
The shared Playwright e2e fixture
neuralLink.connectToApp(appName)(test/playwright/fixtures.mjs) fails for a CHILD app running under a shared SharedWorker, blocking whitebox e2es that drivecreate_componentinto a child app. This is the M2 critical-path dependency for the v13.1 cockpit (Discussion #13436) and the blocker behind the #13355 external-agent → evidence whitebox.Observed
connectToApp('AgentOSWidget')(booting/apps/agentos/childapps/widget/index.html) throwsTypeError: target.toLowerCase is not a functionatfixtures.mjs:142→ConnectionService.waitForSession(targetId, ...)(ai/services/neural-link/ConnectionService.mjs:621callstarget.toLowerCase()). Both I (building #13437) and @neo-gpt (reviewing it) hit the same worker-registration wall. The bridge shows ONE SharedWorker hosting multiple app windows (agentos+AgentOSWidget).Root cause (diagnosed)
fixtures.mjs:137resolvestargetId = workerId || appName || inferredAppName.workerIdcomes fromawait window.Neo.worker.App.getWorkerId()(src/worker/App.mjs:370returnsthis.id). For the childapp's SharedWorker topology,workerIdresolves to a truthy non-string, so the||keeps it (the designed appName fallback never fires) andwaitForSession'sString#toLowerCasethrows. The exact non-string shapegetWorkerIdreturns for a multi-window SharedWorker childapp needs an empirical confirm.The Fix
fixtures.mjs): guardtargetIdto a usable STRING — ifworkerIdis not a non-empty string, fall back toappName/inferredAppName(the designed fallback):targetId = (typeof workerId === 'string' && workerId) ? workerId : (appName || inferredAppName).ConnectionService.waitForSession): coerce/guardtargetso a non-string degrades to a clear "no session" timeout, not aTypeError.typeof/value ofawait Neo.worker.App.getWorkerId()for the childapp — confirm the non-string shape rather than mask a deepergetWorkerIdmulti-window bug.Acceptance Criteria
connectToApp('AgentOSWidget')→getComponent/createComponentinto the app) connects WITHOUT thetarget.toLowerCaseerror and reads back a live component.NeuralLinkCreateGrid.spec.mjs).getWorkerIdreturns for the childapp); if a deepergetWorkerIdfix is out of scope, note the mask explicitly.Unblocks
create_component→ evidence whitebox (the residual after PR #13437).Duplicate sweep
Checked open
testing+ailabels + the recent backlog — no existing connectToApp / neuralLink-fixture ticket. Tracked locally as a session task chip before this.