Skip to content

Server adapter contract #6

Closed
Closed

Description

@dvcolomban

Contract resolved, 2026-10-02

The final resolution records the accepted native adapter interfaces, host/lifecycle ownership, implemented examples, passing CI and the exact follow-up owners. The contract decision is complete. Coverage/reload/authority/script obligations remain with their respective tickets. The portable view choice is accepted and implemented; earlier dated statements that it was awaiting input are historical.

Native authorization revocation, 2026-10-02

The native-auth regression and evidence, committed as a9a9149, verifies a pending action receiving the exact native connection error when its authenticated connection is revoked. Already dispatched work finishes once; native reauthentication requires a fresh portable adapter and does not replay the action. All 50 server tests and affected strict checks pass. No production auth policy or SDK API changed.

Full CI passed at ce546ce68e7df120a1adec6141768a8ca44a24d0, including the full workspace checks, production browser suites, concurrent development transitions and executed API-evidence gate. This proves live connection revocation on the native Devframe host; persistent-token revocation and broader host/UI cases remain open.

Reconciled status, 2026-10-02

The separate startup rollback follow-up, committed as a4cb5b1, adds two real native duplicate-view failure cases in DevTools development/preview. The Vite package now passes 26 tests and strict checks. Its full CI passed; the preceding implementation's full CI passed. Native construction/activation-cancellation and the wider host matrix remain open.

The Vite examples now run the shared native JSON counter through authenticated browser-to-provider actions and state in development, independently built preview and watched-production preview on both Devframe and DevTools. Implementation and executed evidence records six Chromium cases, 30 affected example tests, both live in-app confirmations, the preview-origin correction and remaining limits. Commit 5da838f is on main. Full CI passed.

This completes the previously missing Vite browser counter integration. Automatic discovery, native setup/activation failure coverage and full host/API conformance remain open. The portable view declaration still requires the owner's choice; this example introduces no new SDK view API. Earlier dated checkpoints remain historical evidence.

Reconciled status, 2026-09-30

Native Devframe/DevTools factories, authenticated remote catalogs, explicit server connections, selected-page handoff, native state and JSON action routing are implemented. Host-ownership and remote authorization tests are in packages/server/tests/ownership.test.ts and remote-client.test.ts. Development, live preview and static snapshots have accepted separate lifetimes in the server packet.

Automatic endpoint discovery beyond the explicit handoff, setup/activation failure coverage, generic transform contracts and complete host/API conformance remain open. Native server view-index composition is now delivered in ef43f0f, with Chromium and Firefox lifecycle acceptance. Remaining renderer work concerns the broader browser/catalog/lifecycle matrix.

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.

Accepted two-layer selection amendment, 2026-09-27

The owner chose typed command/results with native state observation, and implementation-owned applicability. Contract migration and authenticated native proof are on main. The architecture diagram and API examples supersede the earlier universal target contract and A1/A2/B mapping questions.

Client selectors choose realm/provider recipients. Selected action/service implementations inspect schema-defined domain/resource input and return their own declared result, such as applied or not-applicable. There is no SDK target envelope, target resolver, accepts hook or new topic/event bus. A not-applicable result is fulfilled; it neither makes the provider unavailable nor triggers fallback/replay. If multiple selected implementations match, all may act.

Provider incarnation, contribution activation generation, exact versions, native authorization/serialization and dispatch ownership remain unchanged. Browser/debugger capabilities still validate actual resources and permissions.

Part of Design a portable contribution SDK and WebExtension runtime.

Current implementation, 2026-09-27: 0c170ec adds the browser-safe native ProviderConnection, authorized catalog query and payload-free invalidations to the existing single-object provider startup and direct strict installation handles. The owner accepted native cancellation: stop local waiting; dispatched backend work may finish; never automatically retry/replay. Native auth, RPC, schema validation, serialization and state remain upstream-owned. dfef733 supplies the runnable browser example on both native hosts. 48 adapter tests, both native examples, 24 Vite-host tests and affected strict checks pass. Full repository CI passed at dfef733: builds, types, strict lint, formatting, packed-consumer checks and tests.

Generic target mapping is no longer a server-adapter prerequisite. Capability inputs and implementations own resource references and applicability. Endpoint discovery, state/renderer/extension integration and full host conformance remain open.

Upstream integration boundary, 2026-09-27

Reuse the existing Devframe/hub/kit contexts and Vite plugins. The implemented createDevframeProvider({ context, ...composition }) and createDevToolsProvider({ context, ...composition }) add owned contributions to those contexts; host construction, authentication, RPC and state retain native APIs. Remote exposure is opt-in adapter work, not a replacement server factory.

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

Question

How should devframe and Vite DevTools providers satisfy the common contribution API in development and when serving watched production builds through a live preview backend?

Context and current behavior

The generic SDK will live initially in dvcol/devkit-extension as pnpm/Turbo packages. Server adapters must execute the same build-time contributions used by extension providers, including JSON UI, actions, state, page injection, transforms and native integrations. Their local context can expose underlying devframe/hub objects and Vite primitives where those actually exist.

The inspected devframe branch at a3f967755af99a0a0d8dd82b7b5d4f3dd4aec0bc already provides live HTTP middleware and WS/SSE through initHub and initDevframe. Its Vite hub adapter mounts during configureServer, tears down across restarts, and emits static snapshots during opted-in builds.

At DevTools commit 121656dfc5866b2f8de5baa8e0b6166ec28599c8, server integration also uses configureServer; production output writes backend: 'static'. Neither inspected adapter implements configurePreviewServer. These are branch observations, not assertions about released APIs. Existing live hosting of compiled assets is reusable, while preview attachment and update coordination remain open.

Requirements and scope

  • Define separate devframe-host and DevTools-host adapters that satisfy the common contribution contract and advertise their actual capabilities.
  • Support Vite development HMR and a distinct workflow with build watching, built assets and a live preview backend. Explicitly separate asset build mode from backend lifetime.
  • Specify HTML/head injection, supported HTTP transformation stages, action execution, shared-state access and browser/server communication. Distinguish transforms available only in Vite's source pipeline from HTTP operations available in preview.
  • Expose native devframe/hub context plus optional Vite development or preview primitives locally. A preview server must not masquerade as a full ViteDevServer.
  • Define ownership of connections, middleware, contribution registrations and disposal across starts, restarts and closes. Integrate routing and state contracts without creating adapter-specific alternatives.
  • Isolate endpoint discovery and credentials for simultaneous server connections, including authentication updates and client recreation. An upstream option or another public integration must have a defined consumer distribution strategy; a repository-only patch does not establish external package compatibility.
  • Ship runnable examples for both host adapters, development and watched-build/live-preview modes, with every public server API and hook exercised on real hosts.

Options and recommendation

Reusing the existing static-build path is suitable for snapshots but cannot supply live actions or server state. Keeping a separate permanently running sidecar offers clear ownership but adds ports, discovery and lifecycle coordination. Attaching a live provider to each host's HTTP lifecycle keeps discovery and assets together, while requiring explicit support for both development and preview server interfaces.

The recommendation to evaluate is a reusable live provider backed by devframe/hub, with thin host bindings for standalone devframe, Vite DevTools development and preview. Reuse upstream middleware and transports where audited exports permit it. Same-preview-process HTTP/backend ownership is accepted. Ordinary updates follow Vite and native host lifecycle. Specify middleware ordering and owned cleanup without adding a generic process-recovery controller.

Proposed API or experiment

Use the implemented provider factory inside the native host setup/lifetime. This example receives an actual hub context and imports the maintained shared contribution:

import { createDevframeProvider } from '@devkit/server';
import { counterCapability, increaseCounterAction } from '@devkit/example-contribution';
import { counterService, counterActionsPlugin } from '@devkit/example-server-contexts';

