Skip to content

Injection and transform contract #11

Open

Description

@dvcolomban

All-stage frame/CSP proof, 2026-10-03

Commit 09e6248 extends three existing test helpers. The working selector and native registration are unchanged; no fixture, production API, frame router or scheduling policy was added.

Actual panel selects world + runAt + allFrames
  → native registerContentScripts
  → top / same-origin child / granted cross-origin child / ungranted matching child
  → ordinary page or nonce CSP
Disable / enable / dispose → inspect native registrations and old/fresh document effects

Definition of Ready: the existing raw HTTP fixture already separates page CSP and frame permissions from Vite injection; all native stage controls and recorders work.

Definition of Done for this bounded slice:

  • All four Chromium/Firefox production/development commands pass. Each receipt has 24 active combinations, six disable/enable lifecycles and twelve disposals.
  • Independent review verifies 168 exact checks and 864 document snapshots, including selected native stage/frame options, absent localhost permission, blocked CSP controls, preserved old effects and empty cleanup registrations.
  • Both native builds, all 31 extension unit tests, strict lint, TS7, formatting and the executed evidence gate pass.
  • Full CI at ac59e94 passed. Downloaded Linux artifacts independently confirm all four42-check frame receipts,24 distinct stage/world/frame/CSP cells each, absent optional permission and864 document snapshots. The complete46-reference/35-payload/400-check gate also passes.

Reproduction and retained receipts. Late stages are absent at the first page script, then execute with native interactive/complete timing. The separate held-resource fixture proves document_end before load. Blank/blob/sandboxed frames, origin fallback, permission transitions, restart, registration/cleanup failures and broader CSP operations remain open. Firefox WebDriver Classic has no global page-error capture here.

Native content-script stage implementation, 2026-10-03

Commit 8277048 adds a private native runAt selector to the maintained extension example. Its existing common defineScript contribution forwards { world, allFrames?, runAt? } to scripting.registerContentScripts; the existing activation scope owns unregistering. Omission retains document_start. There is no SDK contract, stage scheduler, transport or permission-policy change.

Actual panel: world + stage + native frame option
  → existing defineScript setup → native browser registration
  → real document: first script / parsed DOM / held image / eventual load
Disable / dispose → native unregister; future documents uninjected, old effects retained

Each Chrome/Firefox production/development run proves six world/stage cells through the actual selector and install buttons. document_start precedes the first page script; document_end is captured at interactive before a held image completes; document_idle eventually executes with native interactive/complete timing. MAIN exposes the injected global, ISOLATED keeps it private. End/idle additionally disable, preserve old effects, leave fresh documents uninjected, then enable generation 2 at the selected stage. Every stage is disposed and checked on another fresh document.

Definition of Ready: native probes established browser scheduling differences; the existing registration/recorder supplied the feature without portable timing enforcement.

Definition of Done for this slice:

  • Both native builds and all four maintained browser commands pass on Chrome 153.0.8010.12 / Firefox 157.0.
  • Independent review verifies all 40 exact checks and 200 document snapshots across four generated/retained receipts, including native selected stages and all lifecycle registration sets.
  • All 31 affected unit tests, strict Oxlint, TS7, formatting and the executed API evidence gate pass. The new fixture has an actual unused-TCP-peer teardown regression.
  • Existing CI commands/artifact rules run and retain the scenarios; the inventory now requires each receipt's ten exact checks.
  • Full CI at the combined script-stage/routing head passed. Downloaded Linux artifacts independently confirm all four ten-check stage receipts and 200 document snapshots, plus the combined 46 references to 35 payloads and 288 checks.

Reproduction, native contract comparison and retained observations. All maintained idle observations happened to be interactive; a disposable Firefox probe had been complete. Neither becomes a scheduling guarantee. Late-stage coverage is top-level; the complete frame/CSP cross-product, blank/blob/sandboxed frames, origin fallback, permission transitions, restart and native registration/cleanup failure remain separate obligations. The all-stage frame/CSP proof below supersedes that pending cross-product; remaining native edge cases stay open.

Native script frame/CSP acceptance, 2026-10-02

Commit de473a7 extends only the existing example's native registration with allFrames, controlled by one initially unchecked panel checkbox. The common defineScript API and adapters stay unchanged. Both host names match registration, but only 127.0.0.1 has granted permission; the matching localhost child therefore tests native authority rather than a URL mismatch.

Implementation, sketch, commands and retained receipts.

Panel: { world, allFrames }
  → existing defineScript setup
  → native scripting.registerContentScripts
  → top / same-origin / cross-origin permitted documents
  → matching localhost child remains uninjected without host permission
scope disposal → native unregister; future documents lose injection
Tested behavior Actual native result in Chromium and Firefox
allFrames: false Only the top document injects.
allFrames: true Top, same-origin and permitted cross-origin child inject; ungranted localhost child does not.
Ordinary and nonce page CSP, MAIN/ISOLATED Packaged native document-start code runs at loading. MAIN global is page-visible; ISOLATED global is private.
Nonce observer + ordinary inline control Observer runs; under CSP the control stays blocked with a script-source violation. This avoids interpreting a blocked observer as absent injection.
Actual UI disable/enable/dispose Disable unregisters without undoing existing effects; fresh documents stay uninjected. Enable restores generation 2; dispose removes registration for future documents.

Definition of Ready

  • Accepted native configuration plus common contribution lifecycle expresses the feature, with no new declaration or routing policy.
  • The fixture distinguishes frame selection, origin, host permission, CSP and JavaScript world.
  • Native feasibility is measured before asserting CSP behavior; no generic assumption that page CSP blocks packaged MAIN injection.

Definition of Done for this slice

  • Both production builds, strict type-aware Oxlint, TypeScript 7, formatting and all 30 extension unit tests pass.
  • Maintained Chromium/Firefox production and WXT development commands pass on Chrome153.0.8010.12 and Firefox157.0.
  • Four actual receipts retain native registrations, permissions, document observations and contribution generations. Independent verification passes all 56 exact checks and 288 document observations.
  • API matrix now requires 232 native checks across 30 distinct receipts. Public inventory remains 814 paths, 413 linked, 34 gap groups.
  • Full workspace and Linux native CI passed. Independent downloaded-artifact review verifies all 41 references to 30 distinct payloads, all 232 exact checks and all 288 new document observations.

Blank/blob/sandboxed frames, origin fallback, later stages, broader CSP operations, permission transitions, browser restart, native registration dependency loss and cleanup failure remain open. This slice adds no privileged page relay, rollback, permission normalization or SDK enforcement layer.

Complete combined native acceptance, 2026-10-02

Full CI at 0da5f55 passed every workspace and native production/development gate. All 26 retained native receipts were downloaded and independently checked against every exact referenced scenario: 176 native checks, 814 API paths, 407 linked paths and 34 gap groups. This establishes acceptance of the declaration/capture slices; it does not identify the earlier intermittent failures.

Native Firefox cancellation acceptance, 2026-10-02

Commit 01aa441 adds maintained native cancellation evidence in production and WXT development on Firefox 157.0. The byte-prefix recipe, SDK APIs and policies are unchanged. Test-only helpers extract the existing owned server and Selenium boundary, then observe genuine page operations, backend snapshots and HTTP/socket events.

Page operation Observed page outcome Native input and filter outcome
reader.cancel() Pending/subsequent reads finish with done: true; cancellation and reader closure fulfill. During the 1,000 ms observation, the held input/socket remain open and the filter has not stopped. Disposing the contribution stops new admissions. Explicitly releasing the already-admitted input later completes its native stop/close handler and closes the response/socket.
Fetch AbortController.abort() Pending/subsequent reads and reader closure reject with AbortError. The held response/socket close before any server release. The unchanged filter's native stop/close handler runs with no filter error. A later transformed request still succeeds; disposal removes future admissions.

