some more fixes

This commit is contained in:
pj committed 2026-10-03 22:48:49 +05:30
1 parent 7a3c04f170
commit 2b86a407ba
63 files changed
+12172 -44

No files matched your search

+104
View File
@@ -0,0 +1,104 @@
# App facts
Things true of exactly one app. Everything in the other files applies to all four.
## Margin, the writing studio
`python/margin`, package `margin-app`, bundle id `studio.margin.app`, version 0.1.17, FSL-1.1-MIT.
The oldest and most polished of the four, and the one that ships first on any new channel.
Library data is self-contained `{book-id}.margin` JSON files with images embedded as base64, plus
`custom-dictionary.txt`, in `~/Library/Application Support/studio.margin.app/library/`. That
simplicity is what made the Drive backup feature small.
Google Drive backup is built and lives in `src-tauri/src/gdrive.rs`, with `src/backup.ts`,
`src/store/useBackup.ts`, `BackupButton` and the `BackupSettings` panel on the front. Loopback plus
PKCE through the system browser, scope `drive.file` and `openid email`. `drive.file` is
non-sensitive, so there is no Google verification review and no CASA audit, and the consent screen is
set to Production to avoid the unverified warning and the seven-day refresh token expiry that testing
mode imposes.
The Drive layout is a visible `margin/` folder, one file per book, latest only, because Drive keeps
revisions itself. Backup triggers are manual, on app close, and every 15 minutes, all gated on a
dirty check so nothing uploads unless something changed. The cloud icon opens the panel rather than
backing up in one click, because the panel is the single home for back up, restore, disconnect and
account. Restore is offered as an ignorable link on the empty-library state, which doubles as
connect-on-a-new-machine.
The refresh token and sync state sit in plaintext in `backup.json` in the app data directory. That
was a deliberate step back from the keychain, for the reasons in [code-style.md](code-style.md), and
it matches the app's existing local-data model given the limited scope. The newer apps seal theirs
with XChaCha20-Poly1305 instead, and Margin should be brought up to that.
Margin has no test script at all. It is the only one of the four without one.
`appstore/` and `target-mas/` are the Mac App Store build track.
## Margin Calendar
`python/margin-caledar`, package `margin-calendar`, bundle id `studio.margin.calendar`, MIT. The
directory name really is misspelt.
Its `docs/design.md`, `docs/conventions.md` and `docs/architecture.md` are the model the rest of the
suite documents by. When writing docs for another app, follow those.
Prev and next move one day, never a week. Week view is a rolling seven days from the anchor by
default, with `weekMode()` in `src/time.ts` stored under `margincal-week-mode` and `weekAnchor()` as
the single source both `spanFor` and `GridView` use. Never reintroduce a bare `startOfWeek` call in
either. The snapping "calendar" mode exists in Settings, and only there do the arrows step by a week,
because a day step would be invisible.
The vertical axis has contraction hysteresis for the same reason the horizontal one slides by a day:
positional memory is most of the speed of a keyboard-driven calendar.
Persisted localStorage keys are `margincal-folds`, `margincal-bounds`, `margincal-view` and
`margincal-theme`. See [platform.md](platform.md) for how to read them out of the installed app.
This is the app with the Nix flake, and the one whose Linux story the others should copy.
## Margin Docs
`rust/margin-editor`, package `margin-docs`, remote `margin-docs`, MIT. Three names for one thing,
and the directory is the odd one out.
No memory files and no `CLAUDE.md` exist for this app, so nothing was ever written down about it. It
is also the largest front end in the suite at 43,000 lines, and it is a near twin of Margin on the
Rust side: `pdf.rs`, `fonts.rs`, `macspell.rs` and `writingtools.rs` exist in both. That duplication
is the subject of `../typesetting.md`.
## Margin Mail
`rust/margin-mail`, bundle id in the same `studio.margin.*` family, FSL-1.1-MIT. Third in the suite
and the largest Rust codebase at 46,000 lines. No git remote yet.
The premise is a keyboard-first email client over Gmail where the user never feels Gmail. HEY and
Superhuman are the feature vocabulary. Mailspring is the reliability bar.
Product decisions locked on 2026-09-03, not to be reopened unless the user does:
macOS first, then iOS, then minor work for Linux. List plus reading pane in the Superhuman shape,
with HEY's Reply Later and Set Aside piles, and Feed and Paper Trail as views. The Inbox is one list
in time order under Back, with unseen shown by weight alone: no dot, no band, no groups. Seen on open
at once, a new reply makes a thread unseen again, the dock badge stays, and there are no counts in
the list. The Screener is on by default with a first-run pass that screens in anyone who has emailed
before. No AI in v1, though the design leaves room. Trackers are blocked and never sent, because
privacy and ownership are core tenets. Scheduled sending is skipped; snooze and Bubble Up stay,
evaluated lazily when a device opens or wakes. Multiple accounts with per-account views and an
optional unified view. Backends after Gmail are generic IMAP and SMTP, then JMAP for Fastmail.
Calendar invites RSVP inline and hand off to Margin Calendar, with no calendar sidebar. Compose is
inline at the end of the thread, or a floating card for new mail. Full local mirror of mail, with
attachments on demand.
App state must not depend on Gmail or any provider. In the user's words: "if I switch to protonmail
tomorrow I don't want to lose data." Local data is the truth and cloud stores are backup only, behind
one interface, with Google Drive for non-technical friends and Cloudflare R2 for the user. Key
portable state on the RFC Message-ID and the sender address, never on provider ids.
Four Playwright specs fail on a clean tree and are not flakes. `tests/shell.spec.ts` ("New for you
above Previously seen"), `tests/snooze.spec.ts` ("Back above New for you") and `tests/triage.spec.ts`
("Mark all as seen is a link on the heading") all assert Inbox group heads that the app deliberately
no longer draws: `GROUPS` in `src/ipc.ts` has no `new` or `seen` label and `ListColumn` renders
`GroupHead` with no action. The fourth, `tests/kit.spec.ts` ("every text field tells the webview not
to fill it in"), is a static scan that flags an input in `Kit.tsx` and one in `Settings.tsx`. Match on
the test name, not the line number. If exactly these fail, say they are pre-existing and move on.
Fixing them means rewriting the assertions to the current design, which is its own piece of work.