Skip to content

Let a space be pinned to the head of the list - #125

Merged
vmillet-dev merged 1 commit into
mainfrom
feat/a-space-can-be-pinned
Sep 15, 2026
Merged

vmillet-dev merged 1 commit into
mainfrom
feat/a-space-can-be-pinned

Conversation

@vmillet-dev

Copy link
Copy Markdown
Owner

Closes #118.

spaces::store::list ordered by name COLLATE NOCASE and that was the only order
there had ever been. With three spaces it costs nothing; with fifteen, the one
opened every morning sits wherever its initial puts it, under two archives nobody
touches.

The decision the ticket asked for

Pinning, not a manual order. A position column is a migration and a second
thing to keep consistent on every insert and every delete. Pinning is a boolean,
and it is a gesture the application already has — it is what the canvas does to a
note. list_spaces now returns pinned first, then by name, which is the same shape
the canvas gives notes.

One order, everywhere. The switcher, the move-to list and the delete refuge all
read list_spaces. The ticket wondered whether the move-to list might want
alphabetical; giving it a different one means a second query or sorting on the front,
and the front does not sort. One list, one order.

The two traps

⚠️ rename used to answer with what it was sent. It built a Space from its own
arguments, which was harmless while id and name were the whole story — and would
have reported every renamed space as unpinned. It reads the row back now, and there
is a test in both the Rust and the e2e suites.

⚠️ Space.pinned carries #[serde(default)], or every export file written before
the column becomes unreadable — transfer::Bundle deserialises Space itself.
Specta turns that default into an optional key, which the front-end model refuses
to be, so SpacesRepository is where it becomes a boolean. That is the one thing a
space now needs converting for, and it is commented as such.

Also found on the way

The e2e page object had to close behind itself: the edit panel replaces the menu
rather than sitting over it, so spaces.open() — which checks whether the dropdown
exists — did nothing on the second call and left the next caller stranded in the
panel. Two scenarios failed on that before the reason was clear.

Checked locally

cargo test all green (5 new integration tests), cargo clippy --all-targets --all-features -D warnings and cargo fmt --check clean, npm test 984 passing,
npm run lint clean, npm run test:e2e 15/15 in 4:23.

docs/architecture.md and CLAUDE.md record the decision and the serde trap.

🤖 Generated with Claude Code

name COLLATE NOCASE was the only order there had ever been, so the space
opened every morning sat wherever its initial fell, under archives nobody
touches. A pinned space is hoisted and the rest still sort by name — the
same shape the canvas gives notes.

A boolean rather than a position column: an order the user maintains is a
second thing to keep consistent on every insert and delete, where pinning
is a gesture the application already has.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vmillet-dev
vmillet-dev merged commit 6e91e6e into main Sep 15, 2026
9 checks passed
@vmillet-dev
vmillet-dev deleted the feat/a-space-can-be-pinned branch September 15, 2026 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spaces are ordered alphabetically, and nothing can change that

1 participant