Skip to content

Calm connectivity: degrade hysteresis, staging sweep race fix, quiet reconnect UI - #170

Merged
wingleeio merged 4 commits into
mainfrom
zeron/connectivity-ui-calm
Aug 19, 2026
Merged

wingleeio merged 4 commits into
mainfrom
zeron/connectivity-ui-calm

Conversation

@wingleeio

@wingleeio wingleeio commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes the four v0.2.12 field reports on healthy networks:

1. Flashing warnings / phantom "Queued" / "Reconnecting" before sends

compute_connectivity reported raw socket state, so a chat room mid-join (every navigation), an idle link waking for a send, or any sub-second dial read as degraded — flashing the amber notice for ~300ms and stamping sends "Queued" on enterprise-grade connections.

Degradation is now hysteretic (DegradeGrace, engine-side): a source (OS path / registry room / per-chat room) must be raw-degraded for 4s continuously before it's reported; recovery reports instantly. All consumers (pill, composer notice, row Queued/Failed, send_queued) inherit the calm from the one stream. Unit-tested over injected instants.

2. "Couldn't stage the attachment locally"

A real race shipped in the parallel-chunk upload path: Uploads::append runs sweep() before writing, and sweep reclaimed empty staging dirs unconditionally — deleting a sibling chunk's just-created dir between its create_dir_all and first write. 3-wide chunk concurrency made the window live, and the no-delay lockstep retries re-collided. Empty dirs are now judged by their own mtime against the 10-min TTL (regression test included), and chunk retries stagger by seq.

3. Reconnect UI restyle

The amber-bordered strip with the raw transport-error line is gone. Degraded states render as one quiet frost pill — neutral dot + muted 11px label, fade-in entrance — with amber reserved for hard OS-offline. The composer notice drops its warning box for a single caption line ("Messages will send once the connection recovers."). Retry-countdown and last-failure text removed from the sidebar (they read as debug output; the detail still lands in logs).

4. Atomic new-chat sends (the "empty transcript" report)

The staging failure had a worse half on new-chat sends: the pipeline created state before it was entitled to (CreateChat mutate ran before staging; the composer had already selected the minted chat and cleared the input), so a staging failure stranded the user inside a just-created empty chat with their message gone.

  • Attachments now stage first — before the chat row or worktree spec exist anywhere. Staging is chat-independent (uploadId-keyed), so a failure aborts with nothing created. Both the queued local-stage and legacy host-stage flows move together.
  • A post-mutate failure (QueueCommand) best-effort deletes the minted row — no orphan either way.
  • Failure restore targets the canvas for new chats: back to the new-session canvas with prompt text, attachment stash, and the error banner — handling both re-key orderings (the deleted row's watch event can re-key the composer before the failure handler runs; caught live in the rig).

Verified E2E on the headless rig — read-only uploads dir + new-chat image send: canvas retained, no stranded sidebar row, banner + prompt text + attachment chip all restored:

After a forced staging failure: canvas retained with banner, text, and attachment restored; no stranded chat row

Tests

  • New: degrade_grace_tests (blip-never-reports, persist-then-report, hide-fast, per-source independence), sweep_spares_a_fresh_empty_staging_dir.
  • Full sweep: 709 engine/ui/rpc + 38 sync, 0 failures (re-run after every commit on the branch).

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Screenshots

Degraded posture (dead edge, >4s — so the grace has expired and the state is real). Reconnecting is a transparent grayscale spinner + faint caption — no surface, no border:

App in reconnecting state: transparent grayscale spinner and caption in the sidebar, quiet composer line

Detail — sidebar spinner line and composer caption:

Detail of the grayscale reconnecting spinner line and composer notice

On healthy networks neither element ever renders — sub-4s blips (room joins, idle-link wakes, navigation dials) report Connected.

wing-anara and others added 4 commits August 19, 2026 11:08
…t pill

Four v0.2.12 field reports (wing, office/enterprise networks):

1. Amber warnings flashing ~300ms above the composer on chat switches,
   'Reconnecting' before sends, and 'Queued' rows on strong networks: the
   raw connectivity snapshot reported any room mid-join / idle-link wake as
   degraded. compute_connectivity now runs show-slow/hide-fast hysteresis
   (DegradeGrace, 4s) per source (OS path, registry, per-chat room) — raw
   degradation must persist before it is reported; recovery is instant.
   Every consumer (pill, composer notice, Queued/Failed row states,
   send_queued) calms down at once.

2. 'Couldn't stage the attachment locally' on healthy machines: sweep()
   reclaimed EMPTY staging dirs unconditionally, racing the window between
   a parallel chunk's create_dir_all and its first write (3-wide uploads
   made this live; lockstep no-delay retries re-collided). Empty dirs are
   now judged by their own mtime against the TTL, and chunk retries
   stagger by seq.

3. Reconnecting UI restyle: the amber bordered strip (+ raw transport
   error dump) becomes one quiet frost line — neutral dot + 11px muted
   text, fade-in entrance, amber reserved for hard OS-offline; the
   composer notice likewise drops its warning box for a caption line.
   Retry countdown and last-failure detail removed from the sidebar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wing on the frost chip: still reads as a foreign pill. Drop the surface and
