diff --git a/.project-docs/30-worklog/tasks/20260827-x01-preview-injection-9c4e2a71.md b/.project-docs/30-worklog/tasks/20260827-x01-preview-injection-9c4e2a71.md new file mode 100644 index 0000000..6f54e07 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260827-x01-preview-injection-9c4e2a71.md @@ -0,0 +1,95 @@ +# Task: Remediate X-01 preview data injection target + +## Identity + +- Task ID: 20260827-x01-preview-injection-9c4e2a71 +- Mode: Feature +- Branch: codex/20260827-x01-preview-injection-9c4e2a71-x01-preview-injection-9c4e2a71 +- Worktree: D:\Datas\OthersProjects\makelore-x01-preview-injection-9c4e2a71 +- Base commit: 2f346687b173137135dbd5259511d23505ff08dd +- Owner: codex +- Status: Ready for Integration + +## Scope + +- X-01 live-acceptance remediation on exact client coordinator HEAD + `2f346687b173137135dbd5259511d23505ff08dd`. +- Fix the confirmed root `injectProjectData` preview failure in + `electron/agent-browser/module.ts` by passing the intended preview target + Origin explicitly into root preview-data installation. +- Add the narrow Agent Browser regression test and this task-scoped record only. + +## Intent And Constraints + +- Follow Data Service P0 spec §10.4 and §14 groups 2 and 13, plus the X-01 + remediation finding. Preserve explicit opt-in, exact-Origin capability + binding, child/sessionRef behavior, lifecycle cleanup, and ordinary browser + navigation without data injection. +- The confirmed cause is that `open()` initializes `record.url` to the target, + prime navigation to `about:blank` mutates it, and root installation later + derives Origin from the mutated URL. The fix must carry the target URL + directly; it must not weaken Origin checks or add a second browser/preload. +- Only this task worktree may be modified. The occupied coordinator worktree, + its untracked X-01 probe scripts, all other source files, and the prior ML-09 + source worktree are read-only context. +- Do not alter child/sessionRef installation semantics, route behavior, server + code, unrelated E2E selectors, or canonical project memory. + +## Planning Gate + +- Result: Passed on 2026-08-27. +- Concurrent gate ran `check_project_docs.py`, then + `task_context.py start` against the occupied coordinator worktree with + `--base-ref 2f346687b173137135dbd5259511d23505ff08dd`; status JSON verified + this task ID, feature mode, absolute worktree/branch, and exact base. +- Read the required MakeLore project-memory startup set, the coordinator task + record, Agent Browser architecture/data-flow seams, and the X-01 scope. The + coordinator owns the parent worktree and its live probes; this task owns only + the isolated module/test/record paths, with no unresolved semantic conflict. + +## Outcome + +- Passed the intended `targetUrl` explicitly to the root preview-data + installation call. Root session Origin now derives from that stable target + URL even when the prime `about:blank` navigation updates `record.url`; + child/sessionRef installation remains on its existing call path. +- Added a narrow Agent Browser regression whose fake prime navigation emits + `did-navigate` for `about:blank`. Before the fix it observed `origin: "null"`; + after the fix it observes `http://127.0.0.1:4173`. + +## Plan + +1. Inspect the current root/child preview installation seam and add a failing + regression proving a prime `about:blank` navigation cannot change the Origin + used for root injection. +2. Pass the intended target URL through root installation with the smallest + signature/call-site change; keep child/sessionRef handling unchanged. +3. Run focused Agent Browser/preview tests, typecheck, scoped lint and diff/doc + gates, then commit once with a clean isolated worktree. + +## Verification + +- Red-first regression: + `pnpm exec vitest run tests/unit/agent-browser-core.test.ts -t "uses the + target Origin when the prime navigation reports about:blank" --maxWorkers=1` + failed as expected before the implementation (`received origin: "null"`). +- Focused tests: + `pnpm exec vitest run tests/unit/agent-browser-core.test.ts + tests/unit/preview-data-session.test.ts --maxWorkers=1` — 2 files, 84 tests + passed. +- `pnpm run typecheck` — passed. +- `pnpm exec eslint electron/agent-browser/module.ts + tests/unit/agent-browser-core.test.ts` — passed. +- `git diff --check` — passed. +- No Electron E2E or live X-01 acceptance was run in this narrow remediation; + the coordinator must rerun live acceptance after integration. + +## Follow-ups + +- Parent coordinator should integrate the single commit and rerun X-01 with + the real PostgreSQL and signed-in MakeLore preview. Do not treat this + repository-local focused verification as live acceptance. + +## Promotion Candidates + +- None recorded. diff --git a/electron/agent-browser/module.ts b/electron/agent-browser/module.ts index f444e7e..270fb03 100644 --- a/electron/agent-browser/module.ts +++ b/electron/agent-browser/module.ts @@ -391,7 +391,7 @@ export class AgentBrowserModule { this.attachDebugger(record, false), OPEN_TIMEOUT_MS, ); - if (injectProjectData) await this.installPreviewData(record); + if (injectProjectData) await this.installPreviewData(record, undefined, targetUrl); } catch (error) { await this.closeInternal(record); throw toFault( @@ -796,6 +796,7 @@ export class AgentBrowserModule { private async installPreviewData( record: BrowserRecord, sessionRef?: string, + targetUrl?: string, ): Promise { if (record !== this.record || record.view.webContents.isDestroyed()) { throw new AgentBrowserFault( @@ -814,7 +815,7 @@ export class AgentBrowserModule { if (!sessionRef) { const openInput: PreviewDataSessionOpenInput = { projectPath: record.projectPath, - origin: new URL(record.url).origin, + origin: new URL(targetUrl ?? record.url).origin, browserGeneration: record.generation, }; const session = await previewDataSession.open(openInput); diff --git a/tests/unit/agent-browser-core.test.ts b/tests/unit/agent-browser-core.test.ts index 0003119..d010f93 100644 --- a/tests/unit/agent-browser-core.test.ts +++ b/tests/unit/agent-browser-core.test.ts @@ -609,6 +609,33 @@ describe('AgentBrowserModule', () => { expect(externalGlobal.__MAKELORE_DATA__).toBeUndefined(); }); + it('uses the target Origin when the prime navigation reports about:blank', async () => { + const adapter = new FakeAdapter(); + const preview = new FakePreviewDataSession(); + adapter.onCreate = (view) => { + view.webContents.loadHandler = async (url) => { + view.webContents.emit('did-navigate', {}, url); + }; + view.webContents.debugger.responders.set('Page.addScriptToEvaluateOnNewDocument', async () => ({ + identifier: 'script-root', + })); + }; + const module = new AgentBrowserModule(adapter, { previewDataSession: preview }); + + await module.open({ + projectId: 'clock', + projectPath, + url: 'http://127.0.0.1:4173/', + injectProjectData: true, + }); + + expect(preview.opens).toEqual([{ + projectPath, + origin: 'http://127.0.0.1:4173', + browserGeneration: 1, + }]); + }); + it('fails and tears down before target load when preview session setup fails', async () => { const adapter = new FakeAdapter(); const preview = new FakePreviewDataSession();