镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

perf(profiles): keep verified names checked through a planned renewal - #2234

Merged
kalvinnchau merged 4 commits into
mainfrom
peon/fi-verified-renewal
Nov 3, 2026
Merged

kalvinnchau merged 4 commits into
mainfrom
peon/fi-verified-renewal

Conversation

@kalvinnchau

@kalvinnchau kalvinnchau commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Problem

A native NIP-FI socket renews its assertion every ~285 s: the lifetime is capped at 300 s, minus a 15 s margin. live.ts reconnects quietly and the connection stays reported connected, but clearSocket() ends every sent sync with disconnected: live connection lost. Each verified-profile (kind 30382) batch treated that as a failure:

  • it cleared checked for its subjects;
  • it republished the whole profile directory, and every name flipped from checked to cached;
  • the next ensure re-sent the batch, and its replay republished the directory again at EOSE, even though nothing had changed.

With 1,024 verified subjects that is 8 batches. Each renewal therefore caused 16 full republishes and 2,048 changed entries, and every checked name dropped to cached for a moment.

Change

  • A batch that ends with disconnected: is re-sent at once with its checked status kept, as a rebuilt batch already is. The decision waits one microtask. An outage reports the connection down in the same task, which stops every batch first, so an outage still clears status and sends nothing extra.
  • EOSE notifies only when it changed a head, a checked status or a retraction. A replay that confirms what is shown is quiet.

Evidence

Blox matrix: the real createRelaySession with the profile and verified directories over a scripted live transport, 1,024 verified subjects. Each renewal ends every sync as clearSocket() does, while states stay connected. Base and variant runs were interleaved, 5 runs on each of 2 Linux and 2 macOS workstations. Values are medians of 10 per OS.

Metric (5 renewals, ≈24 min of uptime) Linux before Linux after Linux Δ macOS before macOS after macOS Δ
CPU (ms) 327.5 22 −93% 194 27 −86%
Profile notifications 80 0 −100% 80 0 −100%
Entries changed 10,240 0 −100% 10,240 0 −100%
Names checked after 1,024 1,024 0 1,024 1,024 0
Verified REQs / events 40 / 5,120 40 / 5,120 0 40 / 5,120 40 / 5,120 0

What you gain: every listener stops refolding on every renewal, about 12.6 times an hour on a NIP-FI relay, and verified names no longer flicker from checked to cached. Wire traffic is unchanged.

The Blox runs predate the one-microtask deferral. Locally, the same harness gives an identical renewal result (0 notifications, 1,024 checked). An outage scenario keeps main's 40 REQs and clears status as before.

  • verified-profile.test.ts, new: "re-sends a batch a replaced socket ended and keeps its check quiet while connected" fails on main. "does not re-send a batch an outage ended" pins the outage path.
  • vitest run on src/features/relay, src/features/profiles and src/features/messages: 220 files and 5,002 tests pass, 4 skipped. tsc --noEmit and biome are clean.

Related

#2216 makes verified publishes one per macrotask. That reduces how many republishes a renewal causes, but each ended batch still drops its names to cached until the re-sent batch answers. This PR keeps them checked and keeps a confirming replay quiet, so the two compose. Same Blox harness, stacked on #2216, interleaved, 4 runs on each of 4 Linux and 4 macOS workstations. Values are medians of 16 per OS.

5 renewals @1,024 verified Linux #2216 Linux #2216 + this Linux Δ macOS #2216 macOS #2216 + this macOS Δ
CPU (ms) 74.5 21 −72% 64 27.5 −57%
Profile notifications 10 0 −100% 10 0 −100%
Checked↔cached flips 10,240 0 −100% 10,240 0 −100%
Verified REQs 40 40 0 40 40 0

Outage (5 disconnect/reconnect cycles) on #2216 with and without this change: 10 notifications and 40 REQs in both, CPU 78 vs 78 ms on Linux and 132.5 vs 131.5 ms on macOS. The outage path is unchanged.

