Running log of problems hit during implementation, P-nnn, sorted by number. A problem gets a row here; a long one also gets its own note (P-nnn Title, from Problem Template). P-001–P-003 were logged first; numbering continued at P-032 because R-01 … R-31 were reserved for the anticipated problems in the Problem Ranking (until 2026-10-01 those were also called P-nn). Take the next free number.

Not here: the external audit’s twenty GitHub issues — they have their own page, Audit 2026-09-23 (overlaps: #13 = P-069, #17 ⊃ P-086, #19 ⊃ the rest of P-037).

IDTitleStatusPhase
P-001 Graph surface in desktop webviewWhere does the wgpu surface come from inside the desktop webview?open2 → 5
P-002 Dioxus mount point and full-height layout#main mount div broke the full-height workbenchresolved0
P-003 dioxus-workbench theme variablesDark palette override didn’t applyresolved0
P-032 Release-build observabilityNo inspector/stdout in compiled desktop builds → file log, panic hook, JS error forwarding, Diagnostics panel (Debugging and Logging)open1
P-033 WebKitGTK WebGPU flagEnable WebGPU feature via raw webkit2gtk-sys call; measure (Linux Desktop Setup)open2
P-034 Hydration mismatch from cfg! in markupFullstack SSR renders on the server; a cfg!(wasm32) placeholder showed the native text on web. Rule: no compile-time platform branches in rendered output (Milestone 1 - Implementation Log)resolved1
P-035 .gitignore ignored outside git reposignore crate defaults to require_git(true); set false so an editor behaves the same before git initresolved1
P-036 Server-function name clash#[post] fn query(.., query: Query) fails: the generated stub calls query(...) and the parameter shadows it; renamed with suffixesresolved1
P-037 Whole-document change eventsJS reported the full text per keystroke; O(n) per key. Resolved 2026-09-21 (spec 018): the view reports splices (UTF-16 offsets, old text, document order), Rust applies them to a mirror and the document takes the mirror; a 3 MB file registers a keystroke in 87 ms. Remaining O(n): the LSP didChange still sends the full text, and the document is a String (rope later)resolved2
P-038 Desktop link error -lxdodx run in packages/desktop fails at link time: muda needs libxdo.so; install xdotool (Arch) / libxdo-dev (Debian). Docs had it as optional — corrected in Linux Desktop Setupresolved1
P-039 No native folder dialog in Milestone 1By design (out of scope); now rfd (xdg-portal backend) behind WorkspaceConfig::pick_folder on desktop, wired to File → Open Folder…, Ctrl+O and the Explorer button. Requires xdg-desktop-portal + a backend on Linux (Linux Desktop Setup)resolved1
P-040 Custom title bar on an undecorated windowDecorations off; drag/resize/minimize/maximize/close via dioxus::desktop::window() callbacks passed into ui::Frame. Maximize icon doesn’t flip; Wayland resize depends on the compositorresolved (gaps noted)1
P-041 u64 through JSON loses precisionVersion(u64) hashes > 2⁵³ became floats on the BroadcastChannel path and failed to deserialize, silently killing the receiver loop. Version now serialises as a hex string; receiver loops skip bad messages instead of exitingresolved1
P-042 Moved echo check used the wrong field”ignore my own messages” keyed on from, but Moved.from is the origin, not the sender — the origin never closed its copy. SessionMessage::sender() returns to for Movedresolved1
P-043 dx serve missed a Rust changeA change in ext-api was not rebuilt by a long-running dx serve (no rebuild line in the log); restart dx when a non-rsx change seems not to applyopen (tooling)1
P-044 Cross-window drag didn’t work by handThree causes: (1) Firefox never starts an HTML5 drag unless dragstart calls dataTransfer.setData — Dioxus’s synthetic handler can’t, so a native listener on the handle now does; (2) web New Window opened a tab, and a background tab can’t be a drop target — now a popup window; (3) whether WebKitGTK delivers an HTML5 drop across two webviews of one process is unverified, so the offer now survives dragend as a “Move it here” banner in the other window (grab → release → click). Verified on web with a real mouse drag; desktop still needs a manual runresolved (fallback)1
P-045 Cross-window drag and dropFirefox “Server Not Found: wb-tab-editor-…” (unhandled tab drop navigates); desktop drag + folder sync unverified. Tab drag is now the gesture, stray drops inert, desktop seeds sources from the registry, session log + “N windows” status for diagnosisresolved (desktop confirmed by hand)1
P-046 Random element ids vs hydrationGraph panel ids derived from the random WindowId differed between server render and client; getElementById failed silently. Deterministic ids for anything an eval looks up (Milestone 2 - Implementation Log)resolved2
P-047 Eval messages lostSent-before-awaited and sent-then-returned messages are dropped; also an eval mounted from an effect that writes a signal it reads. Pattern: init handshake, park on recv until destroy, mount from onmountedresolved2
P-048 dx serve misses Rust changes (3×)Non-rsx changes to a const &str script were not rebuilt; restart dx each time (~3 min)open (tooling)2
P-049 No GL in headless Firefox; wgpu hangs without a contextProbe WebGL2/WebGPU before create(), show the reason; rendering verified only in real browsersresolved (fallback)2
P-050 wgpu 30 API driftSeveral descriptor fields/enums changed; read the registry sourceresolved2
P-051 Graph view jumped back after draggingEvery layout settle re-fit the camera, and node drags reheat the layout; dragged nodes were also unpinned and drifted. Auto-fit now only after a new graph/relayout until the user moves the view; dragged nodes stay pinnedresolved2
P-052 New side panel stole the active tabAttaching a late panel activates it; default layout lists explorer, links explicitlyresolved2
P-053 dragend missing after a workbench dropFirefox drops the tab on the workbench’s own drop zone and never fires dragend; a drop in the source window now ends the session drag tooresolved2
P-054 Typst preview compiled foreverThe preview effect read busy() reactively and set it after each compile, re-triggering itself; busy.peek()resolved3
P-055 Terminal Ctrl+clickRow index must come from .xterm-rows geometry; long paths wrap so neighbour rows are joined; xterm + headless Firefox swallow real modified clicks — the E2E dispatches a synthetic clickresolved3
P-056 dx serve restartsNon-rsx Rust changes still need a restart of dx (~2–3 min). Never pkill dx: it also kills Daniel’s own dx serve (desktop) in another shell — on 2026-09-19 that took his desktop app down while he was trying the flow editor (WebKit exit segfault, P-061 signature, at 12:14 and 12:31). The test server is now started and stopped by PID with packages/web/tests/e2e/serve.shopen (tooling)3
P-057 Websocket<String, String> in a server fnThe #[get] macro turns a bare String type parameter into str (DeserializeOwned not satisfied); wrap in a Frame(String) newtyperesolved3
P-058 LSP progress text overflowed the status barrust-analyzer’s $/progress messages are n/m: <long path>; cut at the first : in lsp::sessionresolved3
P-059 E2E fixture driftgraph.mjs saves a wiki-link to Another into Home.md; a later links-sqlite.mjs run sees one phantom too many. Restore the fixture between suites (README). Milestone 6: fixture.sh rebuilds the fixture deterministically and the regression run resets Home.md/.moonkale/ per suiteresolved3
P-060 Database internals invisible in the graph viewDaniel: the Graph tab kept showing the folder; the source picker defaulted to index and Show in Graph did not raise the Graph tab (same tile as the table editor). Opening a graph database now selects it in the picker; Show in Graph dispatches Command::ShowPanel("graph"), which the shell applies via PanelLayout::reconcile + activateresolved3
P-061 WebKitWebProcess SIGSEGV in NVIDIA EGL (desktop)Core dumps of WebKitWebProcess inside libnvidia-eglcore, called from WebKitGTK’s compositor. Pinned down (2026-09-18): the web process segfaults while tearing down a live WebGL context — every time the app exits (graceful close included: Daniel’s 13:13 dump was a build with the pagehide handler, closed 13 s after launch) or dx serve kills it for a rebuild. Not a startup crash; not the DMA-BUF renderer (the crashed process had WEBKIT_DISABLE_DMABUF_RENDERER=1); losing the context from JS doesn’t help because WebKit’s own teardown is what crashes. The process is exiting anyway, so the only effect is a 10 MB dump and a KDE crash popup per run. Fix: desktop/main.rs sets the soft RLIMIT_CORE to 0 when the NVIDIA driver is loaded (inherited by the WebKit children; MOONKALE_COREDUMPS=1 keeps dumps for real debugging). Verified: killing the dx-built app produced a dump before, none after; Daniel confirmed no KDE crash popup under dx serve (only a SIGSEGV none journal line remains, which the kernel writes regardless of the limit)resolved (confirmed)3
P-062 Graph view showed only a database’s schemaDaniel expected the actual people/cities with their relations. Databases now have Data / Schema / Query modes (Data is the default after opening one): Query::All { kinds: [Vertex] } returns nodes + relations from the source; vertices are coloured per label (node table), relations per name, with a legend in the toolbar. Vertex keys carry the label (v:Person:0:3) so the host colours without a lookupresolved3
P-063 Graph panel loads racedAdding a source re-ran the load effect before the picker switched; the slower remote index reply overwrote the trace result. Generation counter: only the newest load publishesresolved4
P-064 Agent borrowed across awaitsStreaming into &mut Agent for a whole exchange conflicts with the panel reading its audit log; an audit mirror signal + busy fence (clippy lint allowed with the rationale)resolved4
P-065 Global shortcuts need focus inside the frameThe key handler is on the frame div; Ctrl+Shift+F did nothing when body had focus. Milestone 5: a document-level listener (GLOBAL_KEYS eval in Frame) forwards Ctrl-combos whose target is the bodyresolved4
P-066 Port 8080 taken by the desktop dev serverDaniel’s dx serve (desktop) holds 8080; the web E2E suites take PORT and the test server runs on 8090. Also cleaned up leaked server-* processes from old dx runsresolved4
P-067 Mistral: unavailable models look rate-limitedModels the key cannot use (devstral-*, mistral-small-latest) return 429 “Rate limit exceeded”, not 404. mistral-code-latest / codestral-latest + mistral-embed work through the OpenAI-compatible providerresolved (noted)4
P-068 Graph nodes lost their red channelSince Milestone 2 every node looked cyan/teal regardless of kind: vertex_attr_array! packed the colour attribute at offset 12 while NodeInst pads radius to 16, so the shader read (pad, r, g, b). Spotted from Daniel’s screenshot where the legend colours and the drawn nodes disagreed. Explicit attribute offsets now; renderer rebuilt; Daniel confirmed the colours on desktopresolved (confirmed)4
P-069 terminal.run has no timeoutThe tool ends the shell after the command so the output stream closes, but an interactive command waits forever (no timer primitive on wasm without a JS dependency). Output capped at 200 KB. Follow-up: cancel button on the tool cardopen5
P-070 dx serve served a stale JS bundleAfter npm run build rewrote milkdown.js, the page kept requesting the old content-hashed asset. Restart dx after rebuilding a bundleopen (tooling)5
P-071 Hydration shows server-side settings brieflyThe Settings panel derives the LLM scope badge from env_overrides(), which the server has and the wasm client does not; the server markup stays until the first client re-render (same family as P-034)open (cosmetic)5
P-072 Desktop: last folder not reopened at launchDaniel: the key was remembered but not layout/tabs. Cause 1: nothing reopened the last folder at start — restore only ran after a manual open. Now WorkspaceConfig::reopen_last_folder (desktop true) opens recent_folders[0] after the user settings load, from the frame’s onmounted. Cause 2 (suspected, not confirmed): during my desktop runs the index build stalled at startup — but the KDE session was locked at the time and WebKit suspends invisible pages, so those runs prove nothing. Trace lines (settings: …, open_folder: …) show the sequence in the dx log. Daniel confirmed: the desktop app reopens the last folder as leftresolved (confirmed)5
P-073 dioxus-flow handle geometry lags its layout animationAfter Layout the handle positions used to validate a connection are stale for a few frames, so a drag started right away can miss; also the third palette column sat under the tile splitter at 1500 px. Blocks are placed on a 165 px grid; the E2E wires before laying out. Real fix needs a settled-layout callback from dioxus-flowopen (upstream)6
P-074 Controlled workbench layout is rendered reconciledPanelWorkspace renders a reconciled copy of the controlled signal: newly attached panels and the auto-activated document tab appear before any write to the application’s signal, so reading the front tab from the signal was stale. The phone bar reconciles with the current placements before reading or activating (as ShowPanel already did)resolved6
P-075 dioxus-flow debug warnings in the desktop logWith a flow open, dioxus-flow 0.1.2 logs Changing the props of Style {} (its document::Style { {STYLE} } re-renders) and A Copy Value created in ScopeId(…Canvas) … used in …Flow (its Canvas signals are read by the parent Flow through attach_core) on every render — 15× / 14× in Daniel’s error7.md. Both are upstream, debug-only and harmless here (no failed reads observed); the file’s abrupt end was dx’s SIGKILL relaunch after a Rust edit, not a crash. Worth an upstream report with the next dioxus-flow issue (P-073)open (upstream)6
P-076 Spawned task dropped with its componentThe Explorer’s inline field set edit = None (unmounting itself) and then spawned the create/rename; the task died with the scope and nothing happened, silently. spawn_forever for work that must outlive the component that starts itresolved7
P-077 serde(rename_all) on an enum does not rename variant fieldsThe CodeMirror bridge sent endLine for CodeActions, Rust expected end_line; the parse error ended the bridge’s recv loop so every later editor event was lost. Per-variant rename_all now, and an unreadable message is logged and skippedresolved7
P-078 Completion source never askedThe bundle’s completion source registered its resolver and forgot to call onCompletion; nothing visible failed. Found by loading the bundle in a bare HTML page (cm-test.html) — the fastest way to test the JS side without the appresolved7
P-079 Click before hydration after a form redirectAfter /login the server-rendered page is shown before the wasm hydrates; a click on Open in that window does nothing. Tests wait for networkidle; a loading hint for humans is a follow-upopen (cosmetic)7
P-080 The type-mismatch diagnostic is cargo-check’s, not rust-analyzer’sDriving rust-analyzer 1.98 directly (ra-probe.py): didOpen yields the mismatched types error from flycheck (cargo check), and didChange republishes only native diagnostics (syntax errors) — so fixing the type error does not clear the gutter until the next check, which runs on save. lsp.mjs now saves; the code panel’s Ctrl+S path sends didSave like the toolbar button (it did not before — one save_now callback for all three paths)resolved7
P-081 Long E2E batches time out under loadIn a 23-suite batch, phone and auth hit 30 s timeouts that never reproduce alone or in pairs: by then several rust-analyzer instances (from lsp/lsp2) and, for auth, a second dev server share the CPU. Both pass on rerun; treat a single timeout late in a batch as load, rerun the suite, and only then debugopen (tests)7
P-082 Firefox headless has no WebGLEven with webgl.force-enabled and software rendering prefs, headless Firefox exhausts its GL drivers; the graph renderer was never exercised by a test until Milestone 8. Chromium headless with --use-angle=swiftshader --enable-unsafe-swiftshader --ignore-gpu-blocklist provides WebGL2 (graph3d.mjs); the GL canvas cannot be read back after present, so the suite reads the label overlay and compares screenshotsresolved (tests)8
P-083 Playwright :has-text() is a substring matchlabel:has-text('Name') matched “Secret name” first and the test typed a user name into the secret field; use :text-is() for exact labelsresolved (tests)8
P-084 wgpu 30 depth-state fields are Optionsdepth_write_enabled: Some(true), depth_compare: Some(CompareFunction::LessEqual) — the docs’ examples still show plain valuesresolved8
P-085 Edits anchored on stale textMulti-edit scripts kept failing after cargo fmt reshaped the anchors; each retry cost minutes. Rule: re-read the exact lines right before editing, one file per script, and format lastopen (working rule)9
P-086 Compaction hides old renamesAfter EntityLog::compact, renames before the boundary are folded away; text_at correctly starts from the snapshot keyed by the current id, but the History panel’s key lookup for very old events relies on Event.key (carried since Milestone 8)noted9
P-087 Android WebView drops head elements from the first renderdocument::Stylesheet in a panel that is part of the first frame never reaches <head> on Android (the Explorer, Agent and Git panels were unstyled; panels mounted later were fine). Desktop and web are unaffected. Fix: moonkale_ext_api::Stylesheet — an effect that inserts the <link> itself through document::eval if it is missing, re-run when Workspace::assets_epoch bumps (the frame bumps it from onmounted). Every panel uses it nowresolved9
P-088 import() of an asset URL fails on AndroidThe renderer’s import(JS_URL) threw “base URL is about:blank because import() is called from a CORS-cross-origin script”: eval scripts on the WebView have no base URL. Fix: resolve every asset URL against document.baseURI || location.href before import() and init({ module_or_path })resolved9
P-089 WebGPU device creation never completes on the Android WebViewWebView 125 advertises navigator.gpu, requestAdapter succeeds, and create() then hangs (no error, no timeout from wgpu). Fix: the Graph panel passes prefer: "gl" when the UA is an Android WebView (Android + wv), and create(canvas, overlay, cb, prefer) → Renderer::new(.., gl_only) skips WebGPU. WebGL2 renders the graph at full speed for the vault sizes a phone holdsresolved9
P-090 sRGB surface format washes the graph out on GLOn WebGL2 the surface reported Rgba8UnormSrgb first; the shaders write linear colours, so the background came out grey and the nodes pale. Fix: Renderer::new picks the first non-sRGB format from surface.get_capabilities (falls back to the default). WebGPU on desktop/Chromium is unchanged (it already chose non-sRGB)resolved9
P-091 Graph auto-fit ran before the canvas had a sizeOn the phone the Graph tile is laid out after create() runs, so the layout settled and Camera::fit used a 1×1 canvas: scale clamped to 0.05, every node at the centre (screenshot android10). Fit fixed it by hand. Fix: resize() re-fits while auto_fit is still set (nobody has panned or zoomed), which also keeps a resized panel fittedresolved9
P-092 dx leaves stale hashed assets in the Android projectEvery dx build --platform android adds the new <name>-dxh<hash> asset to target/dx/mobile/release/android/app/app/src/main/assets without removing the previous one: after five renderer rebuilds the APK carried five graph_render_bg.wasm copies (38.8 MB instead of 23 MB). Workaround: delete that assets directory (or dx clean) before a release build; a release checklist item in Androidnoted9
P-093 Highlighting grammars live in the CodeMirror bundleThe rule “no language knowledge in JS” (JS Interop Boundary) assumed tree-sitter highlights from Rust; tree-sitter is native-only and the web client would need a server round trip per keystroke. Decision: highlighting is presentation — Lezer/legacy grammars ship in the bundle (languages.ts, +650 KB), Rust still picks the language id; symbols, links, LSP stay in Rust. The Rust-native editor (JavaScript Inventory) brings its own highlighter when it comesdecided10
P-094 onload on <img> never fires in dioxusload does not bubble, and dioxus delivers events through one delegated listener; the image viewer’s natural size stayed unknown. Fix: onmounted + an eval that awaits img.decode() and returns the size (an eval is a function body — an IIFE expression without return yields undefined, the second half of the same hour)resolved10
P-095 The per-session token showed up in the ssh terminal tabThe remote script printed MOONKALE_TOKEN? and then ran stty -echo; the desktop wrote the token as soon as it saw the prompt, the PTY still echoed, and the hex line appeared in the tab (and in the tee stream). Fix: echo off first, then the prompt, then read; the shim test’s tee output shows no token nowresolved11
P-096 dioxus::server panics without a public/ directoryserve_dioxus_application reads ./public at startup (Couldn't read public directory … No such file or directory) even when only the API is used; the uploaded server died silently until the tee output was printed. Fix: the remote script mkdir -p "$d/public" before exec; an empty directory is enough (the server then serves a default index.html and the API)resolved11
P-097 No display to run the desktop app on this machineThe only X server on :0 is sddm’s login screen (Daniel works through code-server); no Xvfb/weston. Consequence: desktop-only UI (the remote dialog) is verified by Daniel, and workspace logic behind it gets a VirtualDom harness test (ext-api/tests/remote_flow.rs: signals, spawn, phases — 1.2 s) — a pattern for later desktop-only featuresdecided11
P-098 dioxus’s server URL is a OnceLock — set_server_url after launch panicsdioxus::launch (desktop, fullstack) sets ROOT_URL to the dev-server address once; api::client::connect calling set_server_url for the SSH session panicked on the handshake thread (called Result::unwrap() on an Err value: "http://127.0.0.1:33581"), so the UI stayed at “starting the server…” — found on the real desktop once a display was available (the shim test set the URL first and never saw it). Fix: api::relay — a loopback TCP listener installed before launch as the permanent server URL, piping every connection (server functions and typed websockets alike) to the remote that is active, TLS with the WebPKI roots for https://; connect only sets the headers and the target. Unit test in relay.rs; the shim test and the desktop test install it the same wayresolved11
P-099 The desktop under my shell’s environment: Wayland protocol error 71, then a black WebKit window on X11Launched with the shell’s inherited variables the GTK Wayland backend died (“Error 71 (Protocol error) dispatching to Wayland display”); with GDK_BACKEND=x11 WebKit printed “Failed to create GBM buffer … Invalid argument” and rendered nothing (WEBKIT_DISABLE_DMABUF_RENDERER=1 renders, at +250 MB). Launching with env -i and only the session’s own variables (WAYLAND_DISPLAY, DISPLAY, XAUTHORITY, XDG_RUNTIME_DIR, DBUS_SESSION_BUS_ADDRESS) works natively on Wayland — the recipe for running the app from a script. The graph canvas looked black in those runs — not a rendering fault: P-100noted11
P-100 A big graph could not be seen whole — the zoom floor was too highThe Moonkale repository’s graph (2 851 nodes, ideal edge length 28 + 6·ln n ≈ 76 world units) spans more world units than a 0.05 minimum scale can put on a 700 px canvas, so fit clamped to 0.05 (only the middle of the graph in view — and the middle of a ring-shaped layout is empty, hence the “black” canvas of P-099) and the wheel could not zoom out further; Daniel zoomed out and hit the same floor. Fix: MIN_SCALE = 0.002 for both; the view also re-fits on every frame while the layout is still spreading, not only at settle. Verified in the desktop app: the whole graph, isolated-node ring included, fits the panelresolved11
P-101 A desktop dx serve is two gigabyte buildsA fullstack desktop app builds the client and a server binary (target/dx/moonkale/debug/web/server, 1.7 GB in debug) even though the desktop never runs that server; with debug = 2 (the default) each link is a gigabyte-plus and a feature change costs both builds — the 1 767 s Daniel saw after a pull (spec 023). Mitigation: [profile.dev] debug = "line-tables-only" + no debug info for dependencies; my own cargo runs use CARGO_TARGET_DIR=target/agent so they stop invalidating target/debug (178 GB, 2 370 incremental dirs when measured). Open: build the desktop without the server half (dioxus configuration)investigating11
P-102 Opening a markdown file in Rich mode marked it dirtyMilkdown’s parse → serialize round trip normalises bullets, escapes and blank lines and fired markdownUpdated once at load; the panel took that as an edit. Fix: the normalised text becomes the baseline after crepe.create() (reporting suppressed during load), only user edits are reported (spec 021)resolved11
P-103 The remote command goes through the host’s login shellssh host -- sh -c '<script>' is parsed by whatever shell /etc/passwd names on the host — bash, zsh, fish or nushell — and only POSIX shells understand '\''; on this machine (login shell nushell) the command did not even parse. Fix: the script travels as base64 inside the one argument every shell passes through unchanged (a single-quoted string without quotes or backslashes): sh -c 'eval "$(echo <b64> | base64 -d)"'; sh decodes and runs it with the PTY still on stdin. Verified against a real sshd with nushell as the login shellresolved11
P-104 Real ssh without -t echoed the token and let the remote server outlive the sessionWithout a remote PTY the script’s stty -echo is a no-op and the local PTY echoes what the desktop types (the token appeared in the tab, P-095 again); and killing the master ssh did not kill the remote server (no SIGHUP — it lingered after the session). Fix: -t: a remote PTY, raw mode locally, SIGHUP on close; verified with the private sshd (0 lingering processes after six sessions)resolved11
P-105 Remote port collisions when host and desktop are the same machineThe remote port was derived from the local one and landed in the ephemeral range, where a busy machine has thousands of TIME_WAIT sockets (16 000 here after a test batch): 3 of 5 sessions failed with “Address already in use”. Fix: a random port below the ephemeral range (20000–31999); a real listener there is the rare remaining case and the terminal tab shows the bind errorresolved11
P-106 “Stuck at MOONKALE_NEED_UPLOAD” in the app started by dx serveDaniel’s first real session: the host reported it had no server, and nothing happened. dx runs the app from target/dx/<app>/debug/linux/app, so server_binary()’s relative lookup found no dev server binary; the session went to Failed with only a status-bar line, while the host’s script kept waiting for the upload (up to 10 min). Fix: the lookup walks up from the executable and the cwd to the workspace root ([workspace] in Cargo.toml) and takes target/dx/web/{release,debug}/web/server; a failure is now also printed into the ssh terminal tab ([moonkale] remote session failed: …) and the master ssh is killed so the host stops waiting; the message says how to build a server binary. Verified: the release app launched from its bundle dir uploads and connects against the private sshdresolved11
P-107 Two dispatches in one tick keep only the lastWorkspace::commands is one (seq, Option<Command>) signal read by effects; show the terminal panel followed by new terminal in the same handler left the panel without a session (the second write replaced the first before any effect ran). Fix: ui::frame::open_terminal_in shows the panel, yields two renders (YieldNow, a future pending once), then dispatches NewTerminalIn. A queue on dispatch would be the general fix; noted for when a third case appearsresolved12
P-108 A task spawned from a closing dialog is cancelled with itspawn in the terminal chooser’s click handler belonged to the dialog’s scope; open.set(false) unmounted it and the delayed dispatch never ran. dioxus::core::spawn_forever for work that outlives the component that starts itresolved12
P-109 #[component] props need PartialEq — Rc<RefCell<…>> and fn-pointer structsthe macro compares every prop: NativeSession got a by-id PartialEq, AgentSessions (function pointers, one set per platform) a constant eq — comparing fn pointers is a lint for good reasonnoted12
P-110 Edits after cargo fmt silently missedtwo scripted text replacements targeted code rustfmt had reflowed in between and did nothing: the agent.on_server gate and the terminal routing each shipped once as a no-op until a browser suite showed the old behaviour. Verify a replacement changed the file (grep after), format before editingnoted12
P-111 makepkg links fail with undefined duckdb_* / ring_core_* symbolsArch’s default makepkg.conf has the lto option (-flto=auto in CFLAGS/CXXFLAGS): the C/C++ objects that DuckDB’s and ring’s build scripts compile become GCC LTO bitcode inside their static archives, which rust-lld cannot read. Fix: options=('!debug' '!lto') in packaging/arch/PKGBUILD; -bin has no build step. The same applies to any Arch package of a Rust crate with C++ dependenciesresolved13
P-112 The Rust terminal cut off its lower rows on desktopThe grid was sized from one get_client_rect at mount; when the bottom tile got its real height later, no onresize arrived in the webview, so rows (and the PTY size) stayed at the earlier, larger value and the bottom of the screen — the prompt — was outside the panel. Fix: re-measure on a 600 ms timer as well; the screen is bottom-anchored so an oversized grid drops top rows firstresolved14
P-113 Two tree-sitter runtimes cannot share a binarydioxus-code (the Rust editor) uses arborium-tree-sitter, moonkale-index used the tree-sitter crate; both declare links = "tree-sitter" and Cargo refuses (“only one package in the dependency graph may specify the same links value”). Resolution: the index uses arborium’s runtime and grammars (arborium-rust/-julia/-python, standard LanguageFns, identical node kinds — the extractors’ tests pass unchanged). Side effect worth having: the index’s parsers now compile to wasm tooresolved14
P-114 wasm link: undefined symbol: stderr from tree-sitter’s alloc.carborium’s own wasm.rs stubs malloc/free/str*/clock…; stderr and fprintf live in arborium-sysroot, which no Rust code references, so rustc never links it (an unreferenced dependency is dropped). cargo check passes, only the link fails. Fix: editors/code-native/build.rs compiles csrc/wasm_stubs.c (the two symbols) on wasm32resolved14
P-115 The lbug (LadybugDB) crate downloads its C++ library at build timeIts build script fetches liblbug-static-linux-<arch>-<variant>.tar.gz from GitHub (or builds Kuzu’s C++ with CMake, ~1 h) — fine on a developer box, impossible in the Nix sandbox and in a clean-chroot makepkg. Fix for Nix: a fixed-output derivation of the archive (flake.nix: liblbug) + LBUG_LIBRARY_DIR/LBUG_INCLUDE_DIR, which the build script honours (“external” mode). For the AUR’s clean-chroot build the same env pair would point at a source= entry with a checksum — not done yet (makepkg with network works). Nix-built GTK apps on a non-NixOS host additionally need nixGL for EGLresolved13
P-116 Connect to Server… did nothing on the phoneSame shape as P-108, missed in Milestone 12: ServerDialog set open=false and then spawned connect_server — the task belonged to the dialog’s scope and was cancelled when the dialog unmounted, so the button closed the dialog and nothing else (no request ever left the phone; the desktop had the same bug). The terminal chooser’s remember setting was lost the same way. Fix: dioxus::core::spawn_forever in both; a VirtualDom harness test (ui/tests/server_dialog.rs) records the form’s submit listener from the dom’s mutations, fires it and asserts the connect ran after the dialog closed — it fails on spawn, passes on spawn_forever. Verified on the Galaxy S10e against a LAN server (⇅ http://192.168.178.62:8443, the server’s 176-file folder next to the phone’s vault). Rule for the shell: a task started by a component that closes itself must be spawn_foreverresolved12
P-117 A memo that peeks never re-runsThe Agent panel’s folder memo read ws.sources.peek() and the render read sessions.peek(): no subscription, so the saved sessions were never listed and the first session did not render (“starting…” forever). peek is for event handlers and tasks; anything that must follow a value — memos, effects, render — reads with read()/(). Found by agents.mjsresolved15
P-118 Query::Children cannot list .moonkale/The folder source lists children through the ignore walker with hidden entries and .gitignore applied — right for the explorer, useless for the saved agent sessions under .moonkale/agent-sessions/local/. Added the ls text-query dialect (Query::Text{dialect:"ls", text: rel}): a plain read_dir, hidden included, root-jailed; Workspace::list_at uses it, other sources return nothingresolved15
P-119 On macOS, Ctrl+O/Ctrl+N acted as Cmd+O/Cmd+NEvery shortcut check was ctrl() || meta(), so Ctrl+letter — the Emacs cursor keys of every Mac text field — fired application commands. Fix: moonkale_ext_api::keys::primary (Cmd on a Mac, Ctrl elsewhere, never both) at every site, Rust and JavaScript; the Rust terminal sends control bytes for Ctrl only. Reported by a friend on a source build; fixed blind, no Mac to verify (spec 027)resolved (unverified on macOS)—
P-120 The first tagged release produced no release at allv0.1.0 (2026-09-22): Linux, Arch and Nix built, but the release job required every platform job, and three failed — so softprops/action-gh-release never ran and the repository had no release. Fixed before the tag by if: always() on the release job plus a note in the body listing the jobs that failed; the packages that did build are published regardlessresolved—
P-121 dx bundle --package-types msi nsis — “unrecognized subcommand ‘nsis‘“The flag takes one value and repeats: --package-types msi --package-types nsis. Clap read the bare nsis as a subcommand and the Windows job died before compiling anythingresolved, verified on the runner 2026-09-22 (the job now compiles)—
P-122 The macOS Intel job queued for 3 h and never startedruns-on: macos-13; GitHub retired that runner image, and a job requesting a retired label waits forever instead of failing. macos-15-intel is the Intel replacement (macos-14 stays for arm64)resolved, verified: both .dmg jobs green twice—
P-123 The Android job’s build failed with no error textdx build --platform android also builds the fullstack server binary for the host (mobile [x86_64-unknown-linux-gnu]), and that binary links WebKitGTK, GTK 3, libxdo and OpenSSL — ldd on target/dx/mobile/release/web/server lists them — because it is built from the same ui crate as the desktop app. The job installed no system libraries at all, so a *-sys build script failed early (crate ~151 of 1204), which is why the log ends mid-compile. Fix: the Linux job’s apt list plus cmake (LadybugDB compiles its C++ when the prebuilt download fails). --fullstack false does not skip that build — dx detects the crate’s default fullstack feature and builds the server anywayresolved (unverified on the runner)—
P-124 DX_BUILD_ARGS=-v — “unexpected argument ‘-v’ found”dx build spells it --verbose (and --trace); there is no short form, so the attempt to make dx print cargo’s error text killed the job before it started. Check a flag against dx <cmd> --help before putting it in CI — the same class of mistake as P-121resolved—
P-125 Windows link error: cannot open input file 'libssl.lib'dioxus-desktop depends on tungstenite with native-tls — not behind a feature — so the desktop binary needs OpenSSL, which Windows has no system copy of; the job compiled all 1081 crates and then failed at the link step (28 min wasted per run). Fix: [target.'cfg(windows)'.dependencies] openssl-sys = { features = ["vendored"] } in the desktop crate — OpenSSL is compiled from source with the perl and nasm that GitHub’s Windows runners carry. Linux and macOS keep their system OpenSSLresolved, verified on the runner 2026-09-22 (the .msi and the NSIS installer built)—
P-126 A packaged moonkale-server crashed at startup, and had no browser client to serveTwo faults found while documenting the container image. (1) dioxus-server resolves its client as public/ next to the executable and panics when the directory is missing — fine for dx serve, fatal for a distribution that puts the binary in bin/ and its data in lib/ (the tarball, the .deb, both Arch packages and the first ghcr image all shipped the binary alone). (2) packaging/build-release.sh only ran dx build --platform server, which builds the binary and leaves public/ without an index.html — so even the SSH-uploaded server never had a client. Fix: public_dir() in packages/web/src/main.rs sets DIOXUS_PUBLIC_PATH from the first layout that exists (<exe>/public, <exe>/../lib/Moonkale/public, /usr/lib/…, /usr/local/lib/…), and with none of them serves the API only with a printed warning instead of panicking; the packaging builds --platform web too and installs the client into lib/Moonkale/public (tarball, deb, both PKGBUILDs, Dockerfile). Verified end to end: the repackaged tarball’s server, started in a scratch folder with no environment variables, serves the app and Playwright opens a folder in itresolved—
P-127 The release job downloaded every package, then published noneWith if: always() the job finally ran (both macOS builds and the container succeeded this time), but its Checksums step was cd artefacts && sha256sum * — and merge-multiple: true keeps each artifact’s own directory structure, so the macOS .dmgs arrived under bundle/** and sha256sum hit a directory, exited non-zero and skipped the upload. Fix: find the known extensions, move them into a flat release/, refuse only when nothing built, then checksum and upload release/*. Rehearsed locally against a nested layout, then verified: v0.1.0 published with 11 assetsresolved—
P-128 Two .exe files and …_aarch64-arm64.dmg in the first releaseThe Windows job uploaded bundle/**/*.exe, which also matches the raw moonkale.exe (178 MB) next to the NSIS installer, so the release offered two Windows executables with no hint which to take; and a “Name by architecture” step appended -arm64/-x86_64 to .dmg names that dx had already made architecture-specific. Fix: upload *-setup.exe only, and drop the renaming. Cosmetic, but a first release is where a stranger decides whether the project is carefulresolved (applies from the next tag; the v0.1.0 assets can be deleted by hand)—
P-129 The released Linux packages do not start on ArchFound by testing the published v0.1.0 assets on this machine: libxdo.so.3 => not found. Ubuntu 24.04 (the runner) ships xdotool 3, Arch ships xdotool 4 (libxdo.so.4), and the desktop binary links it through tao/wry. That hits the tarball and the Arch package, because moonkale-bin repackaged the Ubuntu tarball rather than building on Arch. The AppImage bundles libxdo.so.3 but dies later on WebKit’s hard-coded helper path (/usr/lib/x86_64-linux-gnu/webkit2gtk-4.1/WebKitNetworkProcess, a Debian path). The .deb is right for its own distributions (Depends: libxdo3). Fix: the CI Arch job builds from source on Arch (packaging/arch/PKGBUILD, which now also builds the browser client and takes its version from the tag); the tarball and AppImage are documented as Debian/Ubuntu artefacts. A -bin package cannot work across a soname changeresolved, verified: a source build on this Arch machine links libxdo.so.4, starts, and its server serves the client; the v0.1.0 Arch package and tarball stay broken on Arch—
P-130 makepkg’s CFLAGS broke the wasm client buildAdding the browser client to packaging/arch/PKGBUILD (P-126) failed with clang: error: unsupported option '-march=' for target 'wasm32-unknown-unknown': makepkg exports Arch’s x86 CFLAGS, cc-rs hands them to clang for wasm32-unknown-unknown, and clang refuses them. Same family as P-111 (makepkg’s -flto breaking the C++ link). Fix: env -u CFLAGS -u CXXFLAGS -u CPPFLAGS -u LDFLAGS dx build --platform web. Found by building the package here before letting CI try itresolved, verified: the package builds and runs on Arch—
P-131 Every CI release APK has a different signatureThe release APK could not be installed over the app on the test phone: INSTALL_FAILED_UPDATE_INCOMPATIBLE. The phone carried a locally built APK signed with the developer’s ~/.android/debug.keystore; the runner has no such file, so Gradle generated a throwaway debug key. That repeats every run, so each release refuses to update the previous one and users must uninstall — losing the app’s private vault — on every upgrade. Not fixed yet: it needs a release keystore Daniel owns, with the JKS (base64) and its passwords as GitHub secrets and [android.signing] filled in a CI-written Dioxus.toml (the block is already stubbed in packages/mobile/Dioxus.toml). Wired up 2026-09-22: build-android.sh builds assembleRelease with -Pandroid.injected.signing.* when MOONKALE_ANDROID_KEYSTORE is set (debug otherwise) and prints the signer’s certificate; the release job decodes ANDROID_KEYSTORE_BASE64 into the runner’s temp dir and passes the three password secrets. Verified here with a throwaway key: 24.6 MB (R8 on), installs, starts on the S10e, no minification crash. Waiting on Daniel to create the real keystore and add the four secrets; the switch costs users one uninstall, and run-as cannot restore into a release build because it is not debuggable — back up first (packages/mobile/README.md)resolved in the build, awaiting the keystore—
P-132 An APK shipped as “Mobile” with the template iconbuild-android.sh patches the app label and launcher icon into the project dx generates, but Gradle caches resources per variant: the release APK built at 21:00 was correct while the debug APK from the same tree said Mobile with dx’s icon, because its merged resources dated from before the patch — and that was the APK on the phone. Fix: drop merged_manifest(s), merged_res, packaged_res and incremental before building, and read the finished APK back with aapt2 dump badging, failing unless the label is Moonkale and a launcher icon exists. The released v0.1.0 APK was checked and is correct. The structural fix — configuration instead of patching — is 029resolved—
P-133 The Arch job fetched crates for the host onlyThe first CI run of the from-source Arch package (2026-09-26) failed in build(): prepare() ran cargo fetch --locked --target <host>, build() runs offline, and dx’s cargo metadata resolves the whole lock file — failed to download android_system_properties. Local makepkg passed only because ~/.cargo already held every crate. Fix: plain cargo fetch --locked; reproduced and verified with an empty CARGO_HOMEresolved—
P-134 A clean Arch container lacks three tools the local build hadThe next three CI runs each got one step further: dx installs a missing wasm32-unknown-unknown with rustup, which Arch’s rust does not have (“No such file or directory” after an 80-minute build) → rust-wasm; arborium-sysroot compiles C for wasm32 with clang → clang; dx strips the browser client with rust-objcopy, which in Arch’s rust is a symlink to /usr/bin/llvm-objcopy from llvm (not a dependency of rust) → llvm. All three are in the container and in makedepends/prepare() checks that fail in seconds. First good package: 260927-proto. Lesson: a build that works on the developer’s machine proves nothing about a clean container; list every symlink target of the toolchain packageresolved—
P-135 dx’s web release profile is named like oursdx builds the browser client with a Cargo profile called wasm-release; the workspace’s own [profile.wasm-release] (made for the graph renderer: opt-level = "s", fat LTO, panic = "abort", strip = true) therefore also applied to the web client — which is why dx stripped it at all (P-134). Resolved 2026-10-02 (Milestone 18 phase 1): the renderer’s profile is now [profile.graph-wasm] (builds byte-identical), and the web client has its own, documented [profile.wasm-release] with the same size settings — kept on purpose, because with dx’s defaults the client grew from 46.2 to 54.9 MB (measured in Milestone 18 - Implementation Log)resolved18
P-136 Moving the web client build first shipped a server without its clientTo fail fast, build() briefly built the browser client first; dx build --platform server then rewrote public/ without index.html, and the Arch package’s moonkale-server served the API only. Found by unpacking the release; the order is back (desktop, server, web) and build() refuses to package without public/index.htmlresolved—
P-137 The keystore password check pasted the secret into the scriptkeytool -storepass "${{ secrets.… }}" puts the secret into the shell text, where $, backticks and \ are interpreted: the right password arrived changed (“keystore password was incorrect”). Fix: -storepass:env with the secret in the step’s environment, as the build step already did. (The old keystore’s password never matched either; a new keystore was made and packages/mobile/set-signing-secrets.sh sets all four secrets after checking them locally)resolved—
P-138 binstall silently installed the x86_64 dx on the arm64 macOS runnerIts 15 s check for dx-aarch64-apple-darwin.zip timed out, binstall fell back to the Intel build, and that dx aborted under Rosetta looking for /usr/local/opt/openssl@3 (exit 134). Fix: BINSTALL_MAXIMUM_RESOLUTION_TIMEOUT=120 for every job and --targets <host> on macOSresolved—
P-139 The Local graph kept the Whole layout’s positionsA neighbourhood is a subset of the whole graph, so set_graph’s incremental path (spec 017) kept every node where the Whole layout had put it — a handful of nodes scattered over the map — and its own layout then moved them, so Whole came back disturbed. Fix: set_graph_fresh for a new Local centre, stash/unstash of the Whole view (graph, positions, layout, camera) around it; graph-local.mjs checks the camera and positions come back exactlyresolved16
P-140 Milkdown writes <br /> for every empty lineremarkPreserveEmptyLinePlugin (in Milkdown’s CommonMark preset) makes the paragraph serializer emit an HTML <br /> for each empty paragraph. The wrapper now drops <br />-only lines and collapses blank runs outside fenced code (src/clean.ts, npm test); the plugin stays so old files still parseresolved16
P-141 “Loading rich editor…” foreverThe mount script waited without limit for the host element (and returned silently without it), for the bundle (a head <script>, which the first render can lose — P-087) and for crepe.create(). Every wait is bounded now, the bundle is inserted by the script if absent, and a failure shows its reason with Retry. The intermittent Linux case was not reproduced; the next occurrence names its causeresolved (cause unconfirmed)16
P-142 The Android WebView starts its own drag on a long pressThe touch-drag script passed in Chromium’s touch emulation and failed on the S10e: at ~500 ms the WebView fires contextmenu and then a native HTML5 drag of the draggable tab, which cancels the touch sequence (touchcancel); the script ended its drag and the native one dropped onto the editor text, where no dock zone was. Traced by logging events in the phone’s WebView over DevTools. Fix: while a finger holds a tab, the tab is not draggable (restored on tap, swipe, drop and cancel); verified on the phone by a long press + drag that docked Terminal below Sources. Desktop touch emulation does not reproduce the native long-press drag — a phone check is needed for anything touchresolved16
P-143 Once, on Linux, the vertical divider moved faster than the mouseSeen once by Daniel (2026-09-27), not reproducible. The workbench’s splitter ratio is start + Δpointer / span, with span measured by get_client_rect on the split’s mount handle when the drag starts; the arithmetic is scale-consistent (display at scale 1, no CSS zoom). Hypothesis, unconfirmed: a stale mount handle after a layout change measured a smaller element, making each pixel worth too much. dioxus-workbench is a crates.io dependency; nothing changed. If it comes back: note what the layout looked like just before (a panel just moved or closed?)open (observed once)16
P-144 LadybugDB’s static library cannot share a binary with Turso, HelixDB or RocksDBThe prebuilt liblbug.a is linked with +whole-archive and carries LadybugDB’s bundled zstd 1.5.7 and SimSIMD with global, unprefixed symbols; zstd-sys (from turso_core’s tantivy, HelixDB’s foyer/tantivy, librocksdb-sys) and simsimd (from turso_core) define the same ones — 184 duplicate symbols (98 zstd, 86 simsimd). Reproduced with nothing but lbug + zstd = "0.13" (173 duplicates) and lbug + simsimd = "6". First worked around with the shared liblbug (behind an off-by-default feature). Reported upstream; lbug 0.21.0 added LBUG_LOCALIZE_BUNDLED_SYMBOLS=1: after downloading the prebuilt archive its build script partially links it (ld -r) and keeps only weak, C++ (_Z*) and lbug_* symbols global (objcopy --keep-global-symbols). .cargo/config.toml sets it for the workspace; the Nix flake (which uses LBUG_LIBRARY_DIR, where the crate does not localize) runs the same recipe in its liblbug derivation. ELF only, so desktop/api enable ladybug only on Linux; macOS/Windows ship without LadybugDB. Verified: all six drivers in one debug binary, 0 global zstd/simsimd symbols left in the archive, E2E ladybug + storesresolved (Linux)17
P-145 Opening a HelixDB store read-only writes into itClient::open_reader (SlateDB underneath) writes a new main/manifest/…manifest file on every open, so a “read-only” source still changes the store: git sees it (the Sources tree marks the store modified), and a store on read-only media probably cannot be opened. Helix’s behaviour; notedopen (upstream)17
P-146 LadybugDB’s prebuilt library follows upstream’s latest releaseWithout LBUG_VERSION, the lbug build script downloads releases/latest — not the release matching the crate. The first CI run (2026-10-01) hit a 404 for liblbug-static-linux-x86_64-compat.tar.gz while v0.21.2 was being published, and the from-source fallback then failed (lbug-src/scripts/collect-single-file-header.py is missing from the published crate). Fixed: LBUG_VERSION = "0.21.0" in .cargo/config.toml, kept equal to the locked crate versionresolved18
P-147 A helper that reads a signal turned an effect into a loop of the last commandThe shell’s command effect re-runs whenever a signal it read changes, and replays the current (seq, Command) — so anything it reads besides commands must be peeked. Phase 2.4’s contributions() helper is called from that effect and, through Workspace::preferred_editor, read the settings; opening a document saves the open-documents list, so Show Settings (the last command) ran again and stole the tab (presence.mjs). Fixed with an untracked variant for effects (preferred_editor_untracked, open_node_by_id peeks) and a tracked flag on the helper. Rule: helpers shared by render and effects take a tracked flag or peekresolved18
P-148 Build output committed from packages/web/targetMy shell exported a relative CARGO_TARGET_DIR=target/agent; serve.sh inherited it and cds into packages/web before dx serve, so the E2E server built into packages/web/target/agent (15 GB). .gitignore covered only the root /target, and the next git add -A packages committed 33 949 build files into the phase 2.4 commit. Caught before pushing; the two local commits were redone without them. Fixed: packages/**/target/ ignored; serve.sh anchors a relative CARGO_TARGET_DIR at the repo root. Rule: check git diff --cached --stat before committing with -Aresolved18
P-149 Event ids came back as floats from the storeThe first store-backed entity log failed its test with invalid type: floating point 1.8458781555546439e+22, expected u128: moonkale_state::decode read every envelope into serde_json::Value first (to hand older versions to migrate), and Value has no u128 — a 128-bit EventId became an f64 and lost its low bits. Fixed: the version is read alone, the current version is decoded straight into its type, only older ones go through Value. Test: record::tests::a_u128_survives_the_envelope. A migration of a record with u128 fields would still need serde_json’s arbitrary_precisionresolved18
P-150 stores fails as the last suite of a full batchFour full batches (phases 3, 5.15, 6.3, spec 030 part 3) ended with stores timing out on a selector after ~40 suites against one dev server; alone, or on a fresh server, it passes every time. Likely the same accumulation as the 2026-10-01 observation (sources and server sessions are never dropped by the server), which stores — it opens five databases — is the first to feel. Not fixed: the server should drop sources nobody holdsopen18
P-151 Saving a setting brought the Settings tab back over the open fileSpec 030: every panel title became t!(ws, …), which reads the language from the settings signal. The shell collects panels inside the command effect with tracked: false (P-147), but the panels themselves now subscribed through t!, so changing any setting (here: the user’s name in presence.mjs) re-ran the effect, which replayed Show Settings and hid README.md. Fixed: moonkale_ext_api::workspace::untracked(…) — inside it Workspace::lang() peeks — wraps panels() on the untracked path. Rule: anything a command effect calls must not subscriberesolvedspec 030
P-152 Themes: the style element broke hydrationSpec 030 part 3: the theme stylesheet was a style { "{css}" } text node. (1) Patching its text after hydration, when a theme file arrived, crashed Dioxus’ DOM patching (textContent of undefined) — the SSR text node is not the one the client’s template expects. (2) SSR inserted a hydration marker comment (node-id4--) into the style text, so the first :root rule was invalid and the page had no default palette until a theme was chosen. Fixed: the built-in sheet is static and rendered with dangerous_inner_html (no text node, no marker); themes from files go into a separate #mk-theme-extra element that the frame fills by eval. Rule: never render dynamic text into a style (or script) elementresolvedspec 030
P-153 relay test failed once in a workspace runrelays_to_the_active_remote_and_refuses_without_one and client::connect_and_disconnect_track_the_remote share the process-global active remote; run in parallel, one saw the other’s remote. Fixed: both take client::REMOTE_TEST_LOCK; five workspace runs cleanresolvedspec 030
P-154 rich and wiki failed once in CIFirst CI run of spec 030 part 3 (run 37147264631): rich timed out clicking the Properties head of Front.md, still in Source mode (the Rich click had no effect); wiki pressed Enter on the [[Be completion and got a newline instead of [[Beta]]. Both passed in the rerun of the same commit and locally, alone and in CI’s suite order. Likely timing on the slow runner (a click before the handler is live; Enter inside CodeMirror’s completion interaction delay). Not fixed; watch for a repeatopenspec 030

Conventions

  • Status: open · investigating · decided · resolved · wontfix.
  • Link the ADR if the resolution became a decision.
  • Include measurements, not adjectives (“30 fps at 50k nodes on WebGL2”, not “slow”).