The recipe's completed count records its native onstop/close handler, including aborted channels. It does not mean successful page consumption. The trace-only investigation also recorded NS_BINDING_ABORTED at native webRequest.onErrorOccurred; an unchanged extension copy reproduced the observable results. That network observation is distinct from StreamFilter.onerror.

// Native page operations tested by the owned fixture; no new SDK API.
await reader.cancel();
// A separate held Fetch is started with controller.signal.
controller.abort();

Definition of Ready for this slice

  • Both cases reproduce through the genuine running-background filter, including an unchanged-copy control.
  • The owned server holds input after first delivered transformed bytes and can observe actual response/socket closure.
  • Native sources explain filter stop versus filter error; bounded non-events are not presented as lifetime guarantees.

Definition of Done for this slice

  • Maintained production and development Firefox commands pass both cases and existing response-byte/encoding/lifecycle scenarios.
  • Both retained receipts equal their generated native results; cancellation outcomes also match between modes.
  • Strict affected-example lint, types, formatting, diff checks and all 30 unit tests pass.
  • Executed inventory links four additional exact checks, totaling 176 native scenarios across 26 receipts; SDK paths remain 814/397 and 35 groups retain gaps.
  • Combined full CI at 0da5f55 passed, including the unchanged cancellation cases and the final executed-evidence gate. The earlier failed run history remains below. Attempt 1 passed the workspace, production checks and both new Firefox cancellation cases in development, then failed navigating to the extension panel after native background reload (firefox-development.ts:171). The downloaded Firefox production/development response receipts each pass all eight exact referenced checks. Attempt 2 stopped earlier at the final Chromium idle screenshot (Page.captureScreenshot timeout), after its functional assertions. Both failure investigations remain open; no reload/capture fix or complete CI acceptance is claimed. The final executed-browser gate ran in neither attempt.

Commands, native source links, measured outcomes and limits are retained with production results and development results.

This is ordinary loopback HTTP Fetch with a running background. The reader non-event observation is bounded; idle wakeup, page destruction, other consumers, encodings/protocols during cancellation and other Firefox versions are not established. It supplies no SDK upstream-cancellation, rollback, reconnect or retry guarantee. The broad injection/transform contract remains open.

Combined validation checkpoint, 2026-10-02

The first attempt of combined CI at bc5baa5 passed the workspace gate and preceding Chromium checks, then timed out taking the final screenshot after the natural-idle recovery assertions. The unchanged scenario passes locally; no cause or fix is claimed from that run. Its second attempt was superseded by a main push. Full CI at 0b533e8 passed every workspace, native production, persistence, idle, quota, debugger, trust, concurrent development and executed-evidence gate. This head only removes expired dependency-age exclusions; it changes no runtime or browser fixture. The original screenshot timeout remains an unexplained intermittent failure, with no fix claimed.

Native Firefox response encoding acceptance, 2026-10-02

Commit c1c4a8b extends the existing native response recipe's actual browser proof. Production code stays unchanged: Firefox supplies native converted bytes, the recipe writes its prefix and forwards each incoming chunk. There is no SDK decompressor, response buffer or header-normalization layer.

Wire: gzip/deflate bytes + original HTTP headers
  → Firefox native content conversion
  → existing filterResponseData prefix + direct byte forwarding
  → Fetch receives original-世界 or native:original-世界
Original Content-Encoding/Content-Length metadata stays visible.

Five cases pass in both production and development: identity with fixed length, gzip with fixed length/chunked framing, and deflate with fixed length/chunked framing. Each compares matched and unmatched raw delivered bytes and all three native framing/encoding headers. Original bytes are15; transformed bytes22. Fixed header lengths stay15/35/23 respectively. All five admitted filters complete. The existing redirect error, subsequent requests, split UTF-8 stream and completion after disposal still pass; the final only native error is the expected Channel redirected.

Primary-source explanation, exact table and scope, maintained fixture/assertions, production receipt, development receipt.

Run the existing commands after building the example:

pnpm --filter @devkit/example-webext test:firefox
pnpm --filter @devkit/example-webext test:dev:firefox

Definition of Ready for this slice

  • The existing public native hook, production recipe and running-background owner are identified.
  • Native Firefox source and its gzip regression establish the conversion boundary; actual browser observations determine this example's outcome.
  • Valid deterministic identity/gzip/deflate HTTP fixtures provide matched/unmatched byte and header observations.
  • Settled native-first policy requires no additional SDK enforcement or owner decision.

Definition of Done for this slice

  • Actual Firefox157 production and development commands pass all five byte/header cases and existing response lifecycle checks.
  • Both exact generated receipt references are linked in the executed API inventory; retained observations match across modes.
  • Strict affected lint/TS7/format checks and all30 extension workspace tests pass. Loopback tests required native socket access; their sandbox EPERM failure is not represented as a code defect.
  • Combined full CI passes at 0b533e8, including this evidence commit and unchanged native fixtures.

This is valid no-store HTTP loopback Fetch composition, not outgoing wire re-encoding. Original Content-Length is not transformed-body length. Brotli/zstd, malformed/truncated encodings, ranges/caching, HTTP/2/3, cancellation, native listener wakeup and the remaining full ticket matrix stay open. Chromium's existing explicit unavailable result remains unchanged. This ticket is not closed by the bounded encoding proof.

Native Firefox response-body streaming, 2026-10-02

Commit bcf4bf1 adds one background-owned defineTransform recipe using native Firefox webRequest.filterResponseData. It matches the owned loopback text fixture, writes a fixed UTF-8 prefix and forwards native byte chunks immediately. Chromium explicitly rejects this unavailable Firefox method through the existing setup-failure diagnostic. No SDK body schema, HTTP pipeline, buffering engine, cancellation supervisor or debugger dependency is added.

Illustrative flow; the actual source includes the native type guard, local counters and browser-owned errors:

defineTransform({
  id: 'example.response-body',
  execution: defineExecution({ id: 'example.background' }),
  setup({ scope }) {
    // Verify the real Firefox method exists before registering.
    const listener = ({ requestId }) => {
      const filter = browser.webRequest.filterResponseData(requestId);
      filter.onstart = () => filter.write(prefix);
      filter.ondata = ({ data }) => filter.write(data);
      filter.onstop = () => filter.close();
      filter.onerror = () => errors.push(filter.error);
      return {};
    };
    browser.webRequest.onBeforeRequest.addListener(listener, fixtureFilter, ['blocking']);
    scope.onDispose(() => browser.webRequest.onBeforeRequest.removeListener(listener));
  },
});
flowchart LR
  Client[Packaged panel] --> Runtime[Existing plugin lifecycle]
  Runtime --> Listener[Firefox native listener]
  Request[Matching loopback request] --> Listener
  Listener --> Filter[Native StreamFilter]
  Filter --> Document[Original chunks plus fixed prefix]
  Dispose[Disable or dispose] --> Remove[Remove admission listener]
  Remove --> Future[Later requests retain original bytes]
  Filter --> Finish[Admitted stream finishes normally]
Loading

Definition of Ready for this slice

  • Firefox method, declared execution, permissions and native byte/error lifecycle identified.
  • Chromium method absence and explicit setup rejection defined without an emulated body API.
  • Real held-output, split UTF-8 and HTTP redirect fixtures compose with the four existing native browser runners.
  • Published type-only Firefox declarations coexist with the existing Chrome/WXT API types; no runtime polyfill or copied declarations.