const provider = await createDevframeProvider({
  context: hubContext,
  providerId: 'example.remote',
  services: [counterService],
  plugins: [counterActionsPlugin],
  expose: {
    actions: [increaseCounterAction],
    capabilities: [counterCapability],
  },
});
await provider.invoke({ action: increaseCounterAction, input: { amount: 1 } });
await provider.dispose();

Use createDevToolsProvider with the same options shape and the actual kit context. The native host owns HTTP, RPC authentication and shutdown. expose registers explicit contracts for the host lifetime; unavailable implementations reject calls, and reusing a host requires its original finite method set. Strict startup and late installation return handles directly. Relaxed mode returns admitted/skipped outcomes. Existing local installation does not automatically expose a contract.

The server package documentation defines native method identity and (expectedIncarnation, input) invocation. Operations carry schema-defined input; implementations own resource applicability, freshness and permissions. Native observer failures leave partial registrations unavailable; no rollback is claimed. Authorized remote catalogs are implemented. JSON-view integration and browser capability implementations remain unfinished.

For preview feasibility, start an actual production build watcher and preview server, open a page, invoke an action and update a JSON spec. Rebuild a renderer, then a contribution backend module, then a page script. Observe which layers can update in place and which require disposal, restart, reconnection or reload. Agree the adapter's lifecycle events and restoration responsibilities; broader reload policy must use those events consistently.

Scenarios and acceptance criteria

  • One contribution works in a standalone devframe example and a DevTools-host example with the same JSON UI and action definitions.
  • A real preview page reaches live actions and receives state updates after a production build; generated static metadata cannot silently select the snapshot backend.
  • A server restart replaces old middleware and connections without duplicate registrations, leaked listeners or hanging calls. Recovery restores only state allowed by the common state contract.
  • Injection and transforms run at the documented stage with deterministic ordering. Unsupported preview transformations return the declared capability outcome instead of pretending success.
  • A failed watched build retains or rejects the last usable output according to a settled rule, and clients receive an explicit status. Partial output must not be advertised as a completed update.
  • The API inventory maps every host-binding hook and feature to runnable examples and real development/preview assertions. Extension hosts verify unsupported outcomes for server-only APIs wherever those APIs remain part of the common SDK.

Dependencies

Blocked by Contribution and realm contract using the tracker's native blocking relationship. Its resolved capability, registration and native-context contracts are necessary inputs. The adapter resolution documents handoff points for routing, state recovery and reload coordination; it does not redefine those independent contracts. The parent map contains the named decision pointer after resolution.

Definition of Ready

  • Name the public native registration/lifecycle APIs and demonstrate any missing cleanup behavior before adding adapter methods. See the native lifecycle investigation.

  • Contribution and realm contract is resolved, with server-relevant operations and lifecycle ownership specified.

  • Upstream reuse findings identify permissible public imports and versions for both adapters.

  • The development and watched-production/live-preview requirement is recorded with actual launch commands available for feasibility checks.

Definition of Done

  • Real host tests preserve native authorization and host ownership; adapter disposal releases its additions without shutting down an externally owned host.

  • A user-reviewed resolution specifies both adapter interfaces, host bindings, capability differences, native contexts, transport/discovery behavior and cleanup ownership.

  • Development, preview and snapshot behavior are explicitly separated; restart and asset-update events have defined consumers and restoration responsibilities.

  • Preview feasibility has direct evidence or a precise blocker; source-dev success is not accepted as preview proof.

  • Runnable example applications and complete API/hook test obligations are enumerated, including unsupported, failure and lifecycle cases across supported hosts.

  • Record remaining cross-ticket dependencies, close this decision, and add a named summary link to the map. Production implementation and its complete test execution belong to subsequent work.

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

Resolution record

Post the selected interfaces, host/mode capability table, middleware and transport decisions, lifecycle sequences, feasibility evidence, runnable-example matrix and rejected alternatives as the resolution comment.