Tradeoff

  • The directory infers a renewal from the documented disconnected: reason and from the connection still being up after the current task. It does not get an explicit signal from live.ts, which keeps the change to one file.
  • During an outage, batches now end through connected(false) alone. That is one profile notification per outage instead of one per batch plus one. The end state is unchanged.
  • A relay CLOSED whose reason starts with disconnected: is now reported as error: relay closed the sync, so only local socket loss takes the renewal path.

🤖 Generated with Claude Code

@kalvinnchau
kalvinnchau force-pushed the peon/fi-verified-renewal branch from b987a1a to 98836c7 Compare November 3, 2026 04:01
@kalvinnchau
kalvinnchau marked this pull request as ready for review November 3, 2026 04:11
@kalvinnchau
kalvinnchau requested a review from a team as a code owner November 3, 2026 04:11

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Carl, an automated reviewer, commenting via Wes's GitHub account.

Verdict: one blocker (P2), inline. The outage-vs-renewal ordering holds: reconnect()/terminal() call clearSocket() then notify() in the same task, so connected(false) lands before the microtask. No hot loop either: syncVerifiedProfiles never closes synchronously, and a missing transport returns undefined and fails.

Exit criteria: carry unpublished pre-EOSE changes into the re-sent batch, plus a probe for two renewals before EOSE. Also drop "no regressions or behavior changes" from the body, since this is one.

Reviewed with Mongo; probe fails at this head and passes with the fix.

kalvinnchau and others added 3 commits November 2, 2026 20:43
a planned nip-fi renewal ends every sent verified-profile sync with
disconnected: while the connection stays reported up. each batch then
cleared its checked status and republished the whole profile directory,
and its re-sent batch republished again at eose. a batch ended that way
is now re-sent at once with its checked status kept, as a rebuilt batch
already is, and an eose that confirms what is shown does not notify.

Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kalvin Chau <kalvin@block.xyz>
a relay closed reason starting with disconnected: reached the verified
profile directory as local socket retirement, which resent the batch at
once and kept its checked status. the live transport now maps such a
relay reason to error: relay closed the sync, so only a lost socket
reports disconnected: and a relay refusal takes the failure path.

Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kalvin Chau <kalvin@block.xyz>
a renewal that ended a re-sent batch before eose dropped a head it had
accepted but not published. the replacement replayed the same head,
accept returned false and no notification followed. the replacement now
inherits the pending change, so its eose publishes it.

Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kalvin Chau <kalvin@block.xyz>
@kalvinnchau
kalvinnchau force-pushed the peon/fi-verified-renewal branch from 9cebcbc to c7e2e09 Compare November 3, 2026 04:45

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Carl, an automated reviewer, commenting via Wes's GitHub account.

Verdict: one blocker (P2), inline. The prior P2 is fixed: the renewal restart carries !ready && dirty, and the new test covers two renewals before EOSE. The live.ts guard keeps a relay CLOSED from selecting the renewal path, and the re-send cannot loop (an empty or invalid batch throws in verifiedProfileFilter and fails once).

Exit criteria: carry pending changes through the schedule() rebuild too, plus a probe for it. I missed this path in the first round; it has been there since the first head.

Reviewed with Mordecai. The probe fails at this head and passes with the sketched fix; verified-profile.test.ts stays green. CI required is green.

schedule rebuilt an open batch with a fresh pending flag, so a head the
old batch accepted before eose stayed unpublished when the rebuilt
batch replayed it unchanged and flipped no checked status. batches now
expose their pending state and both the rebuild and the renewal restart
pass it on.

Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Kalvin Chau <kalvin@block.xyz>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Carl, an automated reviewer, commenting via Wes's GitHub account.

Verdict: no blockers. The rebuild P2 is fixed in 2a7c0a8: Batch.pending() feeds both the schedule() rebuild and the renewal restart, and the only other start() call creates a batch with no predecessor. The new test matches the probe.

Validation: verified-profile.test.ts and live.test.ts pass locally at this head (201 tests). Hosted CI is green, including CI required.

@kalvinnchau
kalvinnchau merged commit 0102c68 into main Nov 3, 2026
41 checks passed
@kalvinnchau
kalvinnchau deleted the peon/fi-verified-renewal branch November 3, 2026 15:56
dr0uleau added a commit that referenced this pull request Nov 3, 2026
…xecution-support-for-native-buzz-33ea2bea

* origin/main: (74 commits)
  feat(host): harden byte lifecycle and add protected image upload (#2199)
  Updated onboarding (#2183)
  perf(relay): read each signed roster once in large channels (#2244)
  AIDA-2346: Keep spoilers hidden in reminder previews (#2261)
  fix: AIDA-2371 Keep sidebar selection pill aligned during resize (#2182)
  fix(relay): skip background rereads of profiles a read found absent (#2147)
  fix: prevent startup logo selection (#1823)
  fix(agents): send sign-in evidence with agent Git credentials (#2240)
  perf(mentions): stop scanning every member on each mention keystroke (#2246)
  fix(attachments): send image dimensions so previews don't shift (#2262)
  feat(shortcuts): add Slack-style hotkeys (#2170)
  perf(plugins): share host request clients across calls (#2243)
  fix(identity): keep federated sessions and agent grants in one keychain item (#2225)
  fix(profiles): evict the least recently requested profile (#2255)
  fix(unread): repair unread from the recovery tick only every 15 minutes (#2252)
  AIDA-2374: Use readable labels in chat titles (#2185)
  perf(profiles): keep verified names checked through a planned renewal (#2234)
  feat(plugins): let a plugin ask Buzz to review an install (#2059)
  fix(identity): sign FI builds in at first run through the native session (FOUNDATION: App.tsx, services.ts) (#2249)
  Place profile verification beside the verified name (#2224)
  ...

Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
dr0uleau added a commit that referenced this pull request Nov 3, 2026
* commit 'c8e882165': (50 commits)
  Scope execution targets by harness session
  Read durable execution state before admission
  feat(host): harden byte lifecycle and add protected image upload (#2199)
  Updated onboarding (#2183)
  perf(relay): read each signed roster once in large channels (#2244)
  AIDA-2346: Keep spoilers hidden in reminder previews (#2261)
  fix: AIDA-2371 Keep sidebar selection pill aligned during resize (#2182)
  fix(relay): skip background rereads of profiles a read found absent (#2147)
  fix: prevent startup logo selection (#1823)
  fix(agents): send sign-in evidence with agent Git credentials (#2240)
  perf(mentions): stop scanning every member on each mention keystroke (#2246)
  fix(attachments): send image dimensions so previews don't shift (#2262)
  feat(shortcuts): add Slack-style hotkeys (#2170)
  perf(plugins): share host request clients across calls (#2243)
  fix(identity): keep federated sessions and agent grants in one keychain item (#2225)
  fix(profiles): evict the least recently requested profile (#2255)
  fix(unread): repair unread from the recovery tick only every 15 minutes (#2252)
  AIDA-2374: Use readable labels in chat titles (#2185)
  perf(profiles): keep verified names checked through a planned renewal (#2234)
  feat(plugins): let a plugin ask Buzz to review an install (#2059)
  ...

Signed-off-by: Daniel Rouleau <drouleau@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
arividar pushed a commit to minniai/minni-buzz-app that referenced this pull request Nov 4, 2026
…block#2234)

## Problem

A native NIP-FI socket renews its assertion every ~285 s: the lifetime
is capped at 300 s, minus a 15 s margin. `live.ts` reconnects quietly
and the connection stays reported `connected`, but `clearSocket()` ends
every sent sync with `disconnected: live connection lost`. Each
verified-profile (kind 30382) batch treated that as a failure:

- it cleared `checked` for its subjects;
- it republished the whole profile directory, and every name flipped
from checked to cached;
- the next `ensure` re-sent the batch, and its replay republished the
directory again at EOSE, even though nothing had changed.

With 1,024 verified subjects that is 8 batches. Each renewal therefore
caused 16 full republishes and 2,048 changed entries, and every checked
name dropped to cached for a moment.

## Change

- A batch that ends with `disconnected:` is re-sent at once with its
checked status kept, as a rebuilt batch already is. The decision waits
one microtask. An outage reports the connection down in the same task,
which stops every batch first, so an outage still clears status and
sends nothing extra.
- EOSE notifies only when it changed a head, a checked status or a
retraction. A replay that confirms what is shown is quiet.

## Evidence

Blox matrix: the real `createRelaySession` with the profile and verified
directories over a scripted live transport, 1,024 verified subjects.
Each renewal ends every sync as `clearSocket()` does, while states stay
`connected`. Base and variant runs were interleaved, 5 runs on each of 2
Linux and 2 macOS workstations. Values are medians of 10 per OS.

| Metric (5 renewals, ≈24 min of uptime) | Linux before | Linux after |
Linux Δ | macOS before | macOS after | macOS Δ |
|---|---|---|---|---|---|---|
| CPU (ms) | 327.5 | 22 | −93% | 194 | 27 | −86% |
| Profile notifications | 80 | 0 | −100% | 80 | 0 | −100% |
| Entries changed | 10,240 | 0 | −100% | 10,240 | 0 | −100% |
| Names checked after | 1,024 | 1,024 | 0 | 1,024 | 1,024 | 0 |
| Verified REQs / events | 40 / 5,120 | 40 / 5,120 | 0 | 40 / 5,120 | 40
/ 5,120 | 0 |

What you gain: every listener stops refolding on every renewal, about
12.6 times an hour on a NIP-FI relay, and verified names no longer
flicker from checked to cached. Wire traffic is unchanged.

The Blox runs predate the one-microtask deferral. Locally, the same
harness gives an identical renewal result (0 notifications, 1,024
checked). An outage scenario keeps `main`'s 40 REQs and clears status as
before.

- `verified-profile.test.ts`, new: "re-sends a batch a replaced socket
ended and keeps its check quiet while connected" fails on `main`. "does
not re-send a batch an outage ended" pins the outage path.
- `vitest run` on `src/features/relay`, `src/features/profiles` and
`src/features/messages`: 220 files and 5,002 tests pass, 4 skipped. `tsc
--noEmit` and biome are clean.

## Related

block#2216 makes verified publishes one per macrotask. That reduces how many
republishes a renewal causes, but each ended batch still drops its names
to cached until the re-sent batch answers. This PR keeps them checked
and keeps a confirming replay quiet, so the two compose. Same Blox
harness, stacked on block#2216, interleaved, 4 runs on each of 4 Linux and 4
macOS workstations. Values are medians of 16 per OS.

| 5 renewals @1,024 verified | Linux block#2216 | Linux block#2216 + this | Linux
Δ | macOS block#2216 | macOS block#2216 + this | macOS Δ |
|---|---|---|---|---|---|---|
| CPU (ms) | 74.5 | 21 | −72% | 64 | 27.5 | −57% |
| Profile notifications | 10 | 0 | −100% | 10 | 0 | −100% |
| Checked↔cached flips | 10,240 | 0 | −100% | 10,240 | 0 | −100% |
| Verified REQs | 40 | 40 | 0 | 40 | 40 | 0 |

Outage (5 disconnect/reconnect cycles) on block#2216 with and without this
change: 10 notifications and 40 REQs in both, CPU 78 vs 78 ms on Linux
and 132.5 vs 131.5 ms on macOS. The outage path is unchanged.

## Tradeoff

- The directory infers a renewal from the documented `disconnected:`
reason and from the connection still being up after the current task. It
does not get an explicit signal from `live.ts`, which keeps the change
to one file.
- During an outage, batches now end through `connected(false)` alone.
That is one profile notification per outage instead of one per batch
plus one. The end state is unchanged.
- A relay CLOSED whose reason starts with `disconnected:` is now
reported as `error: relay closed the sync`, so only local socket loss
takes the renewal path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Kalvin Chau <kalvin@block.xyz>
Co-authored-by: peon <9ac6794b000690b7e814eb1805ad32405d0bec7d52838de3a86cf967565dacc0@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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