Skip to content

Refactor(boundaries): define portable client and server interfaces - #789

Merged
adibhanna merged 6 commits into
mainfrom
refactor/ecosystem-boundaries-pr
Sep 16, 2026
Merged

adibhanna merged 6 commits into
mainfrom
refactor/ecosystem-boundaries-pr

Conversation

@adibhanna

@adibhanna adibhanna commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Desktop, web, and mobile currently depend on private renderer internals and source checkouts, while server builds depend on the frontend build tree. This change introduces explicit public editor APIs, portable packages, and verified browser artifacts so each host can build against a deliberate dependency boundary.

Review groups

  1. Contracts and domain: move portable types into the bridge contract, preserve compatibility exports, and share exact-byte behavior fixtures.
  2. Editor APIs and lifecycle: expose navigation, editor commands, attachments, notes, folders, databases, tasks, settings, and immutable host snapshots. Coordinate saves, file mutations, workspace transitions, and native relocation/rollback.
  3. Package distribution: build immutable core/contract/domain archives, preserve singleton React/CodeMirror dependencies, and verify external consumers on Vite 6 and 8.
  4. Server and viewer artifacts: support Go-only API builds and verified embedded web imports; restore a maintained read-only public viewer with safe Markdown fallback and restricted interactive plots.
  5. Extraction preparation: provide Go repository, Docker, Nix, and draft-release templates for the later ZenNotes/znserver cutover. The current server source and distribution owner remain active until that cutover.

This branch starts from current main after v2.50.4, including its verified AUR/Homebrew/Nix metadata. The asset-reference fix is reconciled with the workspace reservation so pending edits and vault switches cannot interrupt a rename/move rewrite.

Validation

  • Eight workspace typechecks; 4,806 passing source tests, five existing skips.
  • Desktop production build and CLI execution without node_modules.
  • Standalone package installs/builds and 50 browser checks on each Vite generation.
  • Companion Android/iOS consumers pass package tests, native builds, 20 runtime checks and three cold-start checks each; Android also passes four instrumentation checks.
  • Extracted Go module passes vet/tests, API/embedded builds, verified archive import, and TUI HTTP contracts.
  • Docker arm64/amd64 and Linux arm64 Nix builds/runtime checks; v2.50.4 upgrade/rollback preserves exact note bytes at root and prefixed mounts.
  • Public viewer: six actual-Laravel browser cases; five artifact packer tests; production dependency audit reports zero advisories.

Draft status and dependencies

Companion consumer PRs are prepared separately. Current mobile/viewer pins are validated local candidates with honest dirty-source provenance. Clean artifact publication and consumer repinning, account-backed Cloud/iCloud staging, destination CI, and server channel cutover remain explicit gates. This PR does not deploy, publish artifacts, remove the old Go source, or implement Cloud browser login.

See docs/specs/ecosystem-boundaries-and-repository-plan.md, docs/boundary-release-cutover.md, and docs/v2.50.4-boundary-integration.md for ownership, compatibility, evidence, and rollout order.

Related boundary PRs

Desktop, web, and mobile currently depend on private renderer internals and source checkouts, while server builds depend on the frontend build tree. This change introduces explicit public editor APIs, portable packages, and verified browser artifacts so each host can build against a deliberate dependency boundary.

### Review groups

1. **Contracts and domain:** move portable types into the bridge contract, preserve compatibility exports, and share exact-byte behavior fixtures.
2. **Editor APIs and lifecycle:** expose navigation, editor commands, attachments, notes, folders, databases, tasks, settings, and immutable host snapshots. Coordinate saves, file mutations, workspace transitions, and native relocation/rollback.
3. **Package distribution:** build immutable core/contract/domain archives, preserve singleton React/CodeMirror dependencies, and verify external consumers on Vite 6 and 8.
4. **Server and viewer artifacts:** support Go-only API builds and verified embedded web imports; restore a maintained read-only public viewer with safe Markdown fallback and restricted interactive plots.
5. **Extraction preparation:** provide Go repository, Docker, Nix, and draft-release templates for the later `ZenNotes/znserver` cutover. The current server source and distribution owner remain active until that cutover.

This branch starts from current `main` after v2.50.4, including its verified AUR/Homebrew/Nix metadata. The asset-reference fix is reconciled with the workspace reservation so pending edits and vault switches cannot interrupt a rename/move rewrite.
Comment thread tooling/scripts/test-app-core-browser.mjs Fixed
… CodeQL