Definition of Done for this slice

  • Firefox matching responses receive native: while unmatched bytes remain unchanged.
  • Disable removes future admissions; enable creates a fresh activation and restores filtering.
  • An actual HTTP redirect reports Channel redirected from the native stream. Its unmatched destination and a later matching response remain correct. A network interruption is not falsely asserted to emit StreamFilter.onerror.
  • The document receives native:first-caf before the server releases the remaining input. The final exact body is native:first-café-second-世界, preserving a split UTF-8 code point without recipe decoding/buffering.
  • Disposal removes the listener but lets the already admitted stream finish. Later matching requests receive their original body; the provider incarnation is retained.
  • Chromium rejects install with filteringMethodPresent:false, existing setup-failure, no admitted streams and unchanged bytes. Disposal remains usable.
  • All four complete browser commands pass on Chromium 153.0.8010.12 and Firefox 157.0 in production and native WXT development. Captured Chromium page errors are empty; Firefox WebDriver Classic has no global page-error capture.
  • Strict lint, TypeScript 7, formatting, 30 example unit tests and both native production builds pass. Declaration consumers reject numeric request IDs and string stream writes. Bundle checks reject a runtime polyfill and duplicate native publisher modules.
  • Four retained receipts and exact generated scenario mapping pass conformance:check --browser: 164 scenarios from 25 receipts, with 814 API paths, 394 linked paths and 35 groups retaining explicit gaps.
  • Combined full CI passed at bcf4bf1, including this change, workspace gates, both production browsers, concurrent native development transitions and the exact API-evidence gate.

This is running-background registration, not persistent event wakeup. Idle/restart restoration, compressed/other encoded bodies, fixed Content-Length, permission changes, cancellation, broader frames/CSP and the complete interception matrix remain open. The README records the native ownership and exact limits. The preceding full CI passed; its earlier view remount race remains a separate native state investigation. This broad ticket remains open.

Native redirect contribution acceptance, 2026-10-02

Commit 2113958 adds two background-owned defineTransform recipes using native DNR session redirects. The rules match only granted loopback XMLHTTPREQUEST traffic and change the destination path while preserving its origin/port. Native priorities and atomic update failures remain the browser's behavior. No common HTTP pipeline, SDK rule allocator, debugger dependency or new permission is introduced.

defineTransform({
  id: 'example.redirects-lower',
  execution: defineExecution({ id: 'example.background' }),
  async setup({ scope }) {
    await chrome.declarativeNetRequest.updateSessionRules({ addRules: [rule] });
    scope.onDispose(() =>
      chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [rule.id] }),
    );
  },
});

Definition of Ready for this slice

  • Native redirect action, host access, owner-selected rule IDs 1201/1202 and priorities 1/2 identified.
  • Same-origin path transformation composes directly with the accepted native setup recipe.
  • Actual loopback document, server and both production/development browser runners reused.

Definition of Done for this slice

  • Real server sees the selected destination path/body; an active redirect prevents the original matching path reaching it.
  • Higher native priority wins when both rules match; unmatched requests stay unchanged.
  • Actual response URLs preserve the granted origin/port. Both browsers recorded Fetch redirected metadata rather than a fabricated redirect result.
  • Duplicate rule setup and invalid atomic updates reject through native errors without changing existing rules.
  • Independent disable/reenable/disposal preserves the sibling and records activation generations; disposing both restores the original request.
  • All four commands pass locally: test:browser, test:firefox, test:dev:chromium, test:dev:firefox on Chromium 153.0.8010.12 and Firefox 157.0. No captured Chromium page errors; Firefox global capture remains unavailable.
  • Strict affected-example lint, types and formatting pass; 27 tests in seven files pass. Two real TCP regression cases fail when only the fixture teardown correction is removed and pass with it restored.
  • The executed API gate passes. Four new generated receipts contribute 32 exact scenarios; inventory totals 152 scenarios from 21 native receipts. API-path counts stay unchanged.
  • Latest combined full CI passed at 944501a, including the native redirect suites and executed evidence gate. Earlier run 36976855155 failed when the native view was republished after viewPlugin.enable: expected Counter: 6, observed Counter: 5. A delayed native state echo reproduces the same regression and remains under investigation; this unchanged passing CI run is not its fix.

Four retained native receipts, recipe, commands and native limits.

A native browser preconnection reproduced a teardown stall after the header assertions had completed. The socket was accepted but had sent zero bytes/requests. The owned header/redirect HTTP fixtures now call closeAllConnections() after initiating server.close(). Real TCP tests include a completed-request acceptance barrier and bounded teardown; production behavior and assertions remain unchanged.

Response-body recipes, cross-origin redirects, frames/CSP, permission revocation, rule limits, other extensions, interrupted/background-loss lifetimes and the broader matrix remain open. This checkpoint does not close the broad ticket or promise a shared transform order/failure policy.


Native browser header transforms, 2026-10-02

Commit 6bca292 adds two independent defineTransform recipes backed by native declarativeNetRequest.updateSessionRules, plus visible packaged controls. declarativeNetRequestWithHostAccess uses the existing granted loopback request/initiator scope. The two rule owners select IDs 1101/1102 and priorities 1/2; the SDK allocates neither and adds no rule registry, callback transform or HTTP pipeline.

defineTransform({
  id: 'example.headers-lower',
  execution: defineExecution({ id: 'example.background' }),
  async setup({ scope }) {
    await chrome.declarativeNetRequest.updateSessionRules({ addRules: [nativeRule] });
    scope.onDispose(() =>
      chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [nativeRule.id] }),
    );
  },
});

Registration succeeds before acquiring cleanup ownership. The browser supplies matching, priority, header edits, atomic updates and failure semantics. A competing duplicate rule cannot acquire or later remove the existing owner's rule.

Seven assertions passed on each of Chromium 153.0.8010.12 and Firefox 157.0, in production and native WXT development:

  • Actual server-observed request and document-observed response headers change on the matched fixture.
  • Overlapping rules use native higher-priority set behavior.
  • Unmatched requests retain original headers.
  • Duplicate-ID setup rejects without changing the existing rules.
  • An invalid atomic update rejects without its requested removal taking effect.
  • Independent disable/enable preserves the sibling and uses a fresh activation generation.
  • Disposing one preserves its sibling; disposing both restores original headers.

Four retained native receipts include actual request logs, native snapshots and document observations. Chromium records zero captured fixture/extension page errors. Firefox keeps its WebDriver Classic limitation. One parallel Chromium attempt stalled in later native-host checks; its owned process/profile was cleaned up, and the independent full rerun passed without code changes. All four complete native reruns, 25 affected unit tests, strict lint, TypeScript 7, format and the executed API-evidence gate pass. Existing CI commands run all four scenarios; full CI for this commit passed, including both production browsers, concurrent WXT development, persistence/trust suites and the executed API-evidence gate.

Native redirects and response-body recipes, frames/CSP, permission revocation, rule limits, other extensions, worker/restart restoration, encoding/streaming and in-flight cleanup remain open. This header slice does not close the broad ticket or adopt a common failure/ordering policy. Reproduction and limits.

Status reconciliation, 2026-10-02

Common view, script and transform setup recipes are implemented; broader native acceptance remains open. Transform commit 32becdf adds defineTransform({ id, execution, requires?, setup }) to plugin.transforms. It reuses typed native contexts, capability bindings and the existing activation/cleanup lifecycle. Native hosts and capabilities retain matching, stages, priorities and failures. No shared response pipeline, buffering, script loader, paused-request controller or wire callback is added.

The actual Devframe and DevTools Vite hosts each compose two independent native HTML hooks. Reversed plugin configuration still produces native pre then post order. Their real Chromium scenarios inspect received HTTP bytes and the earliest page script through disable, fresh enable, disposal, native HTTP 500 and recovery. Independent builds emit both effects; preview serves the completed output with zero live hook calls. A separate in-app live check confirms independent removal/restoration while already-loaded documents retain previous effects. Contract and ownership diagram, automated receipt, bounded live receipt.

