63 lines
3.3 KiB
Markdown
63 lines
3.3 KiB
Markdown
model: claude-sonnet-4-6
|
|
prompt: model-tests/01-architectural-risk.md
|
|
context: AGENTS.md
|
|
date: 2026-06-04
|
|
reference: true
|
|
|
|
---
|
|
|
|
decision 1: sqlite with "postgres-ready schema"
|
|
|
|
the risk is that "postgres-ready" is not a state sqlite enforces — it's a promise
|
|
the developer keeps. sqlite is dramatically more permissive than postgres: no
|
|
strict foreign key enforcement by default, no real enum types, no CHECK
|
|
constraints with the same semantics, different RETURNING behavior, and timestamp
|
|
handling that silently accepts junk. the gap only surfaces at migration time,
|
|
which is exactly the worst moment to discover it. the specific trap for this
|
|
codebase is the reaction model — user + post + emoji + timestamp with no counter
|
|
normalization is fine, but if you're using sqlite's flexible typing and unquoted
|
|
column names anywhere, your postgres migration will break on things that look like
|
|
they should work. the tus resumable upload state also tends to involve upserts
|
|
and returning clauses that differ between the two.
|
|
|
|
mitigation: enforce PRAGMA strict = ON from day one (bun:sqlite supports it). this
|
|
makes sqlite reject type mismatches the same way postgres would, and it's a
|
|
one-liner that costs nothing and catches the class of bugs that makes migrations
|
|
painful.
|
|
|
|
---
|
|
decision 2: federation off via a flag, activitypub data model active from day one
|
|
|
|
the risk is not technical complexity — fedify handles that. the risk is that
|
|
"flag-flippable later" assumes your object URIs are stable and your actor
|
|
resolution works correctly before you have any external consumers to test against.
|
|
when you eventually flip the flag, you'll discover that your webfinger endpoint
|
|
was returning the wrong content-type, your @context was subtly wrong, or your
|
|
outbox pagination was broken — and you'll find out from confused server admins on
|
|
the other end, not from a test suite. activitypub interoperability is notoriously
|
|
hard to verify in isolation.
|
|
|
|
mitigation: stand up a second test instance (even just a local second process) and
|
|
do one real federation handshake before v1 ships, even with the flag off in
|
|
production. you don't need to turn it on publicly — you just need to know it
|
|
works. this is maybe two hours of work and it retires the "unknown unknowns" risk
|
|
entirely.
|
|
|
|
---
|
|
decision 3: magic-link email auth with no passwords and no push notifications
|
|
|
|
the hidden complexity here is account recovery under adversarial conditions. magic
|
|
links depend entirely on email delivery. if the user's inbox is inaccessible
|
|
(spam filter swallowed the link, mail provider down, user changed email and didn't
|
|
update), there is no fallback — no password reset, no SMS, no TOTP. for a small
|
|
invite-only community this is probably fine in practice, but the specific failure
|
|
mode is: user gets a new phone, opens eutopic, tries to log in, email goes to spam
|
|
or their old address, and they're locked out with no self-service recovery path.
|
|
they have to contact you, the admin, directly. that's not catastrophic at 50 users
|
|
— it's actually fine — but it needs to be a named operational responsibility, not
|
|
a discovered one.
|
|
|
|
mitigation: add a simple admin-side "resend invite / reassign email" capability
|
|
before the first non-technical user onboards. one endpoint, admin-only, takes a
|
|
username and a new email. this is 20 lines of backend code and it means account
|
|
recovery is always solvable without a production incident.
|