Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #550
What this adds
docs/adr/README.md— the index. Lists each record with its status(accepted / superseded), plus how to add one.
docs/adr/0000-template.md— context / decision / consequences / status, witha required "alternatives rejected" section (and an instruction to say so
explicitly when the repo does not record why something was rejected).
decisions that were shipped and later superseded — the replacement only makes
sense against what it replaced, and remnants of both are still in the tree.
devicestable(createdAt, id), not a sequence countersequence_numberuser_devicestableDocs only — 11 markdown files, no code, schema, config or lockfile touched.
Where the content came from
Everything is sourced from the repository: schema comments, route header
comments,
apps/backend/docs/andapps/web/docs/, the0000migration,docs/, and the review history viagh.Verification
Each decision, with the command used to substantiate it and the output that
matters.
0001 — one canonical
devicestable. Every other device-shaped table FKsinto it; the route header records the
user_devicesmerge, PR #206 added thetable that was merged away.
The 9 FKs are
device_key_history,device_prekeys,message_envelopes,messages,mls_commits,mls_group_members,mls_key_packages,mls_welcomes,push_subscriptions.grep -n 'CREATE TABLE' ... | grep -i devreturns exactly three tables, all of them per-device data stores, and no second
device registry.
0002 —
(createdAt, id)ordering, sequence counter dropped.PR #324 implemented the counter (issue #178 asked for it) and it was reverted;
the schema comment and
routes/sync.ts:21are where the reversal is recorded.docs/group-epoch-sync.md:12-25explains why group control does keep asequence log while chat messages do not.
0003 — ciphertext-only storage, archive-then-purge.
messageshas no plaintextcontentcolumn. The policy (and the rejectedin-place tombstone) is in
apps/backend/docs/message-encryption-migration.md;the PR #482 summary records "archive-then-purge, chosen over an in-place
tombstone".
0004 — per-device envelopes.
0005 — sealed box → Signal, per device pair.
The per-envelope
protocolcolumn exists and the enum mirrorsKNOWN_PROTOCOLS; the Phase-2 client adapter still throws, which is why 0005 isrecorded as "accepted, migration not yet activated" rather than done. The
rejected conversation-wide readiness gate and the rejected re-encrypt-history
option are both stated in
apps/backend/docs/signal-migration.md; the librarychoice (
@signalapp/libsignal-clientover the archived JS implementations) is indocs/signal-integration.md.0006 — MLS for groups.
The rejected per-device fan-out for group content is spelled out in
apps/backend/docs/mls-group-files.md("In a 30-person group with 3 devices eachthat is 90 copies of the same bytes"), and the ban on mixing
envelopeswithmlsEpochin bothvalidateMessagePayload.tsand the membership doc.Link integrity
Throwaway script (
/tmp/adr_linkcheck.py, not committed): walks every.mdindocs/adr/, resolves every relative link against the filesystem, skipshttp(s)targets, exits non-zero on a miss.The same check over
IMPLEMENTATION_DOCS.mdreports 12 links, 0 broken.Cross-link from
IMPLEMENTATION_DOCS.mddocs/adr/README.mdcarries the reciprocal line ("Cross-referenced fromIMPLEMENTATION_DOCS.md"), matchingdocs/runbook.md,docs/observability.mdand
docs/threat-model.md.One thing to flag:
IMPLEMENTATION_DOCS.mdis listed in.gitignoreand doesnot exist on
dev(nor on GitHub — the three docs that reference it link to afile only the maintainer has locally). The acceptance criterion asks for a
cross-link from it, so it is added here as a repo-root documentation index and
force-added (
git add -f IMPLEMENTATION_DOCS.md) — it will not be re-ignoredonce tracked. If it should stay local instead, drop that file from the PR and
paste the "Decisions" block into your own copy; everything else is unaffected.
Fidelity notes (things the repo does not substantiate)
The brief was to write what the code actually shows and mark unverified
rationale as unverified, rather than producing plausible-sounding reasons. Three
kinds of gap came up, and each is called out in the record itself:
shared conversation key (0004), sender-keys for groups and searchable
encryption over ciphertext (0003, 0006). The chosen model is in the code;
the debate is not.
ordering comment cites
#137(actually acargo clippyjob) androutes/sync.ts:21cites#128(the treasury proposals table) for theoffline-sync argument;
crypto.tscredits sibling-device coverage to#138(a Rust toolchain pin) and the
device_set_mismatchretry to#133(awithdrawal action) — the sibling-device issue is Multi-device self-sync (sender's own other devices) #188. The behaviour is
verified in code; the comment numbers are not, and the ADRs say so.
0001_mls_group_state.sql,0001_group_control_events.sql,0003_ciphertext_only_messages.sql,0004_envelope_protocol.sqland arollback script;
apps/backend/drizzle/contains only0000_lean_scrambler.sql(plusmeta/), where all the resulting columns andtables do exist. End state is verifiable, the per-migration history is not —
the records say exactly that instead of pretending otherwise.
Also worth a follow-up ticket (found while writing 0002 and 0004): the frontend
still types and sorts on
sequenceNumberfor ordering, which is DRIFT-1 inapps/web/docs/contracts-response-types.md— the ordering now silently collapsesto
0for live and synced messages. The 410 on server-side search also pointsreaders at
github.com/DripWave/clicked/blob/main/docs/message-encryption-migration.md,the wrong owner and path; the doc lives at
apps/backend/docs/message-encryption-migration.md. Both are documented in theADRs, neither is fixed here — docs only.
Testing
No code changed, so there is nothing to run beyond the greps and the link check
above.