mirror of
https://github.com/priyanshujain/margin.git
synced 2026-10-04 20:17:03 +00:00
some more fixes
This commit is contained in:
1 parent
7a3c04f170
commit
2b86a407ba
63 files changed
+12172
-44
No files matched your search
@@ -0,0 +1,106 @@
|
||||
# Risks
|
||||
|
||||
What could go wrong, what should not be shared at all, and the cost of the shape chosen in
|
||||
[repo-layout.md](repo-layout.md).
|
||||
|
||||
## The two-step tax
|
||||
|
||||
Four separate repos consuming a fifth means every shared change is two commits and a version bump.
|
||||
Today a token can be changed and seen in an app on the next dev server restart, because the
|
||||
dependency is a symlink into a sibling checkout. After consolidation that becomes: change the shared
|
||||
repo, tag it, bump four manifests, install four times.
|
||||
|
||||
That is a real regression in the inner loop and it is the price of the shared code being correct
|
||||
everywhere else. The mitigation is a documented local override, `pnpm.overrides` for npm and a
|
||||
`[patch]` or `.cargo/config.toml` `paths` entry for Rust, so day to day work on shared code is still
|
||||
a live edit. The rule is that the override is a switch a developer turns on, never a value the repo
|
||||
ships, because an override committed by accident reintroduces exactly the problem being fixed.
|
||||
|
||||
If in six months the two-step is the main friction, the honest answer is a monorepo, and that
|
||||
conclusion should be allowed rather than argued around.
|
||||
|
||||
## Version skew across four consumers
|
||||
|
||||
Independent apps on independent release cadences will sit on different shared versions. That is
|
||||
normal and fine until a shared change is not backward compatible, at which point one app is broken
|
||||
and nobody notices because it was not the app being worked on.
|
||||
|
||||
The countermeasure is the smallest one that works: the shared repo's own CI builds all four apps
|
||||
against the candidate before a tag is cut. That needs the four repos to be checkoutable from CI,
|
||||
which needs Margin Mail to have a remote, which is the first item in [migration.md](migration.md).
|
||||
|
||||
## Sharing things that only look alike
|
||||
|
||||
The audits found several places where two implementations resemble each other at the top and diverge
|
||||
completely underneath. Extracting those produces an abstraction larger than either thing it replaced,
|
||||
with a configuration surface nobody can reason about.
|
||||
|
||||
The clearest case is the sync engines. Margin Calendar and Margin Mail agree on the poll loop, the
|
||||
sink trait and the event names, and agree on nothing below that: the cursor models differ in kind,
|
||||
the commit points are deliberately opposite, recovery is opposite, and conflict resolution is
|
||||
opposite. One uses etags and `If-Match`, the other uses declarative replay-safe writes. The trait
|
||||
that looks shared in Margin Mail names no Google type and has three implementations; the calendar's
|
||||
names Google Calendar types in every signature and has one. A shared engine here would be a mistake
|
||||
and the plan says so.
|
||||
|
||||
The same judgement applies to spinners and loading states, which are four different product
|
||||
positions and not four copies of one, to badges, to the floating editor toolbar, and to each app's
|
||||
Typst preamble, which the measurement put at roughly 2% overlap between a book and an A4 document.
|
||||
|
||||
Sharing is justified by measured duplication, not by two files having the same name. Every
|
||||
extraction in this plan carries a number.
|
||||
|
||||
## Sharing too early
|
||||
|
||||
`@margin/ui` is the package with the most value and the most risk, because a component API extracted
|
||||
from two call sites is usually wrong. The rule for it: a primitive moves into the kit when three of
|
||||
the four apps want it, or when two want it and the third's absence is a bug. Anything with two
|
||||
honest consumers stays where it is until a third appears.
|
||||
|
||||
## Freezing a bug into the shared copy
|
||||
|
||||
Three of the audits found that when two files drifted, one repo moved ahead and the other kept a
|
||||
defect the first had already found and written a paragraph about. Margin's PDF export ships every
|
||||
heading at weight 400 because it loads variable fonts where Margin Docs cut static instances; its
|
||||
Typst string escaper uses `JSON.stringify`, so escapes Typst does not recognise reach the page as
|
||||
visible backslashes; its Google refresh token sits in plaintext where two siblings seal theirs.
|
||||
|
||||
Extraction must take the better version, not the older one or the one in the repo being worked in.
|
||||
Where the two differ, the plan names the winner explicitly, and the losing behaviour has to be
|
||||
verified as gone rather than assumed. The reverse risk is worse: standardising four apps onto the
|
||||
oldest implementation would make three of them worse at once.
|
||||
|
||||
## The licence conflict is load-bearing
|
||||
|
||||
Margin is FSL-1.1-MIT and Margin Mail will be. Margin Calendar and Margin Docs are MIT. Shared code
|
||||
cannot be under two licences, and the shared package currently lives inside the FSL repo. The plan
|
||||
makes the shared repo MIT, which every app can consume, but that is a decision with consequences and
|
||||
it should be made deliberately rather than discovered during extraction.
|
||||
|
||||
## Uncommitted work blocks repo surgery
|
||||
|
||||
Margin Docs has 123 uncommitted files. Margin Mail has 123 uncommitted files on top of a single
|
||||
scaffold commit and has no remote at all. Moving files between repos, rewriting manifests and cutting
|
||||
tags across that is how work gets lost.
|
||||
|
||||
Nothing in this plan starts until those two trees are committed and pushed. That is not a
|
||||
precaution, it is a precondition.
|
||||
|
||||
## Design drift is the thing being fixed, so measure it
|
||||
|
||||
The reason for all of this is that the same fix keeps being made four times, and the evidence is
|
||||
specific: eleven independent implementations of a square icon button, five different fixes for the
|
||||
same icon baseline problem, the same `--ink-faint` contrast correction discovered independently in
|
||||
two apps while the other two kept the failing value, and a centring fix for one glyph that exists,
|
||||
with a written explanation, in exactly one repo.
|
||||
|
||||
After consolidation, that class of drift should be impossible rather than merely discouraged. The
|
||||
check that makes it so is a lint over each app's CSS for colour literals outside the token layer and
|
||||
for glyph paths defined outside `@margin/icons`. Without it, the tokens get shared and the drift
|
||||
resumes in the app stylesheets within a month.
|
||||
|
||||
## What this plan does not fix
|
||||
|
||||
It does not make the four apps one product, and it should not try. They have different data models,
|
||||
different backends, different keyboard vocabularies and different reasons to exist. The goal is that
|
||||
they share a foundation and a look, not that they share a shape.
|
||||
Reference in new issue
Block a user