Repository navigation
Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391
Description
Activity
- addedwayfinder:mapWayfinder mapWayfinder mapelectron-compatElectron compatibility program areaElectron compatibility program areaepicProgram epic that groups tracer-bullet ticketsProgram epic that groups tracer-bullet tickets
on Oct 6, 2026 - added sub-issues
on Oct 6, 2026 56 remaining items
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.
Independent refuter verdicts — unit X06
Each decision of this unit's research was attacked by fresh-context refuters whose default position was that the decision is wrong.
Lens: invariants
- X06-D1 → refuted — The predecessor skeleton survives (task-level artifacts not parent status per Narrow the product-spine bridge prerequisites to functional subsets #323; window registry as a Keld-native keld-core spec with wire-protocol + public-API gates; push slice on KEL-80; preload injection on the KEL-79 subset; KEL-144/141 gate the claim). Three load-bearing parts do not. (1) FACT: the blocked_by entry 'KEL-102/T3' is stale. T3 is PASSED/LANDED, so all four Linear blockers of KEL-140 are Done and KEL-140 is executable frontier, not a distant gate. X06 trusted an unchecked spec checkbox that is documented drift. (2) FACT: 'Start now (no predecessor)' is false for anything that lands in the repo. The Linear owner is itself a predecessor: root AGENTS.md requires spec + Linear, workflow.md step 1 starts from a Linear issue and a Linear claim, and the worktree tool rejects any non-KEL issue id. The only open compat-corpus owner, KEL-237, has non-goals forbidding compatibility-surface expansion; KEL-72 and KEL-74 are Done; the workspace is at its issue-creation cap. (3) FACT: the proposed KEL-127 reading ('satisfied when KEL-140 and KEL-143 pass') contradicts KEL-127's own text. KEL-127 lists KEL-140/141/142/143 as the spine before the KEL-144 clean-machine proof, and its dependency graph places 'wider compatibility' at G4, after G3. D1 drops KEL-141 and the G3->G4 edge without evidence, and also conflicts with published First proof: drawio-desktop on macOS under explicit legacy profile #432 ('compat lanes consume KEL-142 artifacts on disjoint crates'). Two sources disagree and D1 averages them. INFERENCE: the conclusion that KEL-97 is not a Tier-1 predecessor may still hold, but its cited evidence is misread (see extra findings).
- Correction: Rewrite the entry condition as: (a) remove KEL-102/T3 from blocked_by and record KEL-140 as unblocked-and-unclaimed with the landed T3 artifact (comment cde25f5e, 66ccbbc) as its consumed input; (b) split 'start now' into scratchpad/research-branch analysis (truly unblocked) and repo-landing work (blocked: missing Linear owner); (c) present the KEL-127 reading as a decision packet. Option A: facade implementation after G2 = KEL-140+141+142+143 task artifacts. Option B: after G3/KEL-144, per the graph's G4 placement. Option C: a first-proof-only bounded slice after KEL-140+KEL-143, recorded as a new invariant on KEL-127. Recommendation: C only if the owner records on KEL-127 that the draw.io first proof is not 'broad expansion'; otherwise A. The one remaining question for the owner: is KEL-141 inside G2 for this purpose. (d) Reconcile First proof: drawio-desktop on macOS under explicit legacy profile #432's wording with whichever option is chosen instead of leaving both published.
- Evidence: Linear, fetched 2026-10-06: KEL-102 comment cde25f5e (2026-10-05T13:16Z) 'KEL-102/T3 TERMINAL ARTIFACT — PASS / LANDED', PR feat(core): route guarded filesystem requests #357, landed main 66ccbbc; comment 264b4e6c 'KEL-140 dispatch update: exact T3 predecessor gate is satisfied'; comment fd9d0b91 lists the stale docs including kel102 line 685. Git: 66ccbbc is an ancestor of HEAD b4b907c; /crates/keld-core/src/app_session.rs:5585 routes (FrameKind::Call, FS_CHANNEL); /docs/specs/kel102-host-guard-enforcement.md:685 still reads '- [ ] KEL-102/T3'. Linear: KEL-140 Backlog, blockedBy KEL-142/130/139/133, all four Done; KEL-143 Backlog, blockedBy KEL-140 (Backlog) and KEL-118 (In Progress) plus Done items; KEL-141 Backlog, blockedBy KEL-103 (In Progress). KEL-127 description: 'retain ... KEL-139's exact minimal Mac product contract, then KEL-140/141/142/143 and KEL-144 clean-machine proof'; graph 'G2 Mac minimum product spine -> G3 clean-Mac no-Rust acceptance -> G4 distribution and wider compatibility'; non-goal 'No ... broad Electron API expansion ... before G2'. KEL-237 non-goals: 'No new Electron API implementation, no compatibility-surface expansion'. /tools/workspace.py:356 requires issue to match kel-[1-9][0-9]*. KEL-127 comment d833440d (2026-10-05) quotes Linear: 'You've exceeded the free issue limit for this workspace.'
- X06-D2 → refuted — FACT: the pull order contradicts the first-proof milestone (draw.io on macOS, First proof: drawio-desktop on macOS under explicit legacy profile #432) and Research bounded Electron migration candidates #313 (draw.io first, Zettlr second). D2 ranks Tier-1 mostly by Zettlr token-scan counts, which the briefing classifies as leads, not demand facts. It then puts every arch-04 Tier-2 family behind all Tier-1 brokers, including ones draw.io never calls. But draw.io's main file touches F03, F05 and F09 surfaces at boot and in its primary workflow, so under D2's order the first proof cannot complete until Zettlr-only brokers ship. D2 also places sendSync in the Tier-1 IPC epic although draw.io has zero sendSync, and the map already deferred it past draw.io (sendSync stays a blocking CALL per 02 §5; deferred past draw.io, gated before Zettlr #428). What survives: the tier assignments themselves match arch 04 §4, BrowserWindow before IPC, and utilityProcess not pulled forward (zero corpus demand; KEL-75/T5 owner). No performance claim decides anything here.
- Correction: Separate two axes. Tier label = the arch 04 §4 classification, changed only by a spec amendment. Pull order = milestone:first-proof -> milestone:next -> milestone:parked (labels already live), derived from draw.io resolved call sites on the install + activation + open/edit/save/close path. That order is: app lifecycle and boot facts; BrowserWindow core; ipcMain.on/send + contextBridge; the dialog/shell/Menu subset draw.io calls; the Tier-2-classified slices draw.io needs (webRequest recorded no-ops behind file:// containment + CSP, updater setFeedURL recorded no-op, did-finish-load/executeJavaScript/will-navigate). Park Zettlr-only work (invoke/handle volume, sendSync, protocol.handle, Notification, Tray) under milestone:next.
- Evidence: Corpus drawio-desktop@2edf9fb, src/main/electron.js (line-match counts, read 2026-10-06): session.defaultSession.webRequest listeners at lines 994 and 1010; autoUpdater.* 17, setFeedURL at 2078; did-finish-load 6; executeJavaScript 5; will-navigate 2; setWindowOpenHandler 1; printToPDF 2; ipcMain.on 27 and ipcMain.handle 0; sendSync 0; new Notification 0; new Tray 0; protocol.handle 0. /docs/architecture/04-electron-compat.md §4 lists 'session subset, protocol, webContents surface, ... autoUpdater→keld-update adapter' under Tier 2. GitHub First proof: drawio-desktop on macOS under explicit legacy profile #432 resolution: score only install + activation + 4-step primary workflow for draw.io; 'Zettlr waits'. GitHub Research bounded Electron migration candidates #313: draw.io strongest first candidate, Zettlr second. Not re-verified: the Zettlr counts D2 cites.
- X06-D3 → refuted — FACT: the ticket set is superseded. The map already carries 52 decision tickets and 14 epics; publishing G2/R2/P1/P2/P3 now would duplicate live owners (window registry F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449)/PANEL-D19 (Close-veto deadline expiry semantics (decided 2026-10-07) #439), sendSync sendSync stays a blocking CALL per 02 §5; deferred past draw.io, gated before Zettlr #428, bridge floor F04-T2 (feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465), preload world PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441)). The edge 'G1 -> {E1..E9}' targets nine epics that do not exist in that form. FACT: the claim that 'nothing is left to decide' is false, because D3 has no ticket for three open decisions found here: who the Linear owner is for repo-landing conformance work under the issue cap; which claim surface arbitrates (D3/T2 treats Linear as unavailable, yet comments post normally); and how a conformance entry for an unimplemented surface lands green. INFERENCE: 'Grilling (HITL)' and 'Prototype (HITL)' conflict with the delegation recorded on Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391 ('The user delegated every grilling/prototype question to the agent'). What survives and is still missing from the live map: G1 (the KEL-127 before-G2 / G4 reading; no published ticket addresses it), T4 (Prompt Tracker doc 06 refresh after the phase-gate artifact), and R1's fact that the lifecycle corpus is pinned to Electron 44.3.0 while the map oracle is v44.4.5.
- Correction: Publish only the residual, each mapped to a live issue where one exists: (1) the KEL-127 entry-reading decision packet from the D1 correction; (2) a Linear-owner decision packet — lift the cap, or free a slot by archiving, or the owner designates and re-scopes an existing open issue for compat conformance (KEL-237's non-goals currently exclude it), with consequences for each; (3) one sentence adopting workflow.md's Linear claim as the arbitrating record; (4) the conformance-first landing shape; (5) T4 as parked with its trigger. Map the remaining D3 items onto existing issue numbers instead of opening new tickets, and repoint R1 at KEL-237, which owns that fixture pin.
- Evidence: GitHub, read 2026-10-06: 15 issues carry 'epic' (Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391 plus 14 epics compat(app): Electron app lifecycle, single-instance, session facts and process shim over host-owned lifecycle #444-program(perf): attributed compat-overhead metric registry, the kipc channel-table slice, and bounded hot-path rules (no performance claim before measurement) #506); Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391 has 66 sub-issues; publish_plan.json holds 118 issues. A search of every published body for 'before G2' or 'G2' returned no match. /crates/keld-compat/fixtures/lifecycle-corpus/corpus.json: electron_version 44.3.0, commit 07e4607..., 3 cells. /docs/06-graph-engineering.md:301 'KEL-139–144 remain blocked G2/G3 work' and :318 'pre-authoring the whole roadmap would create stale theater' (clone at 44f8ad3, 2026-09-25). Linear: comment c11c3729 was posted on KEL-127 at 2026-10-06T16:54:21Z, a day after the cap error was recorded.
- X06-D4 → refuted — The constraints D4 names are real (CLAUDE.md capped at 64 bytes, unknown instruction files refused, no 'always' budget raise). The proposed shape is infeasible as written and creates a duplicate rule owner. (1) FACT: D4's open unknown is now measured. The router has 40 bytes of headroom under a hard-coded 4096-byte limit, and root AGENTS.md has 7 bytes under its cap. The checker treats every docs/agents/*.md as an instruction file and requires an exact link to each in the router table, so two new files need roughly 70+ bytes of links alone. (2) FACT: the setup skill also writes docs/agents/domain.md, which D4 gives no manifest row; it would be refused as an unknown instruction file. (3) FACT: clause (5) puts a claim rule ('Agent claim block is posted on the GitHub issue while Linear is at cap') into issue-tracker.md. workflow.md § Agent claim is the single owner and says ownership is declared in Linear; the premise is also wrong because the cap blocks issue creation, not comments. (4) FACT: budget and instruction changes need named Linear scope, which D4 does not name. (5) INFERENCE (YAGNI, doctrine rule 8): the map and 118 issues were published and operate without this config, so the first proof does not need it, and it is not a real blocker of D5/D6.
- Correction: Park the ticket (label milestone:parked, wayfinder:task) with this shape for when it is pulled: scope it under an existing open Linear owner (KEL-124 is the candidate; confirm its scope first); include a byte-neutral router edit that trims at least as many bytes as the new row adds, with before/after bytes in the change record; give every file the skill writes, including domain.md, a routed manifest row or suppress the file; have issue-tracker.md link workflow.md § Agent claim rather than restate or vary the claim rule; keep CLAUDE.md untouched; run just agent-context and just atomic-protocol on the final diff.
- Evidence: wc -c on 2026-10-06: /AGENTS.md 13305 (cap 13312), /.agents/index.md 4056 (cap 4096), CLAUDE.md 10 (cap 64). /tools/agent_context.rs:26 'const ROUTER_MAX: usize = 4 * 1024'; :161-167 is_instruction_path includes paths starting 'docs/agents/' ending '.md'; :408-417 route_visible requires the exact '(../docs/agents/)' link in the '## Task routing' table. /.agents/instructions.md: 'Budget changes require named Linear scope, measured semantic benefit, before/after eval and independent instruction review'; 'One normative owner; consumers link owner + section and add only path operations'. /docs/agents/workflow.md § Agent claim: 'Ownership is therefore declared in Linear before work starts'. Linear: KEL-124 ('role/goal agent operating contract — L0/L1/L2 routing and one-rule-one-owner across agent docs') is In Progress and unassigned.
- X06-D5 → refuted — FACT: live GitHub contradicts the proposed structure on every structural point, and D5's cited facts ('gh issue list --label electron-compat/epic -> empty', 'nine issues') are stale. The epics are sub-issues of the map (D5: 'Epics: NOT sub-issues of the map'). There are 14, not nine. They carry electron-compat + epic + compat:tier-N, without the crate:* and needs-spec labels D5 prescribes. Milestone intent is carried by labels keyed to the first proof rather than by GitHub milestones. D5's two milestones mirror the arch 04 §4 tier exits; that anchors the public surface to Zettlr-era tier exits and an '≥80% median call-site coverage' target while no committed product denominator exists, instead of to the first-proof milestone the doctrine names. 'One issue per never-list surface, closed with reason' would add about a dozen issues for rows the published plan handles as scoreboard rows inside task tickets. The stated blocker (X06-D4) is falsified by the structure having shipped without it. What survives: native sub-issue and blocked-by links, wayfinder: on decision tickets, conformance tickets as ready-for-agent, undated planning, and gate identification on needs-spec tickets (currently in ticket bodies).
- Correction: Record the live structure as the decision: map -> 14 epics and 52 decision tickets as sub-issues; tracer tickets under epics; tier labels per arch 04 §4; milestone:first-proof/next/parked labels for pull order; no GitHub milestones until a committed denominator exists. From D5 keep only the cheap additive part: put gate:wire-protocol, gate:permission-model and gate:public-api labels on needs-spec tickets whose bodies already name those gates. Never-list surfaces stay as rows in the existing task tickets.
- Evidence: GitHub, read 2026-10-06: gh api repos/Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391/sub_issues returns 66 items, 14 of them labelled epic (compat(app): Electron app lifecycle, single-instance, session facts and process shim over host-owned lifecycle #444, compat(window): BrowserWindow over a host window registry — host-minted identity, cancelable close, constructor triage (macOS first proof) #447, compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457, compat(ipc): ipcMain/ipcRenderer/contextBridge over host-routed el:<channel> frames, exact-literal per-window guard grants and a lifted renderer floor (draw.io send/on path first) #463, compat(session): webRequest recorded no-ops behind macOS file:// containment + CSP (first proof); custom schemes, Session = KEL-135 profile and net.online next; permission facade parked #469, compat(native): first-proof dialog, application menu and display/theme facts for draw.io on macOS (legacy profile); shell, clipboard/nativeImage, Tray and the remaining native modules as tracked next/parked slices #476, compat(renderer): app preload in a separate content world, sandboxed-preload require map, renderer process object, zero-<webview> contract (first proof); Zettlr preload extras next; <webview> mapping and browser-quirk ledger parked #483, compat(diagnostics): engine process-gone and hang events, F08 scoreboard rows, parked crashReporter / process-stats / getAppMetrics facades (contentTracing never) #487, compat(update): inert electron-updater adapter for the draw.io proof first; Electron-core autoUpdater, host update channel, keld build translation and bridge recipe parked #490, program(conformance): evidence rules and differential oracle harness — one Electron pin per corpus, shared corpus-manifest owner, red-until-implemented cells, pinned Electron recorder, Keld replayer, comparator, lanes #493, program(migrate): read-only analyzer, one package-manifest alias, a hand-authored draw.io first-proof artefact, a report without percentages, and the electron-apps-v0 product corpus #496, program(runtime): Node/Bun runtime layer for migrated mains — one
electronmodule, main-role process facts before entry, explicit legacy profile key; native addons and child_process parked #501, program(security): Electron security surfaces mapped onto their existing Keld owners (keld-guard, KEL-142 bridge, principalized roles, host-owned signed feed): one row, one owner, one negative test per row #504, program(perf): attributed compat-overhead metric registry, the kipc channel-table slice, and bounded hot-path rules (no performance claim before measurement) #506); gh issue list --label epic shows labels [electron-compat, epic, compat:tier-N] on each; gh label list includes milestone:first-proof, milestone:next, milestone:parked; gh api milestones?state=all returns 0. /docs/engineering/compat-scoreboard.md: 'no committed product denominator ... no compatibility percentage may be published — including 0% or 100%'.
- X06-D6 → refuted — Most of the loop is sound and matches its owners (one read-only L0; one agent/issue/worktree; needs-spec stops at missing-approval; conformance entry first with doc anchor, expected_verdict and negative control in the existing cell shape; prompts stay in Prompt Tracker with no pre-authored compat nodes; L2 leaves read-only). Three parts are contradicted. (1) FACT: the claim mechanism — GitHub self-assign plus an Agent claim comment on the GitHub issue with earliest GitHub createdAt winning 'because Linear is at cap' — creates a second claim arbiter. workflow.md owns claims and arbitrates by Linear's createdAt, with a fallback only 'if Linear is unavailable'. Linear is available: every read succeeded today and a comment was posted on KEL-127 today; the cap affects issue creation only. Two arbiters allow two agents to each win on a different surface for the same paths. (2) FACT: D6's open unknown is resolved against it. The worktree tool rejects any issue id that is not a KEL number, and the claim template hard-codes kel- worktree and branch names, so a GitHub-only ticket cannot start a managed worktree. (3) FACT: 'check the exact task checkbox/SHA' is an unreliable frontier oracle. KEL-102/T3's checkbox is unchecked on main while the task is landed, and that is exactly how X06 mis-stated the frontier.
- Correction: L1 claim: post the workflow.md '## Agent claim' block on the existing KEL issue that owns the surface, with Linear createdAt arbitrating. The GitHub assignee and a link comment are a mirror only. A ticket with no existing open KEL owner is not startable; route it to the Linear-owner decision packet (D3 correction item 2) rather than inventing a gh- convention, which would be a reviewed change to workflow.md and tools/workspace.py needing its own Linear scope. L0 frontier oracle: a predecessor counts as landed only when its terminal artifact comment on the Linear issue names a landed SHA that is an ancestor of origin/main. A spec checkbox is a lead; a checkbox/code mismatch is reported as drift on the owning issue.
- Evidence: /docs/agents/workflow.md: 'The earliest claim by Linear's own createdAt wins'; 'record the ownership conflict on its own Linear issue (or the handoff if Linear is unavailable)'; § Agent claim template 'Worktree: .keld-work/worktrees/kel--', 'Branch: agent/kel--'. /tools/workspace.py:356 'Invalid issue. Use kel-.' and :69 task-name pattern kel-[1-9][0-9]*-. Linear, fetched 2026-10-06: comment c11c3729 on KEL-127 created 2026-10-06T16:54:21Z; cap error text quoted in comment d833440d (2026-10-05); KEL-102 comment cde25f5e is the T3 terminal artifact while kel102-host-guard-enforcement.md:685 is still unchecked.
Extra findings:
- [info] Linear availability for the swarm (the user's request): Linear team KELD is live and readable in this session. Reads work; issue creation is capped; comments on existing issues work. Creation was not retested here (read-only rule), so the cap is the last recorded state from 2026-10-05, not a fresh observation. — FACT (Linear, fetched 2026-10-06): 17 get_issue/list_issues/list_comments calls succeeded with zero failures, covering KEL-127, 140, 141, 143, 144, 237, 80, 97, 79, 124, 72, 74, 103, 118 and KEL-102 comments. Cap: KEL-127 comment d833440d quotes 'You've exceeded the free issue limit for this workspace.' Comments: bridge comment c11c3729 on KEL-127 created 2026-10-06T16:54:21Z. Separately, the mempalace MCP server failed to connect in this session (ENOENT: mempalace-mcp not on PATH); nothing in this unit depended on it.
- [high] The X06 keld_state snapshot is stale on the frontier. KEL-102/T3 is landed, which makes KEL-140 unblocked in Linear terms (all four blockedBy issues Done) and unclaimed. Any swarm text saying 'KEL-102/T3 unchecked' or 'fs broker not reachable from the shipping host' inherits the error. The spec checkbox and several architecture/onboarding sentences are known drift with a docs-only reconciliation PR already decided on KEL-102. — FACT: Linear KEL-102 comments cde25f5e, 264b4e6c and fd9d0b91; git: 66ccbbc 'feat(core): route guarded filesystem requests (feat(core): route guarded filesystem requests #357)' is an ancestor of HEAD b4b907c; /docs/specs/kel102-host-guard-enforcement.md:685 is still '- [ ]'. Live statuses that match X06: KEL-139 Done (2026-09-29), KEL-142 Done (2026-10-01), KEL-140/141/143/144 Backlog, KEL-75/102/103/118/237/53 In Progress, KEL-79/80/97 Backlog, KEL-127 Todo, KEL-72/74/215/15/19 Done.
- [high] No open Linear owner exists for the conformance work the live map marks ready-for-agent. Published conformance tickets name 'Linear owner consumed: KEL-237 / KEL-72', but KEL-237's non-goals exclude compatibility-surface expansion and KEL-72 and KEL-74 are Done. With the cap, the worktree tool and workflow step 1, those 18 ready-for-agent tickets cannot be started in the repo without an owner decision. This is a missing-approval blocker for the owner. Scratchpad and research-branch analysis can continue meanwhile. — FACT: KEL-237 description, Non-goals: 'No new Electron API implementation, no compatibility-surface expansion' (Linear, fetched 2026-10-06); publish_plan.json F01-T1 (conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445) body 'Linear owner consumed: KEL-237 / KEL-72'; /tools/workspace.py:356; root AGENTS.md 'Features require an approved docs/agents/spec-template.md spec plus Linear (KELD)'. First action for the owner: choose between lifting the cap, archiving to free a slot, or re-scoping one existing open issue, and record the choice on KEL-127.
- [medium] KEL-127 places 'wider compatibility' at G4 (after G3, clean-Mac acceptance) and forbids 'broad Electron API expansion' before G2, yet no published map ticket reconciles the program with that text. First proof: drawio-desktop on macOS under explicit legacy profile #432 only says the spine is not reordered and compat lanes consume KEL-142 artifacts. KEL-127 also states compatibility expansion is not a prerequisite for the spine and warns against ticket-wide blocking edges for optional future slices. — FACT: KEL-127 description (Linear, fetched 2026-10-06), dependency graph and Non-goals; a search of all 118 published bodies for 'before G2' or 'G2' found nothing; GitHub First proof: drawio-desktop on macOS under explicit legacy profile #432 resolution text.
- [medium] Default-deny lens: X06's security_mapping classifies ipcMain/ipcRenderer/webContents.send as 'app-internal channels; no manifest grant'. That contradicts the resolved map decision recorded in the briefing (renderer->main boundary = enumerated per-window el: grant, never el:*). The same table marks nativeTheme reads as 'ungated' and app.getPath as 'no capability' without a guard-owner decision. If X06's table is rendered into notes it should defer to the X04 mapping (program(security): Electron security surfaces mapped onto their existing Keld owners (keld-guard, KEL-142 bridge, principalized roles, host-owned signed feed): one row, one owner, one negative test per row #504) rather than stand as a second policy table. — FACT: X06 research.security_mapping rows in swarm.json; live epic compat(ipc): ipcMain/ipcRenderer/contextBridge over host-routed el:<channel> frames, exact-literal per-window guard grants and a lifted renderer floor (draw.io send/on path first) #463 title 'compat(ipc): ipcMain/ipcRenderer/contextBridge over host-routed el: fra...'. The el: grant decision is taken from the briefing's resolved list; it was not re-derived from a Keld spec in this pass.
- [medium] Spec/plan mismatch on tiers in the live map: epic compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457 (webContents) is labelled compat:tier-1 and ticket F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473) (session file:// containment + CSP) is tier-1, while arch 04 §4 lists 'webContents surface' and 'session subset' under Tier 2. Root AGENTS.md treats spec mismatch as a bug in one of them. Either relabel and express urgency with milestone:first-proof, or amend arch 04 §4 through a spec PR. — FACT: /docs/architecture/04-electron-compat.md §4 Tier 2 line; gh issue list --label epic (2026-10-06) shows compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457 with compat:tier-1; publish_plan.json F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473) labels.
- [medium] Conformance-first has no defined green-CI landing shape for unimplemented surfaces. Published F01-T1 (conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445) says 'Entries may fail (red) until the implementing tickets land', but a red test cannot merge under 'CI required' and AGENTS.md forbids stubs and weakened tests. The existing precedent is a cell with expected_verdict 'fail' mapped to a passing test that asserts the divergence or absence, with a negative control. X06-D1 and D6 inherit this gap. — FACT: /crates/keld-compat/fixtures/lifecycle-corpus/corpus.json cell app.quit.return-contract (expected_verdict 'fail', intentional_divergence, mapped passing test); publish_plan.json F01-T1 (conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445) body; root AGENTS.md Working invariants.
- [low] X06-D1 misreads kel97_predecessor_task_id=none. The KEL-102 decision says KEL-97 has no KEL-102 task predecessor (KEL-102/T5 consumes KEL-97, never the reverse). It does not say facades need no KEL-97. The supportable evidence for single-primary Tier-1 facades is KEL-102's identity decision plus KEL-142 being Done; KEL-97 (Backlog, blockedBy KEL-75 In Progress) still gates role-bound identity and utilityProcess. — FACT: /docs/specs/kel102-host-guard-enforcement.md:89 (KEL-102-D6) and :79 ('identity':'approved:accepted-v0-app-link-to-AppProcess'); Linear KEL-97 relations fetched 2026-10-06.
- [low] Instruction-budget headroom is nearly exhausted, which affects any swarm proposal that adds agent-facing docs: root AGENTS.md has 7 bytes left and the router 40 bytes, and every docs/agents/*.md file is treated as an instruction file by the checker. — FACT: wc -c on 2026-10-06 (AGENTS.md 13305 of 13312; .agents/index.md 4056 of 4096); /tools/agent_context.rs:26 and :161-167.
Lens: semantics
- X06-D1 → refuted — Two atoms of the predecessor set fail and one is undetermined. (1) KEL-143 as a hard predecessor of BrowserWindow core has no Electron basis and contradicts the map's resolved first-proof decision. The pinned docs define
closed/destroy/isDestroyed only against window lifetime; nothing in app.md or browser-window.md defines semantics across a main-process replacement. The first proof scores install + activation + open/edit/save/close-with-unsaved-prompt, with no crash recovery. PANEL-D12 (First proof: drawio-desktop on macOS under explicit legacy profile #432) (resolved) says compat lanes consume KEL-142 artifacts on disjoint crates and the spine is not reordered. D1 would put BrowserWindow behind a three-deep serial chain: KEL-102/T3 -> KEL-140 -> KEL-143. (2) Owner error: KEL-79 does not own preload injection. (3) The KEL-127 reading ('KEL-144 is consumed by the claim, not the code') is not determined by the text: the non-goal says 'before G2' while the dependency graph places 'wider compatibility' at G4 after G3. That stays an open user-owned reading, not a fact. Surviving atoms: the start-now set as scratchpad/spec work; KEL-97 is not a Tier-1 predecessor; KEL-102/T3 is still unchecked; the Linear states D1 cites match a fresh fetch.- Correction: Entry condition, restated per slice: (a) KEL-142 (Done) is the only spine artifact every compat lane consumes. (b) Facades that dispatch a guarded broker (dialog-minted fs, shell) additionally consume the landed KEL-102/T3 -> KEL-140 route; this is an inference, to be confirmed by the draw.io boot trace PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420. (c) BrowserWindow core needs the approved window-registry spec, not KEL-143. Replace the KEL-143 hard edge with one decision ticket, 'compat main-role loss policy', defaulting to Electron-faithful behaviour (role loss ends the app session under the legacy profile; the recovery cell is scored unknown until KEL-143 lands). (d) Move preload-injection ownership from KEL-79 to the isolated-world bridge owner (the KEL-142 successor slice), pending PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441). Keep KEL-79 for the renderer origin contract that draw.io's 20
validateSender(e.senderFrame)sites depend on (frame.url must start with a file:// codeUrl). (e) Present the G2/G3/G4 reading as a decision packet quoting both KEL-127 sentences. Cheapest discriminator for (c): run PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420 and list which of the four workflow cells touch a generation-loss path; expected none. - Evidence: FACT (Linear, fetched 2026-10-06): KEL-143 Backlog, blockedBy KEL-140 (Backlog), KEL-118 (In Progress), KEL-142/134/133/139 (Done). KEL-140 Backlog, unassigned; all four blockedBy (KEL-142, 130, 139, 133) are Done, so its remaining gate is KEL-102/T3, which is only relatedTo. KEL-141 Backlog blockedBy KEL-103 (In Progress). KEL-144 Backlog. KEL-102 In Progress. KEL-79/80/97 Backlog. FACT (Keld b4b907c): docs/specs/kel102-host-guard-enforcement.md:685
- [ ] KEL-102/T3; :79kel97_predecessor_task_id:none. FACT (KEL-79 description, Linear): scope is loopback listener, secure origin, Service Worker, CSP, Range/206, per-extension origin isolation; no preload, user-script or content-world text. FACT (KEL-127 description, Linear): graph 'G2 Mac minimum product spine -> G3 clean-Mac no-Rust acceptance -> G4 distribution and wider compatibility'; non-goal 'broad Electron API expansion ... before G2'; delegated direction 'Consume passed task-level artifacts, not whole parent issue completion' and 'Do not add ticket-wide blocking edges for optional future slices'. FACT (publish_plan PANEL-D12 (First proof: drawio-desktop on macOS under explicit legacy profile #432)): 'compat lanes consume KEL-142 artifacts on disjoint crates'. FACT (context-bridge.md v44.4.5:57): world 999 is Electron's contextIsolation world. PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441) leaves preload world placement contested.
- Correction: Entry condition, restated per slice: (a) KEL-142 (Done) is the only spine artifact every compat lane consumes. (b) Facades that dispatch a guarded broker (dialog-minted fs, shell) additionally consume the landed KEL-102/T3 -> KEL-140 route; this is an inference, to be confirmed by the draw.io boot trace PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420. (c) BrowserWindow core needs the approved window-registry spec, not KEL-143. Replace the KEL-143 hard edge with one decision ticket, 'compat main-role loss policy', defaulting to Electron-faithful behaviour (role loss ends the app session under the legacy profile; the recovery cell is scored unknown until KEL-143 lands). (d) Move preload-injection ownership from KEL-79 to the isolated-world bridge owner (the KEL-142 successor slice), pending PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441). Keep KEL-79 for the renderer origin contract that draw.io's 20
- X06-D2 → refuted — Tier labels match arch 04 section 4, but the pull order is wrong for the current milestone and several demand numbers are not resolved call sites. (1) Sequencing: D2 pulls every F06 broker, including Zettlr-only Tray and Notification, before F03/F05/F09. draw.io's activation path needs members D2 puts in Tier 2: session.defaultSession.webRequest is called twice inside whenReady before any window exists, webContents 'did-finish-load' is registered on the first window, and electron-updater properties are set at module import. (2) 'E1 needs only lifecycle-channel extensions except before-quit cancelability' is false: requestSingleInstanceLock returns a boolean synchronously and app.getPath is called synchronously during import, so both need boot-static or synchronous answers while the Bun kipc client cannot block. (3) Cancelable before-quit has zero draw.io demand; its veto is the window
closepreventDefault plus showMessageBoxSync. Cancelable before-quit/will-quit is Zettlr-only. (4) The E3 demand emphasis (invoke 187, handle 25) is Zettlr's; draw.io has zero invoke and zero handle and uses send/on/once/reply. (5) F09 demand is misattributed: every draw.io autoUpdater token is the electron-updater npm package; resolved imports of Electron's own autoUpdater are zero in all three apps. (6) Count errors, one from the members_top source that D2's own caveat disclaims. Surviving atoms: F02 before F04; utilityProcess/MessageChannelMain zero demand; the webview tag has zero demand; BrowserView is deprecated in favour of WebContentsView.- Correction: Keep compat:tier-N labels as the arch 04 scoreboard taxonomy, but order pulls by the first-proof vertical slice taken from the draw.io boot trace (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420), not by family. S0: boot-static facts so the import survives (app.getPath/getVersion/getLocale, electron-store, electron-updater alias per PANEL-D14 (Updater handling for the draw.io proof #434), electron-log). S1: whenReady, single-instance boolean, window registry and BrowserWindow (loadURL file://, close veto, destroy/isDestroyed), with nativeTheme.shouldUseDarkColors and screen getters as synchronous mirrors. S2: session.webRequest recorded no-ops after host containment (PANEL-D17 (session.webRequest listeners: recorded no-ops only after host containment with a negative control #437)). S3: ipcMain.on/once, event.reply, webContents.send, senderFrame.url, contextBridge with callback proxying. S4: dialog open/save/messageBox including the Sync form, Menu, shell.openExternal, webContents did-finish-load/executeJavaScript. Park until the Zettlr proof: invoke/handle, sendSync, protocol.handle, cancelable before-quit/will-quit, Tray, Notification, clipboard beyond draw.io's 3 sites. Replace the demand numbers with the resolved counts above and state F09 demand as 'electron-updater package alias; Electron autoUpdater API 0 resolved sites'.
- Evidence: FACT (drawio-desktop@2edf9fb src/main/electron.js): :17-18
import elecUpPkg from 'electron-updater'; const {autoUpdater} = elecUpPkg; :30new Store()and :58app.getPath('userData')at import; :81-86 autoUpdater.logger/autoDownload/autoInstallOnAppQuit at import; :717nativeTheme.shouldUseDarkColorsand :740-741screen.getAllDisplays()/getPrimaryDisplay()in window construction; :782webContents.on('did-finish-load'); :876dialog.showMessageBoxSync; :947-962mainWindow.on('close', (event) => {... event.preventDefault(); :994webRequest.onHeadersReceived, :1010webRequest.onBeforeRequest; :1718const gotTheLock = app.requestSingleInstanceLock(); :2106app.on('before-quit', function() { cmdQPressed = true })with no event argument. Fixed-string counts, draw.io src + preload:app.exit(3 (:1081, :1324, :1699; the other two exit tokens are process.exit), not 7;ipcMain.on(15;ipcMain.handle(0;ipcRenderer.invoke0;showMessageBox(6 + Sync 1;autoUpdater19;new Tray0;new Notification0. Zettlr@e6c7fd8 source/:ipcRenderer.invoke186 (not 187);showMessageBox(22 (not 24);shell.openPath17 (not 16);new Tray(1 (tray/index.ts:158);new Notification(1 (show-notification.ts:43); before-quit preventDefault at documents/index.ts:382-384; will-quit preventDefault at main.ts:201-204. FACT (v44.4.5 app.md:1077) requestSingleInstanceLock 'Returnsboolean'; (:67-69) before-quit preventDefault cancels termination; (browser-view.md:11-13) 'TheBrowserViewclass is deprecated, and replaced by the newWebContentsViewclass'. FACT (arch 04 section 4) tier lists as D2 quotes them. FACT (Linear): KEL-72 Done 2026-08-18, so 'extend KEL-72' names a closed owner.
- X06-D3 → refuted — The ticket set does not meet its own bar ('nothing left to decide before implementation epics open') and three tickets target the wrong app or platform for the current milestone. Missing decisions that draw.io's resolved call sites force: synchronous main-process APIs; window close veto (D3's G2 names only two-phase Quit for before-quit, which draw.io never cancels); the renderer-origin coupling behind senderFrame.url; session.webRequest handling; third-party package handling for electron-updater and electron-store. Mis-targeting: P1 replays Zettlr invoke payloads, but the first proof's save and open steps ride draw.io's
rendererReqsaveFile/readFile messages andmainRespreplies. P3's parity list (sync return, Error custom-property loss, Function prototype drop) omits what draw.io actually uses: page-world functions passed as arguments and invoked later, repeatedly, from the preload. R2's WKWebView/WebView2/WebKitGTK matrix and P2's sendSync prototype are not needed by a macOS draw.io proof with zero sendSync. Surviving atoms: R1 (single oracle pin and canonical manifest bytes), T4 (do not pre-author tracker prompts), and the 4096-byte inline bound as a real constraint.- Correction: Treat D3 as superseded by the published decision set and fix the three prototypes it contributes. P1: replay draw.io saveFile/readFile and mainResp payloads captured from an instrumented Electron 44.4.5 run, and measure the size distribution before choosing chunking or a larger bound; Zettlr invoke replay follows later. P3: add rows for a page-world callback passed as an argument, called N times from the isolated world, and a function nested in an object argument; run on WKWebView only. R2 and P2: park behind the draw.io proof with an explicit re-entry condition (Zettlr or Windows work starting). Add or link decisions for synchronous main-process APIs (showMessageBoxSync, requestSingleInstanceLock, screen/nativeTheme getters), window close veto, and the file:// origin contract for senderFrame.url. Narrow G2 to window registry plus close veto; move cancelable before-quit to the Zettlr tranche.
- Evidence: FACT (draw.io electron-preload.js:87-123):
exposeInMainWorld('electron', { request: (msg, callback, error) => ..., registerMsgListener(action, callback), sendMessage, listenOnce(action, callback) })withfileChangedListeners[msg.path] = msg.listener; all four return undefined. :125-129 exposesprocess.typeandprocess.versions. FACT (electron.js:4431-4532): oneipcMain.on("rendererReq")switch carries saveFile, writeFile, readFile, showOpenDialog, showSaveDialog. FACT: 20validateSender(e.senderFrame)sites; :208 codeUrl isurl.pathToFileURL(codeDir).href. FACT (context-bridge.md v44.4.5:128) 'Function values that you bind through the contextBridge are proxied through Electron'; (:144) Error custom properties 'will be lost'; (:146) Function 'Prototype modifications are dropped'. FACT (Keld b4b907c): macos_bridge.rs:71 'payload exceeds the 4096-byte renderer bound'; virtual_port.rs:15 MAX_PORT_MESSAGE_LEN 4096; renderer_bridge.rs:100 negative control at 4097. FACT: draw.iosendSync0 sites. FACT (live GitHub Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391): 66 sub-issues, 52 of them decision tickets, against D3's 12. INFERENCE, not measured: draw.io diagram payloads on save/open exceed 4096 bytes.
- X06-D4 → refuted — The upstream facts and label facts hold, but the proposed placement cannot fit and one clause creates a second owner for claim policy. D4 left the byte sizes as an unknown; measured, the router has 40 bytes of headroom under a hard 4 KiB cap, so the proposed pointer row in .agents/index.md cannot be added without removing text. Clause (5) writes a claim-surface rule ('claim block on the GitHub issue while Linear is at cap') into issue-tracker.md, but workflow.md owns claims and says ownership is declared in Linear with Linear's createdAt deciding; workflow.md has 31 bytes of headroom. Sizing: the map was published as Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391-spec(ipc): minimum slice of the architecture 02 §4 channel table — one keld-ipc-owned table of kipc channel ids, its entry fields, consumers and live/destination split (no per-family ranges) #508 with the existing labels and no tracker-config adoption, so this task blocks nothing in the current milestone and the D5/D6 blocked-by edges on it are falsified by live state.
- Correction: Keep the task but park it outside the first-proof path and reshape it. Register docs/agents/issue-tracker.md and triage-labels.md as routed rows with a
skill:<name>trigger, the existing pattern in the budget file, and add no index.md row; if a router row is wanted, the same PR must trim at least (row bytes minus 40) from index.md. Remove the claim-surface sentence from issue-tracker.md: link workflow.md section Agent claim instead, and if the claim surface must change, change it in workflow.md through its own reviewed PR with a matching trim. Name the Linear issue that scopes the instruction change before the PR; creation is capped, so it must be an existing open issue chosen by the owner. Remove the blocked-by edges from D5 and D6. - Evidence: FACT (Keld b4b907c, wc -c): AGENTS.md 13305 of 13312; .agents/index.md 4056 of 4096; docs/agents/workflow.md 16353 of 16384; CLAUDE.md 10 of 64. FACT (.agents/instructions.md): 'router <=4 KiB'; 'Budget changes require named Linear scope, measured semantic benefit, before/after eval and independent instruction review'; 'One normative owner'. FACT (.agents/instruction-budget.tsv): routed files can carry a
skill:<name>trigger (the autofix, code-review and instruction-review rows). FACT (workflow.md section Agent claim): 'Ownership is therefore declared in Linear before work starts'; 'The earliest claim by Linear's owncreatedAtwins'. FACT (mattpocock/skills setup SKILL.md, gh api 2026-10-06): :76 'IfCLAUDE.mdexists, edit it'; :57 the five default labels; :68 the three docs/agents files. FACT (gh label list): triage, needs-info, ready-for-agent, ready-for-human, wontfix, needs-spec exist. FACT (KEL-127, Linear): 'Public normative wording/config/agent instructions need their own synchronized reviewed change'.
- Correction: Keep the task but park it outside the first-proof path and reshape it. Register docs/agents/issue-tracker.md and triage-labels.md as routed rows with a
- X06-D5 → refuted — The label inventory is accurate, but the structure D5 prescribes is not what exists, and the milestone proposal fails the current-milestone and committed-denominator rules. Live GitHub has the epics as sub-issues of the map and there are 14 of them, not nine standalone issues. The blocked-by edge on X06-D4 is falsified: the map and all 118 issues exist while no issue-tracker.md exists. The two proposed milestones skip the only current milestone (the draw.io first proof) and put uncommitted denominators in their titles: '3 corpus apps' when only two non-quick-start apps are pinned, and '>=80% ... 20-app corpus' when that corpus is undeclared. One issue per never-list surface, opened only to be closed, duplicates the single resolved never-list ticket.
- Correction: Record the live structure as the decision: map Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391 with 14 epics and 52 decision tickets as native sub-issues, tracer-bullet tickets under epics, native blocked-by edges. Milestones: at most one now, 'First proof: drawio-desktop on macOS, legacy profile: install + activation + 4-step workflow', matching PANEL-D12 (First proof: drawio-desktop on macOS under explicit legacy profile #432); create tier-exit milestones only after their corpus ids are committed, and keep percentages out of titles until then. Never-list: keep the single resolved ticket and use the compat:never label on matrix rows; open no per-surface issues. Drop the X06-D4 blocked-by edge.
- Evidence: FACT (gh api repos/Wayfinder map: KELD Electron Compatibility Program (Electron 44.x baseline) #391, 2026-10-06): labels wayfinder:map, electron-compat, epic; sub_issues_summary total 66, completed 18; 14 sub-issues carry
epic. FACT (publish_plan.json): 14 Feature issues with parent MAP; 52 Task decisions with parent MAP; 51 tickets under epics. FACT (gh api milestones?state=all): []. FACT (gh label list): wayfinder:map/research/grilling/prototype/task, compat:tier-1/2/3, compat:never, epic, electron-compat, gate:*, type:test, type:feat, ready-for-agent, ready-for-human, needs-spec, triage all exist. FACT (arch 04 section 4): 'Exit criterion: electron-quick-start and 3 corpus apps run unmodified'; 'Public percentages require a committed denominator'. FACT (corpus/): three clones in total. FACT (publish_plan PANEL-D10 (Never-list (unanimous) #430)): 'Never-list (unanimous)' is one ticket.
- X06-D6 → refuted — The loop's L0/L2 rules, conformance-entry-first rule and the no-pre-authored-prompts rule hold. The L1 claim and isolation steps cannot run as written. (1) D6's own unknown resolves against it: the worktree tool accepts only a
kel-<n>issue, so a GitHub-only ticket cannot get a sanctioned worktree or branch. (2) The premise 'Linear at cap, so claim on the GitHub issue' conflates the issue-creation cap with unavailability. Linear reads work and comment writes worked today; workflow.md's only fallback is 'the handoff if Linear is unavailable', not a GitHub comment. (3) There are now three different claim rules (workflow.md; D6's GitHub comment plus self-assign; the published map's 'claim by assigning yourself'), which breaks one-rule-one-owner. (4) No open Linear issue currently owns new-surface conformance entries, so the tickets D1 and D5 call 'startable now' are startable only as scratchpad or research-branch work.- Correction: Split the loop by ticket kind. Decision tickets (research, grilling, prototype; scratchpad or research branch only) claim by GitHub self-assign, as the map says. Any ticket that writes to the Keld repo, conformance entries included, needs a KEL owner id first: the claim is the workflow.md
## Agent claimcomment on that Linear issue (comments are not blocked by the cap) and GitHub self-assign is only a mirror. A repo-writing ticket with no KEL owner is notready-for-agent; it stops at 'missing owner' with the unblock stated: the owner lifts the cap or bridges the epic, or designates an existing open KEL issue. Do not add agh-<n>slug or a GitHub claim surface without a reviewed change to workflow.md and tools/workspace.py. L0 must gate on task checkboxes or SHAs, not Linear relations: KEL-140 shows every blockedBy Done while KEL-102/T3 is unchecked. For the pin: the three existing lifecycle cells can be re-pinned to v44.4.5 mechanically, since their oracle text is unchanged; R1 still has to choose one pin before new cells land. - Evidence: FACT (Keld b4b907c tools/workspace.py:69-70) 'Invalid task. Use kel--.'; (:356)
re.fullmatch(r"kel-[1-9][0-9]*", issue). FACT (workflow.md section Agent claim): template Worktree.keld-work/worktrees/kel-<n>-<slug>, Branchagent/kel-<n>-<slug>; 'The earliest claim by Linear's owncreatedAtwins'. FACT (Linear, fetched 2026-10-06): connector comment on KEL-127 created 16:54:21Z; KEL-72 Done; KEL-74 Done; KEL-237 In Progress with non-goal 'No new Electron API implementation, no compatibility-surface expansion'. FACT (publish_plan MAP body): 'Claim by assigning yourself before any work.' FACT (Prompt Tracker docs/06:318): 'Later distribution/compat prompts are generated only when the phase-gate artifact proves their prerequisites'. FACT (crates/keld-compat/fixtures/lifecycle-corpus/corpus.json:7-8): electron_version 44.3.0, commit 07e4607. FACT (diff of app.md at 07e4607 against v44.4.5): 9 hunks, the first at line 636; the window-all-closed, before-quit, will-quit, quit, app.quit and app.exit sections are byte-identical.
- Correction: Split the loop by ticket kind. Decision tickets (research, grilling, prototype; scratchpad or research branch only) claim by GitHub self-assign, as the map says. Any ticket that writes to the Keld repo, conformance entries included, needs a KEL owner id first: the claim is the workflow.md
Extra findings:
- [info] Linear availability for the swarm: reads are up, comment writes worked today, issue creation is capped as of yesterday and was not re-tested. Agents should read live owner state instead of using the briefing snapshot, and should retry once on a 502. — FACT (Linear, fetched 2026-10-06): get_issue succeeded for KEL-127, 139, 140, 141, 142, 143, 144, 102, 80, 79, 97, 237, 72, 75, 53, 74; list_issues and list_comments succeeded. One failure: KEL-79 returned {"error":"upstream_unavailable","status":502,"requestId":"a4663d9afc81c502"} and succeeded on immediate retry. Comment c11c3729 on KEL-127 was created 2026-10-06T16:54:21Z by the connector account (Amisha Ramani). A KEL-127 comment dated 2026-10-05T20:09Z records the creation refusal 'You've exceeded the free issue limit for this workspace'. UNKNOWN: cap status today (no write attempted). Separately, the mempalace MCP server failed to connect this session (ENOENT: mempalace-mcp not on PATH).
- [medium] Live spine state differs from what a relation-only frontier would show: KEL-140 has no open blockedBy edge in Linear, yet its real gate (KEL-102/T3) is unchecked and is only a relatedTo link. A frontier compiled from Linear relations would list KEL-140 as unblocked. — FACT (Linear, fetched 2026-10-06): KEL-140 Backlog, unassigned, blockedBy KEL-142 (Done), KEL-130 (Done), KEL-139 (Done), KEL-133 (Done); KEL-102 appears under relatedTo. FACT (Keld b4b907c): docs/specs/kel102-host-guard-enforcement.md:685
- [ ] KEL-102/T3; kel139 spec T2 entry: 'exact KEL-142 + KEL-102/T3 + KEL-130/T1 artifacts'. - [high] No open Linear issue owns new-surface conformance entries, and the worktree tool requires a KEL id. The 18 published
ready-for-agenttickets that write to the Keld repo therefore cannot start through the sanctioned workflow until an owner is designated or the cap is lifted. — FACT: tools/workspace.py:69-70 and :356 accept onlykel-<n>. FACT (Linear, fetched 2026-10-06): KEL-72 Done, KEL-74 Done, KEL-237 In Progress with non-goal 'no compatibility-surface expansion'. FACT (KEL-127 connector comment): '18 ready-for-agent, 33 needs-spec'. FACT (AGENTS.md): 'Features require an approved spec plus Linear (KELD)'. INFERENCE: all 18 write to the repo; I did not open each ticket. - [high] draw.io's IPC shape for the first proof is one-way send/on/once/reply with callback-proxying contextBridge functions, not invoke/handle. Lane sizing that leads with invoke/handle parity serves Zettlr, not the current milestone. Every draw.io handler also drops messages silently unless senderFrame.url starts with a file:// URL. — FACT (drawio-desktop@2edf9fb):
ipcMain.on(15,ipcMain.handle(0,ipcRenderer.invoke0,ipcRenderer.send(2,ipcRenderer.on(3,ipcRenderer.once(1; electron-preload.js:87-123 exposes functions that take page-world callbacks; electron.js:694-700 validateSender returns false unlessframe.urlstarts with codeUrl (:208, a file:// href), used at 20 sites. FACT (ipc-main-event.md v44.4.5): senderFrame is 'WebFrameMain | null'. The published plan already mentions validateSender and registerMsgListener, so this is a sizing note for X06, not a new gap in the map. - [medium] Same-window recovery (KEL-143) has no Electron counterpart, and an unmodified Electron main that re-runs after a generation swap would call its createWindow again while the host keeps the old window. X06 treats KEL-143 as defining
closed/isDestroyed under recovery but names no decision for this re-entry case. — FACT (kel139 spec, Recovery): 'The host-owned window/document remains while Bun rotates.' FACT (electron-quick-start main.js, draw.io electron.js:987): the window is created from the whenReady callback on every main start. INFERENCE: duplicate-window or orphan-window behaviour follows unless a policy is chosen; no pinned Electron doc covers it. Cheapest discriminator: extend the existing window-lifecycle logic prototype with one generation-loss edge and record the transcript. - [medium] Claim policy now exists in three inconsistent forms: Linear comment with createdAt ordering, X06-D6's GitHub comment plus self-assign, and the published map's self-assign only. — FACT: docs/agents/workflow.md section Agent claim; X06-D6 proposed_answer; publish_plan.json MAP body 'Claim by assigning yourself before any work.'
- [low] X06 research is pinned to d150a14; origin/main is now b4b907c. The facts I rechecked are unchanged at the new head. — FACT (git rev-parse): HEAD and origin/main are b4b907c. Rechecked there: KEL-102/T3 unchecked; lifecycle.rs:37
windows: u32; arch 05 section 2 'Destination; not implemented in the live hello backends'; @keld/electron index.ts exportsapponly; the 4096-byte bound constants. Not rechecked: MAX_FRAME_LEN 16 MiB, FsBroker constants, research note 214 tables.
- X06-D1 → refuted — The predecessor skeleton survives (task-level artifacts not parent status per Narrow the product-spine bridge prerequisites to functional subsets #323; window registry as a Keld-native keld-core spec with wire-protocol + public-API gates; push slice on KEL-80; preload injection on the KEL-79 subset; KEL-144/141 gate the claim). Three load-bearing parts do not. (1) FACT: the blocked_by entry 'KEL-102/T3' is stale. T3 is PASSED/LANDED, so all four Linear blockers of KEL-140 are Done and KEL-140 is executable frontier, not a distant gate. X06 trusted an unchecked spec checkbox that is documented drift. (2) FACT: 'Start now (no predecessor)' is false for anything that lands in the repo. The Linear owner is itself a predecessor: root AGENTS.md requires spec + Linear, workflow.md step 1 starts from a Linear issue and a Linear claim, and the worktree tool rejects any non-KEL issue id. The only open compat-corpus owner, KEL-237, has non-goals forbidding compatibility-surface expansion; KEL-72 and KEL-74 are Done; the workspace is at its issue-creation cap. (3) FACT: the proposed KEL-127 reading ('satisfied when KEL-140 and KEL-143 pass') contradicts KEL-127's own text. KEL-127 lists KEL-140/141/142/143 as the spine before the KEL-144 clean-machine proof, and its dependency graph places 'wider compatibility' at G4, after G3. D1 drops KEL-141 and the G3->G4 edge without evidence, and also conflicts with published First proof: drawio-desktop on macOS under explicit legacy profile #432 ('compat lanes consume KEL-142 artifacts on disjoint crates'). Two sources disagree and D1 averages them. INFERENCE: the conclusion that KEL-97 is not a Tier-1 predecessor may still hold, but its cited evidence is misread (see extra findings).
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.
Doctrine audit findings for this issue
- Invariant: 'Features need an approved spec + Linear owner': no ticket has a Linear issue; the MAP records 'Linear is at its free issue cap' as a standing condition without a blocker class, an owner or a resolution path (root AGENTS requires an immediate resolution path for a blocker). Whether the cap still holds is an ASSUMPTION — not checked in this audit. → Fix: Record it as a classified blocker (missing approval/capacity) with options: free capacity by archiving, bridge each first-proof ticket onto an existing live owner issue (KEL-127/KEL-237), or an explicit owner ruling that GitHub issues satisfy the gate for this program.
- Duplicate / one-owner (with F04-A1 (Who owns the
windows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398), X04-T1 (spec(security): Electron security-surface → single Keld owner mapping table with a per-engine permission-hook table and one negative-test id per row (no new schema) #505)): Three units each claim the arch 03 §3el:*example fix 'in the same PR' (F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398) question text, X04-T1 (spec(security): Electron security-surface → single Keld owner mapping table with a per-engine permission-hook table and one negative-test id per row (no new schema) #505) 'Revise the el:* example', MAP kill-condition fallback). FACT: docs/architecture/03-security.md:97 still shows "el:*" at b4b907c. → Fix: F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398)'s resolution PR owns the spec amendment and the example fix; delete the claim from X04-T1 (spec(security): Electron security-surface → single Keld owner mapping table with a per-engine permission-hook table and one negative-test id per row (no new schema) #505).
Disposition: each finding stays open on this issue until its fix is applied to the body or refuted with evidence.
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.
Doctrine audit of the published plan
LINEAR AVAILABILITY (the relayed user request): Linear IS reachable in this session — FACT, fetched 2026-10-06 via the claude.ai Linear connector: list_teams returned KELD + GYLDLAB; list_issues(team KELD, 250 rows) and get_issue (KEL-15/79/80/89/140/143/237 with relations) all succeeded. Read-only use only; I wrote nothing. The mempalace MCP server failed to connect (ENOENT mempalace-mcp) and was not needed. Swarms should treat Linear as a live primary source and stop citing 'last recorded state'.
LIVE OWNER STATE of the tickets' "External predecessors" (all FACT, Linear, fetched 2026-10-06): Done = KEL-15, 17, 19, 72, 74, 98, 130, 136, 139, 142, 168, 208, 215. In Progress = KEL-53, 75, 77, 78, 89, 90, 96, 102, 129, 132, 135, 137, 237, 103. Backlog (unassigned) = KEL-76, 79, 80, 97, 140, 141, 143, 144. Todo = KEL-127. Duplicate = KEL-209. Consequences: (a) KEL-79 and KEL-80 — named as owner/predecessor by 11 tickets — are unstarted Backlog issues with no blockers, no assignee and no task-level artifact; (b) KEL-143 is Backlog, blocked by KEL-140 (Backlog) and KEL-118 (In Progress), yet F01-T2 (#446)/F02-T2 (#449)/F02-T3 (#450)/F08-T1 (#488) consume a 'KEL-143 task-level artifact'; (c) KEL-208 is Done and KEL-209 is a Duplicate, so 'needs the KEL-208 owner ruling' (X04-D4 (#416), F06-D4 (#405), F06-T3 (#479)) names no live owner; (d) KEL-89 is the keld-auth OS-broker authentication spec, not a secrets owner (F06-T6 (#482) mis-attributes); (e) KEL-142 is Done, so 'KEL-142 spec revision (third world/relay)' (F07-T1 (#484)) is an artifact nobody owns; (f) KEL-15 is Done but its body is only the RFC brief (Goal/Must decide/AC), documents=[] attachments=[] — no accepted schema text there (comments not read), which makes F09-A6 (#410) answerable today.
VERDICT ON THE PLAN. Mechanically sound in the small (no cycles, 50/51 ticket edge sets resolve) but the published graph does not encode the first proof. Seven defects dominate:
- The proof ticket X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500) is gated only by 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) + X01-T2 (feat(conformance): lifecycle-family tracer and shared Electron-arm recorder for the two-arm harness — main-process lifecycle fixtures (including first-launch activate) recorded under verified Electron 44.4.5 on macOS arm64, replayed under @keld/elect #495) — none of the ~18 implementation tickets it measures, and not PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418)/P3. Under the map's frontier rule it surfaces as takeable while nothing it scores exists.
- The close-with-unsaved-prompt cell is contradictory as published: F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) AC1 requires the draw.io close dance to complete; F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478) AC4 makes showMessageBoxSync throw. FACT (drawio electron.js:851-945): the sync dialog is called inside the isModified-result handler after
modifiedModalOpen = true(:866); a throw leaves that flag set and every later close is ignored (:853) — the window wedges open. There is NO implementation ticket for the worker-owned blocking transport (only PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) experiment, PANEL-D4 (Worker-owned single-link transport is the only candidate sync mechanism; second link refused #424) decision and three fog lines), and F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478)/F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) have no PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) edge. - PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) (boot/authority trace) decides the BootDescriptor, the package-level Electron surface (electron-store/log/context-menu/updater — node_modules and the drawio webapp submodule are both absent from the corpus clone) and the denominator, but gates nothing. F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452) is instead gated by F01-A4 (Where does
userDatalive under the strict profile: guard grant root or KEL-78 role-private container? #392), a strict-profile-only question irrelevant under LegacySandboxOff. - Activation-path members with no ticket: app 'web-contents-created' (:2189), webContents.zoomFactor setter + setVisualZoomLevelLimits (:1835-1836, run inside did-finish-load BEFORE loadFinished()), app.name (:2020), the 'install' cell itself (no .app exists; KEL-141 Backlog).
- Duplicate ownership: boot facts (F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452)/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)), preload runtime (F04-T4 (feat(ipc): contextBridge.exposeInMainWorld value table + ipcRenderer send/on facade + IpcRendererEvent in the app content world (draw.io first-proof slice) #467)/F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484)), permission table (F05-T3 (feat(session): permission request/check facade as one guard decision (missing handler = deny; handlers only narrow) implementing the X04-T1 table #472)/X04-T1 (spec(security): Electron security-surface → single Keld owner mapping table with a per-engine permission-hook table and one negative-test id per row (no new schema) #505), with a dangling {{X04-D1}}), shell.open grant (F06-D4 (shell.openExternal confirm-per-scheme grant (confirm:https) vs exact literals only — permission-model decision (joint with X04-D4) #405)/X04-D4 (shell.open grant spelling for scheme classes: KEL-208 owner ruling (barehttps:is inert today; a distinct confirm-class token vs exact literals) #416)), webPreferences (F02-T4 (feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455)/F07-T2 (task(renderer): zero-<webview> contract — will-attach-webview never emitted, <webview> stays an undefined element #485)), arch 03 §3 el:* fix (three claimants), oracle pin (F04-T5 (task(ipc): scoreboard rows for deferred (MessageChannelMain, MessagePortMain, utilityProcess, UtilityProcess, parentPort, ipcRenderer.postMessage/sendToHost, IpcMainEvent.ports) and documented-never (IpcMainServiceWorker family, exposeInIsolatedWorld #468)/X01-T1 (spec(conformance): two-arm differential oracle harness spec — fixture packaging, verified Electron identity, transcript rows, declared normalisers, per-process ordering with causal edges, fixture-set digest owner, lanes #494)). - Ambiguity laundering: PANEL-D7 (Boot-static values must be synchronous before the app module evaluates #427)'s '[fact] :58 app.getPath pre-ready' is wrong (line 58 is inside a function called from whenReady at ~:991, and
new Store()at :30 sits in try/catch with a null fallback); F03-EPIC (compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457) states the third-world preload as a fixed fact while PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441) is CONTESTED and gates two tickets; PANEL-D5 (Close and quit vetoes are async AppKit hooks; deadline expiry keeps the window open #425) (resolved) and PANEL-D19 (Close-veto deadline expiry semantics (decided 2026-10-07) #439) (contested) cover the same atom; the MAP says draw.io 'uses ' (it disables it) and that its 'single rendererReq channel is enumerable' (electron.js registers 25 distinct ipcMain channels). - Invariant breaches: F02-T4 (feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455) lets a keld.compat.ts quirk 'accept the forfeit' for nodeIntegration/webSecurity:false (quirks may only narrow; never-list); F03-T4 (feat(webContents): setWindowOpenHandler — always invoke the handler, deny without a handler (▲, no quirk), allow via synchronous host window minting with guard ∧ app #461) offers an allow-by-default quirk; features labelled ready-for-agent without a spec (F02-T4 (feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455), F05-T6 (task(session): publish scoreboard rows for every F05 entity not owned by another ticket (never / ▲ / ✘ / unknown, including strict net unknown and proxy assignment) #475), F06-T6 (task(native): scoreboard rows with status and tracking for every F06 entity and member not owned by an implementation ticket (Notification, safeStorage, globalShortcut, power, systemPreferences, MAS/APNs, ShareMenu, desktopCapturer and their structur #482), F08-T2 (task(diagnostics): publish F08 scoreboard rows with explicit status and rationale (crashReporter, contentTracing, ten structures, process diagnostic getters, getAppMetrics, GPU getters); no facade code #489)); F07/F08/F09/X03 implementation tickets have no conformance-entry predecessor; PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) uses a 1,000-call 'diagnostic' RTT ratio as a pass gate.
YAGNI census over the 51 ticket keys (rule: first-proof if ANY slice is required; the reason names the slice and what to park): first-proof 30 (most as narrow slices of L-sized tickets), next 15, parked 6 (F01-T6 (#454), F04-T5 (#468), F05-T3 (#472), F07-T3 (#486), F08-T2 (#489), F09-T2 (#492) — X05-T1 (#507) is parked too, making 7; see rows). Research-pin drift: refuters verified at d150a14; origin/main is b4b907c (5 commits later: KEL-270 S5/S8, KEL-19 T1 ExpectedAppIdentity, KEL-254) — I re-verified at HEAD only: Ready emitted on NavigationReady (keld-core app_session.rs:3390), G2 Ready replay already live (:5087), two generation counters (keld-wv macos_bridge navigation_generation u64 vs guard Principal::Webview.generation), hand-mirrored ECHO/LIFECYCLE channel constants, guard evaluate reads manifest.app only, arch 03 §3 still shows
el:*.NOT VERIFIED (UNKNOWN): Electron v44.4.5 doc receipts were not re-fetched in this audit; electron-store/electron-log/electron-context-menu internals (no node_modules); Linear comments on any issue; whether the Linear workspace is still at its free issue cap (briefing claim, ASSUMPTION); swarm batch-2 results for F06/X03/X05 (0 refuter verdicts in swarm.json for those units).
Evidence files: /publish_plan.json, .../swarm.json, .../corpus/drawio-desktop/src/main/electron.js, .../corpus/drawio-desktop/src/main/electron-preload.js, /crates/keld-core/src/app_session.rs, /crates/keld-wv/src/wkwebview/macos_bridge.rs, /packages/@keld/kipc/src/transport.ts, /docs/architecture/03-security.md.
First-proof frontier (ordered; drawio-desktop on macOS, explicit legacy profile)
- PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420
PANEL-P3 (#420)— Takeable now and upstream of everything: it decides the boot-descriptor field set, the Electron members the four top-level packages touch, the committed denominator and whether the proof is config-only or config+N. Prerequisite work inside it: populate the empty drawio webapp submodule and install node_modules (both absent in the clone). (consumes: corpus drawio-desktop@2edf9fb (src/main/electron.js, electron-preload.js, package.json: electron-store ^11.0.2, electron-log ^5.4.4, electron-updater ^6.8.9, electron-context-menu ^5.1.0); Bun 1.4.2; a throwing @keld/electron stub. Produces: pre-ready call list, package member inventory, fs/net/spawn classification, denominator draft.) - PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418
PANEL-P1 (#418)— Takeable now; kill condition build(deps): Bump actions/checkout from 4 to 7 #1. Decides whether showMessageBoxSync on the close path (electron.js:876) can work, i.e. whether step 4 is config-only. Nothing that parks Bun may be specified before it. (consumes: packages/@keld/kipc transport at b4b907c, the keld-ipc Rust host writer, the existing park-probe prototype (8,192-byte stall measurement). Produces: pass/fail per arm; either the transport ticket (missing today) or the recorded 'config + 1 edit' decision.) - PANEL-P2 (decided 2026-10-07): async AppKit veto hooks match Electron 44.4.5 with six facade rules #419
PANEL-P2 (#419)— Takeable now; gates F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) and the F01-T3 (feat(app): cancelable two-phase quit — before-quit/will-quit preventDefault and host-initiated quit through the per-window close veto #451) quit slice. Supplies the Electron transcript for close → preventDefault → isModified → dialog → destroy and Cmd+Q ordering with two windows. (consumes: Electron 44.4.5 binary on the same Mac; an objc2 AppKit harness; receipts already in PANEL-D5 (Close and quit vetoes are async AppKit hooks; deadline expiry keeps the window open #425) (windowShouldClose:/applicationShouldTerminate:). Produces: diffed transcript + ✔/▲ marks.) - Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441
PANEL-D21 (#441)— Takeable now; gates F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484) and F04-T4 (feat(ipc): contextBridge.exposeInMainWorld value table + ipcRenderer send/on facade + IpcRendererEvent in the app content world (draw.io first-proof slice) #467). Arm G with the real draw.io preload installed. (consumes: Landed KEL-142 bridge (KEL-142 Done; keld-wv macOS bridge and its isolation negative tests), corpus electron-preload.js. Produces: world choice + measured relay cost.) - One navigation-generation owner: unify the bridge counter and the guard webview generation #400
F04-A4 (#400)— Takeable now as a decision packet (evidence already determines the facts); gates F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) and — once the missing edge is added — F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466). (consumes: keld-wv macos_bridge navigation_generation (rotates on navigation start), guard Principal::Webview.generation (0 in live backends, kel102 spec note), KEL-75 WindowGeneration spec. Produces: one named owner + rotation point.) - Who owns the
windows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398F04-A1 (#398)— Takeable now; gates F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) and the grant seeding in 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). The renderer→main boundary has no evaluator (guard evaluate reads manifest.app only). (consumes: arch 03 §2/§3 at b4b907c (03-security.md:97 still shows el:), kel102 spec (KEL-102 In Progress), the 25 literal ipcMain channels in drawio electron.js. Produces: approved amendment naming the windows..channels owner.)* - Who owns the structured-clone-compatible value codec (arch 02 §5 SCV) used by executeJavaScript, ipc and webContents.send? #396
F03-D4 (#396)— Takeable now as an ownership decision; gates F03-T5 (feat(webContents): executeJavaScript on macOS with a completion-backed result envelope encoded by the F04-T11 endpoint codec #462) and F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466). (consumes: arch 02 §5 SCV text; draw.io value shapes (plain objects, strings, an Error instance at electron.js:4541, file contents). Produces: owner + v0 domain + size ceiling.) - Custom-scheme privilege matrix and CSP profile prototype (P2): can a renderer turn a resource locator into filesystem authority, and does the host CSP admit draw.io? #415
X04-D3 (#415)— Takeable now; the CSP profile that F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473) must inject (edge missing today). (consumes: draw.io's CSP string and file:// filter (electron.js:994-1022); a WKWebView fixture. Produces: CSP profile that admits draw.io + the outside-codeDir negative probe list.) - One module-alias owner: package.json
electrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412X02-A1 (#412)— Takeable now (the ticket already contains the recommendation); gates 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) and 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). (consumes: Refuter-run Bun 1.4.2 alias probes (package.json dependency alias reaches node_modules requires; tsconfig paths and bunfig alias do not). Produces: single alias owner.) - spec(ipc): minimum slice of the architecture 02 §4 channel table — one keld-ipc-owned table of kipc channel ids, its entry fields, consumers and live/destination split (no per-family ranges) #508
X05-T2 (#508)— Takeable now (no blockers); must precede the first ticket that adds a kipc channel so no further constants are hand-mirrored. (consumes: KEL-98 codegen (Done) and KEL-136 generated transport (Done); the two mirrored constants in @keld/kipc transport and keld-ipc. Produces: one generated constants source.) - spec(migrate): first-proof output contract — files written and not written, key→owner map, report shape without percentages, and the same-PR architecture errata #497
X02-T1 (#497)— Takeable now (no blockers); fixes the five-file contract and report shape the hand-authored artefact must meet. (consumes: KEL-17 and KEL-19 (both Done), arch 04 §1/§2/§4, KEL-74 claim shape. Produces: approved migrate spec slice.) - conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445
F01-T1 (#445)— Takeable now; conformance-first for ready/whenReady, window-all-closed, activate, before-quit on macOS — after the red-entry mechanism (expected-status cells) is stated. (consumes: KEL-237 lifecycle corpus manifest + runner as landed in keld-compat (KEL-237 In Progress), pinned app.md v44.4.5.) - conformance(window): pinned v44.4.5 KEL-74 cells for the draw.io window path — creation and creation events, focused/all-window getters, maximize state, constructor triage, close/preventDefault, destroy, tombstone, closed #448
F02-T1 (#448)— Takeable now; close/preventDefault/destroy/closed/isDestroyed entries precede F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450). (consumes: KEL-237 manifest/runner; pinned browser-window.md/base-window.md; PANEL-D6 (Destroyed-object and frame-targeting contract #426) tombstone contract.) - conformance(ipc): pinned v44.4.5 entries for the draw.io IPC path — send/on/once, ipcMain.on/once/removeListener, event.reply, senderFrame, webContents.send delivery, IpcRendererEvent, structured-clone throws, contextBridge value rows, navigation-gen #464
F04-T1 (#464)— Takeable now; send/on ordering, event.reply, senderFrame, contextBridge value-table entries precede F04-T2 (feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465)..T4 (sendSync and invoke entries deferred). (consumes: KEL-237 manifest/runner; pinned ipc-main.md, ipc-renderer.md, ipc-main-event.md, context-bridge.md.) - conformance(webContents): first-proof entries for did-finish-load, did-navigate, destroyed, webContents.id, zoom members, registration-safe listeners and executeJavaScript results (macOS) #458
F03-T1 (#458)— Takeable now; did-finish-load, executeJavaScript result and destroyed entries only. (consumes: KEL-237 manifest/runner; pinned web-contents.md.) - conformance(session): pinned webRequest cells and the file:// / CSP probe list for draw.io (first-proof slice) #470
F05-T1 (#470)— Takeable now; only the webRequest-honesty entry is on the path. (consumes: KEL-237 manifest/runner; pinned session.md / web-request.md; PANEL-D17 (session.webRequest listeners: recorded no-ops only after host containment with a negative control #437).) - conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477
F06-T1 (#477)— Takeable after batch-2 refutation of F06 is applied; dialog result and menu-role entries only. (consumes: KEL-237 manifest/runner; pinned dialog.md, menu.md, menu-item.md.) - feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452
F01-T4 (#452)— Next: unblocked once PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) delivers the field set (replace the F01-A4 (Where doesuserDatalive under the strict profile: guard grant root or KEL-78 role-private container? #392) edge). (consumes: PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) pre-ready call list; KEL-75 role spawn contract (spec in repo; KEL-75 In Progress) re-verified at b4b907c.) - 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 #502X03-T1 (#502)— Next: after X02-A1 (One module-alias owner: package.jsonelectrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412) and F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452); makeselectronresolve inside the four node_modules packages. (consumes: X02-A1 (One module-alias owner: package.jsonelectrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412) decision; F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452) payload; KEL-72 module alias (Done).) - feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446
F01-T2 (#446)— Next: after F01-T1 (conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445); must land before the registry so no adoption shim is built. (consumes: F01-T1 (conformance(app): pinned v44.4.5 macOS cells for the first-proof app surface (ready, whenReady/isReady, session facts, single-instance verdict) with runner-asserted expected status #445) entries; the live NavigationReady→Ready emission and recovered-generation replay in keld-core; KEL-139 Ready AC (KEL-139 Done).) - feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449
F02-T2 (#449)— Next: after F02-T1 (conformance(window): pinned v44.4.5 KEL-74 cells for the draw.io window path — creation and creation events, focused/all-window getters, maximize state, constructor triage, close/preventDefault, destroy, tombstone, closed #448), F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446) and X05-T2 (spec(ipc): minimum slice of the architecture 02 §4 channel table — one keld-ipc-owned table of kipc channel ids, its entry fields, consumers and live/destination split (no per-family ranges) #508) (the PANEL-D19 (Close-veto deadline expiry semantics (decided 2026-10-07) #439) edge is not a real gate). (consumes: F02-T1 (conformance(window): pinned v44.4.5 KEL-74 cells for the draw.io window path — creation and creation events, focused/all-window getters, maximize state, constructor triage, close/preventDefault, destroy, tombstone, closed #448) entries; KEL-75 WindowGeneration spec; generated channel constants; a named window-channel contract owner (open — KEL-98 is echo-only).) - feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465
F04-T2 (#465)— Next: after F04-T1 (conformance(ipc): pinned v44.4.5 entries for the draw.io IPC path — send/on/once, ipcMain.on/once/removeListener, event.reply, senderFrame, webContents.send delivery, IpcRendererEvent, structured-clone throws, contextBridge value rows, navigation-gen #464) and X05-T2 (spec(ipc): minimum slice of the architecture 02 §4 channel table — one keld-ipc-owned table of kipc channel ids, its entry fields, consumers and live/destination split (no per-family ranges) #508); the floor that every renderer message crosses. (consumes: F04-T1 (conformance(ipc): pinned v44.4.5 entries for the draw.io IPC path — send/on/once, ipcMain.on/once/removeListener, event.reply, senderFrame, webContents.send delivery, IpcRendererEvent, structured-clone throws, contextBridge value rows, navigation-gen #464) entries; landed KEL-142 wv-link v1 envelope; KEL-80 (Backlog — the spec PR must name itself as its slice).) - feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484
F07-T1 (#484)— Next: after PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441) and F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) (per-view script registration). (consumes: PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441) result; KEL-142 injection seam; corpus electron-preload.js.) - feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466
F04-T3 (#466)— Next: after F04-T2 (feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465), F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398), F03-D4 (Who owns the structured-clone-compatible value codec (arch 02 §5 SCV) used by executeJavaScript, ipc and webContents.send? #396) and F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400). (consumes: Floor v2; channel-grant amendment; SCV v0 domain; generation owner.) - feat(ipc): contextBridge.exposeInMainWorld value table + ipcRenderer send/on facade + IpcRendererEvent in the app content world (draw.io first-proof slice) #467
F04-T4 (#467)— Next: after F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484) and F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) (drop the F04-A3 (Synchronous cross-world function calls: can a contextBridge-exposed function return a value synchronously on WKWebView/WebKitGTK worlds? #399) gate for draw.io). (consumes: F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484) runtime; F04-T1 (conformance(ipc): pinned v44.4.5 entries for the draw.io IPC path — send/on/once, ipcMain.on/once/removeListener, event.reply, senderFrame, webContents.send delivery, IpcRendererEvent, structured-clone throws, contextBridge value rows, navigation-gen #464) value-table entries; F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) routing.) - feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459
F03-T2 (#459)— Next: after F03-T1 (conformance(webContents): first-proof entries for did-finish-load, did-navigate, destroyed, webContents.id, zoom members, registration-safe listeners and executeJavaScript results (macOS) #458), F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449), F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400) — macOS slice (loadURL file://, did-finish-load, did-navigate, destroyed, zoom members). (consumes: Existing page-load-finished observable in keld-wv; generation owner; F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) webview identity.) - feat(webContents): executeJavaScript on macOS with a completion-backed result envelope encoded by the F04-T11 endpoint codec #462
F03-T5 (#462)— Next: after F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) and F03-D4 (Who owns the structured-clone-compatible value codec (arch 02 §5 SCV) used by executeJavaScript, ipc and webContents.send? #396); needed at did-finish-load. (consumes: keld-wv eval seam (fire-and-forget today); SCV v0 domain.) - feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473
F05-T4 (#473)— Next: after F05-T1 (conformance(session): pinned webRequest cells and the file:// / CSP probe list for draw.io (first-proof slice) #470) and X04-D3 (Custom-scheme privilege matrix and CSP profile prototype (P2): can a renderer turn a resource locator into filesystem authority, and does the host CSP admit draw.io? #415); macOS only. (consumes: X04-D3 (Custom-scheme privilege matrix and CSP profile prototype (P2): can a renderer turn a resource locator into filesystem authority, and does the host CSP admit draw.io? #415) CSP profile + probe list; KEL-79 has no artifact (Backlog) — the spec slice for file:// read-root must be produced here and recorded on KEL-79.) - feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455
F02-T4 (#455)— Next: after F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449); accept/ignore slice for draw.io's webPreferences (quirk escape removed). (consumes: F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) constructor path; draw.io option set (electron.js:714-733).) - feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450
F02-T3 (#450)— Next: after F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) and PANEL-P2 (PANEL-P2 (decided 2026-10-07): async AppKit veto hooks match Electron 44.4.5 with six facade rules #419); the modified-document branch additionally waits on the PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) outcome. (consumes: PANEL-P2 (PANEL-P2 (decided 2026-10-07): async AppKit veto hooks match Electron 44.4.5 with six facade rules #419) transcript; F02-T1 (conformance(window): pinned v44.4.5 KEL-74 cells for the draw.io window path — creation and creation events, focused/all-window getters, maximize state, constructor triage, close/preventDefault, destroy, tombstone, closed #448) entries; PANEL-D5 (Close and quit vetoes are async AppKit hooks; deadline expiry keeps the window open #425) resolution.) - feat(app): cancelable two-phase quit — before-quit/will-quit preventDefault and host-initiated quit through the per-window close veto #451
F01-T3 (#451)— Next: after F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) — only the slice 'host-initiated quit enters the per-window veto'. (consumes: F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) close protocol; PANEL-P2 (PANEL-P2 (decided 2026-10-07): async AppKit veto hooks match Electron 44.4.5 with six facade rules #419) Cmd+Q transcript; KEL-139 AC6 single quit owner.) - feat(native): display work areas and nativeTheme.shouldUseDarkColors as host-pushed facts on the F02-T2 mirror, read synchronously with zero kipc traffic #481
F06-T5 (#481)— Next: after F06-T1 (conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477) and F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449)'s mirror primitive — screen workArea + nativeTheme.shouldUseDarkColors only. (consumes: F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) mirror primitive; KEL-102 admission path (In Progress) for new host channels.) - feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480
F06-T4 (#480)— Next: after F06-T1 (conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477), F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449), F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) — application menu with host-side roles only. (consumes: F06-T1 (conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477) role entries; close/quit protocol so roles 'close'/'quit' are cancelable.) - feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478
F06-T2 (#478)— Next: after F06-T1 (conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477) and F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) — open/save/message dialogs returning paths (no scope minting); sync variant per PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) outcome. (consumes: F06-T1 (conformance(native): pinned v44.4.5 cells for the first-proof slice — dialog result shapes (incl. showMessageBoxSync), menu role semantics and close routing, display work areas, shouldUseDarkColors; role-quit cell held at expected fail (F06-T16) #477) dialog entries; F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) window identity for parenting; PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) decision.) - feat(update): inert electron-updater 6.8.9 adapter for the draw.io proof (import-time surface, recorded no-op setFeedURL, honest check outcome) #491
F09-T1 (#491)— Next: after PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) — inert electron-updater adapter slice only (no F09-A2 (Who owns the compiled-in feed base (KEL-53/KEL-19 amendment) that autoUpdater.getFeedURL reports and setFeedURL is compared against? #409) gate). (consumes: PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) list of AppUpdater members touched at import; PANEL-D14 (Updater handling for the draw.io proof #434) resolution; 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) alias.) - feat(app): host single-instance lock verdict — requestSingleInstanceLock/hasSingleInstanceLock read a host-acquired lock with Electron call-time behaviour (first-proof slice) #453
F01-T5 (#453)— Next: after F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452) — lock verdict + registrable listeners only. (consumes: F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452) boot payload; single-instance declaration key agreed with X02-T1 (spec(migrate): first-proof output contract — files written and not written, key→owner map, report shape without percentages, and the same-PR architecture errata #497).) - task(renderer): zero-<webview> contract — will-attach-webview never emitted, <webview> stays an undefined element #485
F07-T2 (#485)— Next and trivial: fold webviewTag acceptance into F02-T4 (feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455); keep will-attach-webview registrable. (consumes: F02-T4 (feat(window): first-proof webPreferences triage — accept draw.io's field set, refuse the six escalating values at construction with no opt-in #455) option triage; F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) webContents emitter.) - 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
X02-T3 (#499)— Next: hand-authored draw.io artefact once the config keys it must contain exist (alias, channels, single-instance, role env, legacy profile). (consumes: X02-T1 (spec(migrate): first-proof output contract — files written and not written, key→owner map, report shape without percentages, and the same-PR architecture errata #497) contract; X02-A1 (One module-alias owner: package.jsonelectrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03) #412); F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398) grant shape; F01-T5 (feat(app): host single-instance lock verdict — requestSingleInstanceLock/hasSingleInstanceLock read a host-acquired lock with Electron call-time behaviour (first-proof slice) #453) declaration key; PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) channel/env findings.) - feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500
X02-T4 (#500)— Last: the proof. Takeable only when every slice above has landed and PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418)/P3 outcomes are recorded. (consumes: The hand-authored artefact; all first-proof slices at named SHAs; PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) denominator draft; KEL-74 schema (Done) and KEL-237 runner pattern; a named owner for the committed product-corpus id (none today).)
YAGNI classification of the 51 classified tickets
milestone:first-proof: 30milestone:parked: 7milestone:next: 14
Hidden coupling made explicit
- F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450), F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478), PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418), X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500): The unsaved-prompt cell couples three atoms with no edges between them. draw.io sets modifiedModalOpen=true (:866) and then calls showMessageBoxSync (:876) inside an async ipcMain listener; if F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478)'s SCAFFOLDED throw fires, the flag is never cleared and every later close is ignored by the guard at :853 — the window can never close. F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) AC1 and F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478) AC4 are mutually exclusive for a modified document. → New atom 'blocking host CALL from a Bun role' (transport ticket) with edges PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) → transport → F06-T2 (feat(native): guarded async dialog broker on macOS (showOpenDialog/showSaveDialog/showMessageBox) parented to host-minted windows, returning paths only under the legacy profile #478)(sync) → X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500)(close cell); F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) AC1 split into unmodified/modified. If P1 fails, a recorded decision 'draw.io = config + 1 edit'.
- F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446), F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449), KEL-143: Ready re-base ↔ recovery ↔ window adoption. Ready is emitted on NavigationReady today and is already replayed to a recovered generation; F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) adds a transitional 'first new BrowserWindow() adopts the host-created primary window until F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446) lands'. Changing the emission point silently changes what the replayed Ready means in generation ≥2 (a window exists) and makes the adoption shim dead or wrong; F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446)'s AC1/AC3 already contradict each other on this. → One atom 'who creates window build(deps): Bump actions/checkout from 4 to 7 #1 and what Ready means per generation', owned by F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446); edge F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) ← F01-T2 (feat(app): re-base host Ready to "host initialized, window module available" before any app window for facade boots (KEL-96 §4.4/§4.5 and KEL-139 amendment) #446) and delete the adoption shim from F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) (two mechanisms for one fact).
- F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400), F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466), F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459), F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449), X05-EPIC (program(perf): attributed compat-overhead metric registry, the kipc channel-table slice, and bounded hot-path rules (no performance claim before measurement) #506): At least four 'generation' notions are used interchangeably: Bun role generation (tombstones, stale-generation errors in F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449)), WindowGeneration (F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449)), bridge navigation_generation u64 rotated on navigation start (keld-wv macos_bridge.rs:335), guard Principal::Webview.generation (0 in live backends per the refuter), plus X05's 'per-window state generation' for the mirror. F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466)'s reply/senderFrame semantics depend on the unification but only F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) is gated by F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400). → F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400)'s resolution names each generation, its minting owner and rotation point; add edge F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) ← F04-A4 (One navigation-generation owner: unify the bridge counter and the guard webview generation #400); forbid the bare word 'generation' in ticket ACs.
- PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441), F03-T5 (feat(webContents): executeJavaScript on macOS with a completion-backed result envelope encoded by the F04-T11 endpoint codec #462), F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459), F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484): The world decision silently changes three other atoms: what executeJavaScriptInIsolatedWorld's worldId can address, where F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459)'s 'same-document change via the isolated-world reporter' runs, and which world host-initiated executeJavaScript lands in (must never be the KEL-142 trusted world holding handler and nonce). → Drop executeJavaScriptInIsolatedWorld from F03-T5 (feat(webContents): executeJavaScript on macOS with a completion-backed result envelope encoded by the F04-T11 endpoint codec #462) (zero demand); add an AC to F03-T5 (feat(webContents): executeJavaScript on macOS with a completion-backed result envelope encoded by the F04-T11 endpoint codec #462) 'app-supplied script never executes in the trusted bridge world' and an edge F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) ← PANEL-D21 (Preload in the KEL-142 isolated world vs a third content world (decided 2026-10-07) #441) for the reporter placement.
- F04-A1 (Who owns the
windows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398), F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466), 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), X02-T2 (feat(migrate): analyzer v0 slice — read-only verb, import-binding-aware call-site inventory and one blocker class (webPreferences security fields) with exact hand-resolved oracles #498): Channel grants ↔ migrate. The runtime boundary (enumerated el:) is only as good as the list migrate emits; F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) carries a migrate AC ('el:* is refused by migrate'), 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) seeds windows..channels which the guard parses and ignores today, and the list for draw.io is derivable from main-side ipcMain registrations (25 literals) but not from the preload, which forwards page-chosen names. → New explicit rule owned by F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398): 'grant list source = main-side literal ipcMain registrations; non-literal registration is reported unenumerable'. Edge 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) ← F04-A1 (Who owns thewindows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)? #398); move the migrate AC from F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) to 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). - F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473), F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466), F07-A6 (Web-storage continuity when
keld migratereplacesfile:///custom-scheme origins: empty first launch (▲) or a one-shot host-side storage import? #406): Page URL identity. draw.io authorizes every IPC with senderFrame.url.startsWith(codeUrl) (:694-700) and filters file:// loads by the same prefix (:1010-1022). If the host serves the app from any origin other than file:// (F07-A6 (Web-storage continuity whenkeld migratereplacesfile:///custom-scheme origins: empty first launch (▲) or a one-shot host-side storage import? #406) contemplates replacing file:// origins; WebView2 'virtual host mapping' in F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473)), validateSender returns false for all 25 channels and the app is silently dead. → AC in F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473): the document URL reported to the app (webContents.getURL, senderFrame.url) equals the file:// URL the app loaded; edge F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) ← F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473); F07-A6 (Web-storage continuity whenkeld migratereplacesfile:///custom-scheme origins: empty first launch (▲) or a one-shot host-side storage import? #406) records this as a constraint. - F06-T4 (feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480), F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450), F01-T3 (feat(app): cancelable two-phase quit — before-quit/will-quit preventDefault and host-initiated quit through the per-window close veto #451): F06-T4 (feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480) executes menu
roleitems host-side 'without a round trip'. draw.io's menu has role 'close' (:2047) and role 'quit' (:2042); executed natively they would bypass the cancelable close/quit protocol that F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450)/F01-T3 (feat(app): cancelable two-phase quit — before-quit/will-quit preventDefault and host-initiated quit through the per-window close veto #451) exist to provide. → AC in F06-T4 (feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480): role close/quit enter the same CloseRequested/quit-request path as the window button and Cmd+Q; edge F06-T4 (feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480) ← F02-T3 (feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450). - F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449), F06-T5 (feat(native): display work areas and nativeTheme.shouldUseDarkColors as host-pushed facts on the F02-T2 mirror, read synchronously with zero kipc traffic #481), PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418): Host-pushed mirrors (window bounds/focus, displays, theme) write events toward a role that may be parked in a sync dialog; the link stalls at 8 KiB (measured probe). Mirror event volume ('move'/'resize') therefore changes whether the blocking transport is safe, and a parked role reads stale mirror values on wake. → PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) arm B adds a mirror-event flood during the park; F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) states the staleness contract (ordered replay before the sync call returns).
- PANEL-D14 (Updater handling for the draw.io proof #434), 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), F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452), F09-T1 (feat(update): inert electron-updater 6.8.9 adapter for the draw.io proof (import-time surface, recorded no-op setFeedURL, honest check outcome) #491): Updater disablement depends on an environment variable: PANEL-D14 (Updater handling for the draw.io proof #434) has migrate write DRAWIO_DISABLE_UPDATE=true into 'the host-declared role environment', read at module top level (:75). That is a boot fact delivered at spawn (F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452) / KEL-75 no-inherited-env) and a migrate output not present in 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)'s file list. If it is absent, the boot-time checkForUpdates runs (:2092-2100) and F09-T1 (feat(update): inert electron-updater 6.8.9 adapter for the draw.io proof (import-time surface, recorded no-op setFeedURL, honest check outcome) #491)'s 'typed error on explicit check' fires at activation. → Name the declared-role-environment field and its schema owner; add it to 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) outputs and to F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452)'s payload; F09-T1 (feat(update): inert electron-updater 6.8.9 adapter for the draw.io proof (import-time surface, recorded no-op setFeedURL, honest check outcome) #491) AC covers both env-present and env-absent boots.
- F04-T2 (feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465), F03-D4 (Who owns the structured-clone-compatible value codec (arch 02 §5 SCV) used by executeJavaScript, ipc and webContents.send? #396), F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466): The payload bound and codec domain decide whether open and save work: file contents travel as IPC payloads (:4441-4447, :4493) and the error reply carries an Error instance (:4541). A JSON-only v0 domain or a bound below the document size turns into silent corruption or a failed save. → F03-D4 (Who owns the structured-clone-compatible value codec (arch 02 §5 SCV) used by executeJavaScript, ipc and webContents.send? #396) packet states v0 domain includes Error and a bulk path or explicit size ceiling with a typed failure; F04-T2 (feat(bridge): renderer floor v2a — one-way window.keld.send in the existing wv-link envelope under a host-enforced credit window (first-proof slice) #465) AC exercises a save above the old floor.
- F01-T5 (feat(app): host single-instance lock verdict — requestSingleInstanceLock/hasSingleInstanceLock read a host-acquired lock with Electron call-time behaviour (first-proof slice) #453), 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): F01-T5 (feat(app): host single-instance lock verdict — requestSingleInstanceLock/hasSingleInstanceLock read a host-acquired lock with Electron call-time behaviour (first-proof slice) #453) AC3 makes requestSingleInstanceLock() without a config declaration a typed diagnostic; draw.io quits when the call returns false (:1718-1722). Whether the proof app boots therefore depends on migrate emitting the declaration, which is listed in 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) but not edged. → Edge 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) ← F01-T5 (feat(app): host single-instance lock verdict — requestSingleInstanceLock/hasSingleInstanceLock read a host-acquired lock with Electron call-time behaviour (first-proof slice) #453) (declaration key) and an X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500) activation precondition.
- 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), F09-T2 (task(build): keld build config translation of electron-builder/forge configs with a per-field disposition report (parked until the keld build slice) #492), F09-A6 (Locate the accepted KEL-15 configuration RFC text (repo has no spec file) and land it as docs/specs before keld.build.ts work #410): 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)'s byte-identical artefact includes keld.build.ts 'per F09-T2 (task(build): keld build config translation of electron-builder/forge configs with a per-field disposition report (parked until the keld build slice) #492)', whose schema has no text anywhere (KEL-15 body is only a brief). Changing the build schema later silently invalidates the golden artefact that defines the generator. → Remove keld.build.ts from the first-proof artefact (nothing reads it under keld dev) or add the edge and accept the delay.
- swarm research pin, all tickets' 'Current behavior': Every 'Current behavior' line was verified by refuters at origin/main d150a14; main is now b4b907c (5 commits: KEL-270 S5/S8 runtime/guard, KEL-19 T1 ExpectedAppIdentity container, KEL-254). F09-A2 (Who owns the compiled-in feed base (KEL-53/KEL-19 amendment) that autoUpdater.getFeedURL reports and setFeedURL is compared against? #409) (feed base in ExpectedAppIdentity) and the role-spawn facts in F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452)/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) touch code that moved. → Stamp each ticket with the verification SHA; re-verify F09-A2 (Who owns the compiled-in feed base (KEL-53/KEL-19 amendment) that autoUpdater.getFeedURL reports and setFeedURL is compared against? #409), F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452), 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) at b4b907c before they are taken.
Coverage gaps (Electron entities not yet covered by a ticket, epic scope, never list or out-of-scope)
(no key) worker-owned single-link blocking transport for @keld/kipc— The only mechanism that lets dialog.showMessageBoxSync (drawio electron.js:876, on the close path) work has no implementation ticket: it appears in PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) (experiment), PANEL-D4 (Worker-owned single-link transport is the only candidate sync mechanism; second link refused #424) (decision), MAP 'Not yet specified', X05 fog and F06-EPIC (compat(native): first-proof dialog, application menu and display/theme facts for draw.io on macOS (legacy profile); shell, clipboard/nativeImage, Tray and the remaining native modules as tracked next/parked slices #476) prose. The first proof's fourth step cannot pass config-only without it. (suggested: New ticket under X05 or F04 (owner KEL-80/KEL-97 per PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418)), gated by PANEL-P1 (PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418) arm B; or an explicit recorded outcome 'draw.io = config + 1 edit' if P1 fails.)app event 'web-contents-created' (and 'browser-window-created')— Zero mentions in any issue body. draw.io registers will-navigate, setWindowOpenHandler and will-attach-webview only inside app.on('web-contents-created') (electron.js:2189-2226); if the facade never emits it, F03-T3 (feat(webContents): guard-first navigation policy with deny-only will-navigate/will-frame-navigate hooks invoked for every page-initiated navigation (outcome = guard ∧ app) #460)/F03-T4 (feat(webContents): setWindowOpenHandler — always invoke the handler, deny without a handler (▲, no quirk), allow via synchronous host window minting with guard ∧ app #461)/F07-T2 (task(renderer): zero-<webview> contract — will-attach-webview never emitted, <webview> stays an undefined element #485) acceptance criteria are unreachable. 'browser-window-created' is what electron-context-menu is believed to hook (INFERENCE: no node_modules in the clone). (suggested: F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) (emit on window/webContents creation) with a conformance entry in F02-T1 (conformance(window): pinned v44.4.5 KEL-74 cells for the draw.io window path — creation and creation events, focused/all-window getters, maximize state, constructor triage, close/preventDefault, destroy, tombstone, closed #448).)webContents.zoomFactor (setter/getter), webContents.setVisualZoomLevelLimits— Only in MAP/F03-EPIC (compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457) fog. FACT: both run inside the did-finish-load listener BEFORE loadFinished() (electron.js:1835-1837); a missing method throws there and 'args-obj' is never sent — activation-path break. (suggested: F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) first-proof slice (typed no-throw member with a recorded ▲ until the per-engine zoom mapping is specified).)first-proof cell 'install'— PANEL-D12 (First proof: drawio-desktop on macOS under explicit legacy profile #432) and X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500) score an install cell but no ticket defines it: MAP states no .app/DMG exists, KEL-141 (prebuilt CLI+host distribution) is Backlog and KEL-103 In Progress (Linear, fetched 2026-10-06), and X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500) runs cells throughkeld dev. (suggested: X02-T4 (feat(corpus): electron-apps-v0 product corpus manifest for draw.io with red-until-implemented install/activation/primary_workflow cells (new manifest; KEL-74 schema and the KEL-237 runner pattern reused through the X01-T4 shared helpers under the X01 #500): define install as an observable (dependency install + migrate + staged host launch) with itskind, or mark the cellunknowngated on KEL-141.)ecosystem packages loaded at draw.io module top level: electron-store, electron-log, electron-context-menu, electron-updater— Their Electron member requirements are owned only by a decision (X03-A6 (Should electron-store / electron-log / electron-context-menu (unmodified, corpus-pinned) form apackagepanel in the compat corpus? #414)), an inventory line in X03-T2 (task(runtime): native addon policy record — KEL-78 four-outcome tree with KEL-215-shaped evidence rows, limited to corpus demand (Zettlr nodehun; fsevents declared without an import site) #503) and PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420). contextMenu({...}) (electron.js:169) and autoUpdater.logger.transports.* (:82-83) execute unguarded at import; any missing member aborts module evaluation. (suggested: PANEL-P3 (PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420) output becomes a named artifact consumed by F01-T4 (feat(app): host-minted session facts at spawn for synchronous app getters (getPath, getVersion, getName/name, getAppPath, getLocale, isPackaged) and the declared role environment — legacy path values #452), F06-T4 (feat(native): macOS application menu — Menu.buildFromTemplate + setApplicationMenu with host-side role execution; role close routed through the vetoable close path; role quit held to a recorded diagnostic until F06-T16 #480), F09-T1 (feat(update): inert electron-updater 6.8.9 adapter for the draw.io proof (import-time surface, recorded no-op setFeedURL, honest check outcome) #491) and 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) (add edges).)webContents 'before-input-event', webContents.pasteAndMatchStyle, BrowserWindow optionicon, app.name, app.disableHardwareAcceleration— Called or registered on the draw.io window-creation path (electron.js:808-816, :720, :2020, :166) but covered only by fog lines or a decision ticket (F08-D6 (What can getGPUFeatureStatus/getGPUInfo/disableHardwareAcceleration honestly report per engine? #408)). Registration must not throw; behaviour needs a recorded ▲. (suggested: F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) / F03-T2 (feat(webContents): first-proof macOS webContents facade — host-minted id, loadURL(file://), did-finish-load, did-navigate on commit, destroyed, registration-safe members #459) member lists (L0 typed members with scoreboard rows).)Dock (class, 11 members, macOS), CommandLine (class)— Named only in F01-EPIC (compat(app): Electron app lifecycle, single-instance, session facts and process shim over host-owned lifecycle #444) scope; Dock has no ticket, no never row and no out-of-scope line although macOS is the first-proof platform. No corpus call site found for either. (suggested: F01-EPIC (compat(app): Electron app lifecycle, single-instance, session facts and process shim over host-owned lifecycle #444) out-of-scope line (zero demand) — no new ticket.)F02 structures: BaseWindowConstructorOptions, Point, Rectangle, WindowSessionEndEvent, ScrubberItem, SegmentedControlSegment, JumpListCategory, JumpListItem, ThumbarButton; classes TouchBarButton, TouchBarColorPicker, TouchBarGroup, TouchBarLabel, TouchBarOtherItemsProxy, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer— Not named in any issue. TouchBar*/JumpList*/Thumbar* are covered only by a class-level out-of-scope sentence ('TouchBar (11 classes)', 'JumpList/Thumbar/Task structures'); Point/Rectangle/BaseWindowConstructorOptions/WindowSessionEndEvent have no disposition, and Rectangle is the return shape of getBounds/workArea used by draw.io. (suggested: F02-T2 (feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449) (Rectangle/Point/constructor options as member shapes); the rest enumerated in F02-EPIC (compat(window): BrowserWindow over a host window registry — host-minted identity, cancelable close, constructor triage (macOS first proof) #447) out-of-scope.)F03: webFrameMain (module), ColorSpace, InputEvent, KeyboardInputEvent, MouseInputEvent, MouseWheelInputEvent, NavigationEntry, PostBody, PreloadScriptRegistration, PreloadScript, PrintToPDFMargins, PrintToPDFOptions, PrinterInfo, Referrer, UploadData, UploadFile, UploadRawData, WebSource, SharedTextureHandle, SharedTextureImportTextureInfo, SharedTextureImportedSubtle, SharedTextureImported, SharedTextureSubtle, SharedTextureSyncToken, SharedTextureTransfer— Not named in any issue. SharedTexture* are implied by the 'sharedTexture/OffscreenSharedTexture' never row and print structures by F03-D6 (How are print/printToPDF/devtools mapped per engine while release policy stays closed? #397), but nothing enumerates them. The epic title promises 'preload registration' yet no ticket covers PreloadScript/PreloadScriptRegistration (session.registerPreloadScript). (suggested: F03-EPIC (compat(webContents): navigation events, guard-first navigation policy, window-open handler, executeJavaScript (consuming the F04-T11 endpoint value codec); devtools/print mapping #457) never/out-of-scope enumeration; PreloadScript* to F07-T1 (feat(renderer): app preload runtime on macOS — separate app content world with its own world-scoped handler (PANEL-D21 A), document-start ordering, sandboxed require map from pinned source, renderer process object (env empty), preload-path containmen #484) or an explicit ✘ row.)F04: IpcRendererEvent, IpcMainServiceWorkerEvent, IpcMainServiceWorkerInvokeEvent— Covered only by F04-T5 (task(ipc): scoreboard rows for deferred (MessageChannelMain, MessagePortMain, utilityProcess, UtilityProcess, parentPort, ipcRenderer.postMessage/sendToHost, IpcMainEvent.ports) and documented-never (IpcMainServiceWorker family, exposeInIsolatedWorld #468)'s blanket 'rows exist for every entity'. IpcRendererEvent is the first argument of every ipcRenderer.on listener in the draw.io preload (first-proof surface) and belongs with the implementation, not a parked rows ticket. (suggested: IpcRendererEvent → F04-T4 (feat(ipc): contextBridge.exposeInMainWorld value table + ipcRenderer send/on facade + IpcRendererEvent in the app content world (draw.io first-proof slice) #467); the two ServiceWorker events stay in F04-T5 (task(ipc): scoreboard rows for deferred (MessageChannelMain, MessagePortMain, utilityProcess, UtilityProcess, parentPort, ipcRenderer.postMessage/sendToHost, IpcMainEvent.ports) and documented-never (IpcMainServiceWorker family, exposeInIsolatedWorld #468).)F05 structures: BluetoothDevice, HIDDevice, SerialPort, USBDevice, CertificatePrincipal, Certificate, Cookie, ExtensionInfo, Extension, FilePathWithHeaders, FilesystemPermissionRequest, MediaAccessPermissionRequest, OpenExternalPermissionRequest, PermissionRequest, MimeTypedBuffer, ProtocolResponseUploadData, ProxyConfig, ResolvedEndpoint, ResolvedHost, ServiceWorkerInfo, SharedDictionaryInfo, SharedDictionaryUsageInfo, SharedWorkerInfo, WebRequestFilter, WebSocketOptions, WebAuthnAccount— Not named anywhere; the only cover is F05-T6 (task(session): publish scoreboard rows for every F05 entity not owned by another ticket (never / ▲ / ✘ / unknown, including strict net unknown and proxy assignment) #475) AC1 'Every F05 entity has a scoreboard row' — an unenumerated blanket in a Tier-3 rows ticket. WebRequestFilter is the argument shape of draw.io's onBeforeRequest({urls:['file://*']}) (electron.js:1010) and belongs to F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473). (suggested: WebRequestFilter → F05-T4 (feat(webview): macOS file:// read containment to the app code directory + host CSP injection, with committed-URL identity preserved (first proof) #473); device structures → F05-EPIC (compat(session): webRequest recorded no-ops behind macOS file:// containment + CSP (first proof); custom schemes, Session = KEL-135 profile and net.online next; permission facade parked #469) out-of-scope list; remainder enumerated in F05-T6 (task(session): publish scoreboard rows for every F05 entity not owned by another ticket (never / ▲ / ✘ / unknown, including strict net unknown and proxy assignment) #475).)F06 structures: ActivationArguments, ClipboardBookmark, DesktopCapturerSource, NotificationResponse, PaymentDiscount, ProductDiscount, ProductSubscriptionPeriod, Product, SharingItem, ShortcutDetails, Transaction, UserDefaultTypes— Covered only by F06-T6 (task(native): scoreboard rows with status and tracking for every F06 entity and member not owned by an implementation ticket (Notification, safeStorage, globalShortcut, power, systemPreferences, MAS/APNs, ShareMenu, desktopCapturer and their structur #482) AC1's blanket row promise ('Product' matches only an unrelated word in X01-EPIC (program(conformance): evidence rules and differential oracle harness — one Electron pin per corpus, shared corpus-manifest owner, red-until-implemented cells, pinned Electron recorder, Keld replayer, comparator, lanes #493)). All have zero corpus demand. (suggested: Enumerate in F06-T6 (task(native): scoreboard rows with status and tracking for every F06 entity and member not owned by an implementation ticket (Notification, safeStorage, globalShortcut, power, systemPreferences, MAS/APNs, ShareMenu, desktopCapturer and their structur #482) or F06-EPIC (compat(native): first-proof dialog, application menu and display/theme facts for draw.io on macOS (legacy profile); shell, clipboard/nativeImage, Tray and the remaining native modules as tracked next/parked slices #476) out-of-scope.)F08 structures: CPUUsage, CrashReport, EnableHeapProfilingOptions, MemoryInfo, MemoryUsageDetails, ProcessMemoryInfo, ProcessMetric, TraceCategoriesAndOptions, TraceConfig, GPUFeatureStatus— No ticket, no never row, no blanket row promise in F08 (GPUFeatureStatus appears only in decision F08-D6 (What can getGPUFeatureStatus/getGPUInfo/disableHardwareAcceleration honestly report per engine? #408)). Zero corpus demand. (suggested: F08-EPIC (compat(diagnostics): engine process-gone and hang events, F08 scoreboard rows, parked crashReporter / process-stats / getAppMetrics facades (contentTracing never) #487) out-of-scope enumeration (or F08-T2 (task(diagnostics): publish F08 scoreboard rows with explicit status and rationale (crashReporter, contentTracing, ten structures, process diagnostic getters, getAppMetrics, GPU getters); no facade code #489) if it is ever un-parked).)EPIC-scope-only entities: BrowserView, ImageView, View, WebContentsView, Task, WindowStatePersistence, Debugger, NavigationHistory, sharedTexture, WebFrameMain, OffscreenSharedTexture, Cookies, WebRequest— Covered by epic scope / never / fog lines only — acceptable as dispositions except WindowStatePersistence (fog, undecided) and WebFrameMain: IpcMainEvent.senderFrame returns a WebFrameMain whose.urldraw.io reads on every IPC (electron.js:694-700), so the first-proof needs a WebFrameMain subset that the epic marks out of scope 'beyond senderFrame' without a ticket member. (suggested: F04-T3 (feat(ipc): ipcMain listener facade + webContents.send routing + IpcMainEvent sender/senderFrame/reply over the el control channel (draw.io first-proof slice) #466) member list: WebFrameMain {url, origin} subset.)
Counts: 10 duplicate/one-owner findings, 19 edge problems, 12 invariant findings, 17 quality findings, 15 ambiguity findings — each posted on its owning issue.
- added sub-issues
on Oct 6, 2026 - added a commit that references this issue
on Oct 6, 2026 - added 4 commits that reference this issue
on Oct 7, 2026 Generated by an AI agent (Claude Code) on behalf of @0monish.
Status while the owner is away (2026-10-07)
Done, with evidence on the issues:
- PANEL-P1 PANEL-P1 (decided 2026-10-07): worker-owned single link (arm B) passes the link-drain gate #418: Design B, the worker-owned link.
- PANEL-P2 PANEL-P2 (decided 2026-10-07): async AppKit veto hooks match Electron 44.4.5 with six facade rules #419: the close and quit veto rules.
- PANEL-P3 PANEL-P3 (decided 2026-10-07): draw.io first proof is config + 1 edit under legacy #420: draw.io needs config plus one source edit, and none once feat(kipc): worker-owned single-link blocking host CALL transport for Bun roles (Design B, PANEL-P1 #418) #528 lands.
- docs(agents): record the #517 GitHub tracker-of-record rule #599 merged: the tracker-of-record rule.
- docs(engineering): add the Electron v44.4.5 compatibility reference #601 merged: the Electron reference doc.
Parked for the owner. Every spec PR has passed independent review; nothing below needs more agent work.
PR What Waiting on #610 Design B blocking-call transport (GH-527) owner approval of the text, then a non-pusher maintainer approval #612 evidence rules, including explicit unverified(GH-532)owner approval, then a maintainer approval #613 kipc channel table (GH-508) owner approval, then a maintainer approval #614 window registry and two-phase close (GH-531) owner D6 choice (A or B; B recommended), then owner and maintainer approval #611 arch 03 updater-seed fix (GH-584) a maintainer approval Held as instructed:
- No implementation (feat(kipc): worker-owned single-link blocking host CALL transport for Bun roles (Design B, PANEL-P1 #418) #528, task(ipc): implement the X05-T2 channel table in keld-ipc — every production consumer derives its id from it, generated TypeScript constants with a drift check, the three hand copies retired #597, feat(window): macOS host window registry with host-minted (WindowId, WindowGeneration), the @keld/api mirror primitive, and the BrowserWindow members draw.io's window path calls #449, feat(window): macOS two-phase cancelable close — host holds tao's CloseRequested, facade close/preventDefault, destroy, tombstone-before-closed, three exits and no host timer #450) before its spec is approved.
- No new specs (spec(profile): explicit Keld
legacyprofile key — one location, parse into admit(Legacy), ProfileState↔AuthorityProfile mapping, forfeit printing,unverifiedunscoreable by design #586, spec(guard): KEL-102 amendment — exact-literal windows.<w>.channels grants for webview principals and the single navigation-generation contract; revise the arch 03 el:* example #541).
Owner housekeeping:
- The startup disk is at about 99%. The agents freed about 3 GB of their own files.
- Re-trust
.codex/hooks.jsonin Codex/hooksafter docs(agents): record the #517 GitHub tracker-of-record rule #599.
Destination
A measured, versioned KELD Electron Compatibility Profile (Electron 44.x baseline, v44.4.5 pinned docs as oracle): drawio-desktop (then Zettlr) runs via
keld migrate+keld devwith config-only changes, scored per-API/per-app against committed KEL-74 denominators, with the facade's overhead measured against 01 §5 budgets and every divergence a tested ▲/✘. Route: GitHub issues (gyldlab/keld) + research-branch artifacts; this effort plans, it does not implement.Notes
v44.4.5(electron-api.jsonrelease artifact: 180 entities, 2,128 raw members, ≈1,941 direct members after inheritance) is the conformance oracle. Keld-owned fixtures cite doc page + section; Electron's ownspec/tree is not run (research note 214).keld.compat.tsquirks flag or a scoreboard ▲/✘, never silent; percentages only in the KEL-74 claim shape{passed}/{N} of {panel} corpus {id}@{digest} ({kind}); measured / target / projection never blended.keld-core/keld-ipc; reuse existing owners (KEL-75/76/77/78/79/80/53/74/102/135/139–144); features need an approveddocs/agents/spec-template.mdspec. Linear (KELD) is at its free issue cap, so GitHub is the public planning surface and maintainers bridge to Linear.wayfinder(this map),research,prototype(LOGIC shape),to-tickets,triage(agent briefs),grill-with-docs; Keld routing via.agents/index.mdanddocs/agents/workflow.md. Paste prompts live in Prompt Tracker (0monish/prompt-tracker), never in a parallel taxonomy here.milestone:first-proof→milestone:next→milestone:parked;compat:tier-Nlabels are the architecture 04 §4 taxonomy, not pull order. Decision, research and prototype tickets write only to scratchpads and the research branch and are claimed by GitHub self-assignment; resolve one decision ticket per session (research may run in parallel), record the resolution as a comment, close it, and add one line below. Any ticket that writes to the Keld repository, conformance entries included, is claimed with thedocs/agents/workflow.md## Agent claimblock on its owning Linear issue (earliestcreatedAtwins); the GitHub assignee only mirrors that claim. A repo-writing ticket with no aligned Linear issue uses its GitHub issue as the tracker of record.needs-spectickets first produce the spec PR for human approval.FACT | INFERENCE | ASSUMPTION | UNKNOWN | BLOCKER; every open decision carries a decision packet (exact decision, determining evidence, alternatives with cost, new invariant, invariant at risk, falsifier, reversibility, one next action with owner); blockers are classified and converted into a bounded experiment, a primary-document receipt, an exact OS handoff or an approval packet; research that leaves a session is a copy-ready Prompt Tracker node in the existing taxonomy; the YAGNI test for every ticket is "can the first proof (drawio-desktop on macOS, explicit legacy profile, install + activation + the 4-step workflow) ship correctly without this?" and anything that fails it is parked, not designed; closure is never manufactured: a precise blocker outranks a fake pass. The doctrine restates rootAGENTS.md; it adds no instruction file and no fifth unique.66ccbbc, terminal artifactcde25f5e), so it blocks nothing; compat lanes consume KEL-142 (Done); repo-landing work needs a tracker of record (see the next note), a conformance entry first, and an approved spec where behaviour is added.## Agent claimcomment, earliest wins) and no Linear issue is created, because the workspace is at its Free-plan cap (275 non-archived issues against 250). Every GitHub ticket is linked from the nearest live Linear issue, titled with its number and tracker of record. Each ticket body names both. The repository instructions record this rule through docs(agents): record the #517 tracker-of-record rule in root AGENTS.md and the workflow claim protocol #520 (docs/agents/workflow.md§ Tracker issue and.agents/coordination.md§ GitHub tracker issue: push-access comments only, first-match states, nothing private on the public issue); until that change merges, cite Linear owner for repo-writing Electron-compat slices (owner decision: align to nearest Linear issue, else GitHub is the tracker of record) #517.to-ticketsandtriage, applied 2026-10-07). Tracer tickets use the to-tickets body (Parent / What to build / Acceptance criteria / Blocked by) plus Keld sections (negative controls, ownership and gates, change log). Each carries one category role (enhancement) and exactly one state role:ready-for-agent(fully specified; the latest Agent Brief comment is the contract),ready-for-human(needs an OS/device observation or an owner judgment; its brief says why),needs-info(waits on an open decision ticket; its Triage Notes comment lists what is still needed),triage(needs triage) orwontfix(superseded, closed as not planned).needs-specis a Keld modifier, not a state: the first deliverable is adocs/agents/spec-template.mdspec PR stopped for human approval. Decision tickets keep the wayfinder roles (wayfinder:research|grilling|prototype|task) and are claimed by self-assignment. New tickets were published in dependency order with native blocked-by links; every AI triage comment starts with the triage-skill disclaimer.research/electron-compat-map(never merged) holds the per-member compatibility matrix (compat-matrix.tsv), per-unit research notes with refuter verdicts, corpus demand scans, the perspective-panel rounds, the execution doctrine (DOCTRINE.md), the doctrine-audit results and adopted decisions (batch2/), and four judged single-file logic prototypes (prototypes/: window lifecycle, IPC bridge, migrate report, compat-matrix cell; open by double-click).{passed}/{N} of {panel} corpus {id}@{digest} ({kind}); no committed product denominator exists, so no percentage (not even 0%/100%) may be published. Every evidence record carries authority_profile (StrictBun | SandboxedAddonWorker | LegacySandboxOff | UserApprovedToolChild) and engine.Electron surface census (direct members after inheritance, v44.4.5)
Corpus demand (shallow clones 2026-10-06): draw.io Desktop (electron ^44.2.0) uses app, BrowserWindow, ipcMain/ipcRenderer, contextBridge, Menu, dialog, shell, session, screen, clipboard, nativeImage, nativeTheme,
<webview>, electron-updater, electron-store, electron-builder; Zettlr (electron ^43.6.0) adds protocol.handle (customsafe-file://), Tray, net, Notification, systemPreferences, webUtils, 187invokecall sites,sendSync×6, native chokidar/fsevents/nodehun.Decisions so far
userDatalive under the strict profile: guard grant root or KEL-78 role-private container?: Choose (a) and park it.keld migrateshould print, for strict: 'userData is role-private storage;windows.<w>.channelsgrant vocabulary and its evaluator (no live evaluator exists; KEL-102 and KEL-80 do not own it)?: Option A: amend the KEL-102 spec with one scoped task unit for per-window channel grants;app.systemliterals evaluated with the existing matcher?: Adopt A. Current evidence determines it: the owning spec already shows the shape, the live matcher allows and denies it correctly with followable fix text and no accidental wildcard (probe), and D5 forbids C and D.confirm:https) vs exact literals only — permission-model decision (joint with X04-D4): Option A is the standing behaviour: exact literal origins only;keld migratereplacesfile:///custom-scheme origins: empty first launch (▲) or a one-shot host-side storage import?: Decided: A. The evidence that determines it: keld migrate is not live;electrondependency alias (X02) vs a Bun preload plugin for the five Electron specifiers (X03): Choose A as the single resolver; no plugin and no bunfig alias.processbroker row (KEL-76) with a child_process-shaped facade conforming to KEL-77 oracles — scope and owner: Close the open question as decided and parked.packagepanel in the compat corpus?: Resolve as: nopackagepanel and no package cells in the product denominator.https:is inert today; a distinct confirm-class token vs exact literals): Option A is the standing behaviour: exact literal origins only;Open decision tickets (frontier and blocked)
prototype,milestone:first-proofprototype,milestone:first-proofprototype,milestone:first-proofprototype,milestone:first-proofprototype,milestone:first-proofprototype,milestone:first-proofshow:false+ready-to-show+backgroundColorbe honoured on system webviews (hidden-paint oracle)? —prototype,milestone:nextresearch,milestone:nextprototype,milestone:nextprototype,milestone:nextresearch,milestone:nextprototype,milestone:nextresearch,milestone:parkedFirst-proof frontier (drawio-desktop on macOS, explicit legacy profile)
electronmodule — self-contained require()-able entry, four subpath exports, one object for ESM and CJS from app code and node_modules — Next: after X02-A1 and F01-T4; makeselectronresolve inside the four node_modules packages.Ordered by the doctrine audit (full rationale in its summary comment on this map); closed decisions were dropped from the list.
Epics (implementation tracks; sub-issues carry the tracer bullets)
electronmodule, main-role process facts before entry, explicit legacy profile key; native addons and child_process parkedKill conditions (test these first)
legacy; keld-native brokers fs.read/fs.write only. If strict never reaches the headline app, legacy becomes the de-facto default and unique feat: land Phase 2 CLI, kipc, GitHub CI, and dual-license files #2 (zero ambient OS authority) erodes. → experiment: E1 (≤1 day, scratchpad): run draw.io's main under Bun 1.4.2 with a throwing @keld/electron stub and a Node-API tracer over install + activation + the 4-step primary_workflow; classify every fs/net/child_process row as scopable to a dialog-minted path grant, scopable to a declared role, or unscopable (execFile at the print/convert path, attrib.exe spawns are Windows-only); also lists every pre-ready API call the import needs (settles the boot-static descriptor). → fallback: Publish the first proof under explicitly declared legacy with every unscopable call listed as a fix-it and authority_profile LegacySandboxOff in each record; headline wording is 'brokers correct, containment forfeited' and never 'default-deny demonstrated for draw.io'; open the strict path (node:fs → FsBroker facade, child_process → declared role or ✘) as its own approved spec consuming KEL-78/KEL-140/KEL-143; never auto-select legacy from Electron options.unknown; any preload change Zettlr would need is disclosed as a code change.Forbidden claims until measured
{passed}/{N} of {panel} corpus {id}@{digest} ({kind}).unverifiedis the live state on every OS.Not yet specified
WindowStatePersistence) mappingbefore-input-event+pasteAndMatchStyleengine hooks (draw.io) — new engine hooks not derivable from navigation signalszoomFactor,setVisualZoomLevelLimits)beforeunloadprimitive (0 demand)keld doctor --web-compatscopeOut of scope
Adopting the mattpocock skills tracker config inside the repo (
docs/agents/issue-tracker.md, triage labels): parked. It is an agent-instruction change that needs the.agents/instructions.mdprotocol (budget-neutral router edit, change record, evals); the first proof does not need it.Any implementation in the Keld repo (crates, packages, docs): this effort plans; scratchpad prototypes only.
Creating GitHub or Linear issues; the orchestrator publishes.
Zettlr beyond the sendSync gating experiment (E4); Element and VS Code (KEL-51 north-star, separate showcase denominator).
Strict-profile draw.io (node:fs/child_process facades over brokers + OS sandbox): its own later spec consuming KEL-78/KEL-140/KEL-143.
Real updater activation and feed trust (KEL-53); PTY/node-pty facade (KEL-76); addon prebuild qualification (KEL-215); GPU/media guard (KEL-132).
Tier 2/3 surfaces (globalShortcut, powerMonitor, safeStorage, session subset beyond webRequest no-ops, protocol.handle, utilityProcess/MessageChannelMain mapping, /BrowserView, desktopCapturer, net) except where named as corpus demand facts.
Windows (WebView2) and Linux (WebKitGTK) migration proofs; the first proof is macOS only.
Reordering the product spine (Choose the end-to-end KELD experience to make real next #312) or re-litigating Research bounded Electron migration candidates #313/Choose the Electron migration proof and evidence standard #319/Derive the executable Linear critical path for the product spine #322/Narrow the product-spine bridge prerequisites to functional subsets #323/Decide the minimum KEL-132 and KEL-135 artifacts required by the product spine #325.
Running Electron's spec/ tree under Bun as an oracle (research 214 REFUSE) or copying its CI retry policy.
Publication-grade performance campaigns (≥20 sessions × 100k calls, product census); S0's RTT numbers are diagnostics only.
Re-pinning the Electron oracle to v44.5.1 or any later major.
Electron API surfaces with zero corpus demand (e.g. beforeunload, tag) beyond recording ▲/✘ with the 0-demand fact.
(F01) Handoff/continuity macOS APIs beyond documenting ✘ (zero corpus demand)
(F01) Windows shutdown-block APIs beyond the documented ▲
(F02) TouchBar (11 classes, macOS) until a corpus app needs it
(F02) JumpList/Thumbar/Task structures (Windows) until a corpus app needs it
(F02) multi-view (View/WebContentsView tree) — Tier 3
(F03) WebFrameMain frame-tree APIs beyond senderFrame (zero demand)
(F04) MessagePortMain facade implementation (KEL-75 T5, after a pinned-oracle fixture)
(F05) Device choosers (HID/USB/serial/Bluetooth) — documented-unsupported, no broker, no principal
(F06) TouchBar (macOS) and JumpList/Thumbar (Windows) until demand appears
(F06) inAppPurchase (MAS) and pushNotifications beyond ✘ rows
(F07)
webFramefull surface beyond the zoom subset (zero demand)VS Code migration (north-star stress lane, separate showcase denominator — KEL-51, ROADMAP).
Clean-room browser engine, native GPU core, mandatory shared memory, extension marketplace mirror (linear-roadmap-mapping.md).
remotemodule, arbitrary Chromium/V8 flags,nodeIntegration: truerenderers, production CDP (documented-never, arch 04 §4 Tier 3).Prior decisions consumed