const transform = defineTransform({
  id: 'example.html-first',
  execution: serverExecution,
  setup({ scope }) {
    enabled = true; // Actual local native Vite hook checks this flag.
    scope.onDispose(() => { enabled = false; });
  },
});
const plugin = definePlugin({ id: 'example.html-first', transforms: [transform] });

The recipe owns whether its already configured native hook acts. Independent static builds use native configuration directly. Completed HTML and effects in existing documents cannot be undone by disabling a live contribution.

This slice's readiness and completion evidence:

  • The native hook, declared execution, build/dev distinction and resource owner are identified.
  • The common declaration is inert, typed and validated; unsupported extra pipeline fields are rejected.
  • Runtime dependency binding, cleanup order, setup failure/explicit retry and replacement cleanup barriers have executable tests.
  • Both actual server hosts have native ordering, independent lifecycle, failure/recovery and build-preview evidence.
  • Affected core/runtime/Vite example lint, TypeScript 7, formatting and tests pass. The executed API gate passes with 814 paths accounted for, 394 linked paths and 35 groups retaining explicit gaps.
  • The full ticket's native header/redirect/body, frames/CSP, permission loss, streaming/encoding and in-flight lifecycle matrix is complete.

The earlier script commit bcd7921 implements the equivalent native registration recipe on actual server and extension hosts. Its full CI passed. Combined full CI passed at bfd62d3d12c5713541bad31ec23ed66d0ab50de1, including workspace checks, both production browsers, native persistence/permission suites, stable Firefox full restart, concurrent development transitions and the executed API-evidence gate.

The two native DNR header-rule contributions are now implemented and verified on both production and WXT browser targets in the checkpoint above. Redirect and response-body work remains; no new shared policy is required for the next native research. CDB remains an optional capability implementation and does not gate the generic contract. Historical pending-choice sections below are superseded by the accepted native-first resolution. This issue stays open.

Reconciled status, 2026-09-30

CDB interception configuration is optional capability integration. The accepted ownership correction supersedes the old pending interception-choice section below. The native blocker on Debugger and CDB contract has been removed; generic injection/transforms do not depend on CDB.

Maintained native script and Vite HTML timing examples provide bounded evidence. Kind-specific declarations, ordering, cleanup, frame/CSP coverage, encoding/streaming and failure behavior remain open. Keep native hooks as the starting point; no generic HTTP pipeline or script loader is implied.

Earlier checkpoints below are dated evidence. Their then-pending items are superseded by this status and later accepted resolutions; they do not reopen settled architecture choices.

Owner clarification: CDB belongs to an optional capability integration

Correction 43c6128 removes CDB interception configuration as a generic SDK architecture blocker. CDB-backed functionality is an ordinary optional capability/service implementation using the framework. CDB itself is an independent native library. Generic routing, contribution lifecycle, renderer integration and other capabilities must not depend on its Fetch/domain-demand choices.