The standalone package check installed the packed archives with npm's
offline mode, which only works when the npm cache already holds registry
metadata for every dependency range. npm ci caches tarballs, never that
metadata, so every fresh CI runner failed to resolve lz-string. The check
now prefers the cache but allows the metadata fetch.

On Windows the packers wrote include and exclude globs with backslashes,
and tsc treats those as patterns that match nothing. Generated tsconfig
paths now use forward slashes on every platform. Behind that failure waited
another: Windows checkouts convert the contract fixtures to CRLF, and the
TypeScript, Go server, and TUI consumers hash those bytes against recorded
provenance. The fixture directories now check out with LF everywhere.

CodeQL flagged eight items in the large diff. The wikilink resolvers trim
slashes with a linear scan instead of a backtracking regex, the browser
harness only dispatches CDP events to registered listeners, and store.ts
drops four unused imports and an unreferenced helper.

Validation: the shared-package check fails on an empty npm cache before and
passes after; the Windows glob is reproduced with path.win32; the CRLF hash
mismatch is reproduced arithmetically against the pinned digests; root
typecheck, every workspace suite with the turbo cache bypassed, the isolated
package check, and the Chrome harness pass with these changes.
…ture

The regression test added with the CodeQL cleanup built its own two-note
array without the title and folder fields that NoteRef requires, so the
app-core typecheck failed on every platform once the earlier steps passed.
Vitest ran the test without complaint because it does not typecheck. Reuse
the module-level fixture, which already holds both notes the test needs.
The installed-editor check ran on a GitHub runner for the first time and
stopped at "editor: timed out" with nothing else in the log. The harness
already collected page errors, failed requests, helper output, screenshots
and DOM dumps, but wrote them into a throwaway temporary directory and never
printed them, so the failure was unreadable from CI.

On failure the harness now prints the collected errors, failed requests,
the tail of the server, preview and Chrome output, and a compact page state.
A small collector copies the screenshots and JSON dumps out of the consumer
directory so the Ubuntu job can upload them as an artifact whether the step
passes or fails.

The first note open pulls the editor, store and Markdown chunks on a cold
runner, so it now gets the same sixty seconds the lazy Mermaid and Typst
renders already had. A real rendering failure still fails, with reasons.

Validation: the harness still passes locally against real Chrome; the
collector gathers fifteen files from a previous local run.
…nd match Windows paths in the rollback test

The Ubuntu runner reached the sidebar before the workspace finished
restoring, so the harness's first openNote landed during the transition and
the public navigation guard dropped it by design: no error, no editor, and
sixty seconds later the page was still Home with the note index loaded. The
harness now waits for the shell's workspaceRestored signal, the same
readiness the later host-command section already required, before opening
its first note. The evidence upload and page dump from the previous run are
what made this visible.

The Empty Trash rollback test refuses the comment-tree move by matching a
rename source that ends in .zennotes/comments/trash. Windows joins that path
with backslashes, so the refusal never fired, the transaction succeeded, and
the assertion that it rejects failed on that runner alone. Compare the
normalized path so the refusal fires on every platform.

Validation: the browser harness passes locally against real Chrome and in a
Debian container with Chromium; the vault suite passes locally; macOS and
Linux arm64 already passed the full build on the previous run.
… the delayed cache write before tests remove a vault

The previous run showed the same restoration race at the harness's next
navigation: after loading the host page it opened a note while the
workspace was still restoring, and the public navigation guard dropped the
call. Every scripted navigation now goes through one readiness helper that
waits for the shell's workspaceRestored signal before it opens a note.

On Windows the vault package failed in cleanup rather than in a test:
ListNotes schedules a note-meta cache snapshot one second later, and the
slow runner reached t.TempDir removal while that goroutine was creating
files, so Windows refused to delete the directory. The same race exists on
main; it only surfaced here because the runner happened to line up with the
delay. The vault now counts its delayed writers and exposes Close to drain
them, and the package's tests keep the writer off through TestMain so no
test can race its own cleanup. A test that opts back in drains with Close.

Validation: the browser harness passes locally against real Chrome; go vet
and the full server suite pass in the branch worktree.
@adibhanna
adibhanna marked this pull request as ready for review September 16, 2026 20:07
@adibhanna
adibhanna merged commit 2f2f00d into main Sep 16, 2026
15 checks passed
@adibhanna
adibhanna deleted the refactor/ecosystem-boundaries-pr branch September 16, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants