feat(agent): browser-extension verification (load, drive, compile, re-run) - #23
Merged
Conversation
…ign [roadmap:autonomous-qa-enhancements] Implements lore-proofkeeper/requirements/req-extension-verification.md and lore-proofkeeper/designs/design-extension-verification.md. Records the capability to load an unpacked extension for the drive, rediscover its runtime ID, and emit a compiled test that re-loads it. Signed-off-by: Tom Ballard <tom@armytage.co>
… [roadmap:autonomous-qa-enhancements] When a session carries an extensionPath, the emitter produces a spec that launches a persistent context with the extension (channel: chromium new headless), rediscovers the extension ID from the MV3 service worker at run time, and rewrites chrome-extension://<recorded-id>/… gotos to the runtime ID. Non-extension sessions emit byte-identically. RecordedSession carries the extension dir. Signed-off-by: Tom Ballard <tom@armytage.co>
…ontext [roadmap:autonomous-qa-enhancements] Adds loadExtension(): discover the extension's runtime ID from the MV3 service worker (MV2 background-page fallback, then wait). The driver surfaces the ID and chrome-extension:// base to the model so it can drive the extension's pages. Signed-off-by: Tom Ballard <tom@armytage.co>
…CLI [roadmap:autonomous-qa-enhancements] browserDrive launches a persistent context with the extension when set; a new --extension flag and a per-environment extensionPath thread through resolveTarget → QaOptions → DriveOptions for both the qa and scoped paths. Signed-off-by: Tom Ballard <tom@armytage.co>
…al-browser drive [roadmap:autonomous-qa-enhancements] Signed-off-by: Tom Ballard <tom@armytage.co>
…roadmap:autonomous-qa-enhancements] Signed-off-by: Tom Ballard <tom@armytage.co>
tcballard
force-pushed
the
claude/extension-verification
branch
from
June 30, 2026 17:09
7001b4f to
99c1a2b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Proofkeeper couldn't test a browser extension: it drove a vanilla, non-persistent Chromium page, had no config for an extension, and the emitter always produced a
test({ page })spec on the default fixture — none of which loads an extension. Chromium loads an unpacked extension only in a persistent context with--load-extension, and an MV3 extension's ID is regenerated on every load.This adds first-class extension verification through the same drive→compile→fidelity→run→write-back loop: load the unpacked extension, let the model exercise its popup/options pages (
chrome-extension://<id>/...) and its effect on host pages, and emit a compiled spec that re-loads the extension and re-discovers the ID at run time — so the committed test and the fidelity gate verify the real extension, never a stale recorded ID.How
src/cli.tsbrowserDrive): when an extension is configured, launch a persistent context withchannel: "chromium"and--load-extension/--disable-extensions-except.channel: "chromium"selects Chromium's new headless — the only headless mode that loads extensions (old headless never does; pure headed needs a display). Verified empirically against this repo's pre-installed Chromium.src/agent/extension.ts):loadExtension()reads the runtime ID from the MV3 service worker (MV2 background-page fallback, then waits for the worker). The driver surfaces the ID and thechrome-extension://<id>/base to the model.src/compiler/emit.ts): a new mode whenRecordedSession.extensionPathis set — emit a persistent-context spec that relaunches with the extension, rediscoversextId, and rewrites recordedchrome-extensiongotos to use the runtimeextId. Non-extension specs are byte-identical to before (regression-guarded).--extension <dir>flag onqa, and a per-environmentextensionPath, threaded throughresolveTarget→QaOptions→DriveOptionsfor both theqaand scoped paths.Usage
Or per environment in the config:
"environments": { "dev": { "url": "...", "extensionPath": "./my-extension" } }.Tests & gates
extensionIdFromUrl/loadExtension(fake context); emitter extension mode (persistent context,channel: "chromium", runtime-ID rewrite, determinism, non-extension unchanged); config parse +resolveTarget.tests/extension.integration.test.ts,PROOFKEEPER_E2E): loads a real MV3 fixture extension (tests/fixtures/extension/), discovers the ID, drives the popup — passing against the pre-installed Chromium. Added to the CI e2e job.typecheck+buildclean.req-extension-verification+design-extension-verificationlinked to theautonomous-qa-enhancementsroadmap,## Verified Bythe new tests.rac validate23/23,rac relationships --validate0 issues,rac review100/100.Scope
MV3 Chromium extensions loaded unpacked. Packed
.crx, the Chrome Web Store, non-Chromium browsers, and a manifest-keystable-ID mode are out of scope (noted in the design). Releasable → next CalVer. Independent of the OpenAI-adapter PR.