A read-only audit found no CDB/CDP-specific dependency or logic in maintained packages/*. CDB dependencies and integration code are confined to the debugger example. Existing native patches and browser regressions support that optional integration; they do not introduce mandatory SDK plumbing. The problem was the plan's dependency framing.

Fixed versus dynamic Fetch patterns, native configuration acknowledgement, leases and recovery stay within the CDB-backed capability. The generic injection/transform requirement remains open and must be designed from shared backend needs. Chrome-specific pattern/stage semantics are not adopted as the generic API by default.

Reclassified integration note. Its retained options are optional integration research, not a pending choice that gates generic framework work. No production code, dependency patch or upstream PR was changed by this correction. Formatting and whitespace checks pass.

Native script reload checkpoint

Maintained script reload tests now establish the same result on Chromium and Firefox: a WXT unlisted-script edit reloads the extension and removes its temporary registration. Existing MAIN documents retain old effects; a new document receives updated code only after explicit native re-registration. Evidence and limits. Strict checks and both development suites pass locally; full CI passes. This supplies native lifecycle facts without choosing a portable script API or a recovery policy.

Native Vite HTML timing

Commit 94f9e18 adds a native transformIndexHtml recipe to the existing Vite example, installed during development and build. It prepends a classic inline script to the application HTML. The first page-owned script records the bootstrap marker and its own readyState; the maintained site displays that snapshot.

Real Chromium 153.0.8010.12 passed all four combinations:

Native host Mode Bootstrap readyState First page-script readyState
Devframe Development loading loading
DevTools Development loading loading
Devframe Build / preview loading loading
DevTools Build / preview loading loading

The browser check starts the actual maintained host config, awaits its real provider, and records its configured identity. Preview serves exactly the built HTML and invokes the added HTML-observation hook zero times. No custom preview middleware, Vite lifecycle, HTTP-transform pipeline, portable declaration or new upstream patch was needed.

Native plugin, recipe and ownership diagram, actual browser receipt.

Validation: affected dependency build, strict TS7, type-aware Oxlint, Oxfmt, all 24 host lifecycle tests and the real browser check pass locally. CI now runs the browser command after its existing Chromium installation. Full CI passes.

This covers native HTML entry transformation on the owned CSP-free fixture. It does not establish arbitrary HTTP response rewriting, CSP support, Firefox execution of this server fixture, contribution enable/disable or a portable script contract. Dynamic interception ownership remains an owner decision. DoD stays open.

Maintained packaged-script timing

Commit 747c3de adds a synchronous packaged script to the WebExtension example. The same recipe is emitted by production Vite and WXT's native unlisted-script entry, then registered through the native browser API before navigation. No portable script contract, extra permissions, page bridge or new patch is introduced.

All four live combinations passed: Chromium 153.0.8010.12 and Firefox 156.0.1, each with production and WXT development builds. The first inline page script records the result synchronously:

Registration Page-visible bootstrap global Early shared-DOM listener First page-script readyState
MAIN loading loading loading
ISOLATED absent loading loading
Removed, then fresh navigation absent absent loading

The tests also verify exact native settings, an unmatched URL in each world, and removal of the owned registration. Production bundle tests require a standalone classic script. Existing browser UI/RPC and development reload checks still pass. Registrations, servers and owned browser profiles are cleaned up.

Recipe and commands, four real receipts, first-script observer.

Validation: affected dependency build, strict TS7, type-aware Oxlint, Oxfmt, three example tests and both production/development browser suites pass locally. Original CI passed the timing checks but failed when the popup test read through a reloading options document. Correction 68d758d waits for that document through its native locator before evaluating popup state. Both real development suites pass locally; new full CI passes.

This covers top-level loopback documents registered before navigation. It does not establish child frames, CSP, persistent registrations, already-open documents, mutation rollback or development replacement of injected code. Vite HTML transformation and the shared script declaration remain separate work. The interception-pattern ownership decision above is still pending; this slice does not choose it. DoD remains open.

Pending owner decision: interception coverage

Decision note at 8c508a0 contains current behavior, proposed API calls, ownership diagrams, failure cases and maintenance costs. It is a proposal, not an accepted or implemented API.

The fixed example proves host-configured coverage. A later subscriber does not reconfigure native Fetch: CDB's public demand API is boolean and only the initial demand enables a domain. Independent raw Fetch.enable would compete with the native owner.

Choice Registration behavior Cost
Host-configured coverage Plugin handlers operate inside the host's existing pattern set; expanding coverage requires host reconfiguration Smaller native change, more host configuration; broad filters can pause unrelated traffic
Contribution-declared coverage, recommended for independent plugins Each contribution declares patterns; the native CDB owner reconciles active configuration while provider-local handlers process responses Requires a narrow native configuration contract/proof; install/disable failure and active-request handling need evidence
// Proposed B only. This factory is not implemented.
defineResponseTransform({
  id: 'example.flags',
  patterns: [{ urlPattern: 'https://example.test/api/flags*', requestStage: 'Response' }],
  transform: ({ body }) => overrideFlags(body),
});

Native CDB would own configuration only. It would not import SDK contribution types or application transformation logic. Neither choice changes client realm/provider routing. Ordering and paused-request failure policy are later dependent decisions. The owner question is pending; no dynamic patch or new upstream PR has been created.

Maintained fixed native response example, 2026-09-29

Commit e099406 promotes the proven fixed CDB response filter into the strict TypeScript debugger example and its existing Chromium CI command. It introduces no portable transform declaration, general pipeline, dynamic pattern registry or new dependency patch.

host supplies responseDebugger(fixed native URL pattern)
  -> existing createDebuggerHost / native ChromeDebuggerPort
  -> CDB alone owns attachment, Fetch enable/disable, subscription and lease
  -> one Fetch.requestPaused response -> getResponseBody -> fulfillRequest
  -> close subscription + release lease
  -> test observes actual native Fetch/Runtime disable completion before detach

The maintained browser check proves a matching status-200 text response changes to server:selected:transformed; concurrent unmatched traffic keeps server:unmatched; subscription close alone retains lease-owned Fetch demand; after lease release and observed native disable, a new matching request receives its original body. It also checks zero dropped events, no overflow in this bounded case, no remaining lease, one attachment/detachment, expected post-detach command rejection and no observed browser errors.

The initial maintained run detached while native Runtime.disable was still pending. The corrected fixture observes both domains' real completion at the native port before detaching. This is test sequencing, not a new SDK cleanup guarantee: native lease release itself still does not acknowledge domain-disable completion. No recovery controller or cancellation wrapper was added.

Recipe, browser scenario, actual receipt, commands and boundaries.

Validation passes locally: affected graph and all three browser builds, strict TS7 Bundler/NodeNext, type-aware Oxlint, Oxfmt, all 11 package tests and the actual Chromium command including its preceding title/lifecycle checks. Latest full CI passes on the same implementation plus the decision documentation. The earlier run was superseded by those documentation pushes.

Scope remains fixed host policy and one root-session ASCII text response. Dynamic plugin patterns/ordering, paused-request failure policy, in-flight body reads, competing demand, overload, child sessions and broader body formats remain open. Firefox continues to prove debugger unavailability, not response-transform parity. The existing exact-version subscription activation patch stays installed. No new upstream PR was opened. The broad DoD below is unchanged.

Part of Design a portable contribution SDK and WebExtension runtime.

Fixed CDB response configuration proved, 2026-09-29

Debugger and CDB contract now supplies a real Chromium proof for fixed response-stage filtering through the existing public ChromeDebuggerPort. The host supplies native Fetch.enable parameters only when CDB invokes that command; CDB remains the sole attachment/domain owner. No patch is required for that fixed policy.

Commit 710c4f8 retains exact source and receipts. A selected response is read and replaced, an unmatched request remains unchanged, and a later matching response returns its original body after subscription close and lease release. Actual native disable completion is observed by the harness; the public release call itself does not acknowledge it.

This resolves fixed-pattern feasibility, not dynamic multi-contribution ordering or general response-transform support. The follow-on CDB activation correction reproduces setup event loss and verifies its exact-version patch. It also proves release-driven recovery after a completed body read. In-flight body reads, other simultaneous demand, overload, child sessions and broader payload coverage remain acceptance work. The earlier unconfigured-activation observation below is still accurate; its implication that configuration necessarily needs a new upstream API is superseded. Full report.

Upstream integration boundary, 2026-09-27

Reuse Vite HTML/server hooks and browser script/interception APIs. A portable declaration describes the actual supported stage and ownership; it does not replace native transformation engines or serialize executable callbacks. Page DOM injection and response-byte transformation retain distinct capabilities. Keep CDB Fetch ownership with its existing owner.

See the implementation and map review. This narrows implementation mechanisms without dropping the accepted feature or real-host coverage requirements.

Question

What portable contracts should contributions use for page injection, HTML transformation, and HTTP interception, and which guarantees can each server or extension adapter provide? Decide timing, ordering, ownership, cleanup, and unsupported outcomes without equating operations that occur at different browser stages.

Context and current behavior

The shared SDK must let a contribution run against a Vite-backed development host or a packaged extension targeting a deployed website. Existing Devframe/Vite integration already uses server configuration and HTML injection hooks. Vite documents transformIndexHtml and server hooks, but those run in a server/build environment; they are not an extension runtime API.

An extension can register scripts at document_start, execute in an isolated or main world, and insert DOM content. Those operations differ from changing response bytes before parsing. Chrome's declarativeNetRequest covers headers and redirects. Firefox's filterResponseData supports response streams. Chromium's debugger Fetch protocol can pause and replace responses, subject to session ownership and protocol constraints.

The inspected CDB revision 89bdf211e8e21d86aba70051c366bb03b38d43d8 reserves Fetch.enable and automatically enables domains without configuration parameters. The inspected source anchors are packages/core/src/cdp-catalogue.generated.ts for reserved Fetch methods and packages/extension/src/selected-tab-publisher.ts for managed-domain activation. Custom interception patterns and response-stage selection are an unresolved integration question. Local checkout behavior must not be confused with published-package support.

Requirements and scope

  • Separate packaged script registration, page-world bootstrap, DOM insertion, HTML response transformation, header modification, redirect, request interception, and response-body replacement where their semantics differ.
  • Define timing and scope for each capability, including registration before navigation, already-open pages, frame selection, cross-origin frames, and document replacement.
  • Compose executable modules at build time. Callback implementations remain local to their executor; RPC carries serializable descriptors, state, requests, and results rather than arbitrary functions or native server/browser objects.
  • Define contribution ordering and disposal, including conflicting transforms. A transport reconnect or HMR cycle must not duplicate script registrations, handlers, or active interception rules.
  • Specify failure behavior for streaming, cancellation, navigation, closed targets, size limits, invalid encodings, and unavailable permissions. A failed transform must not leave a request paused indefinitely.
  • Record capability differences explicitly. A DOM edit must not masquerade as a pre-parse HTML transform, and a fetch monkey patch must not claim interception of all browser traffic.

Options and recommendation

A single transform callback would conceal timing and coverage differences. Browser-specific contributions would expose those differences but force consumers to duplicate feature logic. Restricting everything to injected DOM code would remove capabilities the server and Firefox can supply.

Recommend a small set of semantic capabilities with shared contribution registration and explicit backend support. Reuse existing server and browser mechanisms. Add a richer common operation only where its guarantees can be demonstrated in each claimed host. Let contributions declare required capabilities and choose a documented alternate implementation when product behavior permits it.

Proposed API or experiment

Experiment steps separate executable registration from serializable configuration without inventing a new generic contribution factory:

package a bootstrap module and fixture response transform
server: attach the transform through the actual Vite/HTTP hook
extension: register the packaged module through the supported browser script API
extension response transform: use the supported native/CDB executor, or report unavailable
send only validated configuration and target metadata to the selected executor
bind every registration to its owning contribution cleanup

The bootstrap is a build-time module reference and the transform executes inside its selected backend. Specify how configuration reaches that executor without serializing executable functions. Kind-specific declarations remain owned by this ticket; do not reintroduce the rejected defineContribution factory. Run the same observable fixture through Devframe, DevTools/Vite, Chromium, and Firefox adapters. The fixture should record what the earliest page script sees, the response body received, and cleanup after disposal.

Investigate whether CDB can express response-stage Fetch configuration through a shared owner. If it cannot, specify the required adapter/upstream contract before relying on it. Opening native DevTools must remain part of the debugger-backed experiment in both attachment orders.

Scenarios and acceptance criteria

  • A packaged bootstrap affects the first eligible page script at the documented timing; an already-loaded page gets an explicit outcome rather than a false timing guarantee.
  • Two contributions transform the same fixture in a deterministic order, and disposing one preserves the other.
  • HTML, JSON, binary, compressed, redirected, cached, and streamed fixtures have defined behavior or explicit unsupported outcomes. Record the bounded v1 coverage rather than accepting accidental support.
  • Exceptions, timeouts, cancellation, permission revocation, target closure, worker restart, and reconnect release intercepted requests and registrations according to the chosen policy.
  • Every injection/transform API, hook, and feature has a runnable example and automated tests on every supported host. Include contributions and renderer controls, standalone Devframe, DevTools, Chromium, and Firefox compositions. Assert unavailable capabilities and failures as well as successful transformations.
  • Real received bytes and page-observed effects establish correctness. Mocked responses, screenshots alone, stubbed hooks, and compile-only examples do not meet acceptance.

Dependencies

Depends on Server adapter contract for server lifecycle and existing native hooks, and Permissions and trust for caller authority and resource scope. Debugger and CDB contract owns the optional CDB-backed implementation only; it does not block generic script/transform declarations or other native implementations. Each advertised mechanism still needs its own actual timing, permissions and lifecycle evidence.

Definition of Ready

  • For every stage, name the public native hook and executable owner before adding a descriptor or helper.

  • Dependencies define server lifecycle, permissions, native context, and debugger ownership.

  • Candidate capabilities have timing and traffic-coverage descriptions grounded in browser documentation.

  • Deterministic fixtures can observe response bytes, first-script effects, frame behavior, and request completion.

  • The CDB Fetch configuration gap has an owner and a specific feasibility experiment.

Definition of Done

  • Each advertised stage has real native evidence or an explicit unavailable result; no extra generic HTTP pipeline or script loader is introduced.

  • Capability contracts, ordering, target scope, registration lifetime, cancellation, and failure policies are accepted.

  • The adapter matrix names the exact server/browser mechanism and any unsupported cases for each operation.

  • Real-host experiments establish the risky timing and interception claims; unresolved claims remain blockers.

  • Every public API and hook maps to runnable examples and automated success, unsupported, failure, and cleanup scenarios on every supported host.

  • The resolution identifies implementation and upstream changes without treating this decision ticket as their delivery.

  • The human has confirmed the resolution through discussion; the agent has not supplied the human side of the decision.

Resolution record

Record the accepted contracts, adapter matrix, fixture evidence, transform ordering, remaining blockers, and rejected alternatives in a resolution comment. The parent map links this issue by title and keeps the detailed decision here.

Activity

  1. dvcolomban commented on Sep 22, 2026

    @dvcolomban
    CollaboratorAuthor

    Upstream reuse audit resolution found a precise CDB gap: Fetch.enable and Fetch.disable are kernel-owned; subscription demand enables a domain without configuration parameters. This does not establish support for configured patterns or response-stage interception, nor does it prove all Fetch use impossible.

    Acceptance: identify a supported configuration and lifecycle owner, then transform a fixture response and prove cancellation/disposal cannot strand paused requests. Otherwise mark the affected operation explicitly unavailable. Do not bypass ownership with competing raw Fetch enable/disable calls. Keep the corresponding Vite transform phase and extension target/frame semantics explicit. Catalogue, activation code.

  2. dvcolomban commented on Sep 22, 2026

    @dvcolomban
    CollaboratorAuthor

    Research handoff and acceptance gates

    Sources: Browser capability audit.

    Accountable owner: dvcol, until reassigned. These observations inform this open contract; they do not resolve it.

    Both browsers demonstrated buffered text/HTML-byte transforms. Firefox also reconstructed a UTF-8 character split across three chunks; the filter buffers until onstop and emits once. This is not incremental downstream streaming. Chromium's DNR has no response-body transform; its measured path uses debugger Fetch.

    Acceptance additions:

    • Declare separate mechanisms and capabilities for DNR headers, Chromium debugger bodies and Firefox response filtering.
    • Before promising broader support, exercise compression, binary/large responses, redirects, cache/service-worker responses, strict CSP, frame replacement and cancellation.
    • Put a finite deadline and explicit continue/fail/cancel outcome on every paused request. Verify cleanup on detach and owner loss, and integrate CDB's configured Fetch activation without dual ownership.
  3. dvcolomban commented on Sep 29, 2026

    @dvcolomban
    CollaboratorAuthor

    Maintained fixed native response example, 2026-09-29

    Commit e099406 promotes the proven fixed CDB response filter into the strict TypeScript debugger example and its existing Chromium CI command. It introduces no portable transform declaration, general pipeline, dynamic pattern registry or new dependency patch.

    host supplies responseDebugger(fixed native URL pattern)
      -> existing createDebuggerHost / native ChromeDebuggerPort
      -> CDB alone owns attachment, Fetch enable/disable, subscription and lease
      -> one Fetch.requestPaused response -> getResponseBody -> fulfillRequest
      -> close subscription + release lease
      -> test observes actual native Fetch/Runtime disable completion before detach
    

    The maintained browser check proves a matching status-200 text response changes to server:selected:transformed; concurrent unmatched traffic keeps server:unmatched; subscription close alone retains lease-owned Fetch demand; after lease release and observed native disable, a new matching request receives its original body. It also checks zero dropped events, no overflow in this bounded case, no remaining lease, one attachment/detachment, expected post-detach command rejection and no observed browser errors.

    The initial maintained run detached while native Runtime.disable was still pending. The corrected fixture observes both domains' real completion at the native port before detaching. This is test sequencing, not a new SDK cleanup guarantee: native lease release itself still does not acknowledge domain-disable completion. No recovery controller or cancellation wrapper was added.

    Recipe, browser scenario, actual receipt, commands and boundaries.

    Validation passes locally: affected graph and all three browser builds, strict TS7 Bundler/NodeNext, type-aware Oxlint, Oxfmt, all 11 package tests and the actual Chromium command including its preceding title/lifecycle checks. Full CI passes on the same implementation plus its ownership decision documentation.

    Scope remains fixed host policy and one root-session ASCII text response. Dynamic plugin patterns/ordering, paused-request failure policy, in-flight body reads, competing demand, overload, child sessions and broader body formats remain open. Firefox continues to prove debugger unavailability, not response-transform parity. The existing exact-version subscription activation patch stays installed. No new upstream PR was opened. The broad DoD below is unchanged.

  4. dvcolomban commented on Sep 29, 2026

    @dvcolomban
    CollaboratorAuthor

    Pending owner decision: interception coverage

    Decision note at 8c508a0 contains current behavior, proposed API calls, ownership diagrams, failure cases and maintenance costs. It is a proposal, not an accepted or implemented API.

    The fixed example proves host-configured coverage. A later subscriber does not reconfigure native Fetch: CDB's public demand API is boolean and only the initial demand enables a domain. Independent raw Fetch.enable would compete with the native owner.

    Choice Registration behavior Cost
    Host-configured coverage Plugin handlers operate inside the host's existing pattern set; expanding coverage requires host reconfiguration Smaller native change, more host configuration; broad filters can pause unrelated traffic
    Contribution-declared coverage, recommended for independent plugins Each contribution declares patterns; the native CDB owner reconciles active configuration while provider-local handlers process responses Requires a narrow native configuration contract/proof; install/disable failure and active-request handling need evidence
    // Proposed B only. This factory is not implemented.
    defineResponseTransform({
      id: 'example.flags',
      patterns: [{ urlPattern: 'https://example.test/api/flags*', requestStage: 'Response' }],
      transform: ({ body }) => overrideFlags(body),
    });

    Native CDB would own configuration only. It would not import SDK contribution types or application transformation logic. Neither choice changes client realm/provider routing. Ordering and paused-request failure policy are later dependent decisions. The owner question is pending; no dynamic patch or new upstream PR has been created.

  5. dvcolomban commented on Sep 29, 2026

    @dvcolomban
    CollaboratorAuthor

    Maintained packaged-script timing

    Commit 747c3de adds a synchronous packaged script to the WebExtension example. The same recipe is emitted by production Vite and WXT's native unlisted-script entry, then registered through the native browser API before navigation. No portable script contract, extra permissions, page bridge or new patch is introduced.

    All four live combinations passed: Chromium 153.0.8010.12 and Firefox 156.0.1, each with production and WXT development builds. The first inline page script records the result synchronously:

    Registration Page-visible bootstrap global Early shared-DOM listener First page-script readyState
    MAIN loading loading loading
    ISOLATED absent loading loading
    Removed, then fresh navigation absent absent loading

    The tests also verify exact native settings, an unmatched URL in each world, and removal of the owned registration. Production bundle tests require a standalone classic script. Existing browser UI/RPC and development reload checks still pass. Registrations, servers and owned browser profiles are cleaned up.

    Recipe and commands, four real receipts, first-script observer.

    Validation: affected dependency build, strict TS7, type-aware Oxlint, Oxfmt, three example tests and both production/development browser suites pass locally. Original CI passed the timing checks but failed when the popup test read through a reloading options document. Correction 68d758d waits for that document through its native locator before evaluating popup state. Both real development suites pass locally; new full CI passes.

    This covers top-level loopback documents registered before navigation. It does not establish child frames, CSP, persistent registrations, already-open documents, mutation rollback or development replacement of injected code. Vite HTML transformation and the shared script declaration remain separate work. The interception-pattern ownership decision above is still pending; this slice does not choose it. DoD remains open.

  6. 13 remaining items

  7. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Native browser header transforms, 2026-10-02

    Commit 6bca292 adds two independent defineTransform recipes backed by native declarativeNetRequest.updateSessionRules, plus visible packaged controls. declarativeNetRequestWithHostAccess uses the existing granted loopback request/initiator scope. The two rule owners select IDs 1101/1102 and priorities 1/2; the SDK allocates neither and adds no rule registry, callback transform or HTTP pipeline.

    defineTransform({
      id: 'example.headers-lower',
      execution: defineExecution({ id: 'example.background' }),
      async setup({ scope }) {
        await chrome.declarativeNetRequest.updateSessionRules({ addRules: [nativeRule] });
        scope.onDispose(() =>
          chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [nativeRule.id] }),
        );
      },
    });

    Registration succeeds before acquiring cleanup ownership. The browser supplies matching, priority, header edits, atomic updates and failure semantics. A competing duplicate rule cannot acquire or later remove the existing owner's rule.

    Seven assertions passed on each of Chromium 153.0.8010.12 and Firefox 157.0, in production and native WXT development:

    • Actual server-observed request and document-observed response headers change on the matched fixture.
    • Overlapping rules use native higher-priority set behavior.
    • Unmatched requests retain original headers.
    • Duplicate-ID setup rejects without changing the existing rules.
    • An invalid atomic update rejects without its requested removal taking effect.
    • Independent disable/enable preserves the sibling and uses a fresh activation generation.
    • Disposing one preserves its sibling; disposing both restores original headers.

    Four retained native receipts include actual request logs, native snapshots and document observations. Chromium records zero captured fixture/extension page errors. Firefox keeps its WebDriver Classic limitation. One parallel Chromium attempt stalled in later native-host checks; its owned process/profile was cleaned up, and the independent full rerun passed without code changes. All four complete native reruns, 25 affected unit tests, strict lint, TypeScript 7, format and the executed API-evidence gate pass. Existing CI commands run all four scenarios; full CI for this commit is running.

    Native redirects and response-body recipes, frames/CSP, permission revocation, rule limits, other extensions, worker/restart restoration, encoding/streaming and in-flight cleanup remain open. This header slice does not close the broad ticket or adopt a common failure/ordering policy. Reproduction and limits.

  8. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Full CI for 6bca292 passed. This includes the native header scenarios on Chromium and Firefox production and concurrent WXT development, the existing persistence/trust/debugger/renderer suites, and the executed API-evidence gate. The remaining native redirect/body and broader transform matrix stays open.

  9. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Native redirect contribution acceptance, 2026-10-02

    Commit 2113958 adds two background-owned defineTransform recipes using native DNR session redirects. The rules match only granted loopback XMLHTTPREQUEST traffic and change the destination path while preserving its origin/port. Native priorities and atomic update failures remain the browser's behavior. No common HTTP pipeline, SDK rule allocator, debugger dependency or new permission is introduced.

    defineTransform({
      id: 'example.redirects-lower',
      execution: defineExecution({ id: 'example.background' }),
      async setup({ scope }) {
        await chrome.declarativeNetRequest.updateSessionRules({ addRules: [rule] });
        scope.onDispose(() =>
          chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [rule.id] }),
        );
      },
    });

    Definition of Ready for this slice

    • Native redirect action, host access, owner-selected rule IDs 1201/1202 and priorities 1/2 identified.
    • Same-origin path transformation composes directly with the accepted native setup recipe.
    • Actual loopback document, server and both production/development browser runners reused.

    Definition of Done for this slice

    • Real server sees the selected destination path/body; an active redirect prevents the original matching path reaching it.
    • Higher native priority wins when both rules match; unmatched requests stay unchanged.
    • Actual response URLs preserve the granted origin/port. Both browsers recorded Fetch redirected metadata rather than a fabricated redirect result.
    • Duplicate rule setup and invalid atomic updates reject through native errors without changing existing rules.
    • Independent disable/reenable/disposal preserves the sibling and records activation generations; disposing both restores the original request.
    • All four commands pass locally: test:browser, test:firefox, test:dev:chromium, test:dev:firefox on Chromium 153.0.8010.12 and Firefox 157.0. No captured Chromium page errors; Firefox global capture remains unavailable.
    • Strict affected-example lint, types and formatting pass; 27 tests in seven files pass. Two real TCP regression cases fail when only the fixture teardown correction is removed and pass with it restored.
    • The executed API gate passes. Four new generated receipts contribute 32 exact scenarios; inventory totals 152 scenarios from 21 native receipts. API-path counts stay unchanged.
    • Full repository CI for this commit completes successfully. CI result is pending identification after push.

    Four retained native receipts, recipe, commands and native limits.

    A native browser preconnection reproduced a teardown stall after the header assertions had completed. The socket was accepted but had sent zero bytes/requests. The owned header/redirect HTTP fixtures now call closeAllConnections() after initiating server.close(). Real TCP tests include a completed-request acceptance barrier and bounded teardown; production behavior and assertions remain unchanged.

    Response-body recipes, cross-origin redirects, frames/CSP, permission revocation, rule limits, other extensions, interrupted/background-loss lifetimes and the broader matrix remain open. This checkpoint does not close the broad ticket or promise a shared transform order/failure policy.

  10. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Full CI for 2113958 failed in run 36976855155, at the existing custom/reference renderer browser command. After service contribution reenable, the reference renderer retained Counter: 5 while the assertion expected Counter: 6. The exact failing scenario is being reproduced and instrumented; no timeout/retry or passing rerun is being used to dismiss it.

    The new redirect checks and their scoped validation passed locally. Their broad completion gate remains open until the CI failure is understood and the current full run passes. Combined CI at 944501a is running.

  11. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Native Firefox response-body streaming, 2026-10-02

    Commit bcf4bf1 adds one background-owned defineTransform recipe using native Firefox webRequest.filterResponseData. It matches the owned loopback text fixture, writes a fixed UTF-8 prefix and forwards native byte chunks immediately. Chromium explicitly rejects this unavailable Firefox method through the existing setup-failure diagnostic. No SDK body schema, HTTP pipeline, buffering engine, cancellation supervisor or debugger dependency is added.

    Illustrative flow; the actual source includes the native type guard, local counters and browser-owned errors:

    defineTransform({
      id: 'example.response-body',
      execution: defineExecution({ id: 'example.background' }),
      setup({ scope }) {
        // Verify the real Firefox method exists before registering.
        const listener = ({ requestId }) => {
          const filter = browser.webRequest.filterResponseData(requestId);
          filter.onstart = () => filter.write(prefix);
          filter.ondata = ({ data }) => filter.write(data);
          filter.onstop = () => filter.close();
          filter.onerror = () => errors.push(filter.error);
          return {};
        };
        browser.webRequest.onBeforeRequest.addListener(listener, fixtureFilter, ['blocking']);
        scope.onDispose(() => browser.webRequest.onBeforeRequest.removeListener(listener));
      },
    });
    flowchart LR
      Client[Packaged panel] --> Runtime[Existing plugin lifecycle]
      Runtime --> Listener[Firefox native listener]
      Request[Matching loopback request] --> Listener
      Listener --> Filter[Native StreamFilter]
      Filter --> Document[Original chunks plus fixed prefix]
      Dispose[Disable or dispose] --> Remove[Remove admission listener]
      Remove --> Future[Later requests retain original bytes]
      Filter --> Finish[Admitted stream finishes normally]
    
    Loading

    Definition of Ready for this slice

    • Firefox method, declared execution, permissions and native byte/error lifecycle identified.
    • Chromium method absence and explicit setup rejection defined without an emulated body API.
    • Real held-output, split UTF-8 and HTTP redirect fixtures compose with the four existing native browser runners.
    • Published type-only Firefox declarations coexist with the existing Chrome/WXT API types; no runtime polyfill or copied declarations.

    Definition of Done for this slice

    • Firefox matching responses receive native: while unmatched bytes remain unchanged.
    • Disable removes future admissions; enable creates a fresh activation and restores filtering.
    • An actual HTTP redirect reports Channel redirected from the native stream. Its unmatched destination and a later matching response remain correct. A network interruption is not falsely asserted to emit StreamFilter.onerror.
    • The document receives native:first-caf before the server releases the remaining input. The final exact body is native:first-café-second-世界, preserving a split UTF-8 code point without recipe decoding/buffering.
    • Disposal removes the listener but lets the already admitted stream finish. Later matching requests receive their original body; the provider incarnation is retained.
    • Chromium rejects install with filteringMethodPresent:false, existing setup-failure, no admitted streams and unchanged bytes. Disposal remains usable.
    • All four complete browser commands pass on Chromium 153.0.8010.12 and Firefox 157.0 in production and native WXT development. Captured Chromium page errors are empty; Firefox WebDriver Classic has no global page-error capture.
    • Strict lint, TypeScript 7, formatting, 30 example unit tests and both native production builds pass. Declaration consumers reject numeric request IDs and string stream writes. Bundle checks reject a runtime polyfill and duplicate native publisher modules.
    • Four retained receipts and exact generated scenario mapping pass conformance:check --browser: 164 scenarios from 25 receipts, with 814 API paths, 394 linked paths and 35 groups retaining explicit gaps.
    • Full CI at this commit completes successfully after push.

    This is running-background registration, not persistent event wakeup. Idle/restart restoration, compressed/other encoded bodies, fixed Content-Length, permission changes, cancellation, broader frames/CSP and the complete interception matrix remain open. The README records the native ownership and exact limits. The preceding full CI passed; its earlier view remount race remains a separate native state investigation. This broad ticket remains open.

  12. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Native Firefox response encoding acceptance, 2026-10-02

    Commit c1c4a8b extends the existing native response recipe's actual browser proof. Production code stays unchanged: Firefox supplies native converted bytes, the recipe writes its prefix and forwards each incoming chunk. There is no SDK decompressor, response buffer or header-normalization layer.

    Wire: gzip/deflate bytes + original HTTP headers
      → Firefox native content conversion
      → existing filterResponseData prefix + direct byte forwarding
      → Fetch receives original-世界 or native:original-世界
    Original Content-Encoding/Content-Length metadata stays visible.
    

    Five cases pass in both production and development: identity with fixed length, gzip with fixed length/chunked framing, and deflate with fixed length/chunked framing. Each compares matched and unmatched raw delivered bytes and all three native framing/encoding headers. Original bytes are15; transformed bytes22. Fixed header lengths stay15/35/23 respectively. All five admitted filters complete. The existing redirect error, subsequent requests, split UTF-8 stream and completion after disposal still pass; the final only native error is the expected Channel redirected.

    Primary-source explanation, exact table and scope, maintained fixture/assertions, production receipt, development receipt.

    Run the existing commands after building the example:

    pnpm --filter @devkit/example-webext test:firefox
    pnpm --filter @devkit/example-webext test:dev:firefox

    Definition of Ready for this slice

    • The existing public native hook, production recipe and running-background owner are identified.
    • Native Firefox source and its gzip regression establish the conversion boundary; actual browser observations determine this example's outcome.
    • Valid deterministic identity/gzip/deflate HTTP fixtures provide matched/unmatched byte and header observations.
    • Settled native-first policy requires no additional SDK enforcement or owner decision.

    Definition of Done for this slice

    • Actual Firefox157 production and development commands pass all five byte/header cases and existing response lifecycle checks.
    • Both exact generated receipt references are linked in the executed API inventory; retained observations match across modes.
    • Strict affected lint/TS7/format checks and all30 extension workspace tests pass. Loopback tests required native socket access; their sandbox EPERM failure is not represented as a code defect.
    • Combined full CI completes successfully at bc5baa5; currently running.

    This is valid no-store HTTP loopback Fetch composition, not outgoing wire re-encoding. Original Content-Length is not transformed-body length. Brotli/zstd, malformed/truncated encodings, ranges/caching, HTTP/2/3, cancellation, native listener wakeup and the remaining full ticket matrix stay open. Chromium's existing explicit unavailable result remains unchanged. This ticket is not closed by the bounded encoding proof.

  13. dvcolomban commented on Oct 3, 2026

    @dvcolomban
    CollaboratorAuthor

    Active native script registration across optional-host permission changes, 2026-10-03

    e05dd25 extends only the existing Firefox trust runner and evidence. The actual panel installs the common MAIN/document_start script once; Firefox's native permission UI then controls host access.

    Same registration, options and contribution generation 1
    Granted → fresh document marker at loading
    Revoked → fresh document marker absent
    Regranted → marker at loading, without reinstall
    Dispose → registry empty
    

    Definition of Ready: the maintained Firefox runner already operates genuine permission notifications and the shared timing fixture, with no permissions API override.

    Definition of Done for this bounded slice:

    • Native Firefox 157 command passes 11checks. Independent review verifies true/false/true permissions, loading/null/loading markers, identical registrations/options and generation 1 at disposal.
    • Scoped strict lint, TS7, formatting and exact executed browser evidence pass.
    • Native snapshots and reproduction are retained; no permission policy, automatic disable, retry or reinstall is added.
    • Full CI at e05dd25 passes and its actual Linux transition receipt is independently checked.

    This is top-level Firefox production MAIN/document_start. Already-run code rollback, other stages/worlds/frames, development and Chrome remain open. The separate owner-operated Chrome permission sequence remains pending; its four local files were untouched. Firefox WebDriver Classic lacks global page-error capture. The broader Injection/transform and Permissions/trust contracts remain open.

    The full CI at e05dd25 passed. Its retained artifacts independently verify all 49 browser references, 38 distinct payloads and 414 unique native checks, plus the original 140 core, 94 runtime and 11 Devframe cases. This validates the changes described in this comment; the subsequent invalid-renderer and cleanup-callback regressions have their own pending CI run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

wayfinder:grillingDecision requiring discussion with the project owner

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions