Skip to content

feat(mobile): bring Activity feed and filters to mobile - #9186

Closed
klopez4212 wants to merge 4 commits into
mainfrom
kennylopez-mobile-activity-20261105
Closed

klopez4212 wants to merge 4 commits into
mainfrom
kennylopez-mobile-activity-20261105

Conversation

@klopez4212

@klopez4212 klopez4212 commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Replace mobile Inbox with Activity: All / Threads / Mentions / DMs / Reactions / Reminders / Drafts, Anyone / People / Agents, and an independent Unread toggle. Include participating/followed replies, Solo updates, grouped reactions, and independent DM history; reading a thread no longer reads unrelated channel activity.

Use native iOS glass controls and equal-height rounded Android filter pills with content-sized widths and consistent horizontal padding. Activity and Search keep fixed headers with a 16-point content fade at the top of their clipped lists. Shared navigation backdrops are unchanged. The bulk-read action and ellipsis are removed to match desktop.

Related issue

Related to #7779. Home layout, All / Solo / Team sizing, and the top-row bell are owned by #9193. This PR only renames the existing Inbox entry to Activity, including its accessibility label.

P1 review fixes

All includes approvals and agent lifecycle events. Cold conversation history uses aggregate channel batches, pages past saturated conversations to reach quieter channels, and cursor-pages participation evidence. Reminders and saved drafts remain reachable from the type menu. Activity reads shared conversation metadata and owns its message projection, including forum posts/replies and reactions without recipient tags.

Testing

  • P1 fixes at 6bbf00057: full Flutter suite passed (4,526 tests; 60 skipped), plus 4 unconfigured-push and 27 crypto tests. Analysis, formatting and file-size checks passed.
  • Regressions fail against the old implementation for All visibility, channel batching, forum replies, and e-only reactions. Independent agent review completed. These review fixes have not been installed on physical devices.
  • Native iOS control journeys pass in Flutter; release builds compile and install on device.
  • Earlier visual revision: Activity-only PR build installed in place on Pixel 10 and iPhone Air; saved profiles and communities preserved. Pixel controls verified; live feed verification is blocked by the saved community hostname failing DNS.

Snapshots

Actual screen widgets with synthetic data, Flutter fallback rendering (not native iOS glass):

Before After
Inbox before Activity after

@klopez4212
klopez4212 marked this pull request as ready for review November 6, 2026 16:06
@klopez4212
klopez4212 requested a review from a team as a code owner November 6, 2026 16:06
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T18:42:27.604170Z 6bbf000 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 065c133de0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

child: IosMessageCreateButton(
key: ValueKey(controlKey),
label: label,
labelFontSize: textScaler.scale(16),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply Dynamic Type only once to iOS filter labels

On iOS with a non-default accessibility text size, textScaler.scale(16) already contains the user's Dynamic Type scaling, but JumpToLatestGlassButton.swift subsequently feeds this value into UIFontMetrics.scaledValue, applying the same scaling again. At large text sizes the native label becomes much larger than the once-scaled width and height calculated here and is clipped; pass the unscaled base size (as other callers do) or stop scaling the supplied value natively.

AGENTS.md reference: AGENTS.md:L273-L281

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf53a84a06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

_ActivityMenuButton<InboxFilter>(
controlKey: 'activity-type-menu',
popoverKey: 'activity-type-popover',
semanticLabel: 'Activity type',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Announce the selected Activity type

On iOS with VoiceOver, this constant accessibility label overrides the native button's visible title, so after selecting Threads, Mentions, DMs, or Reactions the control is still announced only as “Activity type” and the current filter cannot be determined without reopening the menu. Include the selected label in the semantic label, as the sender control already does.

AGENTS.md reference: AGENTS.md:L273-L281

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 582516275a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90935278da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +159 to +162
(e) =>
(filter.value != InboxFilter.mention ||
e.category == 'mention') &&
(e.reactionTarget == null || includesSender(e.pubkey)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter grouped events before selecting their sender

When a DM or thread contains messages from both people and agents, this predicate applies the sender filter before grouping only to reactions; the later check therefore classifies the whole conversation by its latest representative. For example, selecting People hides a human reply when a newer agent reply exists in the same group, while selecting Agents includes the human messages in that group. Apply includesSender to every event before buildInboxItems so each sender view is built from matching activity.

Useful? React with 👍 / 👎.

Keep Activity feed, filter controls, and Activity/Search content fade separate from Home layout and bell work in #9193.

Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Signed-off-by: kenny lopez <[email protected]>
Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Signed-off-by: kenny lopez <[email protected]>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 700eca756a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Signed-off-by: kenny lopez <[email protected]>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a30196c9d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

continue;
}
final thread = event.threadReference;
final mentioned = !channel.isDm && tagsAddress(message.tags, viewer);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep original mention tags when applying edits

When another user edits a top-level message that mentioned the viewer, mobile's edit event carries only h, target e, and media tags, while activityMessages substitutes those edit tags into message. Testing relevance against message.tags therefore turns mentioned false and removes the mention from Activity even though only its content was edited; use the original event tags for addressing and thread relevance while projecting the edited content.

Useful? React with 👍 / 👎.

Comment on lines +207 to +210
for (final event in item.groupItems) {
if (!isThreadReply(event.tags)) {
notifier.markContextRead(msgContextKey(event.id), event.createdAt);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Advance the Solo activity marker once

For a Solo channel, the new grouping collapses every top-level entry into one row, but marking that row read performs one markContextRead(msg:...) call per grouped event. ReadStateManager persists on every call and deliberately treats msg: contexts as local-only, so a row containing up to the 500-event history cap causes hundreds of durable writes and does not synchronize the read action to other devices; advance activityContextKey(channelId) once to latestActivityAt, which inboxEventReadAt already uses for these channelCatchUp events.

AGENTS.md reference: AGENTS.md:L259-L264

Useful? React with 👍 / 👎.

Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Signed-off-by: kenny lopez <[email protected]>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6bbf000575

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

await completeActivityColdWindow(
query,
filter,
received.where((e) => _matches(filter, e)).toList(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve derived-channel reactions while paging

When a cold or reconnect query returns a full page containing mobile-created reactions, this raw-tag recheck rejects those reactions because they carry only an e tag, even though the relay deliberately matches #h via the stored derived channel_id (crates/buzz-core/src/filter.rs:164-178). This can make the delta page appear shorter than its limit and stop pagination early, while later cold pages discard the reactions entirely, so older activity or reactions disappear after a busy offline interval. Page these filters without requiring a literal h tag, or resolve the derived channel from the reaction target. Fresh evidence beyond the earlier review is that the new regression fixture adds an h tag to every event at activity_history_test.dart:20-23, so its purported e-only reaction does not exercise the production representation.

AGENTS.md reference: AGENTS.md:L243-L247

Useful? React with 👍 / 👎.

_liveRefreshTimer ??= Timer(const Duration(milliseconds: 250), () {
_liveRefreshTimer = null;
unawaited(_queueRefresh(generation));
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Background refreshes exhaust the shared HTTP quota

With one joined stream and a warm cache, each unrelated incoming message schedules a refresh that issues three separate POST /query requests: addressed history, the channel delta, and update enrichment for the new message. Two messages per second, with reads completing before the next message, consume the default 300-call per-pubkey quota in about 50 seconds. The 250 ms timer bounds refresh operations without accounting for those nested requests.

User/system effect: Activity consumes the shared quota while its page is closed, delaying Activity and other relay reads.

if (!remaining.contains(channel)) continue;
if (reads > 0) result.add(event);
counts[channel!] = (counts[channel] ?? 0) + 1;
if (counts[channel]! >= 100) remaining.remove(channel);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Cold paging can stop before any displayable DM

The cross-channel paging fix still retires each channel after 100 raw events. If a DM’s newest 500 events are reactions to a deleted message, that first page retires the DM even though projection produces no visible rows. Older untagged DM messages remain behind the cursor, and Activity offers no older-history action; refreshing reads the same prefix. The previous message-only DM query was not displaced by those reactions.

User/system effect: An existing DM can appear absent from Activity despite older readable messages.

if (sessionState.status == SessionStatus.connected &&
generation == _subscriptionGeneration) {
unawaited(_subscribeLive(generation));
unawaited(_subscribeLive(generation, since));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Successful Retry does not restore live subscriptions

If the initial HTTP query and WebSocket fallback fail, build() exits before _subscribeLive. A successful Retry only fetches and publishes a snapshot through the refresh queue. With no dependency rebuild, the skipped subscriptions remain uninstalled.

User/system effect: Activity looks recovered but receives no subsequent live updates, including hidden-DM resurfacing.

if (count == 20) {
throw StateError(
'Activity catch-up exceeds its budget. Refresh Activity.',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · An oversized delta leaves automatic recovery stuck

A retained session with 10,500 matching events in one channel batch fills the initial page and all 20 continuation pages. This exception leaves the saved cursor unchanged, so subsequent live refreshes and reconnects repeat the same oversized delta and fail again. The refresh queue retains the old feed without exposing that error.

User/system effect: Activity silently remains stale until the user manually resets history through refresh.

}
}
}
_trimEvidence(events);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Trimming discards the participation proof just fetched

With 4,096 newer evidence events, this trim can evict an older viewer-authored reply returned by participation discovery. ownThreads and ownParents are computed afterward, while the corresponding interest can still be marked cached. Later deltas then skip rediscovering the discarded proof.

User/system effect: Unmentioned replies to a thread the viewer participated in disappear from Activity.

// rows so deleted/edited or no-longer-admitted messages cannot survive.
byId.removeWhere((_, item) => activityMessageKinds.contains(item.kind));
for (final item in conversationItems) {
byId[item.id] = item;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Offline hidden-DM history loses its recovery row

An addressed message in a hidden DM can be returned by the initial history query and then removed here. The replacement conversation projection uses a roster that excludes hidden DMs. If the message arrived offline more than five seconds before startup, the hidden-DM live replay also misses it.

User/system effect: The Activity row that previously opened and recovered that hidden conversation is unavailable.

final pk = pubkey.toLowerCase();
final isAgent = agents.contains(pk) || profiles[pk]?.ownerPubkey != null;
return sender.value == 'Anyone' ||
(sender.value == 'Agents' ? isAgent : !isAgent);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · The sender filter omits channel bot roles

A sender identified as an agent only by its channel bot role is classified as a person here. The row uses the channel-aware agent identity provider, which includes those roles, but this predicate uses only the global directory and cached profile owner.

User/system effect: The same sender renders as an agent under People and disappears under Agents.

return target != null &&
(update.channelId == null ||
update.channelId == target.channelId) &&
(update.kind == 9005 || update.pubkey == target.pubkey);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · Owner-authorized updates leave stale agent content

The relay and mobile message actions permit a human owner to edit or delete their agent’s message. This signer-equality check rejects that accepted update because the human and agent have different keys. The original cached event consequently survives the update.

User/system effect: Activity retains deleted agent content or the old text after an authorized edit, while the conversation applies the update.

for (final target in entry.value) '${entry.key}:$target',
};
if (retained.interests.length > 4096) retained.interests.clear();
if (!overflow) retained.since = startedAt - 5;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · The delta cursor misses accepted timestamp skew

This advances the cursor to the reader’s wall clock minus five seconds, but the relay accepts event timestamps up to 900 seconds from its clock. A valid deletion from a sender one minute behind falls before the next delta. Unrestricted overlay reads only cover newly encountered targets, and live notifications trigger those same cursor-bounded queries.

User/system effect: Cached deleted content can remain visible, and valid edits or unaddressed messages can be omitted until a manual cold refresh.

if (result.length > 4096) {
throw StateError(
'Activity updates exceed the evidence budget. Refresh Activity.',
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤖 P2 · One large edit history disables unrelated Activity

Auxiliary history is collected across retained messages before relevance filtering. More than 4,096 valid edits to a retained message, or across its target batch, triggers this exception and aborts the entire feed assembly. Retry and manual cold refresh encounter the same persisted history.

User/system effect: An unrelated message’s edit history can make DMs, approvals and all other Activity sources unavailable without a working refresh recovery.

brow added a commit that referenced this pull request Nov 6, 2026
The UI-only part of #9186 by @klopez4212, split out so it can land
without the Activity sync changes.

- The Inbox page becomes Activity, with header controls instead of
menus: a type menu (All, Threads, Mentions, DMs, Reminders, Drafts), a
sender menu (Anyone, People, Agents) and an Unread toggle. All of them
filter the feed the app already loads.
- Activity and Search get a top edge fade. Bulk mark-as-read and the
"New" divider are gone.
- DM thread replies group with their DM row, so the DMs filter includes
them.

Left out, for a separate sync PR: the Activity history cache,
subscriptions to every joined channel, the refresh coalescer,
thread-follow evidence, Reactions and Solo rows, and the read-state
changes. The Activity provider and read-state writes are unchanged from
main.

One fix on top: the iOS filter labels pass an unscaled font size, since
the native button already applies Dynamic Type. Before, large text was
scaled twice.

### Validation

- Kenny's added tests for the header controls (`tabs_journey`) and
`TopEdgeFade`, adjusted for the removed Reactions option. Added tests
for the DM filter, marking a DM row with replies under two thread roots
read, and sender filtering per event.
- Full mobile suite: see the latest CI run. Locally, 11 push and
notification-toggle tests fail identically on an unchanged checkout.
- Automated simulator run (iPhone 17 Pro, iOS 27) of a build combining
this PR with its sibling split: Home rows measure 44 pt, the bell opens
Activity and shows its dot after a row is marked unread,
type/sender/Unread filters each narrow the feed, a row opens its
conversation, Search results scroll under the fade, and filter labels
fit at the largest text size. Screenshots are in Buzz rather than here
because they show internal test data. Android was covered only by widget
tests.

### Before merge

- [x] Automated simulator run of Activity filters, row taps, read and
unread, and Search, with screenshots.

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

---------

Signed-off-by: Tom Brow <[email protected]>
Co-authored-by: Tom Brow <[email protected]>
Co-authored-by: kenny lopez <[email protected]>
Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5.5 <[email protected]>
@klopez4212 klopez4212 closed this Nov 6, 2026
klopez4212 added a commit that referenced this pull request Nov 9, 2026
## Summary

A reply in a thread you started, participated in, or followed can light
a mobile channel's attention dot without appearing in Activity. Activity
now includes eligible replies already observed by the channel unread
pipeline in **All** and **Threads**. Tapping a row uses the existing
oldest-unread reply and thread navigation.

Retain the reply payload alongside its bounded unread evidence, then
merge by event ID with the addressed feed. Mentions retain their
category and do not duplicate. Deletion, eviction, and account/community
resets share the same registry. This adds no relay queries or
subscriptions.

Coverage follows the existing channel unread catch-up and live
subscriptions. This does not introduce complete historical thread
discovery: replies outside that retained window, and replies not
eligible for the channel attention dot, are not newly fetched.

### Related issue

Related to #9271 (clearing channel rows) and closed #9186 (broader
Activity feed expansion). #9213 supplied the existing Activity filters.
This PR connects existing observed replies to those filters.

### Testing

- Full mobile suite, push-unconfigured tests, analysis, formatting and
file-size checks.
- Production-provider regression: cold catch-up, live reply, mention
deduplication, excluded unrelated/quiet replies, thread read markers,
deletion/replay and identity reset.
- Real Activity widget journey with fake relay/storage boundaries: show
the unmentioned reply, select Threads, tap the row, and verify the reply
ID and thread ID passed to the conversation page.
- Mutation check: removing reply-payload retention makes the widget
journey fail because the reply is absent.
- Independent agent source review: no blockers.

### Preview

Actual Flutter widgets at phone width with synthetic data and the new
reply wiring disabled/enabled. These are widget-test captures, not
installed-device or live-relay evidence.

| Before | After |
| --- | --- |
| ![Activity omits the unmentioned
reply](https://github.com/user-attachments/assets/a6fc8193-b1ef-4022-a5f1-a1cbbcdf5fb2)
| ![Activity shows the unmentioned thread
reply](https://github.com/user-attachments/assets/b2a6ba13-384a-4d0f-bda3-88d83307d31e)
|

### Human validation pending

Draft per the repository readiness checklist. On a device, receive an
unmentioned reply in a thread you started, replied in, or followed.
Check Activity → All and Threads, tap the row to reach the reply, then
read it and confirm Unread clears without reading unrelated channel
messages. Native/live-relay testing and human confirmation remain
pending.

---------

Signed-off-by: kenny lopez <[email protected]>
Signed-off-by: Tom Brow <[email protected]>
Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <[email protected]>
Co-authored-by: Tom Brow <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>

This branch was successfully deployed

No deployments
codex-review — 6bbf0005 Deployed Nov 6, 2026 by klopez4212 via Run Codex Security Review #13564
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