feat: sharing slice 1 PR 1: scoped auth and admission #827

Closed
kayg wants to merge 55 commits from feat/sharing-s1-pr1 into dev
Owner

PR 1 gates

Gate Result Evidence
Independent notes.read, notes.write and notes.share scopes; write does not imply share PASS cargo test --workspace --locked
Action and registered-route capability inventory, including missing-entry detection PASS cargo test --workspace --locked (every_registered_action_and_direct_route_has_a_capability_classification, route_inventory_check_detects_a_missing_route_entry)
Upgrade from #782 schema v10 to v11; legacy migration and DAV scope compatibility PASS cargo test --workspace --locked; base comparison below
ADR 0060 person visibility and explicit share-scope checks PASS cargo test --workspace --locked (grant_admission_rechecks_person_visibility_and_share_scope)
A staged → revoke at R → A late; B keeps Read access; randomized interleavings; writer progress under a WAL reader PASS cargo test --workspace --locked (late_write_after_revoke_is_refused_while_reader_keeps_sequence_access, randomized_interleavings_keep_admitted_edits_inside_grant_intervals, admission_writer_progresses_while_a_reader_holds_a_wal_snapshot)
Formatting PASS cargo fmt --all -- --check
Clippy with warnings denied PASS cargo clippy --workspace --all-targets -- -D warnings
Locked workspace tests PASS cargo test --workspace --locked

All Rust gates ran on dev-01 through Nix and ~/bin/slot. The schema-six legacy case also passed once on the requested base commit d0a2819a: cargo test -p calternal-auth --test host_cookies upgrading_schema_six_removes_cookie_state_and_keeps_passkeys -- --exact.

Summary

  • Carry credential kind, identity and explicit Notes scopes through Identity, Caller, action dispatch and sync. App-password Notes scopes remain separate from DAV scopes; app passwords remain refused on sign-in and account-management routes.
  • Add the v11 grant schema and resolver plus typed grant, list and revoke actions.
  • Serialize grant changes and note-write admission under the per-note writer fence. A write transaction checks access, assigns note_seq, and commits the source journal row and one fan-out intent before the room or history path accepts the change.
  • Keep sharing actions unavailable (UnknownAction) in this PR. PR 2 adds complete shared-read and control enforcement before enabling them.

Scope decision

Following the recommendation in docs/grills/sharing.md, app passwords may carry notes.share only as an explicit scope. notes.write does not imply it. If this recommendation changes, removing AppPasswordScope::NotesShare from SUPPORTED_SCOPES withdraws it in one line.

Refs #409
Refs #823 (plan head 9bf4a9c5).

## PR 1 gates | Gate | Result | Evidence | |---|---|---| | Independent `notes.read`, `notes.write` and `notes.share` scopes; write does not imply share | PASS | `cargo test --workspace --locked` | | Action and registered-route capability inventory, including missing-entry detection | PASS | `cargo test --workspace --locked` (`every_registered_action_and_direct_route_has_a_capability_classification`, `route_inventory_check_detects_a_missing_route_entry`) | | Upgrade from #782 schema v10 to v11; legacy migration and DAV scope compatibility | PASS | `cargo test --workspace --locked`; base comparison below | | ADR 0060 person visibility and explicit share-scope checks | PASS | `cargo test --workspace --locked` (`grant_admission_rechecks_person_visibility_and_share_scope`) | | A staged → revoke at R → A late; B keeps Read access; randomized interleavings; writer progress under a WAL reader | PASS | `cargo test --workspace --locked` (`late_write_after_revoke_is_refused_while_reader_keeps_sequence_access`, `randomized_interleavings_keep_admitted_edits_inside_grant_intervals`, `admission_writer_progresses_while_a_reader_holds_a_wal_snapshot`) | | Formatting | PASS | `cargo fmt --all -- --check` | | Clippy with warnings denied | PASS | `cargo clippy --workspace --all-targets -- -D warnings` | | Locked workspace tests | PASS | `cargo test --workspace --locked` | All Rust gates ran on dev-01 through Nix and `~/bin/slot`. The schema-six legacy case also passed once on the requested base commit `d0a2819a`: `cargo test -p calternal-auth --test host_cookies upgrading_schema_six_removes_cookie_state_and_keeps_passkeys -- --exact`. ## Summary - Carry credential kind, identity and explicit Notes scopes through `Identity`, `Caller`, action dispatch and sync. App-password Notes scopes remain separate from DAV scopes; app passwords remain refused on sign-in and account-management routes. - Add the v11 grant schema and resolver plus typed grant, list and revoke actions. - Serialize grant changes and note-write admission under the per-note writer fence. A write transaction checks access, assigns `note_seq`, and commits the source journal row and one fan-out intent before the room or history path accepts the change. - Keep sharing actions unavailable (`UnknownAction`) in this PR. PR 2 adds complete shared-read and control enforcement before enabling them. ## Scope decision Following the recommendation in `docs/grills/sharing.md`, app passwords may carry `notes.share` only as an explicit scope. `notes.write` does not imply it. If this recommendation changes, removing `AppPasswordScope::NotesShare` from `SUPPORTED_SCOPES` withdraws it in one line. Refs #409 Refs #823 (plan head `9bf4a9c5`).
kayg added 55 commits 2026-11-01 11:51:56 +00:00
test(auth): retain reader access after late revoke
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled
08876c76f5
Author
Owner

