Notes: plugin backend (CRUD, rename cascade, backlinks, linked notes, daily notes, composer) #14

Open
opened 2026-09-24 10:06:13 +00:00 by kayg · 8 comments
Owner

Codex job notes-backend.

Base: 99aaed887d

Codex job `notes-backend`. Base: 99aaed887d9a1db7043d5e01f92ec6c98b6fa22a
Author
Owner

Started notes backend on branch job/notes-backend at base 99aaed887d. Reading the core, filesystem, index, and plugin contracts before implementation.

Started notes backend on branch job/notes-backend at base 99aaed887d9a1db7043d5e01f92ec6c98b6fa22a. Reading the core, filesystem, index, and plugin contracts before implementation.
Author
Owner

Finding: the plugin host exposed only instance name when building routes. Notes needs the already opened Root and Db to keep all home I/O behind calternal-fs and use the server's SQLite writer. I added optional live handles to PluginContext; static OpenAPI construction leaves them absent. The initial notes schema stores only derived rows plus the durable retitle intent.

Finding: the plugin host exposed only instance name when building routes. Notes needs the already opened Root and Db to keep all home I/O behind calternal-fs and use the server's SQLite writer. I added optional live handles to PluginContext; static OpenAPI construction leaves them absent. The initial notes schema stores only derived rows plus the durable retitle intent.
Author
Owner

Finding: notes-core's retitle planner and target rewrite helper skipped embeds. A Note that embeds the renamed Note would keep a destination that no longer exists. I made the core helpers rewrite matching embeds as well as links, and updated the core regression expectations. The durable retitle order keeps the old file until referrers are rewritten, so replay never exposes a referrer to a removed path.

Finding: notes-core's retitle planner and target rewrite helper skipped embeds. A Note that embeds the renamed Note would keep a destination that no longer exists. I made the core helpers rewrite matching embeds as well as links, and updated the core regression expectations. The durable retitle order keeps the old file until referrers are rewritten, so replay never exposes a referrer to a removed path.
Author
Owner

Implemented Notes CRUD, ETags, journalled retitle and move cascades, Index rows for links/embeds/tags/block IDs, backlinks, linked Notes, Daily notes, composer capture, per-user SSE, search titles/tags, and startup plus hourly reconcile. Targeted tests now pass, including concurrent stale ETags and replay from each persisted retitle step. Core changes are in commit 2c61f02; full workspace gates and generated-contract check remain.

Implemented Notes CRUD, ETags, journalled retitle and move cascades, Index rows for links/embeds/tags/block IDs, backlinks, linked Notes, Daily notes, composer capture, per-user SSE, search titles/tags, and startup plus hourly reconcile. Targeted tests now pass, including concurrent stale ETags and replay from each persisted retitle step. Core changes are in commit 2c61f02; full workspace gates and generated-contract check remain.
Author
Owner

Gate finding: the full workspace test run exposed an Axum panic when the static test app mounted the Notes Plugin without live handles. The Plugin host now skips middleware and nesting for a router with no routes (commit 15dda76). The targeted server test suite passes; full gates are running again.

Gate finding: the full workspace test run exposed an Axum panic when the static test app mounted the Notes Plugin without live handles. The Plugin host now skips middleware and nesting for a router with no routes (commit 15dda76). The targeted server test suite passes; full gates are running again.
Author
Owner

Finished notes backend on branch job/notes-backend.
Head SHA: 78aeae8210

Built: Notes CRUD and ETags, journalled retitle/move and startup replay, derived links/embeds/tags/block IDs, backlinks and linked Notes, Daily notes and composer, title/tag search, shared user-scoped SSE, startup/hourly reconcile, and OpenAPI/TypeScript contract. The worktree is clean. cargo clean removed 7729 files (4.0 GiB).

Decisions for owner confirmation: (1) retitle rewrites referrers before removing the old Note, because deleting first would violate the crash invariant that every referrer points at a readable path; (2) optional folders below Notes/ are accepted as requested by this job, although DESIGN §9 describes flat Notes; (3) the server uses UTC when X-Calternal-Timezone is absent, while the browser supplies its settings/default time zone in that header; (4) reconcile runs at startup and hourly.

Known gaps: list cursors are offset-based and can shift during concurrent edits; retitle/move scans all Notes to discover unresolved wikilinks; user-defined multiline frontmatter properties are preserved on disk but only their first scalar line appears in the structured API projection. File/photo move integration must call the Notes link cascade in its own job.

Gate output (verbatim):

cargo fmt --check: no output, exit 0.

cargo clippy --all-targets -- -D warnings:

   Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/calternal-server)
    Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/plugins/notes)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.45s

