stabilize ids and harden release pipeline
This commit is contained in:
@@ -4,7 +4,8 @@ Date: 2026-11-12 · Revision audited: `8fa79aef` (master) · Scope: entire works
|
||||
|
||||
> **Remediation status (2026-11-12, later the same day):** all ten P0 items from §8 have been
|
||||
> implemented and validated (workspace clippy clean, `cargo fmt --check` clean, 35 tests passing).
|
||||
> See §9 for the per-fix log.
|
||||
> See §9 for the per-fix log. The P1 list (committed as `fd802a88` base) has also been processed —
|
||||
> see §10.
|
||||
|
||||
## 1. Scope and Method
|
||||
|
||||
@@ -905,3 +906,91 @@ Behavior changes to be aware of when testing:
|
||||
- nip60: reconcile now performs one NUT-08 mint round-trip when unseen relay proofs appear.
|
||||
- Reactions render per NIP-25 replace semantics (one reaction per author per target).
|
||||
- Messages keep their line breaks; only URL-adjacent whitespace is tidied.
|
||||
|
||||
## 10. P1 Remediation Log (2026-11-12)
|
||||
|
||||
All eleven P1 items from §8 fixed on top of the P0 commit (`fd802a88`). Validation after the
|
||||
full batch: `cargo clippy --workspace --all-targets` zero warnings, `cargo fmt --all --check`
|
||||
clean, `cargo test --workspace` 38 passed / 0 failed. Diff: 25 files, +1072/−247.
|
||||
|
||||
1. **Dock panel dedup made real** (`workspace/src/dock/mod.rs`, `lib.rs`, `skin.rs`):
|
||||
`PanelKey` — `Named(panel_name)` for singletons, `Room(room_id)` for chat panels — recovered
|
||||
from docked panels via `PanelHandle::of` + downcasts; `add_panel` now focuses the existing
|
||||
tab (reopening a collapsed dock first) instead of stacking a duplicate; group panels dedupe
|
||||
through `Workspace.group_panels: HashMap<GroupKey, PanelId>` (group identity is not readable
|
||||
off a `GroupPanel`), with stale ids pruned via `area.panel(id)` validation. The dead
|
||||
`find_panel`/`move_panel`/`InsertTarget` machinery is deleted, along with `skin.rs`'s
|
||||
write-once `toggle_button_visible`. Known residual: the panel opened by the new-group dialog
|
||||
(`dialogs/new_group.rs`, still plain `add_panel_to`) isn't registered — P2.
|
||||
2. **"Ignore" screening action** (`sidebar/rows.rs`, `dock/mod.rs`): closes the request room's
|
||||
tab via `dock::close_room_panel` (find by room key → `DockArea::remove_panel`) instead of
|
||||
dispatching `ClosePanel` into a focus path that can never reach its handler.
|
||||
3. **Updater observation** (`sidebar/mod.rs`, `sidebar/header.rs`, `auto_update/src/lib.rs`):
|
||||
`AutoUpdater` now exposes `UpdateDisplay` (`up_to_date`, `staged`, `status` text) via
|
||||
`display()`; the Sidebar mirrors it into a small `Entity<Option<UpdateDisplay>>`, updating it
|
||||
only when a rendered fact actually changes, and the header renders from that snapshot (the
|
||||
restart click fetches the global entity at click time). Observing the whole updater and
|
||||
notifying the entire cached sidebar was rejected as too blunt: download-progress ticks would
|
||||
have invalidated the panel on every byte.
|
||||
4. **Wallet invoice flow** (`nip60_ui/wallet.rs`, `nip60/src/lib.rs`): pending mint quotes render
|
||||
in the panel (amount, mint, bolt11 with middle-ellipsis, copy via the house `Clipboard`
|
||||
component, check/claim wired to the existing `Job::ClaimQuote` path, per-quote dismiss via the
|
||||
new `dismiss_mint_quote`); claim results refresh through the existing `WalletEvent::Updated`;
|
||||
an unpaid check emits "Invoice is not paid yet" (gated on `ClaimQuote` — flagged behavior
|
||||
change). Receive-via-lightning is functional end-to-end.
|
||||
5. **Person fetch blacklisting** (`person/src/lib.rs`): `in_flight` is now shared
|
||||
(`Arc<RwLock<HashSet<_>>>`) with the batching task; all three duplicated `get_metadata` error
|
||||
arms factored into `flush_batch`, which releases the whole batch for retry on failure and
|
||||
logs. A 2 s timeout now costs a retry, not a session-long placeholder.
|
||||
6. **Chat trash surfaced** (`chat/src/lib.rs`): the signal consumer counts *freshly* trashed
|
||||
messages (BTreeSet insert dedupes reprocess attempts) and emits one batched
|
||||
`ChatEvent::Error` ("N messages could not be decrypted"), which the workspace already renders
|
||||
as an error notification.
|
||||
7. **chat_ui list fixes** (`chat_ui/src/lib.rs`): room connect/load failures now push persistent
|
||||
error notifications (`notify_failure`, `.autohide(false)`) instead of silently empty rooms;
|
||||
message inserts splice at the real row (`pos + 1`, welcome row accounted for — append case is
|
||||
byte-identical to the old behavior); bulk loads are O(n log n) sort-merge with a single splice
|
||||
and one index rebuild, preserving the old first-arrival-wins timestamp dedup exactly.
|
||||
8. **Dialog fixes** (`workspace/src/dialogs/{profile,new_chat,screening}.rs`, `panels/backup.rs`):
|
||||
profile validates avatar/website URLs before publishing (inline error banner; empty still
|
||||
means "keep saved value"); backup surfaces keyring/decode failures in-panel and its bech32
|
||||
`unwrap`s are gone; new_chat re-filters on `InputEvent::Change` (and profile's avatar preview
|
||||
tracks typing); screening no longer closes all stacked dialogs on release, NIP-05 verification
|
||||
is tri-state (pending/verified/mismatched/failed — network failure no longer asserts "does not
|
||||
match"), and report submission shows failures.
|
||||
9. **Parser recursion** (`common/src/parser.rs`): `NostrParserIter::next` is a loop; the
|
||||
pending-match fields are gone (provably passthrough); 50,000 consecutive malformed `nostr:`
|
||||
URIs now cost loop iterations, not stack frames (regression tests added) — wasm tab-crash
|
||||
vector closed.
|
||||
10. **Stable room ids** (`common/src/event.rs`, `nip29`): `DefaultHasher` replaced by SHA-256
|
||||
(`common::stable_id` 128-bit hex, `stable_id_u64` for u64-keyed consumers); `Event` and
|
||||
`UnsignedEvent` `uniq_id` impls factored into one `pubkey_set_uniq_id` helper; nip29's
|
||||
`GroupKey::uniq_id` and `browse_subscription` unified (verified session-local). **Room id
|
||||
values change** (new hash domain) — existing cached groupings regroup per session as rumors
|
||||
re-arrive; release notes should mention it. Follow-up if 128-bit ids are wanted: chat's id
|
||||
fields are u64-typed; migrating to `String` ids is mechanical.
|
||||
11. **nip4e lifecycle** (`nip4e/src/lib.rs`): approval has an `approving` re-entry guard (the
|
||||
device secret can no longer be double-sent), toast lifecycle is correct on both outcomes
|
||||
(success clears only the matching request; failure rebuilds the toast with a fresh enabled
|
||||
button); rotation aborts before overwrite when load/archive fails (surfaces via
|
||||
`DeviceEvent::error`); the relay listener logs dropped events and its own death instead of
|
||||
stopping silently.
|
||||
12. **Proxy hardening round 2** (`browser-signer-proxy/src/lib.rs`): signed events are checked
|
||||
for correspondence (`event.compute_id()` vs returned id — proves field equality, covers
|
||||
stale ids), closing the event-substitution hole; the response log carries id + ok/error only,
|
||||
never values; request lines/headers are capped (16 KiB → 400), `Content-Length` capped
|
||||
(1 MiB → 413), invalid UTF-8 → 400, and connections are dropped after 30 s (slowloris
|
||||
bound).
|
||||
|
||||
### P1 behavior changes to be aware of when testing
|
||||
|
||||
- Opening an already-open room/group/panel focuses the existing tab; the "Ignore" action closes
|
||||
the request room's tab.
|
||||
- Wallet panel shows a "Pending invoices" section; unpaid checks report "Invoice is not paid
|
||||
yet"; quotes are dismissable.
|
||||
- Room groupings regenerate under a new id scheme — first launch after this change rebuilds
|
||||
rooms from cached rumors (history is kept; grouping self-heals).
|
||||
- Profile saves with an invalid URL now stop with an inline error instead of silently dropping
|
||||
the field; NIP-05 shows "could not be verified" on network failure instead of "does not
|
||||
match"; undecryptable messages and room load/connect failures produce visible notifications.
|
||||
- First message-send/receive after the room-id change republishes `r` tags under the new ids.
|
||||
|
||||
Reference in New Issue
Block a user