Independent review, round 1

Verdict: approve. No P0–P3 findings.

  • P0: none.
  • P1: none.
  • P2: none.
  • P3: none.

Failure scenarios checked

  • A notes.read password attempting a write or share action is refused before handler/replay; a credential with no Notes scope is refused at the Notes bearer boundary. Generic action execution checks the exact capability before idempotency lookup. Login, account and admin actions are session-only. DAV checks its separate scope column.
  • A late write after grant revocation is refused before journal/fan-out insertion. Denied API edits, websocket room updates, and server changes leave room text/history/broadcast unchanged. Under the note lock, the only awaited operation is the SQLite immediate transaction that checks access and commits the sequence, source journal row and fan-out intent; room/history/broadcast work follows after release.
  • The action names sharing.grant/list/revoke are registered but return UnknownAction. There is no dedicated sharing route or UI registration.
  • Adding a temporary route or action without classification made every_registered_action_and_direct_route_has_a_capability_classification fail with the expected unclassified-entry message; both probes were restored.

Verification

All commands ran on dev-01 through Nix and ~/bin/slot.

  • PASS: cargo test -j4 -p calternal every_registered_action_and_direct_route_has_a_capability_classification
  • PASS: cargo test -j4 -p calternal-auth --lib version_
  • PASS: cargo test -j4 -p calternal-auth --lib notes_only_password
  • PASS: cargo test -j4 -p calternal notes_read_password_cannot_flush_a_note
  • PASS: cargo test -j4 -p calternal sharing_actions_are_registered_but_stay_unavailable_in_pr1
  • PASS: cargo test -j4 -p calternal-engine notes_capability_is_checked_before_an_idempotent_replay
  • PASS: cargo test -j4 -p calternal-notes --lib denied_ (4 tests)
  • PASS: cargo test -j4 -p calternal-auth --lib late_write_after_revoke
  • PASS: cargo test -j4 -p calternal-auth --lib grant_admission_rechecks_person_visibility_and_share_scope
  • PASS: cargo test -j4 -p calternal-auth --test app_passwords app_passwords_do_not_reach_anything_outside_dav
  • PASS: cargo test -j4 -p calternal-auth --test host_cookies upgrading_schema_six_removes_cookie_state_and_keeps_passkeys
  • PASS: cargo test -j4 -p calternal-auth --lib opens_twice_and_keeps_schema

Temporary unclassified route and action probes both failed as expected; the source was restored afterward. The v10 test builds the pre-PR schema from its migration DDL before opening it with this revision. The v6 fixture removes v11 tables before resetting its version; separate v7→v11 and v10→v11 checks still run.