cargo test --quiet (workspace):


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 29 tests
.............................
test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 30.37s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 9 tests
i........
test result: ok. 8 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.34s


running 9 tests
.........
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s


running 27 tests
...........................
test result: ok. 27 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.28s


running 354 tests
....................................................................................... 87/354
....................................................................................... 174/354
....................................................................................... 261/354
....................................................................................... 348/354
......
test result: ok. 354 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38s


running 11 tests
...........
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s


running 4 tests
....
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s


running 6 tests
......
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s


running 6 tests
......
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.44s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

bash packages/api-client/check-generated.sh:

   Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/calternal-server)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 22.75s
     Running `target/debug/calternal-server openapi`
$ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts
✨ openapi-typescript 7.13.0
🚀 ../../contracts/openapi.json → src/generated.ts [476.7ms]
Finished notes backend on branch job/notes-backend. Head SHA: 78aeae82101fefff77203d7b26fc5a25d619ac8f Built: Notes CRUD and ETags, journalled retitle/move and startup replay, derived links/embeds/tags/block IDs, backlinks and linked Notes, Daily notes and composer, title/tag search, shared user-scoped SSE, startup/hourly reconcile, and OpenAPI/TypeScript contract. The worktree is clean. `cargo clean` removed 7729 files (4.0 GiB). Decisions for owner confirmation: (1) retitle rewrites referrers before removing the old Note, because deleting first would violate the crash invariant that every referrer points at a readable path; (2) optional folders below Notes/ are accepted as requested by this job, although DESIGN §9 describes flat Notes; (3) the server uses UTC when X-Calternal-Timezone is absent, while the browser supplies its settings/default time zone in that header; (4) reconcile runs at startup and hourly. Known gaps: list cursors are offset-based and can shift during concurrent edits; retitle/move scans all Notes to discover unresolved wikilinks; user-defined multiline frontmatter properties are preserved on disk but only their first scalar line appears in the structured API projection. File/photo move integration must call the Notes link cascade in its own job. Gate output (verbatim): `cargo fmt --check`: no output, exit 0. `cargo clippy --all-targets -- -D warnings`: ``` Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/calternal-server) Checking calternal-plugin-notes v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/plugins/notes) Finished `dev` profile [unoptimized + debuginfo] target(s) in 6.45s ``` `cargo test --quiet` (workspace): ``` running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 29 tests ............................. test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 30.37s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 9 tests i........ test result: ok. 8 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.34s running 9 tests ......... test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.23s running 27 tests ........................... test result: ok. 27 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.28s running 354 tests ....................................................................................... 87/354 ....................................................................................... 174/354 ....................................................................................... 261/354 ....................................................................................... 348/354 ...... test result: ok. 354 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.38s running 11 tests ........... test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s running 4 tests .... test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s running 6 tests ...... test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s running 6 tests ...... test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 8.44s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `bash packages/api-client/check-generated.sh`: ``` Compiling calternal-server v0.0.1 (/home/kayg/Developer/calternal-wt/notes-backend/crates/calternal-server) Finished `dev` profile [unoptimized + debuginfo] target(s) in 22.75s Running `target/debug/calternal-server openapi` $ bunx --package openapi-typescript@7.13.0 openapi-typescript ../../contracts/openapi.json -o src/generated.ts ✨ openapi-typescript 7.13.0 🚀 ../../contracts/openapi.json → src/generated.ts [476.7ms] ```
Author
Owner

Merged local adversarial run at 8d9f86b5 observed one no-response case for GET /api/v1/notes/daily?date=2026-02-30 while the 20,000-file watcher-overflow fixture and Search staged rebuild were active. The request timed out without an HTTP response; other malformed date reads returned 400 but took 9–15 seconds. This is separate from preview attach and has no confirmed root cause. The one adversarial run was stopped at its 25-minute limit.

Merged local adversarial run at `8d9f86b5` observed one no-response case for `GET /api/v1/notes/daily?date=2026-02-30` while the 20,000-file watcher-overflow fixture and Search staged rebuild were active. The request timed out without an HTTP response; other malformed date reads returned 400 but took 9–15 seconds. This is separate from preview attach and has no confirmed root cause. The one adversarial run was stopped at its 25-minute limit.
Author
Owner

Hygiene review: a real-server run still timed out without a response for GET /api/v1/notes/daily?date=2026-02-30 under concurrent load. The cause is unconfirmed, so #14 stays open.

Hygiene review: a real-server run still timed out without a response for `GET /api/v1/notes/daily?date=2026-02-30` under concurrent load. The cause is unconfirmed, so #14 stays open.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#14
No description provided.