Remove [[wiki-links]], backlinks and the graph
CI & Build / Build now, or wait for Android? (push) Successful in 2s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Failing after 6s
CI & Build / Build & push image (push) Skipped
CI & Build / Python tests (push) Successful in 8s
Desktop (Tauri) / Tauri desktop (Linux) (push) Failing after 31s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Failing after 37s
Desktop (Tauri) / Update manifest (push) Skipped
Android / Kotlin + Rust (APK) (push) Failing after 1m56s

Operator, 2026-08-22 (note 2897): ThoughtSync is an intermediary surface. You
write here because it's easy — a notebook in your pocket — and later you recall
the thing and go finish it somewhere else. Recall is the product; organization
is secondary. A linking system is organization, and it isn't what this is for.

So: `[[wiki-links]]`, backlinks, the `[[` autocomplete, the note_links table,
`/api/notes/link-search`, `/api/notes/<id>/backlinks`, the whole graph blueprint
and GraphView. Rust core loses `extract_links`, `backlinks`, `link_search` and
`create_titled`; the desktop loses the three Tauri commands that exposed them.

This subsumes 982d24c rather than reverting it. That commit bound links to a
note id so a rename would stop rewriting other notes' bodies — real infra, but
infra for a feature that is now gone, and nothing it added survives. Alembic
0023 stays in the chain anyway: it shipped in an image and may already be
applied, and deleting an applied revision strands a database's version pointer.
0024 drops the table and takes the column with it. The history stays honest
about the fact that it existed for a day.

Two things deliberately kept, because they were serving recall and only
incidentally serving links:

- `/api/notes/titles` and the titles store. The command palette lists them so
  you can jump to a note by name. `resolve()` — the name→note lookup that only
  linking needed — is gone.
- `display_title`. Every note still has a name for search results and export
  filenames. What that name is FOR changed; that it exists did not.

`notes/links.py` is now `notes/tags.py`, holding the #tag→label reconciliation
it always also owned. A file called links.py with no links in it would have been
exactly the drift this removal is meant to end.

Also swept out on the way: `_escape_like`, whose only caller was link-search,
and the `graph` icon. Nothing lost that a person typed — note_links was always
derived, and the `[[text]]` is still sitting in every body it was written in.
This commit is contained in:
2026-08-22 12:00:57 -04:00
parent 982d24c83b
commit bc22f8e249
38 changed files with 216 additions and 1485 deletions
+1 -4
View File
@@ -16,7 +16,7 @@ import type { Device } from "../stores/devices";
import type { TitleEntry } from "../stores/titles";
import type { User } from "../stores/session";
import type { PublicConfig } from "../stores/config";
import type { Backlink, DeviceToken, ImportResult, Repo } from "./repo";
import type { DeviceToken, ImportResult, Repo } from "./repo";
const NEEDS_SERVER = "That's not available offline — connect a server to use it.";
@@ -51,7 +51,6 @@ export const local: Repo = {
list: (query) => invoke<Note[]>("notes_list", { query }),
get: (id) => invoke<Note>("notes_get", { id }),
create: (input) => invoke<Note>("notes_create", { input }),
createTitled: (title) => invoke<Note>("notes_create_titled", { title }),
update: (id, changes) => invoke<Note>("notes_update", { id, changes }),
completeReminder: (id) => invoke<Note>("notes_complete_reminder", { id }),
snoozeReminder: (id, minutes) => invoke<Note>("notes_snooze_reminder", { id, minutes }),
@@ -73,8 +72,6 @@ export const local: Repo = {
reminders: () => invoke<Note[]>("notes_reminders"),
titles: () => invoke<TitleEntry[]>("notes_titles"),
search: (q) => invoke<Note[]>("notes_search", { q }),
backlinks: (id) => invoke<Backlink[]>("notes_backlinks", { id }),
linkSearch: (q) => invoke<TitleEntry[]>("notes_link_search", { q }),
},
savedFilters: {
-7
View File
@@ -49,10 +49,6 @@ export interface ChecklistItemChanges {
checked?: boolean;
}
export interface Backlink {
id: string;
title: string;
}
export interface ImportResult {
source: string;
@@ -97,7 +93,6 @@ export interface NotesRepo {
list(query: NoteListQuery): Promise<Note[]>;
get(id: string): Promise<Note>;
create(input: NoteCreateInput): Promise<Note>;
createTitled(title: string): Promise<Note>;
update(id: string, changes: NoteChanges): Promise<Note>;
completeReminder(id: string): Promise<Note>;
snoozeReminder(id: string, minutes: number): Promise<Note>;
@@ -119,8 +114,6 @@ export interface NotesRepo {
reminders(): Promise<Note[]>;
titles(): Promise<TitleEntry[]>;
search(q: string): Promise<Note[]>;
backlinks(id: string): Promise<Backlink[]>;
linkSearch(q: string): Promise<TitleEntry[]>;
}
export interface SavedFiltersRepo {
-5
View File
@@ -13,7 +13,6 @@ import type { TitleEntry } from "../stores/titles";
import type { User } from "../stores/session";
import type { PublicConfig } from "../stores/config";
import type {
Backlink,
DeviceToken,
ImportResult,
NoteChanges,
@@ -80,7 +79,6 @@ export const rest: Repo = {
list: async (query) => (await api.get<{ notes: Note[] }>(`/api/notes?${notesQuery(query)}`)).notes,
get: (id) => api.get<Note>(`/api/notes/${id}`),
create: (input: NoteCreateInput) => api.post<Note>("/api/notes", input),
createTitled: (title) => api.post<Note>("/api/notes", { title, body: "" }),
update: (id, changes: NoteChanges) => api.patch<Note>(`/api/notes/${id}`, changes),
completeReminder: (id) => api.post<Note>(`/api/notes/${id}/reminder/complete`),
snoozeReminder: (id, minutes) => api.post<Note>(`/api/notes/${id}/reminder/snooze`, { minutes }),
@@ -103,9 +101,6 @@ export const rest: Repo = {
reminders: async () => (await api.get<{ notes: Note[] }>("/api/notes/reminders")).notes,
titles: async () => (await api.get<{ titles: TitleEntry[] }>("/api/notes/titles")).titles,
search: async (q) => (await api.get<{ notes: Note[] }>(`/api/notes/search?q=${encodeURIComponent(q)}`)).notes,
backlinks: async (id) => (await api.get<{ backlinks: Backlink[] }>(`/api/notes/${id}/backlinks`)).backlinks,
linkSearch: async (q) =>
(await api.get<{ results: TitleEntry[] }>(`/api/notes/link-search?q=${encodeURIComponent(q)}`)).results,
},
savedFilters: {