border entirely — reconnecting is the sidebar's own mini gradient spinner +
a faint caption; offline keeps the amber dot. Transparent, borderless.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same 2x3 snake grid and timing as the brand spinner, single flat tint
(theme.text_muted) so the connection line stays neutral in both themes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
wing's v0.2.12 report, the worse half: a failed attachment stage on a
NEW-chat send didn't just error — it stranded the user inside a
just-created empty chat with the message gone ('completely failed and
showed an empty transcript').

The send pipeline created state before it was entitled to: CreateChat
mutate ran before staging, and the composer had already selected the
minted chat and cleared the input. A staging failure then removed the
echo — empty transcript, empty composer, orphaned sidebar row.

- Attachments now stage FIRST, before the chat row or worktree spec
  exist anywhere. Staging is chat-independent (uploadId-keyed), so a
  failure aborts with NOTHING created. Both flows (queued local-stage
  and legacy host-stage) move together.
- A post-mutate failure (QueueCommand) best-effort deletes the minted
  row — no orphan either way.
- Failure restore targets the CANVAS for new chats: back to the
  new-session canvas, prompt text and attachment stash restored under
  the canvas key, banner keyed there too. Handles both re-key
  orderings (the deleted row's watch event can re-key before the
  failure handler runs — verified live in the rig; the draft-swap-only
  variant lost the text to that race).

Verified E2E on the headless rig: read-only uploads dir + new-chat
image send → canvas retained, no sidebar row, banner + text + chip all
restored. 737 tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@wingleeio
wingleeio merged commit e800e8e into main Aug 19, 2026
1 check passed
wing-anara added a commit that referenced this pull request Aug 20, 2026
ios: port the network-reliability train (PRs #159/#164/#165/#168/#170) to mobile
tobi404 pushed a commit to tobi404/comet that referenced this pull request Aug 20, 2026
…sh#159/zeronsh#164/zeronsh#165/zeronsh#168/zeronsh#170 port)

Send truth:
- ConnectivityCenter: graced connectivity (DegradeGrace 4s per source —
  OS path / registry room / each open chat room; recovery reports
  instantly) feeding one stream every consumer inherits calm from.
- Home bar: quiet "Reconnecting…" spinner / amber "Offline — sends are
  saved" dot, only while degraded past the grace.
- Rows: amber "Queued" / red "Failed" corner pills override the status
  (and suppress the Working spinner — no fake progress); session strip
  shows "Sending…" / "Queued — will send automatically" / "Not delivered
  — tap to retry" with a 2-minute undelivered grace; retry restarts the
  clock, kicks the room, nudges the host, and re-derives escorts.
- Composer: one caption line of pre-send honesty on a degraded path.

Attachments:
- PR zeronsh#164 uploader: ~510KB chunks (was ~45KB), 3-wide window, per-chunk
  retries staggered by seq, whole-upload deadline min(120+15/chunk, 900s),
  "Uploading… N%" narration.
- Queued flow (host ≥ 0.2.12, version-gated via the registry device row):
  the command queues immediately with pending://{uploadId}/{name} refs —
  a durable local write — bytes stash to disk and an escort pushes them
  with retry-forever on the online bus (2s→30s backoff, 15min cap),
  surviving relaunches via re-derivation from the doc's pending refs.
  An image send no longer dies with a dead link (Aug 19 incident class).

New chats:
- New-worktree sends attach RunRequest.worktree {repoPath, base} for the
  HOST to materialize at drain time — the blocking CreateWorktree relay
  RPC before send (the one path that could hang forever on a zombie
  link) is gone; base defaults to HEAD so a branch list that never
  loaded can't silently drop isolation.
- Legacy hosts stage attachments BEFORE the chat row exists — an upload
  failure aborts with nothing created, no stranded empty chat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
guilhermexp pushed a commit to guilhermexp/comet that referenced this pull request Aug 30, 2026
Calm connectivity: degrade hysteresis, staging sweep race fix, quiet reconnect UI
guilhermexp pushed a commit to guilhermexp/comet that referenced this pull request Aug 30, 2026
…sh#159/zeronsh#164/zeronsh#165/zeronsh#168/zeronsh#170 port)

Send truth:
- ConnectivityCenter: graced connectivity (DegradeGrace 4s per source —
  OS path / registry room / each open chat room; recovery reports
  instantly) feeding one stream every consumer inherits calm from.
- Home bar: quiet "Reconnecting…" spinner / amber "Offline — sends are
  saved" dot, only while degraded past the grace.
- Rows: amber "Queued" / red "Failed" corner pills override the status
  (and suppress the Working spinner — no fake progress); session strip
  shows "Sending…" / "Queued — will send automatically" / "Not delivered
  — tap to retry" with a 2-minute undelivered grace; retry restarts the
  clock, kicks the room, nudges the host, and re-derives escorts.
- Composer: one caption line of pre-send honesty on a degraded path.

Attachments:
- PR zeronsh#164 uploader: ~510KB chunks (was ~45KB), 3-wide window, per-chunk
  retries staggered by seq, whole-upload deadline min(120+15/chunk, 900s),
  "Uploading… N%" narration.
- Queued flow (host ≥ 0.2.12, version-gated via the registry device row):
  the command queues immediately with pending://{uploadId}/{name} refs —
  a durable local write — bytes stash to disk and an escort pushes them
  with retry-forever on the online bus (2s→30s backoff, 15min cap),
  surviving relaunches via re-derivation from the doc's pending refs.
  An image send no longer dies with a dead link (Aug 19 incident class).

New chats:
- New-worktree sends attach RunRequest.worktree {repoPath, base} for the
  HOST to materialize at drain time — the blocking CreateWorktree relay
  RPC before send (the one path that could hang forever on a zombie
  link) is gone; base defaults to HEAD so a branch list that never
  loaded can't silently drop isolation.
- Legacy hosts stage attachments BEFORE the chat row exists — an upload
  failure aborts with nothing created, no stranded empty chat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
guilhermexp pushed a commit to guilhermexp/comet that referenced this pull request Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants