Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
950fc2f
created plan.md
adhi-thirumala Jun 12, 2026
1df00de
plan v2
adhi-thirumala Jun 12, 2026
77fa166
add p2p collaboration
adhi-thirumala Jun 13, 2026
759ef58
add collaboration presence status
adhi-thirumala Jun 13, 2026
cf7a449
finished off first pass plan implemnentation
adhi-thirumala Jun 13, 2026
7e7433d
add collaboration presence status
adhi-thirumala Jun 13, 2026
71570bd
finished off first pass plan implemnentation
adhi-thirumala Jun 13, 2026
2b91dae
Merge branch 'fable-collab' of github.com:realartists-gitmo/flowstate…
adhi-thirumala Jun 13, 2026
3a8bc26
run cargo fmt
adhi-thirumala Jun 13, 2026
51fa2b9
add fix plan
adhi-thirumala Jun 13, 2026
2dd3249
more fix
adhi-thirumala Jun 14, 2026
0f065e7
fix.md implemented and coderabbit as well
adhi-thirumala Jun 14, 2026
4c244f9
added logging
adhi-thirumala Jun 16, 2026
0d753e4
Merge branch 'fable-collab' of github.com:realartists-gitmo/flowstate…
adhi-thirumala Jun 16, 2026
c8375bd
new thing
adhi-thirumala Jun 16, 2026
1388ae7
testing xhigh fixes
cxnmai Jun 17, 2026
526d0ca
Fixed double insert
adamhumphrey44 Jun 17, 2026
1a9ff7c
newline stuff
cxnmai Jun 17, 2026
ae8f0cd
loro root
adhi-thirumala Jun 17, 2026
9b9e283
Make single-root LoroText incremental (FIX_LORO_ROOT core)
adhi-thirumala Jun 17, 2026
3fc4951
cargo fmt
adhi-thirumala Jun 17, 2026
928625e
Quiet-by-default logging with env-controlled levels + clippy fix
adhi-thirumala Jun 17, 2026
f318f02
Here you go adhi
adamhumphrey44 Jun 18, 2026
87808ba
finished migration to full loro text backend
adhi-thirumala Jun 18, 2026
004906a
more changes
adhi-thirumala Jun 18, 2026
e13d7d3
Untested slop
adamhumphrey44 Jun 20, 2026
8655d98
Untested slop
adamhumphrey44 Jun 20, 2026
3d2cb82
Bout to unleash the big pick
adamhumphrey44 Jun 20, 2026
ed14ba1
Big pick incoming
adamhumphrey44 Jun 20, 2026
20ffbc5
Somehow instafixed CRDT editing regression
adamhumphrey44 Jun 20, 2026
2bf3728
Doc import/export working
adamhumphrey44 Jun 20, 2026
08c7446
Edit fidelity preserved
adamhumphrey44 Jun 20, 2026
b459052
stuff
adhi-thirumala Jun 23, 2026
67859ee
Fix build and resolve concerns from Loro-native migration
adhi-thirumala Jun 23, 2026
8769acb
Complete Loro-native architecture plan: close all remaining spec gaps
adhi-thirumala Jun 23, 2026
4731ce9
formatted
adhi-thirumala Jun 23, 2026
0d0ecea
fixed clippy
adhi-thirumala Jun 23, 2026
bb2cafc
clanker made changes
adhi-thirumala Jun 25, 2026
9cb8ad8
format
adhi-thirumala Jun 25, 2026
56daff1
fixed flashing edits
adhi-thirumala Jun 25, 2026
023ebad
fixed windows bug maybe
adhi-thirumala Jun 25, 2026
dbc56fc
Fix hotpath compile errors
adamhumphrey44 Jun 26, 2026
053e6b4
Make hotpath not compile so adhi push changes
adamhumphrey44 Jun 26, 2026
aa4abab
Removed annotate from const
adamhumphrey44 Jun 26, 2026
9595543
Csv leads
adamhumphrey44 Jun 26, 2026
ddea048
Bugix
adamhumphrey44 Jul 1, 2026
f712a33
Md
adamhumphrey44 Jul 1, 2026
0f0b9cf
Just checking
adamhumphrey44 Jul 5, 2026
439eab8
Fixed a bunch
adamhumphrey44 Jul 6, 2026
d663415
Fixy
adamhumphrey44 Jul 6, 2026
d278b9a
Lint
adamhumphrey44 Jul 6, 2026
087a383
Lint
adamhumphrey44 Jul 6, 2026
1881bb1
Adhi... uwa~!
adamhumphrey44 Jul 6, 2026
2b26d1d
Chinmay... kawaii~!
adamhumphrey44 Jul 6, 2026
2fda79f
B4 codex
adamhumphrey44 Jul 6, 2026
17a624e
perf(collab): batch cursor resolution in paragraph-metadata prune/repair
adamhumphrey44 Jul 6, 2026
b473b1f
fix(docx-import): map <w:br>/<w:cr> to soft break, not paragraph newline
adamhumphrey44 Jul 6, 2026
866f8c7
test(collab): add GUI-free repro for object-adjacent-empty-paragraph …
adamhumphrey44 Jul 6, 2026
72651ad
Crdt
adamhumphrey44 Jul 6, 2026
d8020a1
test(collab): correct the object-adjacent-empty repro to the traced r…
adamhumphrey44 Jul 6, 2026
5d50099
fix(collab): resolve editor-command Loro positions via durable cursor…
adamhumphrey44 Jul 6, 2026
99d00f0
test(collab): guard caret projection-space round-trip; document the i…
adamhumphrey44 Jul 6, 2026
d4b11ae
feat(collab): N-peer full-op convergence fuzz harness + Join/coordina…
adamhumphrey44 Jul 6, 2026
7186c81
docs(collab): decision doc for object-adjacent empty-paragraph coales…
adamhumphrey44 Jul 6, 2026
5fd6aea
perf: full-codebase runtime optimization sweep (correctness-preserving)
adamhumphrey44 Jul 6, 2026
ba309a2
fix(collab): Fork B pt1 — full rebuild preserves real empty paragraphs
adamhumphrey44 Jul 6, 2026
feb29e9
fix(collab): Fork B complete — full object-adjacent empty-paragraph p…
adamhumphrey44 Jul 6, 2026
66f8c70
docs(collab): scope next fuzz targets — object block positioning + so…
adamhumphrey44 Jul 6, 2026
e0d5db2
fix(collab): correct incremental remote-import paragraph mapping (sof…
adamhumphrey44 Jul 6, 2026
e909924
fix(collab): resolve object block positions from projection structure…
adamhumphrey44 Jul 6, 2026
a1a5a4b
fix(collab): converge the full object block-structure op surface (BUG…
adamhumphrey44 Jul 6, 2026
1cb95f1
feat(collab): fuzz all 9 table ops + fix concurrent-delete column top…
adamhumphrey44 Jul 7, 2026
91b451d
test(collab): complete the fuzz surface — object property ops + Repla…
adamhumphrey44 Jul 7, 2026
53fe154
docs(collab): mark object + table op convergence resolved (24/24 fuzzed)
adamhumphrey44 Jul 7, 2026
9c0f151
test(perf): H1 — large-doc complexity harness + always-on work counte…
adamhumphrey44 Jul 7, 2026
50cf9f3
test(perf/collab): H2 actor-starvation, H4a stale-frontier, H5 docx-d…
adamhumphrey44 Jul 7, 2026
ba020b1
test(render): H3 — layout virtualization keep-up harness (Class 3)
adamhumphrey44 Jul 7, 2026
0c602bc
test(collab/render): H4b reconcile edit-loss + H6 asset-pull-failure …
adamhumphrey44 Jul 7, 2026
9f90856
fix(docx): map body-level w:br to U+2028 soft break on import
adamhumphrey44 Jul 7, 2026
071437a
Bang
adamhumphrey44 Jul 7, 2026
98856a8
Bang
adamhumphrey44 Jul 7, 2026
1f707c1
Lucas... BALLINGER!!!
adamhumphrey44 Jul 7, 2026
40b9c31
Perf opt... CHinmay.... KHALADKAR~!!!
adamhumphrey44 Jul 8, 2026
c1b743c
collab/editor: crdt_runtime + projection + package.rs changes, soak p…
adamhumphrey44 Jul 8, 2026
6a4bad0
tools(citation): debate-cite parser rewrite, sparse target, gold eval…
adamhumphrey44 Jul 8, 2026
0e47179
Instant verbatim achieved
adamhumphrey44 Jul 8, 2026
71cae28
Scrolling fully fixed
adamhumphrey44 Jul 8, 2026
1b708fc
Gort
adamhumphrey44 Jul 8, 2026
6abb955
Act-5 optimization work + new autoflow/citation crates
adamhumphrey44 Jul 9, 2026
5ebfd84
Nonsense
adamhumphrey44 Jul 9, 2026
f5fa6c5
Acts 5-14 perf program + vendored Loro/generic-btree/rdocx/ct2rs patches
adamhumphrey44 Jul 12, 2026
87de21c
Remove scratchpad/citation slop from repo root
adamhumphrey44 Jul 12, 2026
953adfb
Preparing to merge
adamhumphrey44 Jul 12, 2026
8d6c55b
Prep merge
adamhumphrey44 Jul 12, 2026
4619a5a
fix(editor): skip the O(doc) caret-rebase fork on local writes
adamhumphrey44 Jul 12, 2026
df38f19
fix(loro): restore try_split_at_unicode_pos caller in decode_snapshot…
adamhumphrey44 Jul 12, 2026
c59155d
fix(editor): re-arm caret anchor on move so remote edits don't fork t…
adamhumphrey44 Jul 12, 2026
b1343c7
chore: gitignore the local .docx test corpus (purged from history)
adamhumphrey44 Jul 12, 2026
20bac09
Remove citation feature (cite2json parser/model + block + format DSL …
adamhumphrey44 Jul 13, 2026
69f9e33
collab about done
adamhumphrey44 Jul 13, 2026
0f3ccc6
checkpoint: uncommitted branch WIP (collab discovery/comments + caret…
adamhumphrey44 Jul 13, 2026
b145ff2
collab audit fixes: comment auth, secret hygiene, Dropbox bounds, mac…
adamhumphrey44 Jul 14, 2026
771dbea
BLE interop fix + rewrite the macOS/Windows release handoff doc
adamhumphrey44 Jul 14, 2026
ccfe6ff
Gpui headless tests + fix one panic with render
adamhumphrey44 Jul 14, 2026
4839b8f
I highk dk
adamhumphrey44 Jul 14, 2026
01dbcc5
Merge branch 'main' into crdt-materializer-refactor
adamhumphrey44 Jul 14, 2026
f3b04af
Fix CI: fmt sweep, machete, security advisories, license allowances, …
adamhumphrey44 Jul 14, 2026
d26199a
Fix CI build job: libdbus dep, clippy backlog, dead code
adamhumphrey44 Jul 14, 2026
639565b
CI: pin nightly to 2026-06-23 (latest nightly ICEs on test-attr expan…
adamhumphrey44 Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .ast-bro-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
vendor/
helpers/
.agents/
CLAUDE.md
10 changes: 10 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# cargo-audit configuration (CI `cargo audit` job).
#
# quick-xml < 0.41 DoS advisories. Our own untrusted-input parse paths are on
# quick-xml 0.41; the remaining old copies in Cargo.lock are pinned by the
# LATEST releases of third-party crates (xcb 0.30, docx-rs 0.36,
# rdocx-opc/oxml 0.37, citationberg-via-typst 0.38, wayland-scanner 0.39) and
# cannot be bumped without vendoring them. Mirrors the deny.toml ignore list —
# keep the two in sync. Re-check on dependency upgrades.
[advisories]
ignore = ["RUSTSEC-2026-0194", "RUSTSEC-2026-0195"]
5 changes: 5 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ linker = "rust-lld.exe"
[alias]
survey = "run --profile profiler --features profiler"
product = "run --profile product"

[env]
# hotpath-meta 0.16.x looks for "hotpath-samply-meta" but the installed
# binary from hotpath 0.20.x is "hotpath-samply". Point to the correct name.
HOTPATH_META_SAMPLY_WRAPPER_BIN = "hotpath-samply"
1 change: 1 addition & 0 deletions .claude/skills/rust-performance-optimization
29 changes: 26 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,27 @@ env:
RUST_BACKTRACE: "1"

jobs:
raw-authority-guard:
name: Raw-authority guard (Loro-first spec invariant 6)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Forbidden raw-authority surfaces must not exist in production source
run: bash tools/check_raw_authority.sh

fmt:
name: fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# rustfmt config (.rustfmt.toml) uses nightly-only options.
# Nightly is date-pinned across all jobs: nightly-2026-07-13 ICEs while
# expanding test attributes (rustc_test_entrypoint_marker, see the
# 2026-07-14 build failures). Bump the pin deliberately, not implicitly.
- name: Install nightly rustfmt
uses: dtolnay/rust-toolchain@nightly
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-23
components: rustfmt
# Fails the check if anything isn't formatted. The repo's pre-commit hook
# runs `cargo fmt` locally, so this should normally pass on the first try.
Expand All @@ -56,11 +68,14 @@ jobs:

# GPUI links against Vulkan / Wayland / X11 / fontconfig and friends;
# xvfb + a software Vulkan driver cover any test that builds a gpui::App.
# libdbus-1-dev: bluer (BLE collab discovery) links libdbus via
# dbus/libdbus-sys.
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake clang pkg-config \
libdbus-1-dev \
libfontconfig1-dev libasound2-dev \
libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev \
libxkbcommon-dev libxkbcommon-x11-dev \
Expand All @@ -70,9 +85,11 @@ jobs:

# Nightly is mandatory: the workspace uses
# `cargo-features = ["profile-rustflags"]` and `-Z` flags.
# Date-pinned — see the fmt job's pin comment.
- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-23
components: clippy

- name: Cache cargo build artifacts
Expand All @@ -95,6 +112,9 @@ jobs:

# Runs the binaries built in "Build test binaries" (nothing to recompile);
# xvfb + software Vulkan cover any test that builds a gpui::App context.
# The default (fast) suite. The multi_peer_convergence fuzzers run here
# (they converge in ~0.5s). Only the `caret_soak` reconcile-race soak is
# still `#[ignore]`d for wall-clock (~66s); run it explicitly when needed.
- name: cargo test
run: xvfb-run -a cargo test --workspace
env:
Expand All @@ -107,8 +127,11 @@ jobs:
- uses: actions/checkout@v4
# cargo-deny runs `cargo metadata`, which needs nightly cargo to parse the
# workspace's `cargo-features = ["profile-rustflags"]`.
# Date-pinned — see the fmt job's pin comment.
- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2026-06-23
- name: Install cargo-deny
uses: taiki-e/install-action@v2
with:
Expand Down
48 changes: 48 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,51 @@ perf.data
/VIRTUALIZED_VIEWPORT_PLAN.md
flamegraph
.pi/

# Local dev logs (flowstate::logging default dir; per-run timestamped files)
flowstate-logs/

# Compiled Python / caches
__pycache__/
*.pyc

# Local scratch documents (real .db8 fixtures live under helpers/)
/*.db8

# Rustc crash dumps
rustc-ice-*.txt

# Large, regenerable ML datasets produced by tools/citation_finetune
/datasets/

# flowstate-autoflow: large/regenerable data (17 GB audio corpus + generated indexes)
/crates/flowstate-autoflow/audio-stash/
/crates/flowstate-autoflow/rounds.sqlite
/crates/flowstate-autoflow/rounds.jsonl

# Real .docx test corpus (3.3 GB, local fixture from Dropbox; gated by
# FLOWSTATE_CORPUS_DIR). NEVER track this — it bloated .git to 19 GB and was
# purged from history 2026-07-12. Regenerable from Dropbox if lost.
/helpers/corpus/

# Local design/spec scratch docs (kept on disk, deliberately out of git)
/flowstate_*.md
/debate-asr-production-plan.md
/lororef.md
/optimizationnotes.md

# Profiling / probe run artifacts (regenerable captures)
/hotpath*.md
/peer1hotpath.md
/peer2hotpath.md
/*.log
/output.json
/fb_122_output.json

# Vendored-crate build artifacts (Acts 5-14 vendoring)
vendor/*/target/
vendor/*/*/target/

# Root scratch/analysis slop (keep it out of the repo)
/scratchpad_*
/citation_*.xlsx
13 changes: 0 additions & 13 deletions AGENTS.md

This file was deleted.

1 change: 1 addition & 0 deletions CLAUDE.md
200 changes: 200 additions & 0 deletions COLLABORATION_MACOS_WINDOWS_RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# Collaboration release handoff: macOS and Windows

**Status date: 2026-07-13.** This document supersedes the July-2026 draft that
previously lived at this path. That draft's "other incomplete items" list is
obsolete: the discovery coordinator, Dropbox connect flow, checkpoint
compare-and-swap, anchored comments, trust/identity settings UI, and revision
author attribution are now all implemented, wired into the application
lifecycle, and verified on Linux (unit + integration tests, clippy-clean).

What remains is exactly two categories:

- **Yellow zone** — code that is written and cross-compile-checked for
macOS/Windows but has never executed on those platforms. It needs a dev with
the hardware to run, verify, and fix what only a live radio/OS can reveal.
- **Red zone** — packaging, signing, entitlements, and the physical-device
acceptance matrix. Not started here by design; owned entirely by the
macOS/Windows devs.

## Architecture you are inheriting (all verified on Linux)

- `crates/flowstate-collab/src/discovery.rs` — signed `DiscoveryAdvertisement`
(Ed25519, domain-separated contexts, expiry, document-fingerprint scope),
`RendezvousBackend` trait, and `eligible_advertisements` — the single
verification/dedup gate every backend result must pass before UI.
- `crates/flowstate-collab/src/bluetooth.rs` — shared GATT frame codec
(u32-LE length prefix, 60 KiB cap) plus three native backends: Linux/BlueZ
(the behavioral reference), Windows/WinRT, macOS/CoreBluetooth.
- `crates/flowstate-collab/src/dropbox.rs` — PKCE OAuth, rendezvous sidecars,
revision-conditional checkpoint writes (CAS). HTTP clients have bounded
connect/read timeouts and a 256 MiB download cap.
- `crates/flowstate/src/collab/discovery_runtime.rs` — the application-level
discovery coordinator (publish on session start, 30 s renewal, 90 s ad
lifetime, scan-on-request, clear on close/shutdown).
- Comments, identity/trust settings, safety codes, and revision attribution
are application-level and platform-neutral; nothing there needs macOS- or
Windows-specific work beyond running the app.

Security posture (for your review, not rework): discovery ads never carry
admission bearers; admission is granted server-side only to identities in the
document's standing-access set, over the encrypted iroh channel
(`net/direct.rs`); comment delete/edit are author-gated in the CRDT runtime;
the Dropbox checkpoint merge trusts the Dropbox folder ACL as its boundary
(documented at `dropbox_checkpoint.rs`); `settings.toml` (identity seed +
Dropbox tokens) is written `0600` on Unix — see the Windows note below.

## Yellow zone: run and verify the native BLE backends

Both backends compile cleanly today (`aarch64-apple-darwin` and
`x86_64-pc-windows-msvc`). On a real machine, plain `cargo check`/`cargo test`
works natively — no probe rig needed. Neither backend has ever executed.

### macOS (`bluetooth.rs`, `macos_backend`) — rebuilt 2026-07-13, highest risk

The module as originally drafted had never compiled (the
`objc2-core-bluetooth/dispatch2` feature was never enabled). It was rebuilt:

- **Peripheral (publish) side runs on a dedicated actor thread**
(`flowstate-ble-peripheral`): CoreBluetooth objects are `!Send`, so the
backend only passes plain-data commands over a channel. All manager/service
objects live and die on that thread.
- **Both managers get dedicated serial dispatch queues** — callbacks must not
depend on the GPUI-owned main run loop (the scan side blocks its own thread).
- **`wait_for_power` distinguishes states**: fails fast on
PoweredOff/Unauthorized/Unsupported, waits up to 15 s through
Unknown/Resetting to cover the first-run permission prompt.

Verify on hardware, in roughly this order:

1. **Permission**: without `NSBluetoothAlwaysUsageDescription` in the bundle's
Info.plist, modern macOS kills the process on first CoreBluetooth use. This
is the first thing to wire (red zone below) before any run.
2. **Publish**: manager reaches PoweredOn on its queue; `addService` triggers
no `didAdd…error`; the ad is visible to a BLE sniffer / a Linux peer with
the Flowstate service UUID.
3. **Static characteristic long reads**: the signed record is set as the
characteristic's static value; CoreBluetooth serves offset reads itself.
Verify a Linux peer reads the full frame (records are typically 400–500
bytes; ATT caps attribute values at 512 bytes — see the matrix item below).
4. **Scan**: 4 s scan window connects, discovers, reads, disconnects; the
delegate feeds decoded records through `eligible_advertisements`.
5. **Teardown**: Clear command and backend drop stop advertising, remove
services, and nil the delegate; repeated publish replaces cleanly (one
peripheral-manager slot).
6. **Sleep/wake and Bluetooth toggling** while a session is live.

**Known macOS platform constraint (already handled, verify the behavior):**
CoreBluetooth cannot publish service data — macOS ads carry only the service
UUID, not the 16-byte document locator. The Linux scanner was changed
(2026-07-13) to connect-and-verify peers with a missing locator instead of
skipping them; the Windows watcher never used a locator prefilter. Verify a
macOS publisher is actually discovered by both. The post-read signed-record
check is the authoritative document scope test on every platform.

### Windows (`bluetooth.rs`, `windows_backend`) — written by the prior agent, API-verified only

The code compiles and its WinRT usage was reviewed; nothing has run. Verify:

1. **Provider**: `GattServiceProvider::CreateAsync` + characteristic creation
succeed on a real adapter; `StartAdvertisingWithParameters` including the
`SetServiceData` locator (best-effort on older builds — a failure there is
deliberately ignored).
2. **Long reads**: `ReadValueWithCacheModeAsync(Uncached)` performs ATT Read
Blob continuation internally; a truncated frame fails loud in the shared
decoder. Verify against a Linux publisher with a large profile.
3. **Watcher hygiene**: repeated scans must not accumulate callbacks
(`Stop` + `RemoveReceived` run per scan; confirm with a scan loop).
4. **Apartment/threading**: WinRT activation happens from tokio worker
threads; `NativeBluetoothBackend::new` probes watcher creation so settings
gets a synchronous, actionable platform error. Verify with radio off, no
adapter, and after adapter reset.
5. **Packaged vs unpackaged**: BLE works unpackaged for development; under
MSIX the `bluetooth` device capability is required (red zone).

### Dropbox end-to-end (all platforms; code done, no live-account run)

The PKCE begin → system browser → `flowstate://oauth/dropbox` callback →
token exchange → persisted credentials flow, plus disconnect and the
checkpoint CAS conflict-merge path, are implemented and unit-tested. Nobody
has run them against a live Dropbox app key. On each OS verify: custom-scheme
routing to a running instance AND to a cold launch; token refresh persistence;
two clients CAS-conflicting on one bound path and converging.

## Red zone: packaging, signing, and the acceptance matrix

### macOS packaging and privacy

`crates/flowstate/assets/macos/Info.plist` registers `flowstate://` but is not
a release-complete plist.

- Add `NSBluetoothAlwaysUsageDescription` (legacy peripheral key only if the
minimum macOS requires it). Without it, CoreBluetooth use is fatal.
- Confirm hardened-runtime/App Sandbox Bluetooth entitlements for the chosen
distribution model; add only what is necessary.
- Merge URL registration + Bluetooth keys into the real release bundle; the
repository plist must not remain an unused template.
- Verify `flowstate://join` and `flowstate://oauth/dropbox` reach both a
running app and a cold launch.
- Sign, notarize, staple; test the artifact outside the build machine.
Apple Silicon and Intel if Intel remains supported.

### Windows packaging and protocol registration

The PowerShell helper registers associations for unpackaged dev builds only.

- MSIX: declare the `bluetooth` device capability plus protocol/file
extensions in `Package.appxmanifest`; test activation routing through the
packaged lifecycle.
- Unpackaged installer: clean install/uninstall of per-user protocol + file
associations, safe quoting of the executable and URL argument,
upgrade/repair behavior.
- Single-instance URL activation, including with no window open.
- Sign executable and installer/MSIX; test on clean Windows 10 and 11 without
Visual Studio or developer mode.
- **Secrets at rest**: the Unix `0600` on `settings.toml` does not apply on
Windows. Decide on DPAPI (and Keychain on macOS) for the identity signing
seed and Dropbox tokens, or accept per-user-profile ACLs explicitly.

### Physical-device acceptance matrix

Do not enable the nearby-discovery toggle by default on either platform until
all of these pass with release artifacts and physical devices:

- macOS publishes and Windows discovers; Windows publishes and macOS
discovers; each platform interoperates with the Linux/BlueZ reference.
- A macOS publisher (no service-data locator) is discovered by Linux and
Windows scanners; wrong-document locators are skipped pre-connect where a
locator exists, and every record is re-checked post-read.
- Records larger than one ATT payload are reassembled; records approaching
the 512-byte ATT attribute cap are measured. If a real profile (long
display name, many relay addresses) pushes a frame past 512 bytes, GATT
reads will truncate at the OS level on some stacks — the decoder fails
loudly, but delivery needs a design change (trim the endpoint address list,
or move to an L2CAP channel). Measure before shipping.
- Tampered signatures, expired records, oversized frames, invalid offsets,
and trailing bytes are rejected (the shared decoder tests cover the codec;
verify the OS paths deliver bytes unmodified).
- Two Flowstate instances publishing/scanning concurrently where the OS
permits, with a clear degraded state otherwise.
- Permission denied, radio disabled, no adapter, adapter reset, sleep/wake,
suspend/resume, and document/session closure leak no tasks, handlers,
services, or advertisements.
- Discovery never displays an unverified or out-of-scope identity and never
transports a session admission bearer.
- Battery and scan/connect rates acceptable during a long editing session
(current cadence: one BLE publish round-robin + Dropbox refresh per 30 s
tick, 4 s scan windows on demand).
- Accessibility text explains why Bluetooth is requested; discovery can stay
disabled without impairing invite links.

### Deliberate design decisions (do not re-litigate without cause)

- Dropbox folder membership **is** the checkpoint trust boundary; checkpoint
packages are not additionally signed.
- Discovery admission requests carry a nonce but are not replay-tracked:
a 30 s expiry, the encrypted direct channel, and the standing-access
identity gate bound the exposure.
- Trust attestations have no expiry; revocation is removing the trusted key
in settings. Key-change alerting is future UX, not release-blocking.
- Background (app-closed) BLE discovery stays out of scope until it has a
separately reviewed privacy/battery design.
Loading
Loading