Repository navigation
One module-alias owner: package.json electron dependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412
Description
Activity
- addedwayfinder:grillingWayfinder human decisionWayfinder human decisionelectron-compatElectron compatibility program areaElectron compatibility program area
on Oct 6, 2026 Generated by an AI agent (Claude Code, Fable 5.1) on behalf of @0monish, 2026-10-06, under the map's execution doctrine. Statements are labelled FACT / INFERENCE / UNKNOWN by their author; nothing here authorizes implementation.
Decision packet
Decision: Which single mechanism resolves 'electron' and 'electron/main', 'electron/renderer', 'electron/common', 'electron/utility' to @keld/electron in a migrated app's Bun main role (package.json dependency alias with package exports, a Bun preload plugin, or tsconfig paths), and what architecture 04 sections 2 and 3 say afterwards.
Classification:
decided· Milestone (YAGNI test against the first proof):first-proof· Reversible: Yes. It is one package.json line plus package exports; switching to a plugin later changes no wire format, permission or host contract. The arch 04 wording changes through a spec PR. · Owner: Architecture 04 (docs/architecture/04-electron-compat.md), whose spec owner is KEL-17 (Done, assignee GYLDLAB), and the packages/@keld/electron package from KEL-72 (Done, unassigned); Linear fetched 2026-10-06. Neither is open, so the live tracking surface is #412 under map #391. The reserved migrate verb points to KEL-17.Facts
- Linear (team KELD) was reachable read-only in this session on 2026-10-06; every call succeeded. KEL-17 'RFC: Electron compat layer and migration path' is Done (2026-07-10, assignee GYLDLAB). KEL-72 'compat: bootstrap @keld/electron - module alias + app lifecycle shim' is Done (2026-08-18, unassigned). KEL-19 is Done (GYLDLAB). No open Linear issue owns the alias. Source: Linear get_issue, fetched 2026-10-06.
- Electron itself uses one resolver for the five names: electronModuleNames is the set {electron, electron/main, electron/renderer, electron/common, electron/utility} and Module._resolveFilename returns 'electron' for all of them. Source: electron v44.4.5 lib/common/init.ts:109-122 (copy in the scratchpad refuter directory, read 2026-10-06).
- Re-run by me on Bun 1.4.2, 2026-10-06, scratchpad prototypes/x03-sem-alias. Arm N (npm-shaped electron in node_modules, no alias): every form returns npm's path string, and all four subpaths throw 'Cannot find module'.
- Same re-run, arm Pl (Bun preload plugin registered through bunfig.toml): all five specifiers resolve to the shim for ESM and CommonJS, in app code and in node_modules dependencies, when run from the directory holding bunfig.toml.
- Same re-run, arm Pl started from a different working directory: bare 'electron' silently returns npm's path string and the subpaths throw. The plugin was not loaded and there was no error. Under Node 26 the same arm also returns npm's string.
- Same re-run, arm T (tsconfig paths with 'electron' and 'electron/*'): all five resolve on Bun from any working directory; under Node 26 they return npm's string or throw.
- Reported by the X02 refuters, sources read but not re-executed by me (installing would write files): a dependency keyed 'electron' pointing at a shim with an exports map resolves app ESM imports, the 'electron/main' subpath and a CommonJS dependency's require on Bun 1.4.2; bun install honours the npm: alias form and both Bun 1.4.2 and Node 26 then resolve require('electron') from app code and from a dependency. Source: wayfinder notes/X02.md decision X02-A1 (One module-alias owner: package.json
electrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412) verdicts; probes/file-alias-probe sources. - Reported by the same refuters: bunfig.toml [alias] is still inert on Bun 1.4.2; and with no node_modules present Bun auto-installs the real electron package and returns its binary path with no error. Source: notes/X02.md extra findings.
- draw.io needs the alias on its boot path: its main is ESM ('type': 'module') and imports named members from 'electron' at src/main/electron.js:5; it imports electron-log, electron-updater, electron-store and electron-context-menu at :9, :17, :20, :22. None of its sources use a subpath specifier. Source: corpus/drawio-desktop at 2edf9fb, fixed-string grep 2026-10-06.
- Those dependencies import the bare name in both module systems: electron-store 11.0.2 and electron-context-menu 5.1.0 use 'import electron from "electron"' (ESM default import); electron-log 5.4.4 uses require('electron'). Source: package sources fetched by the X03 refuter, read 2026-10-06.
- @keld/electron is not consumable as a package today: its exports map has only '.' pointing at ./src/index.ts, it is ESM TypeScript, and src/app.ts:8 imports '../../api/src/app.ts' from outside the package. Arch 06 says 'no npm wrapper is currently shipped'. Source: packages/@keld/electron/package.json and src/app.ts at origin/main cb7d8e9; docs/architecture/06-runtime-and-tooling.md:420.
- Architecture 04 section 2 lists 'package.json (edited)' and 'bunfig.toml/bundler alias (edited)' as the migrate-edited files; section 3 says bunfig.toml 'is not the v0 Bun runtime resolver', that the runtime resolver is tsconfig paths, and that 'treating that file as the resolver is a defect'. Source: docs/architecture/04-electron-compat.md:40-41, 65-68, 108-115.
- The panel resolved that electron-updater is aliased to an adapter for the first proof, which is a second package-name alias of the same kind. Source: panel/synthesis.md:68.
- X02-T3 (task(migrate): hand-authored draw.io first-proof artefact — keld.config.ts, literal-only keld.permissions.jsonc and package-manifest edits under the X02-T1 contract #499) (task(migrate): hand-authored draw.io first-proof artefact — keld.config.ts, literal-only keld.permissions.jsonc and package-manifest edits under the X02-T1 contract #499) and X03-T1 (feat(runtime): @keld/electron as the single
electronmodule — self-contained require()-able entry, four subpath exports, one object for ESM and CJS from app code and node_modules #502) (feat(runtime): @keld/electron as the singleelectronmodule — self-contained require()-able entry, four subpath exports, one object for ESM and CJS from app code and node_modules #502) are both blocked by this decision; X03-T1 (feat(runtime): @keld/electron as the singleelectronmodule — self-contained require()-able entry, four subpath exports, one object for ESM and CJS from app code and node_modules #502) already says 'package exports for subpaths'. GitHub One module-alias owner: package.jsonelectrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412 is open with zero comments. Source: publish_plan.json; gh issue view, 2026-10-06.
Inferences
- All three mechanisms can resolve the five names on Bun 1.4.2, so the choice is decided by ownership and failure mode, not by capability.
- The plugin and tsconfig mechanisms leave the real electron package installed and fail silently when not in force (wrong working directory, Node-run script): the app receives a path string instead of the API. A dependency alias makes node_modules itself the truth, so every resolver agrees.
- Package exports can express Electron's contract: map all five specifiers to one file. Mapping import and require conditions to different files would create two module instances and split the app singleton, so one file is required.
- CommonJS require of an ESM entry works on Bun and Node 26 only without top-level await. That matches the already-resolved rule that boot-static values are synchronous at import.
- Under real Electron the builtin resolver wins before node_modules, so an Electron-arm fixture is unaffected by the alias. Not run.
- With types supplied by the aliased package, migrate has no reason to write tsconfig paths, and bunfig.toml loses its only stated purpose.
Unknowns
- Whether the real @keld/electron resolves through the alias from draw.io's actual dependency set. It cannot be tested until the package is self-contained.
- Whether Bun auto-install honours a package.json alias when node_modules is absent.
- Whether a transitive package that lists electron under dependencies would bring a nested real electron.
- tsc and webpack resolution through the alias. Not tested by anyone.
- Whether a workspace-style spec can alias the name 'electron' inside the Keld monorepo fixtures.
Alternatives
Option Cost New invariant created Existing invariant at risk A. package.json dependency keyed 'electron' pointing at @keld/electron (npm: once published; file: or link: before), with package exports mapping all five specifiers to one entry. @keld/electron must become an installable, self-contained package with one require()-able entry and four subpath exports. migrate must rewrite or remove 'electron .' and electron-builder scripts in the same edit. An installed-tree check is needed (exactly one electron, and it is the shim; Bun auto-install detected or disabled). node_modules/electron is @keld/electron; all five specifiers and both module systems resolve to one file; no runtime resolver hook exists. The 'five files, nothing else' promise if the script rewrite is not done in the same edit; correctness if a nested real electron goes undetected. B. Bun preload plugin for the five specifiers (the X03 proposal). A Keld-owned hook in every role. Observed today: loaded by working directory through bunfig.toml and silently absent otherwise; Bun-only, so types and Node-run scripts need a second mapping; the real electron package stays installed. Every role starts with the alias preload active, which the host would have to enforce on the role command line. One rule, one owner (plugin for runtime plus tsconfig for types); loud failure (it degrades to the wrong module silently); the host spawn path would carry a compat concern. C. tsconfig paths (today's KEL-72 v0 mechanism). No new code. Bun-only. A JavaScript app such as draw.io has no tsconfig, so migrate would edit a file outside arch 04 section 2's table. The X02 refuter reported one intermittent failure when a CommonJS dependency required the TypeScript ESM shim through it. tsconfig is a runtime input. The five-file contract; Node-run consumers silently get the real electron package. D. Ship A and B together. Two resolvers that can disagree. None. Root AGENTS rule that parallel copies and diverging fallback paths are defects. Recommendation
Choose A as the single resolver; no plugin and no bunfig alias. Record it in arch 04 section 2 (the package.json row carries the 'electron' dependency; the bunfig.toml alias row is removed) and section 3 item 1 with its v0 note, inside the X02-T1 (#497) spec PR. X03-T1 (#502) adds the four subpath exports to the one entry. The KEL-72 fixtures keep tsconfig paths only until @keld/electron is consumable as a package, then switch to the same dependency form. Evidence that determines it: Electron's own one-resolver contract, the working-directory and Node probes re-run today showing B and C fail silently, and arch 04 section 2 already admitting the package.json edit. Any further use of bunfig.toml (for example disabling auto-install) is a separate decision.
Falsifier: With draw.io's four packages at the corpus-pinned versions installed beside an 'electron' dependency alias pointing at an @keld/electron-shaped package (ESM, one entry, exports for five specifiers), any of the following on Bun 1.4.2: a specifier form (ESM default, ESM named, CommonJS require, any subpath) from app code or a dependency not resolving to the shim; require of the entry failing in any of 20 runs; or require('electron').app and (await import('electron')).app being different objects. Any of these means exports cannot express the contract, and the plugin (with a host-passed preload) is reopened.
Missing evidence: The positive dependency-alias arm executed against the real @keld/electron and draw.io's real dependencies (blocked until the package is self-contained); tsc and webpack resolution; Bun auto-install behaviour with the alias declared but node_modules absent. These are acceptance checks for X03-T1 (#502) and X02-T3 (#499), not blockers of the choice.
Next action: Orchestrator records the decision on #412, citing the working-directory probe, and the X02-T1 (#497) (#497) spec author carries the arch 04 sections 2 and 3 erratum in that spec PR for exact-content owner approval. First check: #412 reads resolved with the probe cited, and the spec PR's arch 04 section 2 table no longer names bunfig.toml as the alias file.
- addedmilestone:first-proofNeeded for the first migration proof (drawio-desktop on macOS, explicit legacy profile)Needed for the first migration proof (drawio-desktop on macOS, explicit legacy profile)
on Oct 6, 2026 Generated by an AI agent (Claude Code, Fable 5.1) on behalf of @0monish, 2026-10-06, under the map's execution doctrine. Statements are labelled FACT / INFERENCE / UNKNOWN by their author; nothing here authorizes implementation.
Resolution
Choose A as the single resolver; no plugin and no bunfig alias. Record it in arch 04 section 2 (the package.json row carries the 'electron' dependency; the bunfig.toml alias row is removed) and section 3 item 1 with its v0 note, inside the X02-T1 (#497) spec PR. X03-T1 (#502) adds the four subpath exports to the one entry. The KEL-72 fixtures keep tsconfig paths only until @keld/electron is consumable as a package, then switch to the same dependency form. Evidence that determines it: Electron's own one-resolver contract, the working-directory and Node probes re-run today showing B and C fail silently, and arch 04 section 2 already admitting the package.json edit. Any further use of bunfig.toml (for example disabling auto-install) is a separate decision.
Falsifier (reopen if observed): With draw.io's four packages at the corpus-pinned versions installed beside an 'electron' dependency alias pointing at an @keld/electron-shaped package (ESM, one entry, exports for five specifiers), any of the following on Bun 1.4.2: a specifier form (ESM default, ESM named, CommonJS require, any subpath) from app code or a dependency not resolving to the shim; require of the entry failing in any of 20 runs; or require('electron').app and (await import('electron')).app being different objects. Any of these means exports cannot express the contract, and the plugin (with a host-passed preload) is reopened.
Resolved under the user's delegation on the evidence in the decision packet above, after independent refutation of the underlying research. Reopen by comment with contrary primary evidence.
Parent map: #391 · Unit: X02 (migrate-tooling) · Wayfinder type:
grilling· Status: open (not resolvable from current evidence)Question
The refuter proved tsconfig paths does not reach a node_modules dependency's
require("electron"); a package.json dependency alias does on Bun 1.4.2. X03 proposes a Bun plugin to also coverelectron/main|renderer|common|utility. Recommendation: package.json alias as the single runtime resolver (bundler-neutral) with packageexportsfor the subpaths; a plugin only if exports cannot express them. Decide and fix the arch 04 §2 bunfig wording.What is known / why it is still open
No evidence-backed resolution yet; see the unit research note for the proposed answer and refuter verdicts.
Context
Epic #496 · research note
wayfinder/electron-compat/notes/X02.mdon the research branch.