Conversation
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 34682882 | Triggered | Generic High Entropy Secret | 2dd47ba | browser/lib/src/pairing.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
This was referenced Apr 6, 2026
v5 matches on event.code mapped through its key table, so punctuation hotkeys must be written as code names: pressing ? gives code "Slash", which never equals the registered "/". Both shift+/ (shortcuts overlay) and \ (sidebar toggle) silently stopped matching in the v4 -> v5 upgrade - the same class of breakage as the cmd+ alias already noted in HotKeyWrapper. Register them as shift+slash / backslash and teach displayShortcut to render the code names as ? and \. The shortcuts overlay's hand-maintained list (a third copy of the bindings, already missing cmd+up) now renders from the central shortcuts registry, and its duplicate dead '?' registration uses the registry value too. Claude-Session: https://claude.ai/code/session_016i33YGkTZTowvaeq33yLs3
…data loss) Cherry-picked from d5f79da on forms-#875 (the outbox portion only — the FormBuilder/FieldRow.tsx + forms.spec.ts hunks are dropped, since that work isn't on this branch). Applied as a 3-way delta so did's RBSR changes to store.ts are preserved. Two data-loss races closed: - Debounce window: a save parked in a UI debounce timer (useValue, useDebouncedSave) was invisible to getSyncStatus — "synced" while a write was still pending in memory, dropped on reload. Now tracked via Store.start/finishScheduledSave so pendingDirtyCount stays > 0. - drain() snapshot gap: a drain() arriving mid-pass shared the in-flight promise, so `await drain()` could resolve while the caller's subject was still dirty and un-POSTed (Resource.save reporting 'persisted' for a write the server never got). Now chains one follow-up pass with a fresh snapshot. - Cold drain now loads the resource itself (OPFS-first, then server, gated on clientDb ready) instead of stranding an entry no view will ever hydrate. Verified on this branch: lib + react build and typecheck, lint clean, 43 lib unit tests pass (incl. the new outbox-race + store tests), and the sync / offline-persistence / offline-reload / offline-create-then-online / clientdb-edit-persistence e2e specs all pass (8/8). Claude-Session: https://claude.ai/code/session_01CRafFfZwmuSmcHJfmGcT7v
…e JDK/AAR wiring The embedded server now runs on Android: rustls-platform-verifier is initialized with the app's JVM context before the server thread starts (reqwest 0.13 always verifies TLS through the Android trust store and panics otherwise; ndk-context is gone since tao 0.35, so the handles are bridged from wry's jni 0.21 via with_webview + jni_handle into the verifier's jni 0.22 API). The verifier's Kotlin component is bundled by resolving its AAR out of the cargo registry with cargo metadata, keeping the gradle dependency in lockstep with Cargo.lock. useCurrentSubject now resolves the root path against the embedded server's origin instead of the unfetchable tauri://localhost webview origin. Claude-Session: https://claude.ai/code/session_0136CyX67ohdcXnhzZPgq6iS
The overlay's input looked like a search field but was readOnly, and the list overflowed the fixed-height panel (rows rendered past the rounded corner). Typing now filters by label or key; the list scrolls inside the panel. Claude-Session: https://claude.ai/code/session_016i33YGkTZTowvaeq33yLs3
…lope spec atomic://pair QR/deep-link envelope with onboard (secret-in-QR, v1) and pair (routing-only) kinds; mDNS/pkarr as routing-only discovery; drive enrollment recorded in KnownPeer from day one. Resolves serverless-p2p OQ3, narrows OQ1/OQ4. Flags the agent_secret-in-logcat leak as P0. Claude-Session: https://claude.ai/code/session_0136CyX67ohdcXnhzZPgq6iS
The Tags popover (frosted translucent + scale(0) pop, no border) and the More context menu (opaque, dark-mode-only border, plain fade, hardcoded 8px radius) each defined their own look, with CustomPopover as a third copy. floatingSurface.ts now owns the surface (frosted bg + blur, theme radius, soft shadow, dark-mode border, prefers-contrast fallback) and a shared 100ms fade+grow entrance; all three consume it. Menu items are transparent so the frosted surface shows through, and TagSelectPopover drops its opaque background override. Claude-Session: https://claude.ai/code/session_016i33YGkTZTowvaeq33yLs3
Three behavioral gaps vs the (Radix) popovers: - The entrance transition ran while the menu was still visibility:hidden awaiting positioning, so it played unseen and the menu popped in. The transition now starts one frame after reveal (data-positioned). - Positioning overlapped the bottom half of the trigger (a triggerHeight/2 offset), making the trigger unclickable for closing. The menu now sits above/below the trigger with a small gap. - Clicking the trigger while open blurred the menu, whose blur handler closed it - then the same click's toggle reopened it. A pointerdown- on-trigger guard leaves closing to the click's toggle. Claude-Session: https://claude.ai/code/session_016i33YGkTZTowvaeq33yLs3
Canvas broadcasts the pointer's world position (throttled) via useResourcePresence().setData and renders remote cursors mapped through the local viewport; tables announce the selected cell as (row subject, column property) — identity, not indexes, so peers with different sorts/filters match cells correctly — and ring remote-selected cells. Shared PresenceUserTag name pill keeps agent identity consistent with avatars and document cursors (colorForAgent). FancyTable gains a presence-agnostic onSelectedCellChange prop. Receivers validate payload shape: a cleared data field arrives as null, not undefined (found in live two-session verification, crashed the first cursor overlay). Also removes dead code in CanvasPage (unused store/navigate/imports) and documents that same-subject presence announcers compose in usePresence. Plan + verification notes in planning/presence-views.md.
Account login becomes a third pairing issuer: atomic-saas already holds the password-encrypted secret (/api/recovery-secret) and enrollments; add a per-account device directory (node_id, relay hint, origin, last_seen) so a fresh sign-in restores identity and seeds KnownPeers without QR or typing. Safe under Principle 1 (directory output is routing-only; same-agent AUTH still gates); directory client lives behind the cloud session per FOSS guardrail 3. Passkey+PRF noted as the one-step-restore v2. Claude-Session: https://claude.ai/code/session_0136CyX67ohdcXnhzZPgq6iS
…local-only drives
A one-click, fully client-side new-user demo and a Meetings feature that
supersedes ad-hoc follow-sessions.
Demo (chunks/Demo, DemoRoute):
- Spins up a fresh local-only drive per run ("Atomic Demo") with a meta
onboarding kanban board whose cards ARE the tour steps, a team table,
scripted teammates that show presence, type into a doc, and chat.
- Guest agent so logged-out visitors get the full experience in one click;
bulletproof cleanup of prior demo drives via atomic.demoDrives.
- SimulatedTypist forks the doc and flushes deltas through applyIncoming;
moodboard strokes baked in.
Local-only drives (@tomic/lib):
- Store.registerLocalOnlyDrive / isLocalOnlyDrive / isLocalOnlySubject;
suppress outbox, websocket SUB/SYNC_VV, and server fetches for them so
did: subjects resolve OPFS-first. saveLocalOnly() signs at save and
materializes locally. All guards are inert when no local-only drive is
registered (size-0 short-circuit), so synced drives are unaffected.
- presence.injectEntry/removeEntry: seam for scripted teammates.
Meetings (#1127) — a front door for follow mode:
- Meeting = ChatRoom+Meeting listed in drive.currentMeetings; live meetings
surface a "Meet"/"Join" control in the nav bar and context menu (same
weight as Share/Comments). Join = follow the leader + open the meeting
chat; opening a live meeting auto-joins. Optional title (defaults to
"Meeting · {date}", click-to-edit via EditableTitle), participant
facepile, and a "meeting ended" message that keeps the ended panel.
- Follow-sessions deprecated; chat renders event descriptions verbatim.
Also: responsive sidebar/right-panel widths (narrower under 1728px), and
new lib unit tests (local-only drive, presence). Refs onboarding tour #1233.
Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
…-fill - websockets: WsClient.close() now flips serverConnected(false) and rejects in-flight requests synchronously instead of waiting for the WS `close` event. Once the transport is already blocked (offline toggle, dropped link), Chromium can suppress/delay that event, leaving serverConnected stuck true and pending GETs/commits hanging. The event handler still runs if it fires — both paths are idempotent. De-flakes the offline-edits-sync test (was ~1/5, now 5/5) and is the correct fix for disconnect() generally. - table-views-filters: "Add view" became a menu (pick Table/Kanban/Calendar); the test clicked it expecting an immediate new view. Now opens the menu and selects Table. - tables create-and-fill: the tag picker's Escape drops the grid from Edit to Visual mode, so Tab no longer wraps into the next row. Rewrote fillRow to self-position by clicking each row's first cell (matching the initial setup) and the post-loop edit to click its target cell, instead of relying on the dead Tab-wrap / cursor-column assumptions. Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
Two pieces of planning/device-pairing.md: P0 hygiene: set_default_agent logged the entire config file - agent secret included - via tracing::warn! on first boot. On Android that lands in logcat (bug reports, adb logcat history); on servers in log aggregators. Now logs only the config path plus a pointer to the pairing/sign-in flow. P2.5 zero-scan pairing (browser side): helpers/managed/devices.ts registers this device in the account's directory (Tauri-only - a web tab has no Iroh node of its own, /iroh-node-id there names the connected server) and seeds the account's other devices into the same atomic-peers KnownPeer records the QR flow writes, so they appear in the Sync page one tap from syncing. Fired once per session from IdentityReconcileGate after identity convergence; complete no-op without a managed session (FOSS guardrail: the open server never phones home). On 409 the per-install device id is rotated and retried once, so a shared machine that switches accounts gets its own record instead of hijacking the previous account's. Control-plane side landed in atomic-saas aab521a. Checks: lint, typecheck, 77 unit tests, cargo check -p atomic-server, e2e chromium 102 passed / 1 pre-existing search flake (passes in isolation) / 6 skipped. Claude-Session: https://claude.ai/code/session_01Ffyo9voLDLbGZe4cU7us6P
The versioned QR / deep-link payload from planning/device-pairing.md:
one format, two kinds - onboard (routing + agent secret, for a fresh
device) and pair (routing only). Decode is strict: unknown v gets its
own error code ('update the app', never best-effort parsing), a pair
envelope carrying a secret is rejected (a routing-only code must not
smuggle an identity), node DIDs / urls / drive lists are validated,
and encode round-trips through the same validator so we can never
mint a QR this module would refuse to scan.
11 unit tests; full lib suite 156 green.
Claude-Session: https://claude.ai/code/session_01Ffyo9voLDLbGZe4cU7us6P
Device pairing P0/P1 (render side, planning/device-pairing.md): the Sync page's Node DID row gains 'Pair device', opening a dialog with two QR codes built on the lib's atomic://pair envelope: - pair (default, safe): routing only - scanning tells the other device where this node lives; same-agent AUTH still gates everything. - onboard (opt-in): routing + the agent secret, for setting up a fresh device. Blurred until an explicit 'Reveal setup code' press, with the same sensitivity framing as the copy-secret button; hidden entirely when no local agent exists. The secret is rebuilt from agentStorage's plaintext fallback record (new getAgentSecretFromIDB) - the SubtleCrypto keypair itself is non-extractable. The peers input also accepts a pasted atomic://pair link (routing only; an onboard link pasted there is deliberately NOT an identity import - that belongs to the scan flow). New dep: uqr (zero-dependency QR-to-SVG renderer). Locale catalogs carry the extracted dialog strings. Not yet built: the phone-side scan path + atomic:// deep link (tauri-plugin-deep-link / scanner spike on a real device). Checks: typecheck, lint, unit 77 + lib 156, e2e chromium 101 passed / 2 known flakes (ontology, query-drive-filter - both pass in isolation) / 6 skipped. QR dialog verified live. Claude-Session: https://claude.ai/code/session_01Ffyo9voLDLbGZe4cU7us6P
…i, roster order Four fixes from hands-on demo testing: - Canvas draw crash: drawing onto a canvas whose strokes were seeded in bulk via set() (demo/template content) threw "pushContainer is not a function" and dropped the stroke. Root cause: loroSetProperty stored an array of objects as a LoroList of PLAIN values (list.push), while pushListItem / replaceListItems expect container elements. loroSetProperty now reuses writeJsonToLoroList (object elements → LoroMap containers); pushListItem is hardened to promote a plain-array value to a container, and removeListItem likewise. Regression test added. - Team table: only had a text Role column, which doesn't show off the table. Added a tags column (Responsibilities), a relation (Doing task → a checklist card), and a checkbox (Completed onboarding), with per-persona values. - Say hi / meeting ordering: the director wound down (ended the meeting, team left) on a 45s timeout even if the user hadn't chatted, so a later "hi" landed in a dead room and never ticked the card. The "Say hi" payoff is now reactive and memoized (completeSayHi) — fired by the chat listener the moment the user posts, and the script waits generously before winding down. It also ticks the user's "Completed onboarding" checkbox. - Roster order: the user's row now sorts to the BOTTOM (below the seeded members) — the guest profile and the created row get an explicit createdAt so the createdAt-ascending default sort places them last, not first. Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
…r name - The welcome doc no longer types a redundant "Explore the / Doodle on the / Meet the" todo list (the kanban board already IS the tour). Keeps the doc from distracting the user before they've opened the onboarding meeting. - Resource mention nodes (block + inline) are atoms with no text content, so copying text that contained them dropped the visible resource name from the clipboard. Add `renderText` (→ schema `toText`) so plain-text copy emits the resource's title, matching what's on screen. Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
The QR pairing loop closes without an in-app scanner: the QR encodes an
atomic://pair URI, so the system camera scans it and launches the app
via deep link. This wires that path end to end:
Shell (desktop/src/lib.rs): tauri-plugin-deep-link + a VIEW/BROWSABLE
intent filter for scheme 'atomic' (gen/android manifest; desktop scheme
in tauri.conf.json). Links are forwarded to the webview as
'atomic-deep-link' DOM events - no Tauri JS API or capabilities needed,
the frontend stays Tauri-free. Queued Rust-side and flushed on every
finished page load with a delivered-set, merging get_current(), so the
cold-start link (camera scan launches the app) is delivered exactly
once; helpers/deepLinkQueue.ts queues from module scope before React
mounts.
Import flow (components/PairingLinkHandler.tsx, mounted at the root):
'pair' links persist a KnownPeer (shared helpers/knownPeers.ts) and
open the Sync page; 'onboard' links import the secret via the sign-in
primitives (Agent.fromSecret -> setAgent -> saveAgentToIDB), then
navigate to the personal drive. A device already holding a different
agent gets an explicit 'Switch account?' confirmation - never a silent
key replacement; an onboard code for the agent already held degrades to
routing-only. Unknown envelope versions toast 'update this app'.
Verification: typecheck, lint, unit suites green; desktop crate cargo
check clean; receiver paths (pair persist+navigate, unsupported
version, malformed) verified live by dispatching the DOM events;
presence-follow + meetings e2e pass against a fresh HEAD server with
this change. Full-suite runs are currently unreliable for environmental
reasons: the long-lived dev server on 9883 died mid-run, and its
datastore now 500s ('class not found') on some e2e fixtures - the same
specs pass against a fresh --initialize server, so this is data state,
not code. On-device Android verification (deep link + scanner spike,
OQ1) still pending.
Claude-Session: https://claude.ai/code/session_01Ffyo9voLDLbGZe4cU7us6P
Reworks the message row in the Comments panel and ChatRoom: - Alignment: drop the extra 1rem inline padding so the message text lines up with the panel title and the composer; the hover band bleeds subtly into the panel padding via a negative inline margin instead. - Long authors: the name/DID truncates with an ellipsis so it can no longer shove the timestamp off the row. - Timestamps: a new compact formatter — "5 minutes ago" / "yesterday" for the last week, "Jul 1" within the year, else a short numeric date — replacing the long "7/9/2026 at 8:37:49 AM". - Actions: the edit/reply/link/copy buttons use the app's subtle IconButton instead of the bright-blue filled icon button (the `icon` prop was overriding `subtle`), matching the rest of the UI. Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
- Show each message author's avatar (profile image or initial) to the left of
the message, in both the Comments panel and meeting/ChatRoom.
- Give follow-event lines ("Started the meeting.", trail "Viewing …") the same
treatment as regular messages: truncate a long author name/DID so it can't
push the timestamp off the row, and use the compact relative time instead of
a full clock string. Line them up with the messages too.
Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
- Comments / AI / Meet nav buttons now show the theme's main colour (over a subtle background) while their sidebar panel is open — the same "current item" cue the left sidebar uses. Extracted the shared LabelButton so the meeting button matches the others instead of its own pill shape. - The meeting button is a proper toggle: clicking it while you're in the meeting and the panel is open now closes the panel, like the other toggles. - A refreshed leader keeps their meeting going: activeMeeting is stashed in sessionStorage (per tab, per drive) and restored on load. A follower's meeting isn't restorable, so instead of a dead "No meeting yet" placeholder the follow-session panel just closes; the top-bar Join banner still offers any live meeting. Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
- AgentAvatar gains an optional green "online" dot (agent has a live presence entry). - PresenceAvatarMenu (Show profile / Follow / Stop following) now computes online status from drive presence, shows the dot, and only offers Follow for someone else who's actually online — never yourself or an offline author. - Use PresenceAvatarMenu wherever an agent avatar appears: chat/comment message avatars and the meeting facepile, so the menu is consistent everywhere. (The Following badge keeps its own menu — nesting one inside it would conflict.) Claude-Session: https://claude.ai/code/session_01WFDphAnkgand2pab1SDErz
Ships the "Local cache and session isolation" mechanism from planning/encryption.md: after sign-out or an agent switch, a session can no longer read the previous agent's cached private data — without wiping the cache. - Split the single per-origin atomic_data.redb into one OPFS database per agent (fingerprint filenames; shared plaintext anon DB when signed out). Leader lock + RPC channel are scoped per database, and the worker restarts on agent change. The in-memory seed only runs on the first start of a page load so an identity switch can't copy one session's resources into another identity's database. - Encrypt each agent's database at rest with XChaCha20-Poly1305 at the redb StorageBackend layer (new EncryptedBackend: 4 KiB blocks, fresh random nonce per write, block-index AAD, key-check header) so resources, Loro snapshots, blobs and derived indexes are all ciphertext. - Key hierarchy per the vault plan: random 256-bit DbKey per agent, wrapped by HKDF(agent private key) — the agent key wraps, never encrypts bulk data. Session copy in IDB is cleared on sign-out; the wrapped copy is unwrapped at the next sign-in, so the same agent regains their intact cache. - Migrate the legacy shared database into the active identity's file (encrypting on the way) on first start; adopted, never dropped, since it can hold local-only data with no server fallback. - Attempt ghost-leader lock stealing on all browsers (verified working on Firefox/Zen, previously assumed Chromium-only), silence election errors from superseded workers, and prevent destroyed workers from re-attaching to the Store. - Sync page: disable Disconnect while no working local store exists — the server would otherwise be the only data source. Design, tradeoffs and known gaps: planning/opfs-per-agent-encryption.md
…ew drive" Creates a drive on the connected node and immediately enrolls it in Cloud Sync via the existing enableCloudSyncForDrive helper, then opens it — the portal only ever holds a session cookie, never the agent's private key, so drive creation has to happen here rather than there.
The post-steal wait reused the 2s election timeout, but leadershipGained only resolves after the stolen leader's FULL init — wasm import + OPFS open — which legitimately takes seconds on a cold dev server. Slow successful steals were misreported as 'reclaiming the lock did not succeed' even though the DB recovered moments later. The steal now gets its own 15s budget that ends early on success, on another tab announcing leadership (-> follower), or on a definite init failure — in which case the real error (typically the OPFS file handle still held by a live background tab, which a stolen Web Lock cannot take) is surfaced instead of the generic message.
An i18n commit accidentally reverted QuickCreateRow.tsx back to its pre-meeting-feature state, silently dropping the New Meeting button (and demoting its translation string to obsolete in every locale) — the drive page rendered New Document/Table/Folder/ChatRoom but no way to start a meeting. Restore the button and re-activate the string.
Two React warnings on document open: - "Cannot update a component (BubbleMenu) while rendering... (CollaborativeEditor)": the AI-diff comparison sync ran via useOnValueChange(cb, deps, true), which invokes the callback directly in the render body. That callback dispatches a ProseMirror transaction (editor.commands.setComparisonContent), which BubbleMenu subscribes to via useEditorState — so a re-render of CollaborativeEditor synchronously forced a state update in the already-mounted BubbleMenu mid-render. Moved the sync into a plain useEffect keyed on the same dependencies. - "Can't perform a state update on a component that hasn't mounted yet": useEditor's onCreate option relied on tiptap's Editor.mount(), which schedules its 'create' event via a genuine setTimeout(0) outside React's render/commit cycle. An abandoned render attempt (e.g. a Suspense retry) could still have that timeout fire later and call setEditorReady on a fiber that never mounted. Replaced onCreate with a useEffect that subscribes to editor's 'create' event (or fires immediately if editor.isInitialized already), tying the listener's lifetime to a committed instance of the component. Verified interactively (both warnings reproduced and gone after the fix) and via tests/documents.spec.ts.
Db::apply_commit held its per-subject lock across the entire function,
including the AFTER APPLY COMMIT HANDLERS loop that fires class-extender
after_commit hooks. A plugin's after_commit is allowed to issue its own
follow-up commit to the same subject (atomic_plugin::commit, via the
commit host function in server/src/plugins/wasm.rs) — that re-enters
apply_commit for the same subject while the outer call's guard is still
held, and the task deadlocks waiting on a lock only it could release.
subject_lock.rs's own invariant comment already named the danger
("do not acquire a subject's lock while already holding it") but claimed
nothing could trigger it, since the plugin ABI seemed to have no store
access — stale: the commit() host function has let a plugin self-commit
since #73, well before the subject lock was introduced, and the two were
never reconciled.
Fix: drop the guard right after the write-back transaction and
subscriber notification are done (the read-modify-write it protects),
before running after_commit handlers. before_commit handlers still run
under the lock, since they precede the write.
Root-caused via browser/e2e/tests/plugin.spec.ts:21 hanging on the
plugin's rename commit; the existing race regression tests
(concurrent_commit_and_peer_apply.rs) still pass.
…MIC_REPOPULATE_DEFAULTS populate::bootstrap() only calls populate_base_models (genesis, drive, the Commit class, and the other fixed base-model properties/classes) once, on a store's very first init. A store seeded before a base model was added never gets it, and ATOMIC_REPOPULATE_DEFAULTS's repopulate path only re-ran populate_default_store — the JSON ontology imports — leaving no way to retrofit an already-seeded store short of wiping it. Both writers upsert (overwrite_existing: true), so calling populate_base_models here too is idempotent and safe against live data.
…tched versions Routine, compatible-range updates fixing 6 of the 12 real vulnerabilities cargo-audit flags against this branch's Cargo.lock (the other 6 — hickory-proto x2, rustls-webpki x4 — all trace to the already-known, already-deferred iroh 0.35 transport migration; see planning/rust-dependency-upgrade-audit.md, not attempted here): - wasmtime/wasmtime-wasi/wasmtime-wasi-http 45.0.0 -> 45.0.3 (RUSTSEC-2026-0182, RUSTSEC-2026-0188 — the WASM plugin sandbox) - quinn-proto 0.11.14 -> 0.11.16 (RUSTSEC-2026-0185) - crossbeam-epoch 0.9.18 -> 0.9.20 (RUSTSEC-2026-0204) - plist 1.9.0 -> 1.10.0, pulling quick-xml 0.39.4 -> 0.41.0 (RUSTSEC-2026-0194, RUSTSEC-2026-0195 — Tauri desktop's plist chain) Verified: cargo check on atomic-server --features wasm-plugins and on the desktop (Tauri) crate; atomic_lib (278/278) and atomic-server (46/46) test suites; the plugin e2e spec (exercises the bumped wasmtime directly) plus sync/tables specs against a rebuilt server.
…ides pnpm audit against this branch's actual pnpm-lock.yaml (not the stale, 842-commits-behind develop numbers Dependabot reports) found 48 real advisories: 1 critical, 17 high, 25 moderate, 5 low. All but one were transitive — mostly under netlify-cli (dev tooling), the MCP SDK's hono peer, and vite-plugin-webfont-dl's axios — so a plain `pnpm update` either couldn't reach them or, when tried broadly, swept in unrelated major bumps to react/vite/tiptap/loro-crdt that were never part of the ask. Used pnpm-workspace.yaml's `overrides` instead (package.json's `pnpm.overrides` key is no longer read by pnpm 10.x) to force each vulnerable package to its minimum patched version, one at a time, verifying no unintended major-version drift after each addition: - an open-ended ">=x" override let pnpm resolve straight past the patched version into a newer unrelated major wherever nothing else in the graph pinned one — caught @babel/core jumping 7.29.0 -> 8.0.1, fast-uri 3 -> 4, http-proxy-middleware 3 -> 4, and linkify-it 5 -> 6 this way; every override below is now bounded to >=patched <nextMajor. - brace-expansion needed two scoped overrides (its 2.x and 5.x lines coexist) plus a parent-scoped `minimatch>brace-expansion` override, since the range-selector alone didn't reach older minimatch@5.x/9.x duplicates still resolving the vulnerable 5.0.6. - cookie is scoped to `cookie@0` only: cookie 1.x is independently required elsewhere (@sveltejs/kit, fastify, @netlify/redirects all declare ^1.x directly), so an unscoped override would have fought that instead of just patching the 0.x line advisories target. Remaining state: 0 vulnerabilities (was 1 critical, 17 high, 25 moderate, 5 low). One pre-existing peer-only @babel/core@8.0.1 (an orphaned @rolldown/plugin-babel peer, unconstrained by any direct dependency) is left as-is — it isn't itself vulnerable and isn't caused by these overrides. Verified: pnpm typecheck, pnpm test (one pre-existing agentStorage.test failure confirmed identical on the baseline lockfile, unrelated), pnpm lint (failures confined to unrelated in-progress files), @tomic/lib and data-browser production builds.
…affordance, empty column - Add per-view-kind icons (table/kanban/calendar) to the view tabs and the "+ new view" dropdown, sourced from a new VIEW_KIND_ICONS map. - Give kanban column headers a subtler darker background and a bolder, slightly larger status pill. - Rework the "Add card" control to reuse SkeletonButton (dashed, card-shaped, rounded) instead of a plain hover-highlight button, and drive its label from the table's own row name (e.g. "Add Issue") rather than a hardcoded "card". - Hide the "No status" kanban column when it has no cards, keeping it visible for the duration of a drag so a card can still be dropped there to clear its status.
… color A new appearance setting. When on, ChromeTheme (a nested ThemeProvider around the sidebar and navbar) swaps the neutral ramp for tones of the main color, so no grey ever sits on a colored surface; content and text stay neutral for readability. bgBody gets a whisper of the same hue. Off, the theme is byte-identical to before. The main-color presets move to styling.ts as presetColors, now also the default tag palette (replacing the neon tagColours). Includes a stray oxfmt fix in AllProps.tsx.
Drive name and switcher form one segmented control: the name fills the row and truncates to a single line, the switcher (now a double caret, always visible) is pinned right. Header inset matches the tree rows.
The splash now follows prefers-color-scheme via CSS, and an inline script applies the in-app dark mode override (localStorage 'darkMode') before first paint. Replaces the old end-of-body script that wrote the OS preference as inline styles, which could not be overridden and ignored the in-app setting.
Adds a camera toggle to the meeting side panel that starts a fully peer-to-peer call via Trystero (WebRTC, Nostr signaling): the meeting subject is hashed into the room id and doubles as the signaling password, so only participants can join or read the handshake. Media never touches a server. The call UI (tile grid, mute/camera/hang-up controls, mic-only and permission-denied fallbacks) lives in a lazy chunk, so the ~24 kB gzipped library is only fetched when someone actually starts a call. Mentioned in #1127
Replace the floating tag pill with a header strip that's part of the same rounded rectangle as the card list below it: solid background in the tag's own color, white title text, and the card list gets a faint wash of that same hue over the usual grey instead of a flat neutral background. useTagData is now exported from Tag.tsx so KanbanColumn can read the raw color/text without rendering the pill itself.
…r More menu The navbar meeting banner now only shows while a meeting is live (Join pill / open-chat pill); the idle "Meet" start button is gone. The More menu loses its Start meeting and New draft quick-actions — creating meetings and drafts belongs to the New page — along with the meeting plumbing in ActionContext that only they used. E2e follows the new UX: the top-bar test asserts the affordances are absent, the two-session meetings tests start via New Meeting → Start meeting, and the drafts spec is a fixme until the New page offers drafts. Locale catalogs regenerated (wuchale --clean) after the string removals.
The PWA manifest allows one theme_color (white); these per-scheme metas override it so installed-app titlebars and mobile browser UI follow dark mode.
…vers
The origin serving the app is usually an atomic-server node worth
listing on /sync, but the managed deployment serves the SPA from a
shared app origin that is not a node — listing it would offer a
'Switch' that points the store at something that can't answer. Ask
/server first (isAtomicServer) and register only real nodes; a
non-answer also removes entries older builds added blindly.
Rescued from stash@{0} (2026-07-23); its Kanban/locale hunks were
already landed elsewhere.
…tually works Tantivy only scopes a JSON-field query to a path when the clause is prefixed with the field's own name (`propvals.<path>:<value>`). The `filters` param's documented syntax is bare `<property-uri>:<value>`, which tantivy silently fails to constrain (no parse error, no match) — so `filters=isA:File`, used by the File picker's `parents`+`isA` query, never actually found anything. Rewrite each AND/OR-joined clause to add the `propvals.` prefix before parsing, so the documented unqualified syntax works without any client change. Added an integration test that uploads a file and confirms it's found via the exact query FilePickerDialog issues.
…set component @tiptap/suggestion's plugin view runs its update handler async: it assigns a shared `props` before awaiting `items()`, and only calls `onStart` (which is what creates our `component`) after that await resolves. Its `destroy()` teardown (fired on editor unmount) only checks that `props` was ever set, not that `onStart` ran — so if the editor is torn down in that window, `onUpdate`/`onKeyDown`/`onExit` can fire on a `component` that was never created, throwing "can't access property 'destroy', component is undefined". Guard all three handlers. This bug predates recent commits but is much easier to hit now that editor mount/create timing changed (Suspense retry handling).
…t drops The interactive New-Resource form (useNewForm.ts) mints a client-only `_new:<random>` subject via store.createSubject() and relies on Resource.new staying true until an explicit save derives the real did:ad: subject (store.newResource() mints that DID up front instead and never has this problem). Resource.subscribeLocalUpdates only gated dirty-tracking on `.new`, assuming the subject already carries its real DID. If anything reset `.new` to false first (e.g. applyToStore merging in an unrelated fetch response) before the resource completed its genesis save, the next local edit reached the outbox's plain incremental-commit path with the subject still literally `_new:...`. The server rejects that (it was never a complete resource), and onTerminalDrop's best-effort refetch could itself reset `.new` again — re-arming the same failure on the next edit, producing a repeating "Dropped stuck commit" error. Skip dirty-tracking for `_new:` subjects regardless of `.new`, and skip the terminal-drop refetch for `_new:`/`_local:` subjects (nothing to realign with on the server). Added a regression test that reproduces the loop condition directly and confirms it fails without the fix.
…ort keys, query ids Collection queries no longer decode a Loro CRDT snapshot per member: they read the materialized Tree::Resources row and attach the stored snapshot bytes raw as loroUpdate (wire-identical, zero decodes). Subjects-only queries skip bodies entirely; rows missing (endpoints/externals) fall back to the full path. 1000-member query: 62ms -> ~6ms (-90%), non-sudo ~7ms. - hierarchy::RightsCache: per-request memo threaded through check_rights, so a listing resolves shared drive/parent ancestry once, not per member - QueryMembers keys (members_index_v6): 16-byte blake3 query id prefix instead of the full serialized filter, plus order-preserving typed sort keys (null < bool < f64-keyed numbers < case-folded strings). Fixes numeric sort order (#287) and string-prefix ordering; QUERY_UPDATE subscriptions now route by id - Watched filters routed by (drive, property): commits only evaluate filters referencing the changed property (create -12%, edit -14%) - AND-filter index builds pick the most selective constraint via scan-capped cardinality estimates and verify all constraints against rows (also fixes unverified single non-equality filters) - Behavior: sorted collections now include members lacking the sort property (sorted first; previously dropped by accident), and QueryResult::resources stays empty when include_nested is false planning/index-performance.md rewritten as the architecture doc (Loro authoritative, rows for reads, indexes for candidates, intersection planner) with paired benchmark results.
…ments The write-path gains claimed in the previous commit (create -12%, edit -14%) did not reproduce in a clean paired f235561 vs 3578d08 run — they came from a Criterion baseline recorded under concurrent machine load. Clean paired numbers: write path is flat-to-slightly-negative on a fresh store (create +10%, edit +6% Rust-level; ~noise over HTTP). The verified wins: - 1000-member query: 51.8ms -> 5.9ms Rust (-88.5%), ~104ms -> ~30ms over a single HTTP round trip (-70%); ~5x from NextGraph's comparison query, down from ~20-25x - Filter routing pays off exactly where it was built to: with accumulated watched filters. New paired scaling measurement (lib/tests/watched_filter_scaling.rs, ignored-by-default): per-create cost before grew linearly with bystander filters (14.5ms at 0 -> 52.6ms at 10k, +263%); after it is flat (~15-17ms) — 3.2x faster at 10k filters. Fresh-store benchmarks can't see this win.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Most insane PR ever.
did:adResolvingdid:adlocal-first resources #1146 , refactors subject completely Refactor Subject (resource identifiers / urls / dids / ids) #1139Checklist