## Independent review, round 1 **Verdict: approve. No P0–P3 findings.** - **P0:** none. - **P1:** none. - **P2:** none. - **P3:** none. ### Failure scenarios checked - A notes.read password attempting a write or share action is refused before handler/replay; a credential with no Notes scope is refused at the Notes bearer boundary. Generic action execution checks the exact capability before idempotency lookup. Login, account and admin actions are session-only. DAV checks its separate scope column. - A late write after grant revocation is refused before journal/fan-out insertion. Denied API edits, websocket room updates, and server changes leave room text/history/broadcast unchanged. Under the note lock, the only awaited operation is the SQLite immediate transaction that checks access and commits the sequence, source journal row and fan-out intent; room/history/broadcast work follows after release. - The action names sharing.grant/list/revoke are registered but return UnknownAction. There is no dedicated sharing route or UI registration. - Adding a temporary route or action without classification made every_registered_action_and_direct_route_has_a_capability_classification fail with the expected unclassified-entry message; both probes were restored. ### Verification All commands ran on dev-01 through Nix and ~/bin/slot. - PASS: cargo test -j4 -p calternal every_registered_action_and_direct_route_has_a_capability_classification - PASS: cargo test -j4 -p calternal-auth --lib version_ - PASS: cargo test -j4 -p calternal-auth --lib notes_only_password - PASS: cargo test -j4 -p calternal notes_read_password_cannot_flush_a_note - PASS: cargo test -j4 -p calternal sharing_actions_are_registered_but_stay_unavailable_in_pr1 - PASS: cargo test -j4 -p calternal-engine notes_capability_is_checked_before_an_idempotent_replay - PASS: cargo test -j4 -p calternal-notes --lib denied_ (4 tests) - PASS: cargo test -j4 -p calternal-auth --lib late_write_after_revoke - PASS: cargo test -j4 -p calternal-auth --lib grant_admission_rechecks_person_visibility_and_share_scope - PASS: cargo test -j4 -p calternal-auth --test app_passwords app_passwords_do_not_reach_anything_outside_dav - PASS: cargo test -j4 -p calternal-auth --test host_cookies upgrading_schema_six_removes_cookie_state_and_keeps_passkeys - PASS: cargo test -j4 -p calternal-auth --lib opens_twice_and_keeps_schema Temporary unclassified route and action probes both failed as expected; the source was restored afterward. The v10 test builds the pre-PR schema from its migration DDL before opening it with this revision. The v6 fixture removes v11 tables before resetting its version; separate v7→v11 and v10→v11 checks still run.
Author
Owner

Rebase and auth-regression status (2026-11-02)

Rebased onto current origin/dev (55f35fcd), fixed the missing Caller.credential initializer in crates/search/tests/note_generation.rs, and pushed head 322cb24582a7003e894a401a2a9615ef02e787ad. The all-target check passes.

Offline sign-out passed 10/10 on WebKit-390 and 10/10 on Chromium-390 on both dev and this head. The old-session request returned 401 in every run, so #827 did not cause the reported 200 and no server-side change was needed. The combined #824+#827 retests also did not reproduce the four other browser failures; details and the search-corpus shared-data caveat are in the #834 status comment.

Rebase and auth-regression status (2026-11-02) Rebased onto current `origin/dev` (`55f35fcd`), fixed the missing `Caller.credential` initializer in `crates/search/tests/note_generation.rs`, and pushed head `322cb24582a7003e894a401a2a9615ef02e787ad`. The all-target check passes. Offline sign-out passed 10/10 on WebKit-390 and 10/10 on Chromium-390 on both `dev` and this head. The old-session request returned 401 in every run, so #827 did not cause the reported 200 and no server-side change was needed. The combined #824+#827 retests also did not reproduce the four other browser failures; details and the search-corpus shared-data caveat are in the #834 status comment.
Author
Owner

bm7 diagnosis and source fix: pushed 91a19dcf0a.

both tasks.set-status and tasks.set-status-many already exist at the train base; #833 did not introduce these registrations. this branch omitted them from its capability inventory. both are now explicitly SessionOnly, consistent with the other task actions and the sharing plan's Notes scope boundary. unknown task actions remain denied; no blanket allow or app-password scope widening.

added task_status_actions_remain_session_only. that regression and the shipping action/route inventory pass on the local eight-head merge b05d4ccd10. no rebase of #833 was necessary. browser session errors were separately traced to #828's saved file stamps.

the repeated requested chromium/webkit matrix passed 22/22 with zero retries. the full workspace gate remains red: an unchanged timed crash-test append-count assertion observed 96 instead of >100; a subsequent run skipping it reached #833's upcoming kept-row ordering assertion. neither is hidden or weakened. no train branch was changed.

bm7 diagnosis and source fix: pushed 91a19dcf0a9cf3844861e0e6acf4318618f3ea33. both tasks.set-status and tasks.set-status-many already exist at the train base; #833 did not introduce these registrations. this branch omitted them from its capability inventory. both are now explicitly SessionOnly, consistent with the other task actions and the sharing plan's Notes scope boundary. unknown task actions remain denied; no blanket allow or app-password scope widening. added task_status_actions_remain_session_only. that regression and the shipping action/route inventory pass on the local eight-head merge b05d4ccd102ccbefeb2711ceffedff3bd19372ef. no rebase of #833 was necessary. browser session errors were separately traced to #828's saved file stamps. the repeated requested chromium/webkit matrix passed 22/22 with zero retries. the full workspace gate remains red: an unchanged timed crash-test append-count assertion observed 96 instead of >100; a subsequent run skipping it reached #833's upcoming kept-row ordering assertion. neither is hidden or weakened. no train branch was changed.
Author
Owner

Authorization argument before code changes

Fresh API edits will keep the local notes.write scope guard before receipt lookup, then rely on admit for the single database authorization. admit takes the per-note writer lock shared with grant and revoke, and checks credential liveness, scope and current access in its immediate transaction before assigning a sequence or fan-out intent. A revoke that wins before admission leaves no sequence, room/history mutation or broadcast; an edit admitted first is ordered before the revoke sequence and stays within that grant interval.

The stored-receipt and Yjs writer-clock replay exits bypass admission, so each will perform one current authorization check before returning the prior result. That check will use the same per-note writer lock as grant/revoke. A revoked credential or grant therefore fails; after re-grant, a still-authorized caller may replay the old receipt without creating a sequence or bypassing the re-grant baseline and server/device fences.

Owner writes still pass once through admission; the transaction checks a supplied credential and resolves owner access. Internal caller=None work remains server-originated. I’ll keep coverage for fresh admission, both replay forms, replay across revoke/re-grant, owner writes, the shared lock, and refusal before room mutation when revoke wins before admission. Existing late_write_after_revoke_is_refused_while_reader_keeps_sequence_access continues to cover the real auth admission race and its sequence/fan-out outcome.

## Authorization argument before code changes Fresh API edits will keep the local `notes.write` scope guard before receipt lookup, then rely on `admit` for the single database authorization. `admit` takes the per-note writer lock shared with grant and revoke, and checks credential liveness, scope and current access in its immediate transaction before assigning a sequence or fan-out intent. A revoke that wins before admission leaves no sequence, room/history mutation or broadcast; an edit admitted first is ordered before the revoke sequence and stays within that grant interval. The stored-receipt and Yjs writer-clock replay exits bypass admission, so each will perform one current authorization check before returning the prior result. That check will use the same per-note writer lock as grant/revoke. A revoked credential or grant therefore fails; after re-grant, a still-authorized caller may replay the old receipt without creating a sequence or bypassing the re-grant baseline and server/device fences. Owner writes still pass once through admission; the transaction checks a supplied credential and resolves owner access. Internal `caller=None` work remains server-originated. I’ll keep coverage for fresh admission, both replay forms, replay across revoke/re-grant, owner writes, the shared lock, and refusal before room mutation when revoke wins before admission. Existing `late_write_after_revoke_is_refused_while_reader_keeps_sequence_access` continues to cover the real auth admission race and its sequence/fan-out outcome.
Author
Owner

Authorization argument and implementation plan (before code changes)

Fresh edits continue through one admit call. For shared notes, admission holds the per-note writer lock shared with grant and revoke, then checks the credential and current edit grant in the same immediate transaction that assigns the sequence and fan-out intent. There is no gap between that check and durable admission: if revoke wins before the transaction commits, admission fails before room/history mutation; if admission commits first, its sequence precedes the revoke sequence and the device/server fences govern delivery.

Stored-receipt and writer-clock replays bypass admission, so each still performs one current authorize_write check under that same lock before returning the prior result. Revoked credentials or grants fail; after re-grant, a currently authorized caller may receive the old receipt without creating a new sequence or bypassing the re-grant baseline and fences.

The measured owner/unshared cost is the immediate transaction and note_shares existence query on every append. I will add a bounded, positive cache of only “no note_shares row exists.” A miss is populated only after the immediate transaction confirms absence while holding the writer lock. A cache hit is restricted to an owner-side session/development or internal owner write; the owner ID and notes.write scope are checked under the lock. App-password writes still recheck credential liveness in the database, and all recipient writes, shared notes, and receipt replays keep their database checks. Grant and revoke remove the entry under the same lock before touching the database; revoked note_shares rows remain, so a revoked or re-granted note cannot be cached as never shared. This relies on the single server/Auth service in ADR 0009, whose clones share the same Inner.

Bound and failure behavior: at most 4,096 note keys, O(1) lookup/insert. A full cache or a cache miss falls back to the existing immediate transaction. Grant/revoke invalidation before a failed transaction only causes a safe cache miss. A row present at any time remains on the database path.

Tests and gates: keep fresh editor and owner writes, stored and clock-based replay, replay across revoke/re-grant, the per-note lock wait, and late-write-after-revoke/no-room-mutation coverage; add a cache transition test proving first-use fill, grant invalidation, and no recache after revoke/re-grant. Then run touched-crate Rust tests and admin-sharing.spec.ts on dev-01 Chromium, plus the same 200-append harness with at least ten interleaved runs on both perf VMs. The perf target is within 1% of origin/dev, with auth-db lock counts recorded.

## Authorization argument and implementation plan (before code changes) Fresh edits continue through one `admit` call. For shared notes, admission holds the per-note writer lock shared with grant and revoke, then checks the credential and current edit grant in the same immediate transaction that assigns the sequence and fan-out intent. There is no gap between that check and durable admission: if revoke wins before the transaction commits, admission fails before room/history mutation; if admission commits first, its sequence precedes the revoke sequence and the device/server fences govern delivery. Stored-receipt and writer-clock replays bypass admission, so each still performs one current `authorize_write` check under that same lock before returning the prior result. Revoked credentials or grants fail; after re-grant, a currently authorized caller may receive the old receipt without creating a new sequence or bypassing the re-grant baseline and fences. The measured owner/unshared cost is the immediate transaction and `note_shares` existence query on every append. I will add a bounded, positive cache of only “no `note_shares` row exists.” A miss is populated only after the immediate transaction confirms absence while holding the writer lock. A cache hit is restricted to an owner-side session/development or internal owner write; the owner ID and `notes.write` scope are checked under the lock. App-password writes still recheck credential liveness in the database, and all recipient writes, shared notes, and receipt replays keep their database checks. Grant and revoke remove the entry under the same lock before touching the database; revoked `note_shares` rows remain, so a revoked or re-granted note cannot be cached as never shared. This relies on the single server/Auth service in ADR 0009, whose clones share the same `Inner`. **Bound and failure behavior:** at most 4,096 note keys, O(1) lookup/insert. A full cache or a cache miss falls back to the existing immediate transaction. Grant/revoke invalidation before a failed transaction only causes a safe cache miss. A row present at any time remains on the database path. **Tests and gates:** keep fresh editor and owner writes, stored and clock-based replay, replay across revoke/re-grant, the per-note lock wait, and late-write-after-revoke/no-room-mutation coverage; add a cache transition test proving first-use fill, grant invalidation, and no recache after revoke/re-grant. Then run touched-crate Rust tests and `admin-sharing.spec.ts` on dev-01 Chromium, plus the same 200-append harness with at least ten interleaved runs on both perf VMs. The perf target is within 1% of `origin/dev`, with auth-db lock counts recorded.
Author
Owner

Verification for current #827 head 0543321b34f9a739275f70e31c79c5575d680259

The authorization rationale and test plan were posted before implementation in comment #75206. The current branch is still at this head; no PR was merged.

Gates

  • PASS: ~/bin/slot nix develop -c bash -c 'cargo test -j4 --no-fail-fast -p calternal-auth -p calternal-notes' on dev-01. Auth library: 53 passed; notes: 513 passed, 6 ignored; all package integration suites passed. Relevant cases passed: owner_unshared_admission_is_cached_until_a_grant_and_never_after, late_write_after_revoke_is_refused_while_reader_keeps_sequence_access, and fresh_editor_write_uses_only_admission_and_receipt_replays_recheck_access.
  • PASS: admin-sharing.spec.ts on dev-01 Chromium, 3/3 at 1440px and 3/3 at 390px. The route/UI is supplied by #842, so this ran in a disposable integration tree combining #842 head bf616240bd91 with current #827 head 0543321b34f9 (tree 3b5a2d03eb85). The cache field/admission path/grant-revoke invalidation were carried into #842's existing fenced resolve_resource_in transaction; no #842 branch or PR was changed.

200-append performance

20 alternating dev/#827 pairs per VM, 200 sequential acknowledged appends per run, fresh 1,000-line note and Home, --dev-user, with exact-once content checks. Startup, create, verify and shutdown were outside the timed interval. Both binaries were built on dev-01 in the unoptimized profile, relayed through the control host, and passed sha256sum -c on both perf VMs.

VM dev median / p90 (s) #827 median / p90 (s) median delta
perf-01 0.617887 / 0.654544 0.621978 / 0.631522 +0.662%
perf-02 0.628654 / 0.649793 0.629720 / 0.650042 +0.170%

Both medians are within 1% of dev. Each VM had 40 successful measured runs (20 per revision), with every content check passing. Three diagnostic traces per revision per VM counted fcntl calls to auth.db*: dev 63 each; current #827 69 each. The current count is down from the earlier reported 869 at the culprit head. fdatasync and fsync counts were unchanged in every trace: 262 and 10.

Stack status

The current #827 head is not an ancestor of #829 head d45584294273; #829 needs a rebase. #835 head 19071be8455d descends from that stale #829 head and should be refreshed after #829. #842 head bf616240bd91 also does not include current #827 and needs a rebase if it remains stacked on #827. None of those branches were changed.

## Verification for current #827 head `0543321b34f9a739275f70e31c79c5575d680259` The authorization rationale and test plan were posted before implementation in [comment #75206](https://git.kayg.org/kayg/calternal/pulls/827#issuecomment-75206). The current branch is still at this head; no PR was merged. ### Gates - **PASS:** `~/bin/slot nix develop -c bash -c 'cargo test -j4 --no-fail-fast -p calternal-auth -p calternal-notes'` on dev-01. Auth library: 53 passed; notes: 513 passed, 6 ignored; all package integration suites passed. Relevant cases passed: `owner_unshared_admission_is_cached_until_a_grant_and_never_after`, `late_write_after_revoke_is_refused_while_reader_keeps_sequence_access`, and `fresh_editor_write_uses_only_admission_and_receipt_replays_recheck_access`. - **PASS:** `admin-sharing.spec.ts` on dev-01 Chromium, 3/3 at 1440px and 3/3 at 390px. The route/UI is supplied by #842, so this ran in a disposable integration tree combining #842 head `bf616240bd91` with current #827 head `0543321b34f9` (tree `3b5a2d03eb85`). The cache field/admission path/grant-revoke invalidation were carried into #842's existing fenced `resolve_resource_in` transaction; no #842 branch or PR was changed. ### 200-append performance 20 alternating dev/#827 pairs per VM, 200 sequential acknowledged appends per run, fresh 1,000-line note and Home, `--dev-user`, with exact-once content checks. Startup, create, verify and shutdown were outside the timed interval. Both binaries were built on dev-01 in the unoptimized profile, relayed through the control host, and passed `sha256sum -c` on both perf VMs. | VM | dev median / p90 (s) | #827 median / p90 (s) | median delta | |---|---:|---:|---:| | perf-01 | 0.617887 / 0.654544 | 0.621978 / 0.631522 | +0.662% | | perf-02 | 0.628654 / 0.649793 | 0.629720 / 0.650042 | +0.170% | Both medians are within 1% of dev. Each VM had 40 successful measured runs (20 per revision), with every content check passing. Three diagnostic traces per revision per VM counted `fcntl` calls to `auth.db*`: dev **63** each; current #827 **69** each. The current count is down from the earlier reported 869 at the culprit head. `fdatasync` and `fsync` counts were unchanged in every trace: **262** and **10**. ### Stack status The current #827 head is not an ancestor of #829 head `d45584294273`; #829 needs a rebase. #835 head `19071be8455d` descends from that stale #829 head and should be refreshed after #829. #842 head `bf616240bd91` also does not include current #827 and needs a rebase if it remains stacked on #827. None of those branches were changed.
Author
Owner

BM9 clippy repair pushed: 76f11dc4b (parent 0543321b). Collapsed the nested optional-caller/scope check in crates/notes/src/room/edit.rs:43 into the same let-chain form used below it. Authorization order and behavior are unchanged.

PASS on dev-01, Nix shell and ~/bin/slot: cargo clippy --workspace --all-targets --locked -j4 -- -D warnings (exit 0). Also passed git diff --check before commit. The #779 Nix tooling overlay was used only in the VM and was not committed. No train branch changed.

BM9 clippy repair pushed: `76f11dc4b` (parent `0543321b`). Collapsed the nested optional-caller/scope check in `crates/notes/src/room/edit.rs:43` into the same let-chain form used below it. Authorization order and behavior are unchanged. PASS on dev-01, Nix shell and `~/bin/slot`: `cargo clippy --workspace --all-targets --locked -j4 -- -D warnings` (exit 0). Also passed `git diff --check` before commit. The #779 Nix tooling overlay was used only in the VM and was not committed. No train branch changed.
Author
Owner

Closing: head 76f11dc4 is already in dev (reached via aace16a1); nothing left to merge. Branch kept.

Closing: head 76f11dc4 is already in dev (reached via aace16a1); nothing left to merge. Branch kept.
kayg closed this pull request 2026-11-04 13:04:53 +00:00
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
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!827
No description provided.