Server comments describe the code to a stranger (#6221)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Android / Core and FFI clippy and tests (push) Skipped
Android / Kotlin + Rust (APK) (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 9s
CI & Build / Python tests (push) Successful in 13s
Android / Build the server image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Skipped
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
CI & Build / integration (push) Successful in 1m30s
CI & Build / Build & push image (push) Successful in 32s

Rule 32 "Comments describe the product to a stranger" sweep over
src/, alembic/ and tests/. Comments and docstrings now say what the code
does and the reason as a present-tense constraint, briefly.

Removed:
- issue, task, note, rule, milestone and family-idea references
- "used to" / before-and-after narration
- quotes of decisions and incident stories from the deploying instance
- paragraph-length arguments, where a line or two carries the fact

Kept every hazard as a present-tense fact, e.g. timing oracles, the
proxy hop direction, and migrations that must stay frozen.

Also:
- Three test names lose "still"/"used to"/"pre_m304" phrasing.
- pyproject's description drops "FabledSword family".

The history these comments carried stays in Scribe and in git log.
A comment-stripping diff (Scribe snippet #6226 "codeonly.py — prove a
diff changed only comments") shows no code changed apart from the
renamed tests and the description string.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:07:47 -04:00
co-authored by Claude Opus 5.5
parent 5556bb2136
commit a51a563fe7
108 changed files with 779 additions and 1610 deletions
+64 -120
View File
@@ -1,17 +1,11 @@
"""The real-Postgres lane (family rule 6).
Everything else in this suite is deliberately DB-free, which means the schema the
migrations build has never been checked against the models that read it. That gap is
what this file closes, and it is not theoretical: M13 dropped three columns and
rebuilt a generated column, and until now `alembic upgrade head` ran for the first
time when the operator's container started.
"""The real-Postgres lane: the schema the migrations build, against the models and
routes that use it.
Marked `integration` and excluded from the unit lane by `-m "not integration"`, so a
workstation without Postgres runs the rest of the suite unchanged.
The schema comes from real migrations, never `metadata.create_all` (rule 82) — the
point is to test what actually ships, and `create_all` would build a schema no
deployment has ever seen.
The schema comes from real migrations, never `metadata.create_all`, so it is the one
that ships.
"""
from __future__ import annotations
@@ -92,7 +86,7 @@ async def owner(db):
async def test_the_migrated_schema_matches_the_models(db, owner):
"""The check that has never run: insert through the ORM, read it back.
"""Insert through the ORM, read it back.
A column the models expect and the migrations never created — or the reverse —
fails right here, instead of when a container starts.
@@ -109,7 +103,7 @@ async def test_the_migrated_schema_matches_the_models(db, owner):
async def test_the_dropped_columns_are_actually_gone(db):
"""M13 dropped three. If a migration silently no-opped, this is where it shows."""
"""Dropped columns are really gone; a migration that silently no-opped shows here."""
cols = set(
(
await db.execute(
@@ -143,11 +137,7 @@ async def test_the_dropped_columns_are_actually_gone(db):
async def test_the_search_vector_was_rebuilt_over_the_name(db, owner):
"""0026 had to drop and recreate a STORED GENERATED column.
Postgres refuses to drop a column another generated column depends on, so getting
this wrong doesn't produce a subtly wrong ranking — it produces a migration that
won't run at all. Worth proving the replacement actually indexes something.
"""0026 recreates a stored generated column; the replacement must index something.
"""
note = Note(owner_id=owner.id, body="ferry tickets\nbook before friday", display_title="ferry tickets")
db.add(note)
@@ -173,12 +163,7 @@ async def test_the_search_vector_was_rebuilt_over_the_name(db, owner):
async def test_a_note_keeps_its_prose_on_both_sides_of_its_list(db, owner):
"""The shape M304 made expressible at all.
The old model could not hold this: a row had a position in a table and none in the
text, so a checklist could only ever render AFTER the body. Prose, list, prose is
the case that proves the storage changed, not just the styling.
"""
"""Prose, list, prose: a checklist can sit between two paragraphs."""
body = "weekend shop\n\n- [ ] milk\n- [x] eggs\n\nback before six"
note = Note(owner_id=owner.id, body=body, display_title=derive_display_title(body))
db.add(note)
@@ -191,12 +176,7 @@ async def test_a_note_keeps_its_prose_on_both_sides_of_its_list(db, owner):
async def test_ticking_an_item_is_a_body_edit(db, owner):
"""What replaced `_apply_note_items`: there is no separate thing left to apply.
The regression that function guarded against — a sync silently eating a checklist
off a note that also had a body — cannot recur, because there is nothing to delete.
A pushed body either has the lines or it does not.
"""
"""A pushed body carries its checklist; there is nothing separate to apply."""
body = "packing\n\n- [ ] socks"
note = Note(owner_id=owner.id, body=body, display_title="packing")
db.add(note)
@@ -213,11 +193,10 @@ async def test_ticking_an_item_is_a_body_edit(db, owner):
async def test_a_standalone_tag_leaves_the_body_and_becomes_an_ordinary_label(db, owner):
"""M311. The tag was being shown twice — as text and as a chip — so the text goes.
"""A tag on its own line leaves the text and shows as a chip.
`via_tag=False` is the load-bearing half. It is what makes the chip's × appear in
both editors (they gate it on exactly this), which matters because deleting the
text is no longer a way to remove the tag: there is no text.
`via_tag=False` is what makes the chip's × appear in both editors, the only way
to remove a tag with no text.
"""
note = Note(owner_id=owner.id, body="#todo\nreorganize the homepage", display_title="#todo")
db.add(note)
@@ -226,8 +205,7 @@ async def test_a_standalone_tag_leaves_the_body_and_becomes_an_ordinary_label(db
await db.commit()
assert note.body == "reorganize the homepage"
# Re-derived by the lift itself. Every caller sets display_title BEFORE calling,
# so if the function did not do this the note would be named after a line it had
# Re-derived by the lift itself, or the note would be named after a line it had
# just deleted.
assert note.display_title == "reorganize the homepage"
@@ -237,11 +215,8 @@ async def test_a_standalone_tag_leaves_the_body_and_becomes_an_ordinary_label(db
async def test_a_tag_moved_onto_its_own_line_graduates_instead_of_vanishing(db, owner):
"""The bug a naive lift has, pinned.
A tag that is still in prose stays derived. Move it to its own line and it must
become an ordinary label — NOT be detached for no longer appearing in the body,
which is what happens if the row is dropped before it is graduated.
"""A tag in prose stays derived. Moved to its own line it becomes an ordinary
label, rather than being detached for no longer appearing in the body.
"""
note = Note(owner_id=owner.id, body="call #mom tomorrow", display_title="call #mom tomorrow")
db.add(note)
@@ -265,8 +240,7 @@ async def test_a_tag_moved_onto_its_own_line_graduates_instead_of_vanishing(db,
async def test_deleting_an_inline_tag_still_detaches_it(db, owner):
"""The old behaviour, unchanged where the text is unchanged. A tag still living in
prose is still owned by that prose."""
"""A tag still in prose is still owned by that prose."""
note = Note(owner_id=owner.id, body="call #mom tomorrow", display_title="call #mom tomorrow")
db.add(note)
await db.flush()
@@ -281,11 +255,7 @@ async def test_deleting_an_inline_tag_still_detaches_it(db, owner):
async def test_a_note_with_only_a_list_still_has_a_name(db, owner):
"""The hole that made removing the title unsafe, still closed — by a different
mechanism. There is no item table to fall back to any more; the name comes from
the first line with its marker stripped, because calling the note "- [ ] milk"
would show someone the storage instead of the note.
"""
"""A checklist-only note is named by its first item, without the marker."""
body = "- [ ] milk\n- [ ] eggs"
note = Note(owner_id=owner.id, body=body, display_title=derive_display_title(body))
db.add(note)
@@ -297,10 +267,9 @@ async def test_a_note_with_only_a_list_still_has_a_name(db, owner):
async def test_auto_unfurl_stores_a_preview_and_skips_what_is_cached(db, owner, monkeypatch):
"""The background pass, run inline so the assertions are deterministic.
The network is stubbed — this is about what reaches the DATABASE, not about
parsing someone's OpenGraph tags (unfurl.py's own tests cover that). What matters
here is the part only a real database can show: the unique constraint holding, the
upsert going to the right row, and a second pass not re-fetching.
The network is stubbed; this is about what reaches the database: the unique
constraint holding, the upsert going to the right row, and a second pass not
re-fetching.
"""
note = Note(
owner_id=owner.id,
@@ -373,11 +342,10 @@ async def test_detection_agrees_with_what_gets_stored(db, owner, monkeypatch):
async def test_registration_closes_itself_once_an_admin_exists(app_client, db):
"""The gap this removes: registration was open between "my account exists" and
"I remembered to turn it off", and on a public host that gap starts at DNS.
"""Registration closes as soon as the admin account exists.
Runs against a real database because it is the interaction between two writes —
the user row and the settings row — inside one transaction.
Real database: it is two writes, the user row and the settings row, in one
transaction.
"""
# The instance is empty (the fixture truncated it), so this is the first account:
# allowed unconditionally, and it becomes the admin.
@@ -413,11 +381,9 @@ async def test_registration_closes_itself_once_an_admin_exists(app_client, db):
async def test_security_settings_are_live_and_bounded(app_client, db):
"""The security values are settings now, not constants — so saving one has to take
effect without a restart, and a dangerous value has to be refused.
Real database because the whole point is the round trip: write through the admin
API, re-read into the cache the throttle consults, observe the new number.
"""Saving a security setting takes effect without a restart, and a dangerous
value is refused: write through the admin API, re-read into the throttle's cache,
observe the new number.
"""
# An admin to authenticate as. First account, so it is allowed and becomes admin.
reset_live()
@@ -433,9 +399,7 @@ async def test_security_settings_are_live_and_bounded(app_client, db):
assert live("trusted_proxy_hops") == 1
assert live("signin_limit_per_account") == 10
# A value that would disable the protection is REFUSED, not clamped — storing a
# different number than the one typed is how somebody ends up believing a limit
# is set to something it is not.
# A value that would disable the protection is refused, not clamped.
bad = await app_client.patch("/api/settings", json={"signin_limit_per_account": 0})
assert bad.status_code == 400
assert "at least" in (await bad.get_json())["error"]
@@ -498,14 +462,8 @@ async def _revision_count(db, note_id) -> int:
async def test_a_session_of_edits_costs_one_revision(db, owner):
"""The change that makes autosave affordable.
Version history used to snapshot on EVERY body write, so the clients saved as
rarely as they could — only when an editor closed — and a crash mid-session lost
everything typed. Durability was paying for history. Now a sitting earns one
revision no matter how many times it is written, so a client can write whenever
it likes.
"""
"""A sitting earns one revision however often it is written, so clients can
autosave."""
note = Note(owner_id=owner.id, body="one", display_title="one")
db.add(note)
await db.commit()
@@ -563,13 +521,8 @@ async def test_renaming_a_tag_onto_an_existing_one_merges_into_the_older(app_cli
"""Renaming a tag onto a name another tag holds merges them, and the OLDER row
is the survivor — whichever side the caller happened to be renaming.
Runs against a real database because the whole question is about `created_at`
ordering and the note_labels rows moving, neither of which a unit test sees.
Age decides, rather than "the one that already held the name", so that renaming
A→B and renaming B→A land on the same row. If the incumbent won, the survivor
would depend on which way round someone typed it, and two clients racing the
same tidy-up would disagree about which id still exists.
Age decides, so renaming A→B and B→A land on the same row and two clients racing
the same tidy-up agree on which id survives.
"""
reg = await app_client.post(
"/api/auth/register",
@@ -626,9 +579,8 @@ async def test_the_rename_merge_survivor_does_not_depend_on_the_direction(app_cl
async def test_creating_a_tag_that_differs_only_in_case_returns_the_existing_one(app_client, db):
"""A case-sensitive match here used to mint "Groceries" beside "groceries". No
synced client can hold both — their `labels` index is unique on `lower(name)` —
so the pair was a pull that would fail later, on a phone, with no UI in the path.
"""Case-insensitive: no synced client can hold both "Groceries" and "groceries",
since their `labels` index is unique on `lower(name)`.
"""
reg = await app_client.post(
"/api/auth/register",
@@ -646,12 +598,10 @@ async def test_creating_a_tag_that_differs_only_in_case_returns_the_existing_one
assert len(listing) == 1
# --- A deleted tag is a tombstone on every path (#5382) ---------------------------
# --- A deleted tag is a tombstone on every path ----------------------------------
#
# The web deleted the row outright, so the change feed never carried the delete and
# devices kept the tag. A device's delete left a tombstone the web still listed and
# still matched by name. One definition now: `labeling.tombstone_label`, and every
# read of the catalog goes through `labeling.live`.
# So the change feed tells devices. One definition, `labeling.tombstone_label`, and
# every read of the catalog goes through `labeling.live`.
async def _label_in_feed(app_client, lid: str) -> dict | None:
@@ -666,7 +616,7 @@ async def _push_label(app_client, lid: str, op: str, edited_at: str, name: str =
async def test_a_tag_listing_says_when_each_was_last_used(app_client, db):
"""The rail keeps the most recent few (#5931): a tag is as recent as the newest
"""The rail keeps the most recent few: a tag is as recent as the newest
note carrying it, and a note in the trash does not count."""
await _signed_in(app_client, "lastused")
used = await (await app_client.post("/api/labels", json={"name": "errands"})).get_json()
@@ -751,11 +701,10 @@ async def test_a_device_can_make_a_deleted_tags_name_again(app_client, db):
assert [lb["id"] for lb in listing] == [new]
# --- One save path for a note's text (#5164) ---------------------------------
# --- One save path for a note's text -----------------------------------------
#
# A body edit is a sequence: keep a revision, rename the note, lift #tags, commit,
# queue link previews. It was written out once per route, and the copies drifted —
# restoring a revision skipped the previews. These pin the sequence at each door.
# queue link previews. These pin the sequence at each route.
async def _signed_in(app_client, who: str):
@@ -774,9 +723,7 @@ def _record_previews(monkeypatch, module: str) -> list[tuple[str, str]]:
async def test_restoring_a_revision_queues_previews_for_its_links(app_client, db, monkeypatch):
"""The bug that motivated the shared path: restore was the one copy of the edit
sequence without the unfurl step, so a link brought back by a restore stayed a
bare URL on every surface."""
"""A link brought back by a restore gets its preview."""
await _signed_in(app_client, "restore")
queued = _record_previews(monkeypatch, "inkwell.notes")
@@ -845,8 +792,8 @@ async def test_a_pushed_note_is_named_tagged_and_queued_like_a_typed_one(app_cli
async def test_a_pushed_edit_keeps_the_clients_edit_time_when_a_tag_is_lifted(app_client, db):
"""Last-write-wins compares edit times, so the stored one has to be the client's.
Lifting a tag rewrites the body in a second flush, and the column's onupdate
used to stamp the server's clock over the time the client sent."""
Lifting a tag rewrites the body in a second flush, where the column's onupdate
would stamp the server's clock over the time the client sent."""
await _signed_in(app_client, "edited")
nid = str(uuid.uuid4())
await app_client.post(
@@ -858,7 +805,7 @@ async def test_a_pushed_edit_keeps_the_clients_edit_time_when_a_tag_is_lifted(ap
assert datetime.fromisoformat(note["updated_at"]) == datetime(2026, 1, 1, tzinfo=timezone.utc)
# --- attachments as a sync entity (#5168) ---------------------------------------
# --- attachments as a sync entity -----------------------------------------------
async def _note_revision(app_client, nid: str) -> int:
@@ -912,8 +859,7 @@ async def test_an_offline_attachment_uploads_once_under_its_own_id(app_client, d
async def test_a_purged_note_and_its_files_read_as_gone(app_client, db):
"""A purged note reads as absent (#2128). Opening it and its attachment selected
with the ACL inline and skipped that filter, so a tombstone came back 200 (#5383)."""
"""A purged note reads as absent, opened directly or through its attachment."""
await _signed_in(app_client, "purged")
nid = await _pushed_note(app_client)
aid = str(uuid.uuid4())
@@ -1008,7 +954,7 @@ async def test_a_preview_arriving_or_leaving_moves_its_note_in_the_feed(app_clie
assert await _note_revision(app_client, nid) > arrived
# --- the export format, pinned against the shared fixture (#5170) ---------------
# --- the export format, pinned against the shared fixture ----------------------
async def test_an_export_writes_the_keys_the_shared_fixture_names(app_client, db):
@@ -1043,7 +989,7 @@ async def test_an_export_writes_the_keys_the_shared_fixture_names(app_client, db
async def test_a_keep_note_that_is_only_a_photo_imports(app_client, db):
"""It used to be skipped as empty. The core's importer keeps it as well."""
"""A photo-only note is a note, as in the core's importer."""
import io
import json
import zipfile
@@ -1066,7 +1012,7 @@ async def test_a_keep_note_that_is_only_a_photo_imports(app_client, db):
assert att.mime == "image/png"
# ---- invites (#5172) ---------------------------------------------------------------
# ---- invites -----------------------------------------------------------------------
_PASSWORD = "a-long-enough-password"
@@ -1082,8 +1028,8 @@ async def _admin_with_invite(app_client, **body) -> str:
async def test_the_first_account_is_refused_once_the_setup_window_has_closed(db):
"""A fresh server on a public address must not belong to whoever finds it first
(family idea #5105, practice 8). Past the window, nobody becomes admin."""
"""A fresh server on a public address must not belong to whoever finds it first.
Past the window, nobody becomes admin."""
from inkwell.auth import SETUP_WINDOW_S
ratelimit.reset_all()
@@ -1217,8 +1163,7 @@ async def test_two_people_racing_one_invite_cannot_both_get_in(app_client, db):
assert count == 2, "the admin and exactly one of the two"
# --- Admin-issued password reset links (#5173) ---------------------------------
# --- Admin-issued password reset links -----------------------------------------
async def _admin_and_guest(app_client):
@@ -1323,7 +1268,7 @@ async def test_a_short_password_leaves_the_reset_link_usable(app_client, db):
assert ok.status_code == 200
# --- Storage per account (#2939 §4) ---------------------------------------------
# --- Storage per account --------------------------------------------------------
_GB = 1024**3
@@ -1417,7 +1362,7 @@ async def _back_to_default(key: str) -> None:
await fresh.commit()
# --- Changing a password, and signing out everywhere else (#5105, practice 4) ---
# --- Changing a password, and signing out everywhere else ----------------------
async def _elsewhere(app_client):
@@ -1505,14 +1450,13 @@ async def test_sign_out_elsewhere_from_a_device_keeps_that_device(app_client, db
async def test_revoking_this_device_from_a_web_session_is_a_bad_request(app_client, db):
"""A session-cookie caller holds no device token, so "revoke the one I'm using"
has nothing to name. Moved here from the unit lane when the session check began
reading the account (#5173)."""
has nothing to name."""
await _signed_in(app_client, "web")
resp = await app_client.delete("/api/auth/devices/self")
assert resp.status_code == 400
# --- The audit log (#2939 §5) --------------------------------------------------
# --- The audit log -------------------------------------------------------------
async def _activity(client) -> list[dict]:
@@ -1580,7 +1524,7 @@ async def test_activity_older_than_its_retention_is_swept(app_client, db):
assert emails == {"owner@example.test"}
# --- Sharing a note (#5174) ---------------------------------------------------
# --- Sharing a note -----------------------------------------------------------
#
# Owner, a recipient, and a stranger who is on the instance but not shared with.
@@ -1656,7 +1600,7 @@ async def test_a_view_share_writes_nothing_and_an_edit_share_writes_only_text(ap
nid = await _owners_note(app_client, "first line\n- [ ] milk")
await _share(app_client, nid, people["recipient"], "view")
# View: every write is a 404, the same answer a stranger gets (#1984).
# View: every write is a 404, the same answer a stranger gets.
writes = [
recipient.patch(f"/api/notes/{nid}", json={"body": "mine now"}),
recipient.patch(f"/api/notes/{nid}/items/0", json={"checked": True}),
@@ -1684,7 +1628,7 @@ async def test_a_view_share_writes_nothing_and_an_edit_share_writes_only_text(ap
assert "fromguest" in owner_tags
assert (await (await recipient.get("/api/labels")).get_json())["labels"] == []
# Everything else but their own pin and archive (#5176) stays the owner's.
# Everything but their own pin and archive stays the owner's.
assert (await recipient.patch(f"/api/notes/{nid}", json={"remind_at": "2099-01-01T00:00:00Z"})).status_code == 403
assert (await recipient.patch(f"/api/notes/{nid}", json={"body": "x", "recurrence": "daily"})).status_code == 403
assert (await recipient.post(f"/api/notes/{nid}/trash")).status_code == 404
@@ -1769,7 +1713,7 @@ async def test_a_share_names_someone_else_on_this_instance(app_client, db):
assert (await app_client.delete(f"/api/notes/{other}/shares/{sid}")).status_code == 404
# --- Shared notes over sync (#5175) -------------------------------------------
# --- Shared notes over sync ---------------------------------------------------
async def _feed(client, since: int = 0, shares: bool = True) -> dict:
@@ -1794,7 +1738,7 @@ async def test_a_share_reaches_the_recipients_feed_and_a_revoke_takes_it_back(ap
assert held is not None, "the grant moved the note past the recipient's cursor"
assert (held["permission"], held["shared_by"]["display_name"], held["labels"]) == ("view", "owner", [])
assert granted["revoked"] == []
# A client that never asked for shares gets only its own notes, as before.
# A client that never asked for shares gets only its own notes.
assert _feed_note(await _feed(recipient, shares=False), nid) is None
assert "revoked" not in await _feed(recipient, shares=False)
assert _feed_note(await _feed(stranger), nid) is None
@@ -1902,7 +1846,7 @@ async def test_deleting_a_shared_note_reaches_the_recipients_devices(app_client,
assert _feed_note(gone, nid) is None
# --- Groups (#5177) ------------------------------------------------------------
# --- Groups --------------------------------------------------------------------
async def _group(app_client, name: str, *member_ids: str) -> str:
@@ -1982,7 +1926,7 @@ async def test_deleting_a_group_ends_every_share_made_to_it(app_client, db):
assert (await (await app_client.get(f"/api/notes/{nid}")).get_json())["shared"] is False
# --- Password reset by email (#5266) ------------------------------------------
# --- Password reset by email --------------------------------------------------
#
# The SMTP hand-off is replaced by a list; everything up to it is real.
@@ -2024,7 +1968,7 @@ async def test_the_smtp_password_never_leaves_the_server(app_client, db):
assert (await app_client.patch("/api/settings", json={"smtp_password": ""})).status_code == 200
async with session_scope() as fresh:
assert await get_setting(fresh, "smtp_password") == "hunter2"
# And the row itself holds it sealed, not as text (#5927).
# And the row itself holds it sealed, not as text.
row = await fresh.get(Setting, "smtp_password")
assert "hunter2" not in row.value and sealing.PREFIX in row.value
@@ -2035,7 +1979,7 @@ async def test_the_smtp_password_never_leaves_the_server(app_client, db):
async def test_a_credential_stored_before_sealing_is_sealed_and_a_lost_key_asks_again(app_client, db):
await _mail_off()
await _admin_with_invite(app_client)
# As an instance from before #5927 left it: the password as plain JSON.
# A password stored in the clear, as plain JSON.
async with session_scope() as fresh:
fresh.add(Setting(key="smtp_password", value='"hunter2"'))
await fresh.commit()
@@ -2150,7 +2094,7 @@ async def test_the_test_email_goes_to_the_admin_and_reports_a_failure(app_client
assert "bad credentials" in (await failed.get_json())["error"]
# --- backups (#5918–#5921) --------------------------------------------------------------
# --- backups ------------------------------------------------------------------------
async def _backup_settings_off() -> None: