Current State
The test story is uneven across the monorepo.
The mobile workspace focused E2E suite exercises the touch-first shell contract: mobile mode switching, mounted sidebars, right-edge-aligned sidebar reveal, pointer-driven pan gestures with live drag progress and snap settlement, main-panel tap-to-close behavior, center-panel anchored floating controls, scroll-hidden mobile chrome, left-sidebar search routing, the Vaul-backed more-actions drawer, mobile menu drawer rendering, mobile tab actions drawer, mobile settings dialog/sidebar mounting, and startup error tracking for compatibility status-bar plugins.
What exists today
- the root package defines shared
build,test,lint, and formatting commands - the root package now defines
pnpm test:smoke, the app smoke gate documented inAGENTS.md; it runs the workspace dev-server boot suite and the Electron desktop boot suite when a change can affect the running app; local runs use the desktop dev renderer while CI keeps the full desktop production build - the root package now defines
pnpm test:daily-use, which runs the workspace Chromium daily-use journey after app smoke in CI andpnpm docker:ci-check; the journey covers note creation, rename persistence, search indexing, notebook execution, reload, and restored notebook outputs - the root package now defines
pnpm test:official-plugins, which builds the local official external plugin packages, creates a signed local registry fixture with test-only keys, runs the workspace Playwright official-plugin matrix, installs every plugin from the release tooling’s official definition list through the real registry installer with official provenance required, asserts default enablement, install progress cadence, ESM-only runtime diagnostics, reload persistence, and one runtime smoke assertion each for Canvas, Docs, Graph, Markdown Lint, Notebook, PDF, Slides, and Telemetry; the shared CI verify action, Forgejo browser lanes, and official plugin asset publish workflow bootstrapscripts/ensure-xvfb-run-deps.shbefore running this command underxvfb-run; when the local registry builder is asked to--skip-build, it now still materializes missing official plugindist/outputs from Turbo cache in the current job before packaging fixtures - after any code change, the expected validation path is to run the narrowest relevant
pnpm check:allcommand (package-local or repo-root) on modified packages so formatting, source-resolution guards, script tests, package-local static checks, ESLint, spec markdown lint, Svelte warning regressions, and TypeScript regressions are exercised before finishing the change; also runpnpm --filter <package> test(orturbo run test --filter=…) on each modified package that defines tests; runpnpm test:smokeonly when the change can plausibly affect workspace or desktop boot, runtime, UI, plugin loading, or related cross-package integration .forgejo/workflows/checks.ymlruns a warmed cache-build job first (pnpm ci:build:checks) and then fans out independent CI lanes forrepo-checks(static checks),unit-tests,app-smoke,daily-use-e2e, andofficial-plugin-e2ewithstrategy.fail-fast: falseso one lane failure does not cancel the others; each browser lane uploads Playwright artifacts withactions/upload-artifact@v3; and Turborepo remote cache runs againsthttps://turbo-cache.app.ju.mawhile every lane uses the warmedcode.ju.ma/lapis-notes/lapis-ci:latestcontainer image- the root package defines
check:all, which runscheck:source-resolution,plugin-host:check,test:scripts,turbo run check:all,check:format:root,lint:root, andspec:lintas the default post-change validation entrypoint; see Monorepo Scripts - the root
check:allflow runscheck:source-resolutionbefore Turbo package checks so first-party Vite development graphs fail fast when any local@lapis-notes/*import resolves to a packagedist/artifact instead of the dependency’ssrc/tree - individual packages expose package-local
check:alland targetedcheck:*scripts so work can be checked narrowly without always running the root workflow - Turbo orchestrates package
check:*tasks in parallel with local caching under.turbo/and optional hosted remote cache in CI; package-local tools stay quiet on success throughscripts/run-quiet-check.mjs - the root package defines
check:types, which runs package-localcheck:typesscripts across the workspace through Turbo so cross-package TypeScript regressions fail in one place instead of surfacing piecemeal during plugin development - the root package defines
check:format, which runsturbo run check:formatacross workspace packages and thencheck:format:rootfor repo-root paths outside packages (scripts/,spec/, agent docs, CI workflows, and similar) - package
check:allruns static checks only throughscripts/run-package-check-all.mjs; tests run separately throughpnpm testor package-specific test scripts - the root package defines
pnpm e2e-vault:prepare, which stages and verifies a full copy of the trackede2e-vaultfixture (including rootINDEX.md) before atomically swapping it into a generated writable vault copy ate2e-vault-tempby default, or a caller-provided path for future e2e harnesses.pnpm media:siteconsumes that prepared copy for public-site screenshots, restores the tracked default workspace layout for the landing hero still, and usesWorkspace: Focus Leafbefore capturing the full workspace shell for view-specific stills. The script renames an existing target aside instead of deleting it in place, so--forcereplace is reliable when the vault is closed; if the swap fails, the error message points at a retained staging directory for recovery. Generated targets are replaced on every run; unmarked existing custom targets require--force. Success is indicated by.lapis-e2e-vault-copyplus rootINDEX.mdin the prepared target. - the root package defines
pnpm test:scripts, which runs Node tests for repo scripts such asscripts/prepare-e2e-vault.mjs, and the rootcheck:allflow includes it before Turbo package checks. - newly added packages should define package-local
check:all,check:format, andcheck:typesscripts, pluscheck:sveltewhen the package owns a Svelte UI surface, and that Svelte check should fail on warnings so accessibility and reactive-state regressions stop the normal package check path instead of relying on a second repo-wide warning pass - the root package defines
spec:lintandspec:lint:fixfor markdownlint-based spec checks; rootcheck:allalready runsspec:lint, and the root/spec Makefiles still exposespec-lint,spec-lint-fix,lint, andlint-fixaliases for narrow spec-only passes packages/apihas the strongest explicit test surface, including Vitest tests and parity fixtures undertest/paritypackages/apibrowser-storage tests now cover portable browser-vault transfer behavior in both directions, including import overwrite semantics and export into a user-picked directory handlepackages/apinow also has focused workspace-model coverage for grouped sidebar layout compatibility, grouped layout round-trips, traversal through grouped leaves, active-leaf restore, sidebar placement defaults, hidden panel persistence, and leaf/group conversion helperspackages/apiworkspace-model tests now also cover layout drag/drop event ordering and cancellation plus floating-pane and supported/unsupported popout host capability paths, so drag/drop helper regressions fail without needing a real secondary windowpackages/apinow validates SQLite app-database bind compatibility in tests with a sqlite-wasm-like mock that rejects malformed or unused named parameters, so worker-only query regressions such as invalidbind()names fail in CI instead of only in browser sessionspackages/apinow also covers plugin-manager boot order, failure rollback, manifest preflight, runtime-aware community plugin preflight, failed plugin restart diagnostics, and vault-scoped workspace-trust gating for trusted desktop runtime entries plus brokered capabilities with targeted integration testspackages/apinow also covers frontmatter mutation and metadata-type regressions, including first-block creation, last-property block removal, no-op suppression, concurrent frontmatter write retry, nested property membership cleanup, nested rename collision reporting, and falsey-value-preserving metadata renamespackages/apinow also covers Bases custom-view registration persistence across plugin startup order so plugin-contributed.baserenderers survive enable-order differencespackages/plugins/plugin-basesincludes a test script and now has a focused regression check around virtualized Bases table search state so empty filtered result sets do not reuse stale virtual rows while scrollingpackages/plugins/plugin-basesnow also preserves custom view types when.basedocuments are normalized back from source mode so plugin-registered task-specific Bases views do not collapse to the fallback rendererpackages/plugins/plugin-canvasnow includes focused Vitest coverage for the JSON Canvas serializer and Svelte Flow bridge, andpackages/workspacenow carries Playwright canvas smoke coverage that opens.canvasfiles, verifies the canvas renders without the old top banner, confirms the built-in controls stay anchored in the top-right corner, checks colored nodes and arrow-ended connectors render in the workspace shell, checks the loaded graph is fit into view, ensures dragged nodes stay clipped to the pane body, and seeds text, file, link, and group nodes together so runtime page errors such as Svelte effect loops fail the smoke pathpackages/plugins/plugin-graphnow includes focused Vitest coverage for graph assembly, orphan filtering, and local-graph depth derivation from metadata cache fixturespackages/plugins/plugin-telemetrynow includes focused Vitest coverage for the trace-tree helpers that drive the local telemetry waterfall and span-search behaviorpackages/notebooknow includes focused Vitest coverage for notebook parsing, dependency graph construction, DuckDB app-table registration, dedicated worker-client transport behavior, and cross-cell execution/value propagationpackages/notebooknow also includes focused Vitest coverage that Safe Mode blocks active notebook execution commands before they hand work to the runtimepackages/workspacenow has a Playwright browser regression suite for markdown rendering, exercising live-preview and source-mode heading gutter alignment, wrapped plain-indent guides, nested list rendering, live-preview blockquote widgets, source-mode markdown table reformatting onTabandEnter, source-modecm-tableline styling, table widgets, and reading-view embeds against the real workspace shellpackages/workspace/e2e/pwa-title-bar.spec.tsnow clones the production Window Controls Overlay media rules, injects simulated native-control blocker rectangles, and verifies pane-owned top-titlebar geometry stays in flow while interactive controls avoid those blocked regions on macOS and Windows, alongside sidebar split-inset checks, painted-icon visibility, blocker-based non-overlap for sidebar tab buttons, WCO border coverage (including a:root::before1px divider probe at--workspace-safe-area-top, an outer top-tabborder-bottomguard against active-tab notch leakage, and a[data-sidebar="rail"]extends-into-safe-area-strip assertion), anelementsFromPointprobe asserting the sidebar dock radio is the topmost paint at its own centre under WCO (regression guard against root pseudo-elements masking the icons), and reference screenshots clipped to the macOS top-left/top-right and Windows top-right corners undere2e/__screenshots__/pwa-title-bar.spec.ts/packages/workspace/e2e/markdown-showcase.spec.tsopens the trackede2e-vault/plugin-markdown/CodeMirror Layout Showcase.mdcontent and checks source mode, live preview, and reading mode against the same fixture for tables, grid tables, quoted lists, indentation, wrapping, embeds, links, tags, math, and code rendering.packages/workspace/e2e/csv-editor.spec.tscovers CSV table preview/source sync, 1-based row numbers, header edits, preview undo, column move menu, selection grips, and source-mode lint diagnostics against trackede2e-vault/plugin-csvfixtures.packages/plugins/plugin-markdownnow also has focused widget regressions that exercise text-widget commit behavior on blur and Enter plus checkbox writes on change, which protects the shared frontmatter editor against focus-handoff and remount data losspackages/workspacenow also covers frontmatter editing regressions through the real shell, including live-preview property rename, File Properties checkbox commits against vault-backed note contents, and frontmatter-to-search propagation without a manual rebuildpackages/workspacenow also includes focused Playwright coverage for open-note file lifecycle behavior, proving an active note retargets on rename and closes cleanly on delete instead of keeping stale leaf statepackages/workspace/e2e/markdown-hashtag-lint.spec.tscollapses both workspace sidebars and captures Chromium screenshot baselines for source-mode hashtag pills under syntheticcm-lintRangegeometries (full-line wrap, prefix split, trailing lint after the tag name, mid-line tags, path tags, and dual-tag lines) via__LAPIS_SYNTHETIC_LINT__without depending on markdownlint rule IDspackages/workspace/e2e/markdown-lint-tooltip.spec.tscollapses both workspace sidebars before capturing Chromium screenshot baselines for markdownlint MD041 hover tooltips (lapis-lint-tooltip.svelteinside the Lapis-owned.cm-lapis-tooltip), verifies users can move from the lint range into the tooltip, checks MD041 marks the full source line and keeps both the lint gutter row and visible marker centered against the line-number gutter, verifies lint gutter markers also open that custom tooltip, and covers the inline problem widget opened through View Problem, including clipping and below-line placement regressionspackages/workspacenow also exercises shared menu regressions through the real markdown workspace surface, including right-click table context-menu submenus plus pane-header dropdown menus, and asserts those paths no longer throw the previousObject.entries requires that input parameter not be null or undefinedruntime error in Chromiumpackages/workspacenow runs its app Playwright suite against Chromium, matching the Electron renderer engine, and the workspace shell owns a canonical Chromium visual-regression fixture that seeds the file explorer plus a multi-tab, multi-split layoutpackages/workspacenow also includes focused Playwright coverage for grouped sidebar views, including real grouped panel rendering, group-menu and visible-panel basics, vertical grouped-panel resizing, serialized panel-size state, and expanded panel content filling the available pane bodypackages/workspace/e2e/tab-drag-drop.spec.tsnow includes focused deterministic drag-policy assertions alongside the browser flows, exercising explicit strategy overrides, auto mouse/touch/pen routing, activation thresholds, touch jitter tolerance, flick cancellation, and the held-drag initiation delay alongside the existing Playwright pointer regressionspackages/workspacenow also includes focused Playwright coverage for Safe Mode recovery, covering a failing community plugin path that enters Safe Mode with community plugins disabled plus the visible targeted disable action, and a broken saved-layout path that provesworkspace.loadLayout()rejects malformed layout JSON before the shell restarts with layout restore skippedpackages/workspacenow also includes notebook Playwright coverage for notebook opt-in commands, starter cell insertion, SQL and table output rendering, chart output rendering, downstream markdown interpolation, loading-progress UI during initial notebook execution and stale reruns after notebook source changes, cursor-scoped notebook execution, notebook runtime package install and uninstall flows through the Packages side view, notebook runtime-status and output-restoration messaging in the notebook-owned status banner, and notebook-relative CSV loading in the legacy browser vaultpackages/workspacenow also includes a Chromium-scoped daily-use journey Playwright path that boots an OPFS vault, creates and renames notes, verifies search indexing, executes a notebook, reloads the shell, and confirms the renamed note plus restored notebook outputs survive restart on the supported browser shell;e2e/daily-use-journey.spec.tspluspnpm test:e2e:daily-userun that journey throughplaywright.daily-use.config.ts, and CI pluspnpm docker:ci-checkinvoke it through rootpnpm test:daily-useafter the Electron smoke phase unless--skip-daily-useis passedpackages/workspacenow also includes focused Playwright coverage for the search sidebar query input, proving shell clicks focus the CodeMirror editor with a visible caret andArrowUp/ArrowDownrecall persisted recent searches from the start of the querypackages/workspacenow also includes Playwright coverage for the bundled Tasks plugin, exercising markdown task-note creation, completion toggling through mapped frontmatter writes, deletion, note-opening actions, custom task-folder plus field-role mappings, inline task conversion from the current line, selection, and note-wide batches for supported prefixed task candidates, reading-mode plus source-mode and live-preview convert buttons for supported prefixed Markdown task candidates, task-note summary widgets in reading mode, source mode, and live preview, compact task-link overlays in reading mode, source mode, and live preview, partial metadata extraction for hashtags plus explicit ISO due-date tokens, opening a generated Task List.basefile through the custom task Bases renderer against the real workspace shell, and a Fizzy-board regression that verifies tasks land in the expected Maybe/Open/Done lanes without surfacing the previous Svelte effect-depth page errorpackages/plugins/plugin-tasksnow also carries adapter-backed TaskNotes validation coverage for a claimedcore-litebridge againsttasknotes-spec0.1.0-draft, checking canonical mapped writes plus strict completed-date, due-date, and temporal-order rules, alongside representativemeta.*,date.*,field.*,config.*,validation.*,create_compat.create,op.*, anddelete.removeoperations plus explicit known-deviation metadatapackages/plugins/plugin-tasksnow also carries focused package tests for inline-task line parsing and conversion, andpackages/workspace/e2e/tasks.spec.tscovers the initialCreate inline taskMarkdown-editor command flow alongside the existing Tasks list regressionspackages/workspacenow also covers browser SQLite coordination with Playwright two-tab regressions that boot an OPFS vault, verify owner and proxy session modes, edit a markdown note from the proxy tab, assert delegated app-database search state updates without invalid named-bind runtime errors, and verify a proxy tab promotes itself after the owner tab closespackages/workspacenow includese2e/app-boot-smoke.spec.tspluspnpm test:e2e:smoke, which runsturbo run build --filter @lapis-notes/workspace, clears stored vault profiles, boots through the normal dev-server path with a fresh Browser (OPFS) vault, waits for visible shell readiness, asserts.workspaceand coreappservices, and fails on startup page errors plus targeted renderer console diagnostics such asderived_inertwarnings and ViteFailed to load source mapmessages; the smoke Playwright timeout now stays above the helper’s internal boot timeout so CI failures surface the startup checklist/message snapshot instead of a raw runner timeout, cold CI workers get extra first-boot headroom beyond local runs, timeout snapshots now report chooser-loading state/message as well as in-shell startup state, and the chooser submit path falls back to the Create vault button when Enter does not dismiss the dialog; the olderdev-server-startup.spec.tspath still covers additional dev-server regressionspackages/workspacenow includese2e/app-boot-smoke.spec.tspluspnpm test:e2e:smoke, which runsturbo run build --filter @lapis-notes/workspace, clears stored vault profiles once per Playwright browser context, boots through the normal dev-server path with a fresh Browser (OPFS) vault, waits for visible shell readiness, asserts.workspaceand coreappservices, and fails on startup page errors plus targeted renderer console diagnostics such asderived_inertwarnings and ViteFailed to load source mapmessages; the smoke Playwright timeout now stays above the helper’s internal boot timeout so CI failures surface the startup checklist/message snapshot instead of a raw runner timeout, cold CI workers get extra first-boot headroom beyond local runs, timeout snapshots now report chooser state plus chooser-loading state/message as well as in-shell startup state, and the chooser submit path falls back to the Create vault button when Enter does not dismiss the dialog; the olderdev-server-startup.spec.tspath still covers additional dev-server regressionspackages/workspace/e2e/mobile-workspace-stage-gesture.spec.tsnow covers stepped mid-screen touch pointer paths that must fully open left/right mounted sidebars (tracktranslateXsettles to0/-2 * sidebarWidth) and short swipes that snap back to center without opening a sidebarpackages/workspace/e2e/mobile-workspace-mode.spec.tsnow covers the mobile workspace shell in Chromium, proving the shared renderer switches between auto, forced-desktop, and forced-mobile display modes through the registered workspace commands, and exercising the compact always-visible floating dock, hidden full view header plus visible editable mobile inline title inside the active view content, title scroll-out with the editor page, scroll-hidden top chrome, single-page mobile leaf viewport without the desktop root tab strip, floating left toggle, pointer-driven mounted-sidebar pan gestures with live pre-release transform updates, snap-back, touch-style reveal, and DevTools-style mouse close, body-only sidebar content with bottom name selectors, capped main-tab-only live mobile tab preview tiles, fixed open-tab count and Done controls, the mobile tab actions drawer, mobile app-owned menus rendered through drawers, left-sidebar search entry point without opening the command palette, settings sidebar recovery, and Vaul-backed bottom action drawer without runtime page errors;mobile-workspace-navigation.test.ts,mobile-inline-title.test.ts,mobile-workspace-stage-helpers.test.ts,mobile-sidebar-panel.test.ts, andmobile-scroll-chrome.test.tsalso cover the mobile sidebar editor-stage state transitions, inline title fallback, deterministic reveal offsets, swipe input/direction decisions, pan snap-point decisions, sidebar selector labels, and scroll chrome state directlypackages/desktop-electronnow includese2e/app-boot-smoke.spec.tspluspnpm test:e2e:smoke, which compiles main/preload and boots through the Vite dev server locally (or runs the full production build in CI), launches Electron with isolated user data and an Electron-safe environment that stripsELECTRON_RUN_AS_NODE, asserts the vault chooser and workspace mount, and fails on renderer or main-process startup errors plus the same targeted renderer console diagnostics before the broader startup-shell integration suite runs. Focused desktop E2E also covers the shared Plugin registry settings tab so registry UI changes cannot ship browser-only.packages/desktop-electronnow includes package-local Playwright Electron coverage that launches the built app with isolated user data, auto-selects~/Documents/vault-copy, seeds and opensUntitled.md, asserts the visible note header, verifies native file-watching by writing a file outside the renderer, smoke-tests the available plugin-sidecar lifecycle plus initial brokered capabilities, exercises the pane-headerSplit rightaction, covers grouped sidebar rendering/menu/resizing behavior against the real packaged shell, verifies vault-backedtransformers-jssemantic indexing with an explicitly selected embedding model, confirms the packaged desktop app returns vector hits for that indexed vault data, settles the footer semantic-search status item back to its ready/completed state, and exercises native Markdown language-service diagnostics throughdesktop_ls_capabilitiesanddesktop_ls_diagnosticswithout main-process sidecar failurespackages/workspacenow also includes a Playwright History regression that seeds tracked file revisions, opens the History sidebar, launches the fullscreen compare overlay, asserts the vendored two-pane diff surface mounts through the real workspace shell without runtime import failures, verifies syntax-highlight overlay tokens render, exercises saving edits back through the editable current-file pane, and restores a selected revision through the overlaye2e-vaultis now the canonical tracked sample vault for broad manual and future automated app coverage. Itsplugin-*folders provide documentation-like content for markdown, bases, canvas, csv, graph, search, history, notebook, pdf, slides, telemetry, notifications, markdown-lint, Harper, Tasks, and a vault-local manifest-onlyplugin-testcommunity plugin. Theplugin-csvfolder documents CSV table preview, source rainbow highlighting, lint fixtures, and settings verification; seee2e-vault/plugin-csv/CSV Feature Tour.md. Theplugin-testfixture also exercises declarative settings widgets (object groups, enums, lists, object grid, typed string formats, deprecation, and unsupported JSON fallback) through Settings → Community plugins → Plugin Test Fixture; seee2e-vault/plugin-test/Declarative Plugin Fixture.mdand Configuration and Settings. The tracked source vault should remain clean; usepnpm e2e-vault:preparebefore running workflows that mutate vault content.- most other packages lean more heavily on
build,prepack, andsvelte-checkthan on dedicated automated tests - manual desktop release paths run the same verification gates before building or uploading release assets unless explicitly skipped; see Release Management
What this means architecturally
- the runtime package is the most obvious candidate for regression protection
- view-layer and workspace-shell behaviors still depend heavily on manual validation outside the covered markdown, shell-visual, notebook, tasks, canvas, history, and startup slices
- the workspace shell now has a small but concrete browser-level regression surface for markdown view rendering, which is the right place for geometry-sensitive bugs that unit tests miss
- the desktop host now has a packaged Electron smoke path, so shared-renderer startup regressions can fail in automation instead of relying only on manual local host checks
- plugin lifecycle now has targeted manager coverage, but layout persistence and workspace-shell plugin flows still need broader integration coverage
- the spec now has a markdown style check that can be run independently or paired with
mdbook build specthrough Makefile targets
Documentation gap this spec addresses
Several package READMEs are still template defaults. That makes code inspection the main source of truth for architecture today. This book is intended to reduce that gap and give future tests and ADRs a stable narrative reference.
High-value future coverage
- broader workspace-shell integration for community plugin loading, dependency injection, and failed-view fallback beyond the current plugin-manager and Safe Mode slices
- metadata-cache to chunk and vector search propagation beyond the current frontmatter-driven search update coverage, including embedding invalidation
- multi-leaf and non-markdown rename/delete lifecycle behavior beyond the current active-note coverage
- markdown and bases view mode transitions beyond the current markdown rendering regression slice