Activity

  1. dvcolomban commented on Sep 22, 2026

    @dvcolomban
    CollaboratorAuthor

    Upstream reuse audit resolution identifies @devframes/vite/hub@1.0.0 and @vitejs/devtools-kit/node@0.7.5, including createPluginFromDevframe, as released server integration boundaries. Keep their Node/Vite contexts local.

    Acceptance: name the public factories and compatible package family; specify setup, authentication, restart and disposal ownership; exercise the shared contribution's state/action success and failure in standalone Devframe and Vite DevTools. Distinguish a live backend serving compiled assets from static snapshots. Do not infer preview integration from the existing configureServer hook. Vite adapter, kit integration.

  2. self-assigned this
    on Sep 22, 2026
  3. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Server adapter review: independent scripts and live preview

    Working deliverable for Server adapter contract, based on the settled core architecture. The process workflow and failed-build policy below are owner decisions. The adapter signatures and remaining reset choice are under review; this document does not claim completed SDK implementations.

    Accepted workflow

    The owner requires independently runnable build:watch and preview, plus dev:production starting both in parallel through pnpm's script-name regex. preview owns the HTTP server and its live action/state backend. The build watcher is a separate process, so restarting preview need not restart the watcher.

    {
      "scripts": {
        "build:watch": "node ./scripts/build-watch.ts",
        "preview": "node ./scripts/preview.ts",
        "dev:production": "pnpm run --parallel \"/^(build:watch|preview)$/\""
      }
    }

    These are the intended example entry points, not commands present in the old root application scaffold. Each script must work alone. The combined command uses an exact anchored selector so it cannot select itself or unrelated scripts. pnpm documents regex script selection and parallel execution; the pinned feasibility environment is pnpm 12.5.1. pnpm run.

    Preview must tolerate starting before the first build completes. Until a successful generation exists, it exposes build status and reports assets unavailable. Once there is a complete build, an in-progress or failed rebuild leaves that generation available and exposes the current build failure. Merely avoiding deletion of dist does not prove that partially overwritten files cannot be served.

    flowchart LR
      Combined["dev:production: pnpm parallel regex"] --> Watch["build:watch process"]
      Combined --> Preview["preview process"]
      Watch --> Candidate["Candidate build output"]
      Candidate -->|"only after successful completion"| Published["Published build generation"]
      Watch --> Status["Current build status"]
      Published --> Preview
      Status --> Preview
      Preview --> HTTP["Built pages and live backend on one HTTP origin"]
      HTTP --> Client["Shared client and JSON UI"]
    
    Loading

    The last-successful-build rule concerns asset availability. It does not silently preserve arbitrary in-memory backend state or replay interrupted actions. Those are governed by the state and routing contracts.

    Public reuse boundary

    The released baseline follows Upstream reuse audit: Devframe/hub/Vite integration 1.0.0 and Vite DevTools/kit 0.7.5. The attachment probe uses Vite 8.3.0 and Node 26.9.0. Future implementation must recheck dependency freshness and peer compatibility rather than treating this evidence pin as a permanent version choice.

    Integration Public API direction Ownership
    Existing standalone Devframe/hub Install portable definitions into its actual Node/hub context Adapter owns only its registrations; embedding application owns its existing HTTP server and hub
    Vite Devframe development Reuse the public Vite hub binding where it satisfies the contract Vite binding owns attachment, restart and teardown integration
    Vite DevTools development Use the public kit context and createPluginFromDevframe bridge Existing DevTools host owns RPC/state and its native context; portable adapter owns its additions
    Built-output live preview Public initHub, attach(PreviewServer.httpServer) and nodeMiddleware have direct evidence Preview entry owns HTTP; attached hub owns its transport; adapter owns contribution resources
    Full DevTools live preview Genuine createKitContext with an actual preview-specific public DevframeHost, then a live hub using that context Implement correct preview mounts/origin/metadata; do not pass a preview config to the default development host and assume parity

    Sources: hub public instance contract, DevTools bridge, kit context. These source references explain audited APIs; the downloaded released packages are the operational evidence, without a claim of byte-identical source builds.

    The released DevTools package publicly exports createDevToolsContext and createDevToolsHub from its root. The missing piece is their default host binding: preview config has command: 'serve' without a ViteDevServer, while createViteDevToolsHost requires that server to mount client assets, omits frame connection metadata without it and derives origin from development-server settings. Its generic constructor is not a complete preview adapter. Use the existing public DevframeHost seam for real preview mounts and native context ownership. The kit context must remain genuine; a hub-shaped substitute does not establish DevTools native feature parity.

    This conclusion comes from inspecting the released artifacts, without executing a new DevTools preview. DevTools 0.7.5 artifact exports the constructors in dist/index.d.ts lines 9 and 41–78 and dist/index.js lines 1–3. Its dist/plugins-C4WN3Ft6.js contains context construction at line 250 and the development server hook at line 550; the published files contain no configurePreviewServer. Kit 0.7.5 artifact exposes createKitContext in dist/node/index.d.ts lines 45–69; the default host mismatch is in dist/node/index.js lines 435–473. Hub 1.0.0 artifact documents its supplied-context path in dist/node/initiate.d.mts lines 145–152.

    The supported preview composition to prove is:

    const nativeHost = createPreviewDevframeHost(previewServer);
    const context = await createKitContext({
      host: nativeHost,
      cwd: previewServer.config.root,
      mode: 'dev',
      viteConfig: previewServer.config,
    });
    const hub = initHub({ context, base: '/__tools/' });
    const detachUpgrade = hub.attach(previewServer.httpServer);
    // The owned preview host supplies each frame's assets and live metadata.
    // Install packaged definitions through the actual context and mount hub.nodeMiddleware.

    createPreviewDevframeHost is proposed adapter code implementing the existing public host interface; it is not an upstream export or a new generic host abstraction. This sketch omits embedding configuration and shutdown code, which must be explicit in the runnable implementation. The supplied host must retain middleware ownership and derive origin from the actual listening preview server. A genuine kit context with a hub viewer proves a different scope than the complete DevTools shell and its native plugins; both need separately named assertions.

    Do not use private package files, publicly named internal escape hatches, or a cast from PreviewServer to ViteDevServer. An actual kit context can expose its kit descriptor. A hub-only preview cannot advertise kit just because both share some methods.

    Proposed minimal adapter API

    Install into an existing native hub or kit context. The initial standalone host is Devframe with its public hub; a lower-level bare Devframe context adapter is not implied by these signatures. Keep host construction, Vite configuration and the DevTools plugin model recognizable. The following names are proposed SDK exports; native names are actual upstream APIs.

    interface ServerComposition {
      readonly providerId: string;
      readonly strict?: boolean;
      readonly services?: readonly ServiceDeclaration[];
      readonly plugins?: readonly PluginDefinition[];
    }
    
    interface ServerProviderHandle {
      readonly provider: ProviderDescriptor;
      readonly services: DefinitionInstallationApi<ServiceDeclaration>;
      readonly plugins: DefinitionInstallationApi<PluginDefinition>;
      readonly startup: {
        readonly services: readonly InstallationResult[];
        readonly plugins: readonly InstallationResult[];
      };
      /** Dispose this adapter's owned registrations, not its embedding HTTP server. */
      dispose(): Promise<void>;
    }
    
    declare function installDevframeProvider(
      context: DevframeHubContext,
      composition: ServerComposition,
    ): Promise<ServerProviderHandle>;
    
    declare function installDevToolsProvider(
      context: KitNodeContext,
      composition: ServerComposition,
    ): Promise<ServerProviderHandle>;

    The two entry points reflect different real native contexts. Their admission, service/action definitions, installation handles and diagnostics are identical. They do not start a second RPC server, clone state authority or add a second provider identity around the same host. A shared internal installer may implement both. Installed portable service recipes use adapter-owned identities and cleanup rather than pretending upstream package-service cache entries have the SDK's exact-version ownership semantics.

    Startup preflights the complete ServerComposition before any of its setup. installDevframeProvider and installDevToolsProvider settle after the initial activation pass. startup.services and startup.plugins preserve the corresponding composition-list order and admitted/skipped outcomes. Individual setup failures remain observable through admitted child handles as required by the core. Waiting dependencies do not prevent the provider handle from being returned. A strict invalid startup batch rejects the adapter installation before its setup runs.

    Standalone composition sketch:

    let provider: ServerProviderHandle | undefined;
    const hub = initHub({
      base: '/__tools/',
      async configure(context) {
        provider = await installDevframeProvider(context, composition);
      },
    });
    await hub.ready;
    // The embedding application owns hub attachment and HTTP lifetime.
    // Before closing the hub, await provider.dispose() and handle failed cleanup.

    DevTools composition sketch:

    const integration = createPluginFromDevframe(packagedToolDefinition, {
      async setup(context) {
        provider = await installDevToolsProvider(context, composition);
      },
    });

    packagedToolDefinition is a normal native definition containing the tool's packaged client assets. The bridge's kit callback adds the portable provider. It must not install the same portable composition again from that definition's own setup. The Vite integration must retain provider and dispose it through an awaited host close/restart path. A callback without such an owner is not a complete integration.

    Preview attachment has a concrete tested composition in the preserved probe. configurePreviewServer mounts the live middleware before static assets and SPA fallback, attaches WebSocket upgrade handling to the actual HTTP server, and awaits hub readiness. Vite documents preview as a distinct hook with a PreviewServer. Vite plugin API.

    Native context and mode table

    Context/feature Standalone live Devframe Vite development Built-output live preview Static snapshot
    Actual Devframe/hub context Available when owned Available when integrated Available in the attached live backend No live provider
    Actual kit context Only if genuinely constructed by kit Available in DevTools host Conditional on supported kit integration, not assumed No live provider
    ViteDevServer Absent Actual server Absent Absent
    PreviewServer Absent Absent Actual server Absent
    Live actions and shared state Yes, subject to capabilities Yes, subject to capabilities Verified in standalone hub attachment No live mutation backend
    Source module graph and Vite HMR Absent unless integrated Actual Vite APIs Unavailable Unavailable
    Build-time HTML transform Outside standalone server Vite build pipeline when building Runs in the separate build process Already applied when built
    Request-time HTTP/HTML handling Only where adapter installs it Middleware stage supported Middleware stage supported Only what the static hosting platform provides
    Renderer/view updates Existing live view protocol Existing live view protocol plus renderer HMR Live view protocol; rebuilt renderer update governed by reload contract Snapshot only

    Capability advertisement must reflect implemented operations and eligible executions, not this table alone. A runtime HTTP rewrite is a different operation from transformIndexHtml in Vite's source/build pipeline. Injection before script execution cannot be promised by rewriting already-loaded DOM. Injection and transform contract owns exact stages, schemas, ordering and browser parity.

    Backend mode and asset mode are separate. In the real probe the live hub reports mode: 'dev' while Vite serves production-built assets. A build flag must not silently choose a static backend when the selected workflow is live preview.

    Lifecycle, routes and update handoffs

    Event Adapter responsibility Consumer/follow-on contract
    HTTP start Initialize the actual native context, preflight portable composition, expose live metadata only for that provider generation Discovery validates identity and authorized endpoint
    Connection metadata request Answer the live route before static __connection.json and SPA fallback; preserve mount base and actual transport URL Client connects to the advertised live backend
    Build starts Publish building status; continue serving the last complete generation Status UI observes current state, including when mounted late
    Build fails Retain published generation; publish failure with build identity Failure display does not depend on the failed tool contribution
    Build completes Publish only a complete generation; emit asset-generation change Reload contract chooses renderer/page reload and cached asset retention
    Backend code changes Preflight successor, quiesce calls and dispose owned activation Automatic whole-backend reset permission is the pending owner decision
    Connection lost Mark provider unavailable; reject pending calls with appropriate portable error Routing never redispatches; state contract decides restoration
    Adapter disposal Stop admitting new calls; cancel, await resources, remove owned registrations and attachment; preserve embedding server if not owned Incomplete cleanup blocks successor
    Preview process exits Stop live backend and HTTP, close watcher/status subscriptions; watcher process remains independently usable Combined command must propagate shutdown to its children

    Mount only under the configured namespace. Authentication/origin checks run before tool endpoints and protected transformations. Do not copy the probe's authentication-disabled loopback configuration into shipping examples as a default. Permissions and trust owns that policy. Ordinary application requests fall through unchanged unless a declared transform matches them.

    Use a stable owned middleware delegate per attachment rather than accumulating a Connect layer on every plugin replacement. Detach upgrade listeners explicitly. Hub close tears down observed transports; it is not a universal contribution disposer. Scoped-state changes, view disposal, service resources and custom native callbacks need their own handles. No deadline proves a running handler has stopped.

    Do not treat upstream's memoized service-ready barrier or first-package-wins cache as portable startup/dynamic equivalence. Adapter admission and setup sequencing must honor the core contract. Released service integration analysis.

    Direct evidence and limits

    The real production-built browser page invoked an action returning 7, observed state 0 → 7 → 11, rejected a deliberate handler error, and rejected an interrupted pending call with a connection error after hub close. Upgrade listeners changed 0 → 1 → 0. Disabling owned middleware delegation and closing the hub preserved built-page serving; closing PreviewServer stopped HTTP. The process exited and the temporary browser tab was closed. Report, results, cleanup.

    This proves the public same-server attachment, not Vite DevTools preview, HMR, authentication, arbitrary handler cancellation, renderer mounting or completed-output publication. The deliberately unresolved handler stopped affecting the client, but its resources were not universally disposed by hub close.

    Oxlint and the limited probe-source type check pass. Full declaration checking fails in upstream dependencies: six errors reproduce with imports only; four more scoped-state declaration errors appear with registry augmentation. Validation output. These are explicit adoption blockers for a fully strict example. They do not justify a blanket skipLibCheck policy or a false passing conformance claim.

    The preserved source is the exact executed experiment. Its lint evidence uses the recorded default Oxlint command. An additional broad pedantic audit reports two function-length warnings and one top-level-await preference; it is not represented as passing the eventual monorepo's strict lint policy. The probe's native registry augmentation demonstrates the released upstream API, not a change to the SDK's explicit-descriptor authoring decision.

    Required example and test inventory

    Every row applies to both server hosts where the feature is supported. Chromium and Firefox verify explicit unsupported outcomes for server-only APIs exposed through a common contract. Compile-only and mocked tests supplement real hosts.

    Public interface or hook Runnable example obligation Required assertions
    installDevframeProvider examples/devframe-host Startup/dynamic recipes, exact versions, waiting/partial status, native descriptors, no renderer dependency
    installDevToolsProvider and bridge setup examples/devtools-host Same plugin/action/UI; actual layered kit context; no duplicate portable installation; Vite lifecycle ownership
    ServerComposition and startup handles Both server examples Strict preflight atomicity, relaxed skip, each child observable, independent setup failure, dependency ordering
    Provider service/plugin installation APIs Both server examples Exact core matrix including dynamic install, retry, disable, replace and failed cleanup
    configureServer integration Development mode for both host examples Actual module graph, source HMR, restart, middleware/upgrade listener counts, pending calls
    configurePreviewServer integration Production-development mode for both host examples Actual built files, live metadata/actions/state, no fake dev-server context, supported kit differences
    build:watch, preview, dev:production Each relevant application package Scripts work independently and together; parallel first-start race; termination; no accidental self-selection
    Build status and generation handoff examples/watched-preview First success, failure retains complete output, late status subscriber, recovery, no partially mixed assets
    Native context descriptors examples/native-context Correct actual types; absent dev server in preview; remote exclusion; no native object serialization
    Action/state/view integration Shared contribution and renderer examples Wire validation, real action result/error, subscriptions, view updates, remount and reconnect
    Request-time transforms/injection Transform-only/page-only examples Documented request stage, ordering, cancellation, unsupported stages, target validation
    Adapter/provider disposal Both server examples Unsubscribe, detach, native owned cleanup, repeated dispose, leaked-resource check, unrelated server remains live
    Full process restart Development and production-development modes Permission policy, verified old process exit, interrupted calls not replayed, new provider generation, state restoration only as declared
    Snapshot output Static example Explicit static metadata, no false live actions/capabilities, no assumed preview lifecycle

    Decision frontier

    The owner has settled independent scripts, their combined pnpm command, same-process preview/backend ownership as clarified in the discussion, and last-successful-build retention with failure status. One question is pending: when backend code cannot unload safely, may development tooling automatically restart the complete backend, briefly disconnecting other contributions and clients, or must it await an explicit restart?

    The full DevTools preview public composition and watched-output publication checks are investigations, not questions for the owner. Source/release inspection has identified the supported kit/custom-host seam and the default host’s preview mismatch; actual full DevTools shell behavior remains a separate proof obligation. Their findings must be incorporated before this ticket's resolution. The follow-on Live preview and reload contract owns exact renderer/module/page update strategy and shutdown/reconnect sequencing; this ticket supplies lifecycle events and truthful native host bindings.

    The issue remains open until the adapter declaration inventory is complete, the owner decision is incorporated and the Definition of Done is checked against the evidence. Complete production implementation and real-host matrix execution remain later work.

    Versioned deliverable and remaining checks

    Download the adapter proposal and complete executed attachment probe. The archive is from local ticket commit c29df35 on dvcol/wayfinder/server-adapter, based on core commit 195e066. It includes the source, lockfile, actual browser/server results, shutdown checks and declaration-check failures. SHA-256: c16ccbdd1ecbda170bf2556069b64b59e6e18eac0f431630fafb3c317805241f. The branch remains local; this archive provides the reviewable files. Document-file links above point to that archive.

    The owner’s independent-script/regex requirement is accepted. The exact pnpm invocation remains under a finite concurrency probe: preliminary evidence on the pinned installation did not match the documentation, so the displayed launcher must not be counted as verified. The actual watched-build retention check is running independently of that launcher check. Its results will be added here; the earlier attachment test is not used as evidence for either guarantee.

    This is a review update, not a final resolution. The pending owner choice is whether development tooling may automatically restart the entire backend when safe plugin unloading is impossible. That restart can interrupt unrelated contributions and pending calls, so it cannot be inferred from per-plugin cleanup ownership.

  4. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Watched production workflow: direct evidence

    The requested independent scripts and regex-based concurrent launcher now have an executed feasibility fixture. Local server-ticket commit: a0495eb, following c29df35 and the settled core commit 195e066.

    Download the updated adapter proposal and both complete probes. SHA-256: 7273569bbdcbbfab5f076c4a411d3e9fb0a95e8ef177692f34b7f24c9d9587b6. The archive includes the canonical core documents, updated docs/planning/006-server-adapter.md, and source, pinned lockfiles, results and reproduction instructions under docs/probes/server-preview and docs/probes/watched-production. The branch remains local.

    Verified command

    {
      "scripts": {
        "build:watch": "node build-watch.ts",
        "preview": "node preview.ts",
        "dev:production": "pnpm --workspace-concurrency=2 run \"/^(build:watch|preview)$/\""
      }
    }

    This is the exact command executed by the final watcher/preview test. Both underlying scripts also run independently after fixture preparation. Their filenames here belong to the small probe; the eventual example packages will use their own script paths.

    This corrects the earlier illustrative --parallel command. Finite timestamp controls on the installed pnpm 12.5.1 showed that plain regex matching and --workspace-concurrency=2 overlapped, while adding --parallel serialized scripts within this package. The effective workspace-concurrency setting was undefined. launcher-evidence.json records every tested form and timestamp. The root cause of that flag interaction was not investigated further; the final command itself is verified. pnpm regex documentation.

    Actual build failures and recovery

    The controller edited real TypeScript/CSS sources watched by Vite 8.3.0. It produced an early syntax error, recovered, then triggered a real late plugin error in generateBundle, and recovered again. It did not simulate build events.

    Transition Serve Vite's working output directly Publish complete generations separately
    First successful build HTML/JS/CSS return 200 HTML/JS/CSS return 200
    Syntax failure Previous page remains available Exact previous HTML/JS/CSS remain available; status reports failed
    Recovery New page returns 200 New complete generation returns 200
    Late generateBundle failure Page returns 404 Exact previous HTML/JS/CSS remain available; status reports failed
    Second recovery New page returns 200 New complete generation returns 200
    Older generation asset URLs Not asserted Still return 200 with their original hashes

    The raw late-failure result matters: writing directly into the served directory does not meet the selected last-successful-build guarantee. Vite's output preparation can empty that directory before a later build stage fails. The published probe therefore builds into staging, copies completed output into an immutable generation directory, and advances the active generation only after the actual BUNDLE_END event. A temporary-file rename publishes the current generation/status in this local experiment. Relative asset URLs remain tied to their page's generation.

    This publication mechanism is adapter/build-tooling work around Vite's public hooks, not a transaction guaranteed by Vite itself. The report distinguishes Vite's behavior from the probe's added behavior. Pinned Vite artifact, build output options.

    Verification and limits

    result.json retains actual HTTP response bodies, asset SHA-256 hashes, build/status responses, watcher events and cleanup results. Parent review independently compared the successful and failed published snapshots; they match exactly. Both public close handles completed, their child processes were absent and both former HTTP endpoints refused connections.

    The watched-output probe passes TypeScript 7.0.2 strict checking with declaration checking enabled and the recorded default oxlint *.ts command. It uses Node 26.9.0, pnpm 12.5.1 and Vite 8.3.0. Its reproduction instructions require a fresh directory without previous .runs state. These scoped checks are distinct from the first live-attachment probe's documented upstream declaration errors and from the eventual monorepo's strict lint preset.

    The earlier probe separately proved built-page live actions/state and transport teardown. This second probe proves HTTP asset/status retention and the launcher. It does not combine backend generation replacement with the asset publisher, implement visible failure UI, or prove full HMR. Full DevTools shell behavior, arbitrary application paths, generation garbage collection, Windows/crash consistency, competing publishers, continuous concurrent requests, and backend/state restoration remain named implementation obligations.

    Remaining owner decision

    The independently runnable scripts, same-preview-process live backend and last-successful-build policy are accepted. The pending choice is:

    When backend code changes and safe plugin unloading is impossible, may development tooling automatically restart the entire backend, or must it await an explicit restart?

    The recommended automatic development restart briefly disconnects clients and interrupts unrelated contributions/pending calls. It still cannot replay actions or start a successor before the old execution has ended. This choice is pending in the live discussion, so the server contract remains open. The updated adapter proposal, lifecycle table, native-context differences and complete example/test obligations are in the attached archive.

  5. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Strict TypeScript 7 dependency proof

    Separate local commit 371fd61 records the investigation and exact reproducible artifacts. It is not pushed. Download the committed report, patches and fixture.

    Archive SHA-256: 438ea5f300922d860971fc764137a20b8ced7399e0a698fcac3db6f0665bda0e.

    The public Devframe 1.0.0 / hub 1.0.0 / DevTools kit 0.7.5 dependency graph can pass strict TypeScript 7.0.2 without skipLibCheck, ambient any, or casts replacing the native host types. The original six imports-only errors and ten augmented-registry errors reproduce. Additional fixtures identify the kit's missing whenexpr dependency and H3's exact-optional-property mismatch.

    The tested remedies are narrowly scoped:

    • A type-only common-types export in crossws 0.4.12, consumed by the Devframe and H3 declarations, avoids loading Bun/Cloudflare-only declarations for a Node adapter.
    • Devframe's scoped-state key constraint uses Extract<keyof ..., string>, preserving inferred values. Package extensions supply cac and whenexpr referenced by published declarations.
    • H3 2.0.1-rc.32 declarations support the ES2023 Error baseline and represent the four properties that its actual constructor creates with undefined values.

    All runtime JavaScript compared byte-for-byte unchanged: 86 Devframe files, 28 crossws files and 22 H3 files. No upstream checkout or implementation-workspace dependency was modified.

    Copy docs/probes/server-type-compatibility from the archive to a fresh directory outside the workspace, then run:

    pnpm install --frozen-lockfile --ignore-scripts --registry=https://registry.npmjs.org
    node check.mjs

    A second clean frozen-lock install passed five compiler configurations: the original baseline, the augmented preview source, real public kit/host types, strict exact-optional/indexed-access checks with scoped inference, and the same strict configuration with ESNext.Error. All retain skipLibCheck: false. The executable H3 constructor check also passed. The report and exact result files name the affected APIs, published artifacts and limitations.

    This resolves declaration feasibility only. The server adapter, actual DevTools UI, authentication, HMR, reconnect and real-host matrix remain incomplete. Repository pnpm patches would not automatically fix an external package consumer; distribution or verified upstream fixes remain an adoption requirement. No upstream PR was opened.

    The backend restart choice remains pending: whether tooling may restart the complete backend when safe unloading is impossible. This comment does not choose that policy or close issue 6.

  6. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Tested upstream option for independent server connections

    The released-client experiment exposed two cross-client effects: another baseURL can inherit cached A metadata, and a successful A authorization-code exchange replaces B's retained token. A recreated B connection then rejects authentication. Explicit initial descriptors alone do not solve the second problem.

    A separate ticket-6 prototype adds one opt-in option to a disposable copy of Devframe 1.0.0. This is proposed upstream API, not an SDK declaration or a released option:

    const client = await connectDevframe({
      connection: { connectionMeta, metaBaseUrl },
      authToken,
      isolateConnection: true,
      otpParam: false,
      simpleAuth: false,
      webmcp: false,
    });

    The option bypasses shared connection/token discovery and writes, and creates no shared authentication BroadcastChannel. Per-client authentication, complete RPC, shared state, services and close behavior stay on the existing upstream implementation. Omitting it or passing false preserves current behavior. The exact two-file JavaScript/declaration patch applies to pristine released client artifacts with zero fuzz; earlier TypeScript-only compatibility repairs are recorded separately.

    Actual comparison

    All three profiles used the same proposed package in real browser clients and two authenticated headless hubs on a Vite preview server. Each profile had its own process, port and storage. Browser observations and Node execution receipts were inspected directly.

    Profile Endpoint and credential behavior Recreated B Close A
    Default clients Reproduces cached A endpoint and A token broadcast into B Unauthorized, attempted mutation never reaches B handler Explicit B credential restoration works; B reaches 15
    Both clients isolated Distinct endpoints; B token stays unchanged after A OTP Authenticated; B receipt handler count 3 → 4 B remains connected and reaches 17
    Default A, isolated B B independently selects B and retains its own token despite A's broadcast Authenticated; B receipt handler count 3 → 4 B remains connected and reaches 17

    The isolated profiles include a bounded 250 ms unchanged-token observation followed by actual client recreation and a server receipt. That window alone is not an indefinite absence proof. Eight direct boundary tests separately cover cache reads/writes, explicit connection/metadata/base discovery, local token updates, default parity and channel creation/cleanup. Two negative type fixtures check the option's type. Strict TypeScript 7 with declaration checking, strict type-aware Oxlint and Oxfmt pass. All three browser runners exit 0 after awaiting hub/preview cleanup; all former endpoints refuse HTTP connections.

    Delivery and remaining obligations

    Separate local commit 44a7917 contains this proposal and evidence. Download the complete committed workspace through 44a7917. SHA-256: c55f859ae82df89338da6679078b08e41d656c2f3ee571c69acbb6b7d08f7902. Commits remain local and unpushed.

    The bundle contains the exact patch, baseline/patched hashes, preparation script, tests, browser fixture, per-profile results and exact executed source. Generated credentials, OTP codes, storage and dependency copies are excluded. Preparation reuses the frozen dependency fixture and changes neither upstream checkout nor the SDK dependency graph.

    This establishes bounded feasibility. It does not prove a genuine DevTools server/UI, extension transport, Firefox/current-stable matrix, separate provider origins/processes, revocation or process-restart recovery. The kit browser wrapper is exercised, not a KitNodeContext. Adoption requires an explicit public API/release strategy and appropriate upstream regression coverage; no upstream PR or publication was performed.

    The previously pending owner decision about automatic whole-backend restart remains unanswered. This prototype supplies connection evidence without choosing that policy or closing the server adapter contract.

  7. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Owner-confirmed host lifecycle boundary

    The owner agreed to the clarified Vite ownership model in the live review on 2026-09-23. Separate ticket commit 3c4addf records it in ARCHITECTURE.md, GLOSSARY.md and docs/planning/006-server-adapter.md.

    Ordinary development compilation, HMR, watching and server restarts belong to Vite and the existing Devframe/DevTools host integration. The portable adapter owns the contributions it installs and connects their disposal to that native lifecycle. It does not own an externally supplied HTTP server or hub. Core will not introduce a generic process supervisor or automatic whole-backend recovery controller.

    The earlier blanket automatic-restart question is withdrawn. Vite's in-process server restart and a process reset are different operations; neither a timer nor a server lifecycle event proves arbitrary contribution work stopped. Failed cleanup still blocks replacement under the accepted core contract. Any additional process-restart mechanism must follow a concrete host need and a separately scoped ownership policy.

    The independently runnable build watcher and preview scripts, combined pnpm regex launcher, and last-complete-build retention remain accepted. Bundled dev mode is an optional Vite development mode, not a substitute for production-built preview. Build publication does not restore backend state or replay interrupted actions.

    Implementation is continuing with thin installers over actual Devframe/hub and kit contexts, reusing the existing private lifecycle implementation and typed native context access. No new RPC/state engine or claimed full HMR is implied. Issue 6 stays open for the complete adapter inventory, integration contracts and real-host obligations; it is no longer blocked on the withdrawn restart question.

  8. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Native server adapter implemented; lifecycle wiring still open

    Ticket-6 commit caa9ac3 adds the private @devkit/server package and the strict dependency graph it needs. Both public entry points install the same portable definitions into genuine native contexts:

    const provider = await installDevframeProvider(hubContext, composition);
    // Or installDevToolsProvider(actualKitContext, composition).
    await provider.invoke(actionDescriptor, input);
    const resolution = await provider.resolve(capabilityDescriptor);
    await provider.dispose();

    Both advertise devserver / devkit.server; typed descriptors expose the actual Devframe, hub and optional kit objects. Each installation receives a fresh incarnation. A shared context-ownership guard covers pending setup and both installer entry points. The handle delegates startup, dynamic admission, replacement, calls and cleanup to the existing runtime. There is no second RPC/state engine or recovery supervisor.

    The 11 integration tests use real hub and kit contexts. They cover waiting dependencies, dynamic installation/replacement, strict and relaxed admission, custom kinds, setup diagnostics, idempotent disposal and cleanup failure. Failed cleanup retains ownership and blocks replacement. Native shared state remains mutable after disposal; unrelated commands still execute; an actual HTTP request proves the embedding server remains live. Parent verification independently repeated all 11 tests, strict TS7, type-aware Oxlint, Oxfmt and Vite/declaration builds.

    Correction to earlier dependency evidence: the first supposedly isolated frozen replay could resolve cac from an ancestor directory. A packageExtensions entry did not install Devframe's existing optional peer. The corrected fixture explicitly installs cac@7.0.0, checks every ancestor for node_modules, verifies actual package resolution stays inside the fixture and passes all five strict compiler configurations. Original snapshots remain intact. See docs/probes/server-dependency-isolation and docs/research/server-type-compatibility.md in the published source. Runtime JavaScript remains unchanged by the declaration patches. These private-workspace fixes do not establish standalone consumer distribution.

    Ticket-14 commit 0873f1d supplies maintained headless examples for both contexts using the existing contribution contracts. Each runs 3 → 7, service disable/enable and cleanup against native state through built package exports.

    Ticket-6 commit 459f8db preserves a Vite restart trace that establishes an additional integration constraint: replacement configureServer setup runs before old teardown. closeBundle is awaited but its failure is swallowed by environment shutdown; global closeServer failure rejects server.close(). Therefore an eager setup plus closeBundle disposal is insufficient to prove nonoverlapping backend replacement. The published source preserves the exact bounded trace; it is not a completed host integration.

    Remaining DoD includes native Vite lifecycle wiring, live remote action/state/view integration, full DevTools shell/preview, production build-status publication, authentication and the complete real-host API matrix. #6 stays open.

    Source is published on main, with the current checkpoint at 0fbaf3e. The history is linear and commits remain separated by ticket. Direct commit references replace source-archive delivery. Full repository CI passed builds, strict lint, type checks, formatting, packed-consumer checks and tests. The complete supported-host conformance matrix remains open.

  9. dvcolomban commented on Sep 23, 2026

    @dvcolomban
    CollaboratorAuthor

    Real Vite host integration follow-up

    82a1265, published on main for #14, adds maintained examples using the actual released Devframe and Vite DevTools plugins. Source and commands. The full repository CI gate passed at this exact commit.

    The earlier hook trace now has real-host evidence. A config factory creates fresh native plugin instances; native setup captures its genuine context, HTTP listening activates portable contributions, and Vite's application-level closeServer awaits their disposal. No process-recovery layer was introduced. listen() itself does not await asynchronous provider activation, so local callers await the example's readiness promise.

    Twelve passing integration tests cover both hosts: native HTTP metadata and shared actions/state, delayed cleanup across restart, stable ID/fresh incarnation and stale binding rejection, logged/observable cleanup failure on close, shutdown before listening, automatic restart after a real config-file write, and client-module invalidation preserving the backend. Strict TS7, Oxlint, Oxfmt, build and both runnable demo commands pass.

    This is example-local lifecycle wiring, not a newly settled public Vite adapter API. closeServer runs after native host teardown; contribution cleanup cannot assume an open native network connection. The tests establish successful restart ordering and failed close, not failed-restart candidate cleanup. Vite constructs the replacement native host before old cleanup, so failure-path disposal of that candidate remains a specific obligation. Native setup failure, changes during activation, middleware mode, preview, bundled dev and browser HMR also remain unproven. Portable remote transport/discovery/authentication and JSON/browser-host integration remain open. The full server adapter contract is not complete.

  10. 22 remaining items

  11. dvcolomban commented on Sep 27, 2026

    @dvcolomban
    CollaboratorAuthor

    Native catalog and shared-client delivery

    Implemented in 0c170ec. The owner selected native cancellation behavior: caller abort, client/connection disposal or native disconnect stops local waiting; already-dispatched backend work may finish. There is no automatic retry, replay or backend-cancellation protocol.

    The browser-safe @devkit/server/client entry borrows an existing DevframeRpcClient, including the compatible Vite DevTools client. Native APIs continue to own authentication, method authorization, transport, schemas, serialization and state. The adapter supplies the missing catalog projection and portable ProviderConnection.

    import { createClient } from '@devkit/client';
    import { createDevframeProviderConnection } from '@devkit/server/client';
    
    // rpc is the caller-owned native Devframe or DevTools client.
    const connection = await createDevframeProviderConnection({
      rpc,
      providerId: 'example.remote',
    });
    const client = createClient({ connections: [connection] });
    await client.actions.invoke({ action: increaseCounterAction, input: { amount: 1 } });
    
    client.dispose();     // Detach and stop local waits.
    connection.dispose(); // Remove adapter listeners; native RPC remains caller-owned.

    Ownership and synchronization

    • One native authorized query projects only contracts listed in server startup expose. An omitted exposure publishes nothing; an empty exposure publishes an empty catalog. Local/private services do not leak through it. Catalog visibility is controlled by its native method authorization; operation calls still pass their own native gate.
    • A payload-free native event invalidates the snapshot. Each read is authorized again. No client-writable state key, polling loop, separate codec or authentication service is introduced.
    • The native host/client retain a finite set of definitions. Adapter disposal removes subscriptions and current availability. No private unregister/Map mutation is used. Registration collisions and failed native registration observers reject clearly.
    • Responses are validated/frozen; an invalidation arriving during a query forces another read before publication. A connection pins one provider incarnation. A successor requires a new connection/attachment, never silent rebinding.
    • Static clients and caching of catalog/effect methods reject explicitly. Remote bindings expose portable context, not backend native handles.

    Validation

    48 server tests pass, including real authenticated WebSocket calls, deny behavior, capability/action routing, disable/enable, stale incarnations, cancellation, disposal, finite-registration reuse, cached/static rejection and metadata guards. The malformed/mismatched and held-response cases mock the actual native call boundary; ordinary delivery/cancellation runs through real sockets. Native browser-client tests supply scoped location in Node and restore it afterward.

    Strict TypeScript 7, type-aware Oxlint, Oxfmt and affected builds pass. The maintained examples pass against both native hosts; all 24 affected Vite-host tests pass. The browser example delivery separately proves manual increment/reload against both hosts, and its automated production-bundle check excludes Node/backend-runtime imports. Browser smoke evidence does not establish complete HMR, renderer or extension conformance.

    Full repository CI passed at dfef733: builds, types, strict lint, formatting, packed-consumer checks and tests.

    Remaining work and next decision

    This does not close the full server contract. Endpoint discovery, authoritative targets, renderer integration, extension actors and complete host conformance remain open. No new upstream patch or PR was introduced; existing PRs remain drafts and Vite remains unpatched.

    The target investigation finds that native RPC sessions authenticate callers, while in-page channel identity survives reload. Neither is a document-generation authority. Required-target exposure still rejects explicitly.

    The next owner question is how a selected document maps across realm fallback: A, let the host map the UI's selected document to the chosen provider's native reference before dispatch, rejecting missing/stale mappings; or B, require the caller to supply a fresh provider-specific target. A is recommended for the shared-UI requirement. Both retain adapter authorization, exact-document execution and no remapping after dispatch. No new mapping API is approved or implemented yet.

    Adapter API, catalog source investigation, coverage matrix.

  12. dvcolomban commented on Sep 27, 2026

    @dvcolomban
    CollaboratorAuthor

    Expanded the pending target-resolution review in de675e7. Read the concrete scenario, API sketches, ownership diagrams, failure cases and tradeoffs.

    The previous A/B summary was too restrictive: caller-side target acquisition can live in host code, so it does not require another human page selection. The actual implementation choices are:

    Choice Ownership and cost
    A1: shared-client resolver hook The router chooses a provider and invokes a host resolver; this expands generic selection typing, cancellation, binding and broadcast behavior.
    A2: host connection adapters, recommended The router remains unchanged; the selected host adapter resolves the opaque document selection for its fixed provider. One shared UI remains possible.
    B: explicit provider-specific calls Calling code acquires the provider target and invokes that pinned connection; a host facade can automate it but must preserve existing ownership checks.

    All proposed document integrations and resolver APIs are labeled unimplemented. Native required-target exposure still rejects. No choice has been accepted, and this commit changes no runtime API.

    The concrete prerequisite remains an actual page/document executor and a native association with the selected document. URL equality or RPC authentication cannot establish document identity. Missing/stale associations reject. Target-aware fallback after failed resolution is not implicitly approved; the current no-reroute rule remains. Entry checks alone cannot replace exact-document execution.

    The owner also requested this depth for every major decision. AGENTS.md now requires current behavior, concrete examples, option sketches/diagrams, failure cases, maintenance costs and an explicit recommendation before asking for a choice. Affected server/client strict lint and type checks, formatting and diff checks pass.

  13. dvcolomban commented on Sep 27, 2026

    @dvcolomban
    CollaboratorAuthor

    e525d1c adds the native integration proof for the owner's two-layer selection decision, following the core migration.

    The test and fixture open four authenticated Devframe connections between two clients and two backends. The client broadcasts to both devserver providers. Each implementation checks its schema-defined domain/resource input: one returns applied, the other not-applicable. Both outcomes are fulfilled and both providers remain available. Direct capability invocation enforces the same check. A second client reads their separate values and continues making calls after the first closes. Catalogs carry no universal target metadata.

    All 48 server tests pass. Both server examples, browser bundle checks, 24 Vite host tests and 5 contribution tests pass. Affected builds/types/strict lint/format and isolated packed consumers pass. Full repository CI passes on adc48d7, which also fixes two formatter-moved compile-only fixture comments.

    This proves command/results and explicit reads, not live state subscriptions or reconnect recovery. The server adapter retains native authentication, serialization, method ownership and local-wait cancellation; no upstream patch changed. Endpoint discovery, state/renderer integration and real WebExtension conformance remain open. Generic target mapping is no longer a blocker.

  14. self-assigned this
    on Oct 1, 2026
  15. dvcolomban commented on Oct 1, 2026

    @dvcolomban
    CollaboratorAuthor

    Live Vite browser integration, 2026-10-02

    Implementation: 5da838f.

    The maintained Vite page now renders the shared native JSON counter and dispatches through the existing portable client/provider connection. Both Devframe and DevTools compositions explicitly expose the counter action and capability. The examples reuse publishCounterView({ context, actionName }), which owns native view publication and its counter-state subscription. This is example composition, not a new portable view declaration or renderer API.

    Vite page -> native reference JSON renderer
              -> existing createActionCall binding
              -> portable client -> authenticated native RPC -> selected provider
    provider counter state -> native JSON view state -> both open pages
    

    The browser uses native authentication, connection metadata and shared state. Built assets contain no baked credential or backend selection tied to the build mode. The actual native metadata base selects the example host, and Vite's development HMR context distinguishes development from built preview. Closing a connection removes its renderer and disables controls; reconnect is an explicit document reload with native authentication. No retry, replay or recovery layer was added.

    The DevTools preview composition supplies its real preview origin through the public native host callback. Without it, the native authentication banner advertised the development port. The correction also applies to native origin-dependent URLs and does not replace authentication.

    Executed evidence

    • Both affected examples pass strict Oxlint, TypeScript, formatting and builds. The native JSON example's 6 tests and Vite host example's 24 tests pass.
    • Real Chromium 153.0.8010.12 passes both hosts in development and independently built preview, plus both hosts with actual production build watching. The four development/preview cases authenticate two pages, dispatch native JSON actions, read the portable capability, observe shared updates, unmount/remount, explicitly disconnect/reload and remove both renderers after backend closure. The two watched-preview cases serve two built generations to separate documents, preserve the existing document/assets, and keep one provider/state across both. The receipt records zero page errors.
    • Live in-app Chromium 154 confirmation passed Devframe development and DevTools built preview: native OTP-link authentication, rendered action from 3 to 4, capability read 4, renderer cleanup, and development remount. An actual source edit caused native Vite page reload; the same provider and counter survived. Both test launchers and temporary browser tabs were closed.
    • Maintained instructions and limits, browser receipt. CI runs the expanded browser command and retains its generated receipts/screenshots.

    Full-repository CI passed at 5da838f, including workspace checks, the expanded Vite browser command, Chromium and Firefox extension/debugger suites, concurrent development suites, and the API evidence gate.

    Still open

    This does not establish automatic production-page refresh, cross-backend state merging, automatic endpoint discovery, full Firefox Vite-page coverage, the DevTools shell's full UI, or portable view declaration/lifecycle. Native setup/activation failures and the remaining host/API conformance matrix still need evidence. Existing owner decisions remain pending; this checkpoint does not resolve the whole Server adapter contract.

  16. dvcolomban commented on Oct 1, 2026

    @dvcolomban
    CollaboratorAuthor

    Native publication failure rollback, 2026-10-02

    Separate test commit a4cb5b1 covers a real failure after provider installation and before example readiness. An independent plugin uses the public devtools.setup hook and native createJsonRenderView to own the same scope/ID before the counter example publishes its view.

    foreign plugin publishes native counter view
      -> example installs provider, service and action
      -> native publisher rejects duplicate scope/ID
      -> example rolls back its partial startup
      -> readiness rejects with the native duplicate-view diagnostic
    

    The two cases cover actual DevTools development and preview compositions, without mocks, private imports, production test seams or production changes:

    • Native command events prove the service was registered and then removed. The retained catalog returns unavailable; retained action and capability methods reject as unavailable. Native RPC definition lifetime is preserved.
    • Development keeps serving native HTTP metadata, and the foreign view remains present and editable after rollback. Explicit close surfaces the saved activation failure.
    • Preview rejects both startup and readiness and removes the native transport's upgrade listeners. It owns and closes that failed host.
    • Host-owned counter state is not required to disappear when the provider is disposed.

    The affected Vite package passes 26 tests, strict Oxlint, TypeScript, formatting and diff checks. Tests and scope notes are committed. The root README now describes delivered Vite browser/preview behavior and removes obsolete blanket claims about already implemented extension and renderer integrations.

    Full CI passed at a4cb5b1, including all workspace, Chromium/Firefox production, development and API-evidence checks. The implementation's full CI passed at 5da838f.

    Failures during native host construction, cancellation during activation and complete cross-host conformance remain open. This is one bounded setup-failure scenario, not completion of the entire failure matrix or a new architecture decision.

  17. dvcolomban commented on Oct 1, 2026

    @dvcolomban
    CollaboratorAuthor

    Commit a9a9149 adds a maintained native-session revocation check. It changes tests, example-fixture access to its own token, documentation and evidence links. No SDK/runtime API or authentication layer changes.

    The actual HTTP/WebSocket regression starts a portable action, then calls Devframe's public revokeActiveConnectionsForToken(context, token) while that backend action is held:

    native authenticated client -> portable action begins
    server revokes that active native session
      -> caller receives the exact native DevframeConnectionError, kind=auth
      -> adapter catalog disappears; pending local wait ends
      -> dispatched backend action can still finish once
    native explicit reauthentication with still-allowed credentials
      -> native client becomes trusted again
      -> old adapter remains disposed
    fresh adapter -> same provider/state, next action succeeds, no replay
    

    Seventeen exact assertions cover error identity/type, trust status, catalog invalidation, mutation/call counts, absence of fabricated backend cancellation and explicit connection recreation. This exercises the SDK boundary using real native auth and RPC. It does not revoke persisted credentials, design authentication UI, or promise DevTools/browser parity. The native server can also report its own rejected post-revocation state-update request as DF0036; the test does not suppress native diagnostics or claim an empty error log.

    The package documentation now explains the existing lifetime. The API inventory links both exposed connectionError paths to this exact executed case. It now links 320 of 769 paths to 179 distinct tests, retaining all other gaps and the unchanged browser scenario count.

    Validation: all 50 server-package tests passed, followed by the focused test after final fixture cleanup. TypeScript 7, strict type-aware Oxlint, formatting, unchanged-inventory classification and exact generated-result verification pass. Full CI on the subsequent reload-test correction is running and includes this server commit.

    The broader server adapter contract remains open; the pending portable-view declaration and other host/mode obligations are unchanged.

    CI reconciliation, 2026-10-02: Full CI passed at ce546ce68e7df120a1adec6141768a8ca44a24d0, including the combined changes, all production browser suites, concurrent development transitions and the executed API-evidence gate. The Firefox panel observation correction resolves the later actor-destruction failure; the earlier failed run remains historical evidence.

  18. dvcolomban commented on Oct 2, 2026

    @dvcolomban
    CollaboratorAuthor

    Resolved: native server adapter contract

    The accepted contract is implemented on main through 52bc770, and full CI passed. The owner confirmed native host ownership, compact provider composition, native authentication/serialization/cancellation, separate Vite development/preview lifetimes and the portable view setup recipe through the recorded review. This closes the contract decision. Full framework delivery remains tracked by the parent map and its implementation/coverage tickets.

    Accepted interface and ownership

    const provider = await createDevframeProvider({
      context,
      providerId: 'example.devserver',
      services: [counterService],
      plugins: [counterActionsPlugin, counterViewsPlugin],
      expose: { actions: [increaseCounterAction], capabilities: [counterCapability] },
    });
    // createDevToolsProvider accepts the same composition with its genuine kit context.
    await provider.dispose();

    The supplied native host owns HTTP, RPC, authentication and shared state. The adapter owns its portable contribution registrations, catalog exposure and cleanup. Disposal releases its additions while keeping an externally owned host alive. Raw native context descriptors expose genuine local hub/kit objects. Definitions are inert; initial installation settles after the activation pass, while admitted setup failures remain observable on their handles. Cleanup failure blocks replacement.

    Development delegates lifecycle and browser updates to Vite and the native host plugins. Built preview runs the live backend on the preview HTTP server; build:watch and preview can run independently, with dev:production starting both through the accepted pnpm regex. Static output alone has no live provider. Capability/resource applicability stays inside implementations. Native cancellation stops local waiting; already dispatched work may finish once, with no automatic replay.

    Evidence and complete handoff

    Area Maintained artifact and verification
    Public factories, local native access, host ownership, failure/cleanup Server API, real hub/kit tests in packages/server/tests, including owned disposal and actual native authentication revocation
    Remote catalogs and actions/capabilities Browser-safe native connection adapter, genuine HTTP/WebSocket tests, simultaneous server/extension examples; independent connections retain native auth
    Development and live preview Vite example: 28 tests, both hosts in development/preview and watched-production browser cases, publication rollback and retained-build behavior
    Native publication lifecycle View delivery: one shared defineView recipe in server/Vite/extension providers; native state remains host-owned

    Remaining work already has an owner: backend/renderer reload and failed-restart behavior belong to Live preview and reload contract; script/transform registration belongs to Injection and transform contract; privileged page authority belongs to Permissions and trust. Examples and API coverage contract retains the exact missing host/mode assertions, including native construction/activation cancellation, broader auth cases and Firefox Vite fixtures. Release and conformance contract retains packed consumer and full completion gates. The executable inventory continues to report 33 groups with gaps.

    These are implementation and validation obligations, not an unanswered server-adapter architecture choice. Historical checkpoints remain evidence for their recorded commits. Closing this decision does not claim those follow-ups complete.

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

Metadata

Metadata

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