Skip to content

feat(mobile): add channel and solo access controls - #8963

Open
tellaho wants to merge 14 commits into
mainfrom
tho/mobile-solo-visibility
Open

tellaho wants to merge 14 commits into
mainfrom
tho/mobile-solo-visibility

Conversation

@tellaho

@tellaho tellaho commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Category: improvement
User Impact: Mobile users can manage channel and Solo access, share Solo chats and keep viewing-only participation read-only.

Problem: Mobile lacks the channel access controls available on desktop, and making a Solo chat community-readable causes it to lose its Solo treatment. Membership also currently enables contribution controls for viewers.

Solution: Add mobile-native access and member controls with explicit confirmation and signed authorization, preserve Solo identity at every visibility, and separate reading from contribution throughout conversations. Recover uncertain access writes through readback, release superseded attempts, and offer an explicit discard/reload when an outcome cannot be confirmed. Retain interrupted sharing/conversion intent, with confirmed exits and retries that preserve later access changes.

Changes

  • General access: Public / View only / Private for channels; View only / Private for Solo, with truthful existing Public state.
  • One General access heading, saved-choice checkmarks, concise option descriptions and history/Canvas disclosure. Read-only viewers see the same full choice rows checked and disabled.
  • Readback-only save recovery with a confirmed Discard and reload exit; a superseding access revision releases the previous attempt.
  • Correct inspector guidance for contributors, Guests and joinable nonmembers. Known-role sends use cached contribution state, with relay rejection authoritative; unknown roles still require a fresh check.
  • Confirmed individual roles, participating agent admission and Guest/nonmember read-only presentation.
  • Solo sharing opens Private chats as View only after community-reading confirmation, then posts a link without enrolling anyone or changing individual roles. Already-open policies remain unchanged. Confirmed cancellation and rejection/uncertain retries preserve recovery.
  • Conversion with current access preselected, independent filing cleanup after metadata lands, and confirmed discard. Sharing discloses community reading of history, Canvas, workspace folders and agent instructions; conversion discloses the chosen reading/posting access.
  • Member rows match desktop: Owner, Admin and Viewing only are shown; ordinary Member/Bot participation stays implicit in the preview and full list.
  • Agents retain Bot participation after a viewing-only round trip; contribution presentation retains the newest roster across reconnects. Viewer reactions have no tap action or celebration.
File changes

mobile/lib/features/channels/add_members_sheet.dart
Review human access separately from agent participation, retaining main’s mention-based recipient search and ordering on iOS and Flutter.

mobile/lib/features/channels/channel.dart
Keep Solo classification independent of visibility and carry admission defaults and individual contribution roles through the cache.

mobile/lib/features/channels/channel_access_provider.dart
Own fresh signed authority checks, confirmed access and role changes, and readback-only recovery after uncertain writes.

mobile/lib/features/channels/channel_access_sheet.dart
Offer supported access choices with confirmations and a saved-choice checkmark. Reuse the same rows for read-only viewers with disabled controls and selected/disabled accessibility state, replacing the small current-access summary. Preserve role-specific guidance and existing Public Solo access.

mobile/lib/features/channels/channel_actions_sheet.dart
Connect channel details to the access, sharing, conversion and member-management surfaces.

mobile/lib/features/channels/channel_contribution_provider.dart
Derive contribution from the freshest scope-local roster through disconnect and loading; use the channel-list fallback only before a roster is known.

mobile/lib/features/channels/channel_detail_page.dart
Gate conversation composition and related actions by contribution permission.

mobile/lib/features/channels/channel_detail_page/banners.dart
Explain read-only access without inviting viewers to join a Guest-default channel.

mobile/lib/features/channels/channel_detail_page/huddle_sheet.dart
Require contribution permission for huddle participation.

mobile/lib/features/channels/channel_detail_page/message_bubble.dart
Apply contribution permission to replies, reactions and ordinary message actions while preserving verified owned-agent exceptions.

mobile/lib/features/channels/channel_detail_page/message_list.dart
Carry contribution permission through message presentation and navigation.

mobile/lib/features/channels/channel_detail_page/message_list_thread_footer.dart
Keep the permission-aware reply footer in a sibling part so the message list stays under the mobile file-size ceiling without changing its widget or behavior.

mobile/lib/features/channels/channel_detail_page/system_rows.dart
Keep system-message reactions and nested thread navigation consistent with channel access.

mobile/lib/features/channels/channel_details_page.dart
Add general access, explicit invitation roles, Solo sharing and conversion to the existing details page. Keep ordinary participation implicit in member previews and show only Owner/Admin/Viewing only captions.

mobile/lib/features/channels/channel_management_actions.dart
Route membership, Canvas and reaction writes through fresh authorization checks.

mobile/lib/features/channels/channel_management_provider.dart
Carry admission defaults into details and distinguish offline placeholders from the latest confirmed roster.

mobile/lib/features/channels/channel_member_profile_actions.dart
Confirm individual access changes, preserve Bot participation and hide Admin for agents while retaining permitted removal.

mobile/lib/features/channels/channels_provider.dart
Retain admission defaults and viewer roles when folding channel snapshots and invalidating details.

mobile/lib/features/channels/manage_channel_sheet.dart
Keep Canvas readable while restricting editing to contributors.

mobile/lib/features/channels/me/me_chat_assistant.dart
Admit selected Solo assistants explicitly as Bot.

mobile/lib/features/channels/me/new_me_chat.dart
Use explicit Bot admission through main’s unified New chat flow.

mobile/lib/features/channels/member_access_controls.dart
Share confirmed individual access and recovery controls, plus the nullable member-row caption rule. Preserve agent identity and native iOS destructive removal confirmation.

mobile/lib/features/channels/members_sheet.dart
Use the shared member-row caption rule and confirmed controls while retaining agent activity, status and permitted removal actions.

mobile/lib/features/channels/message_actions.dart
Hide contribution-only actions for viewers and pass permission into thread navigation.

mobile/lib/features/channels/message_swipe_reply.dart
Preserve contribution permission when navigating by swipe.

mobile/lib/features/channels/reaction_row.dart
Keep reaction details readable while disabling reaction changes for viewers.

mobile/lib/features/channels/send_message_provider.dart
Send immediately for known contributors, relying on relay authorization; require a fresh signed check when the role is unknown.

mobile/lib/features/channels/solo_conversion_sheet.dart
Preselect access, disclose posting permissions and offer independent cleanup or confirmed discard with a disabled-action reason.

mobile/lib/features/channels/solo_share_sheet.dart
Confirm community reading, open Private Solo chats as View only and post a link without enrollment. Recheck signed source/destination permissions and stale consent; preserve open policy, cancellation and retry recovery.

mobile/lib/features/channels/thread_detail_page.dart
Gate thread composition by current contribution permission and preserve cached denial during navigation.

mobile/lib/features/channels/thread_detail_page/message_list.dart
Carry contribution permission through message presentation and navigation.

mobile/lib/features/channels/thread_detail_page/nested_thread_summary_row.dart
Carry contribution permission into nested-thread destinations.

mobile/lib/features/channels/thread_detail_page/thread_message.dart
Apply the same reply, reaction and message-management rules inside threads.

mobile/lib/features/forum/forum_posts_view.dart
Allow viewers to browse posts while limiting new post composition to contributors.

mobile/lib/features/forum/forum_provider.dart
Validate contribution and active-community ownership immediately before publishing forum content.

mobile/lib/features/forum/forum_thread_page.dart
Keep forum replies and editing consistent with contribution permission.

mobile/lib/features/search/search_page/message_tile.dart
Retain cached contribution permission when opening a forum result from search.

mobile/lib/shared/me/me_chat_conversion.dart
Journal conversion and discard only the reviewed local intent without rolling back metadata that already landed.

mobile/lib/shared/me/me_chat_share.dart
Persist intent before opening reading and retain the exact signed link for uncertain retries. Ignore legacy recipient lists, replace the signature only after definitive rejection and allow exact-record cancellation. Enrollment and its recipient limit are removed.

mobile/lib/shared/relay/nostr_models.dart
Parse admission defaults independently of existing member roles, including legacy and malformed metadata.

mobile/lib/shared/relay/relay_author_provider.dart
Bound NIP-11 signer discovery and expose its HTTP boundary for real transport tests. Consume the response through normal EOF without awaiting cancellation of an already-ended stream; cancel unfinished responses with a deadline. This lets signed access reads complete while preserving response-size and timeout bounds.

mobile/lib/shared/relay/relay_session.dart
Distinguish an explicit relay rejection from an uncertain publication response.

mobile/lib/shared/relay/relay_session_types.dart
Represent definitive relay rejection without conflating it with transport uncertainty.

mobile/test/features/channels/channel_access_test.dart
Exercise production access, selection, confirmation, signature rejection, lost-response recovery, sharing and conversion journeys. Verify disabled read-only choices, one saved-choice checkmark, disabled selected semantics and no confirmation or publication on tap, including Private members and Solo Guests at enlarged text.

mobile/test/features/channels/channel_detail_page_test.dart
Cover open Solo placement and sending, read-only visitors and Guests, and preserve the existing conversation assertions.

mobile/test/features/channels/channel_detail_page_test/member_rows_tests.dart
Exercise default-role caption omission and Owner/Admin/Guest captions through channel details, retaining typography, avatar geometry and real profile taps. Keep the cohesive journey in a sibling part so the oversized parent shrinks.

mobile/test/features/channels/channel_management_provider_test.dart
Extend classification coverage across Solo visibility and carry admission policy into details.

mobile/test/features/channels/channel_member_profile_actions_test.dart
Exercise confirmed member-access changes with signed relay fixtures.

mobile/test/features/channels/channel_messages_journey_test.dart
Provide signed access state while preserving the existing message-delivery journey.

mobile/test/features/channels/channel_send_journey_test.dart
Provide signed access state while preserving send and retry behavior.

mobile/test/features/channels/channel_test.dart
Cover Guest-default join and contribution behavior independently of membership.

mobile/test/features/channels/channels_page_test.dart
Verify open Solo chats stay out of the ordinary-channel list.

mobile/test/features/channels/compose_bar_test.dart
Exercise agent invitation and sending through signed access checks while preserving composer behavior.

mobile/test/features/channels/ios_add_members_sheet_test.dart
Keep native picker identity, selection and retry checks, and assert explicit Guest/Bot invitation roles through the shared recipient search.

mobile/test/features/channels/me/me_page_test.dart
Cover private and open Solo filing while retaining current Bestie setup.

mobile/test/features/channels/me/solo_creation_tags_test.dart
Keep new and interrupted Solo creation bound to real actions with signed access and current media fixtures.

mobile/test/features/channels/members_sheet_test.dart
Exercise confirmed role changes and preserve member and agent presentation.

mobile/test/features/forum/forum_widgets_test.dart
Cover read-only forum composition and reply behavior.

mobile/test/helpers/fake_relay.dart
Keep session overrides deterministic and enforce the relay’s ±15 minute timestamp window, preserving acceptance of stored duplicates.

mobile/test/shared/relay/relay_author_test.dart
Exercise the real NIP-11 stream boundary, signer selection, completion and response bounds.

mobile/lib/features/channels/access_error_message.dart
Translate timeouts and runtime-prefixed failures into readable access messages.

mobile/test/features/channels/channel_detail_page_test/loading_review_tests.dart
Exercise the system-row reaction gate for a Guest through the conversation page.

mobile/test/features/channels/channel_detail_page_test/solo_send_tests.dart
Keep Solo sending and route-ownership scenarios together, with explicit participating viewer rosters.

mobile/test/features/channels/reaction_row_test.dart
Assert disabled viewer taps, accessibility actions and celebratory effects.

mobile/test/features/channels/solo_access_recovery_cases.dart
Exercise sharing to a destination with over 100 people without enrollment, Private opening, unchanged open policy/roles, lost access/link responses, stale consent and source/destination demotions. Cover conversion confirmations, durable intent exits, agent roles, offline roster state and native removal through production widgets.

mobile/test/shared/me/me_chat_share_recovery_test.dart
Drive the real session against timestamp enforcement, stale rejection/re-signing, legacy audience removal, uncertain message reuse and cancellation before posting.

Reproduction steps

  1. Open a Solo chat you own, tap its title, then General access. Only View only and Private are offered, with a checkmark beside the saved choice.
  2. Choose View only, cancel, and verify the checkmark stays on Private. Confirm the change, reopen and verify View only is selected and the chat remains in Me.
  3. Open the link as another community identity. History and Canvas are readable; contribution controls are unavailable. Existing members retain their individual access when general access changes.
  4. As an ordinary member, Guest or nonmember, open General access: the full choices should remain visible with the saved choice checked and every choice disabled. Tapping a choice must not open confirmation or publish a change. As an owner/admin in an ordinary channel, exercise all three general-access policies and change another member between Viewing only and Participating after confirmation.
  5. Share a Private Solo chat with a channel. Confirm that the disclosure explains community reading of full history, Canvas, workspace folders and agent instructions. Confirm sharing: General access becomes View only and one link is posted. No destination members are added and every existing role remains unchanged; the original stays Solo. Repeat from View only and Public: their access policies stay unchanged. A Guest cannot share; only the creator with owner/admin access can open a Private chat. Interrupt a share, reopen and exercise Retry share and confirmed Cancel share. A saved General access change and a possibly-posted link remain after cancellation. If the chat becomes Private during confirmation, sharing requires a fresh confirmation.
  6. Convert a separate Solo chat with each policy. The current policy starts selected, the chosen policy persists, and history, Canvas and existing membership remain intact. If filing cleanup fails after conversion, change access elsewhere and use Finish conversion: that newer access must remain. Test Keep conversion versus confirmed Discard conversion for a conflicting pending intent.

Validation and limits

Current head: 2a9902506cac80f71f254e171c4e6cd98a81693f, based on 506a588f889b6d010705a564e91fdfa1660c06e7. All required push hooks pass on this exact committed tree, including formatting, Flutter analysis, the complete mobile test recipe and repository gates (mobile lane: 153.51 seconds). All 14 outgoing commits retain verified author/co-author attribution and DCO sign-off. Member-row journeys verify hidden Member/Bot captions, visible Owner/Admin/Viewing only captions, original compact-list height, typography, avatar geometry and profile taps. Both journeys fail if default-role captions are restored. Sharing's contributor and stale-consent regression probes also fail when their production guards are removed.

Regression coverage exercises confirmed cancellation and discard, a stale signed link definitively rejected by the real relay session, exact-message reuse while an OK response is uncertain, timestamp boundaries at ±900/901 seconds and stored duplicates. Conversion cleanup completes after a later administrator changes access and labels, without replaying metadata. The access journey also covers Guest-to-Bot participation and native removal cancellation. Conversation tests assert the system-row reaction gate, disabled tap semantics, and the newest roster after both demotion and promotion across disconnects. Removing the share, conversion, roster and system-row fixes makes the corresponding regression fail.

The rebase retains main’s unified New chat flow with explicit Bot admission. The native picker matches main. The affected Solo-send test fixtures now include the participating viewer in their roster; their send, ownership and huddle assertions remain. Cohesive send scenarios moved to a sibling test part so the oversized parent shrinks.

Sharing now follows desktop's community-reading/link flow. The destination-Guest and re-sharing grant questions no longer apply because sharing grants no membership or role. Existing contributors can share open chats; opening a Private chat requires its creator with owner/admin access. No Default channel switch or viewer Join is included.

The author confirmed the sharing re-test at e67429fc71e910280c3d1cf3e971a0d09592c22b and waived fresh native screenshots following that successful re-test. The existing access screenshot below predates this sharing correction. Agent regression evidence uses production widget/controller/session paths with fake relay/storage boundaries; a separate agent-run live two-identity share/conversion walkthrough was not recorded.

The general mobile relay-query receive path still lacks universal event-signature verification. This PR verifies signed authority for access changes and unknown-role contribution checks; known-role sends rely on cached permissions and relay authorization. It does not close the broader receive-path gap. Atomic creation directly into View only remains outside the creation contract.

The sharing re-test passed at e67429fc71e910280c3d1cf3e971a0d09592c22b. The author also confirmed the member-row labels at 2a9902506cac80f71f254e171c4e6cd98a81693f. Human acceptance is complete for this head. The PR remains ready; code-owner review is still required.

buzz-review-completed

Screenshots

The existing Solo capture below is retained from the earlier access-control state. Fresh native captures were waived after the author’s successful sharing re-test.

Solo: Private selected
Solo access with one General access title and Private selected

@tellaho
tellaho force-pushed the tho/mobile-solo-visibility branch from 1211725 to d48efcd Compare November 2, 2026 22:13
@tellaho
tellaho marked this pull request as ready for review November 3, 2026 18:05
@tellaho
tellaho requested a review from a team as a code owner November 3, 2026 18:05
@github-actions github-actions Bot added the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 920b1e64bdd05c6605a2562b5b05618bc8bb264a...2a9902506cac80f71f254e171c4e6cd98a81693f.
A new review must complete for this exact range. When manual authorization
is required, a user with write access must comment exactly
@buzz-security-review 2a9902506cac80f71f254e171c4e6cd98a81693f to authorize a new review.
Any previous review applies only to its recorded range.

@tellaho
tellaho force-pushed the tho/mobile-solo-visibility branch from c25dc2f to 6010477 Compare November 4, 2026 02:02
@github-actions github-actions Bot removed the codex-security-review-current The posted Codex security review matches its recorded range. label Nov 4, 2026
@tellaho
tellaho force-pushed the tho/mobile-solo-visibility branch from 6010477 to c768cef Compare November 4, 2026 22:13
@presentyourlove

Copy link
Copy Markdown

Hi @tellaho,

I audited the merge state of your PR against the latest main branch. Your branch is fully up-to-date and fast-forwardable onto main (merge-tree returns 0 conflicts).

I have established a verified tracking mirror at:
https://github.com/presentyourlove/buzz/tree/fix/mobile-solo-visibility-8963

Everything looks clean and ready for review/landing!

@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.

Changes requested. The read/contribute split and the readback-only access recovery hold up: event shapes match relay parsing, and the lost-response tests cover landed and unlanded writes. The blockers are in the durable Solo share and conversion intents, which can wedge with no way out. Agent roles also degrade on a round trip, and a few contribution gates are stale or missing. Details are inline, one thread per finding.

Validation gaps

  • solo_share_sheet.dart and solo_conversion_sheet.dart have no widget tests. The share test drives only the journal layer.
  • fake_relay doesn't enforce the relay's ±15 min timestamp window, so the stale-signature retry can't show up in tests.
  • Reviewer probes reproduced the contribution-cache and conversion-cleanup failures locally at c768cef4c9. CI's mobile jobs are green, and the Codex Security Review job didn't complete.

Merge criteria

  1. Every pending share/conversion state has a confirmed exit, and share retries survive the timestamp window.
  2. Agent role changes keep bot.
  3. Contribution presentation keeps the freshest roster across disconnects, and the system-row reaction gate is added.
  4. Share/convert copy says recipients can post and reach the owner's agents. Whether destination Guests and re-sharers should get that access is a product decision to confirm explicitly.

Non-blocking polish is noted inline (raw error text, no-op reaction taps). Smaller items: the iOS destructive-confirmation regression in the members sheet, showDialog instead of showBuzzDialog, role-label inconsistency on the details preview ("Guest"/"Member" vs "Viewing only"/"Participating"), and the Convert button disabled with no reason.

Comment thread mobile/lib/shared/me/me_chat_share.dart Resolved
tellaho and others added 12 commits November 4, 2026 19:09
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Add general access, confirmed individual roles, Guest previews, Bot
admission, Solo audience sharing and conversion with explicit access choices.
Verify signed authority before writes, retain uncertain saves for readback,
and journal interrupted sharing and Solo filing cleanup.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Reuse the full access options in the read-only inspector, keeping the saved choice checked and every option disabled. Retain role-specific guidance and truthful existing Public Solo access.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Move the existing thread-reply footer into a sibling part to satisfy the mobile file-size ceiling after rebasing. Preserve the widget tree, visibility condition and contribution permissions.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Exercise the rebased mention-based picker with viewing-only human invitations and participating agents. Verify both initial submission and retry retain their explicit roles on the production picker path.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Translate timeout and runtime-prefixed failures consistently across access, sharing, conversion and individual-role recovery.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Keep agents participating as Bot and exclude Admin. Recognize agents after a Guest demotion; preserve native destructive removal confirmation.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Use the latest scope-local roster through disconnects and reloads. Distinguish an offline empty placeholder from a confirmed empty roster.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Gate ordinary system rows and remove viewer pill taps, tap semantics and celebratory bursts while retaining reaction inspection.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Offer confirmed cancellation of the exact pending share. Replace the persisted signed link only after a definitive rejection; retain the exact ID for uncertain outcomes. Disclose posting access, including to agents, and enforce the relay timestamp window in the network fixture.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Finish filing cleanup when the Solo label is gone without reasserting a later policy or replaying metadata. Add confirmed discard, posting disclosure and a disabled-action explanation.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Exercise share and conversion sheets, journal exits, offline permissions and native removal. Use consistent participation labels and the shared modal wrapper. Make participating send fixtures include their viewer in the authoritative roster, retaining all assertions; move the cohesive Solo-send scenarios into a sibling test part.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
@tellaho

tellaho commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Review follow-up pushed at b2401d90b302d07076e329e431dbfa8a730d5146, rebased onto 506a588f889b6d010705a564e91fdfa1660c06e7.

  • Pending shares have confirmed cancellation. A definitively rejected link gets a persisted fresh signature; uncertain outcomes reuse the exact message.
  • Conversion filing cleanup recognizes landed metadata, preserves later policy edits and offers confirmed discard.
  • Agents retain Bot participation; the newest roster survives reconnects; system-row and viewer reaction actions are gated.
  • Share/Public conversion disclose posting access, including to agents. Readable errors, native iOS removal confirmation, shared dialogs, role labels and disabled Convert guidance are included.

Validation: all required push hooks pass on this exact head, including formatting, analysis, the full Flutter suite, gateway recipe and unconfigured-push checks, crypto tests and the file-size gate. New production widget/session regressions cover the reviewed recovery, permissions, timestamp-window and confirmation cases; removing the corresponding guards reproduces the share, conversion, roster and system-row failures. Main’s unified New chat flow is retained with Bot admission. Attribution and DCO were audited on all 12 outgoing commits.

The disclosure/policy thread remains open: destination-Guest grants and who may re-share are unchanged pending the author’s two decisions. Fresh native captures and two-identity live share/conversion acceptance remain pending; the available simulator is in another active workflow. The PR remains ready as directed; CI and reviewer approval remain separate.

Open Private Solo chats as View only after community-reading consent, preserving already-open policies and every individual role. Recheck signed source and destination access before dispatch; preserve cancellation, readback-only access recovery and exact link IDs for uncertain retries. Remove recipient enrollment and its size limit, including legacy pending audiences.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>
Match desktop member rows with Owner, Admin and Viewing only captions. Share the row rule between details previews and the full member list, keeping permission choices explicit. Extend widget journeys to cover the role captions, original compact-list height, typography, avatars and profile taps; move the preview journey into a sibling part.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz>
Signed-off-by: Taylor Ho <[email protected]>

@kazemek21 kazemek21 left a comment

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.

Kyle reviewed this PR and the Nexus review-tracker notes. Approving with the non-blocking recovery comment below.

Posted by Codex (gpt-6.1-sol) on behalf of kylez

bool check = false,
bool discard = false,
}) async {
if (busy.value || base == null) return;

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] Allow recovery without a loaded base snapshot

With a pending save, a failed initial load leaves base == null, so both recovery buttons silently return here. "Reload access" is also hidden in pending mode, meaning reconnecting does not make either button usable. Could the base-snapshot requirement apply only to new mutations? checkSave and discardSave already load fresh state themselves.

Posted by Codex (gpt-6.1-sol) on behalf of kylez

@jedwards27 jedwards27 left a comment

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.

🤖 :bot: Jude’s code review agent — blocking recommendation: changes needed (GitHub COMMENT event, per this repository’s AGENTS.md agent-review policy).

Reviewed: base 506a588f889b6d010705a564e91fdfa1660c06e7 → clean head 2a9902506cac80f71f254e171c4e6cd98a81693f (mobile channel/Solo access controls, 66 files). Risk: high: signed authorization, privacy consent, and uncertain relay-write recovery. The systems/integration and product/UI review paths were reconciled against the production controller/share flows and mobile vision.

  1. [P2, blocking] Persist uncertain signed access writes across restart. mobile/lib/features/channels/channel_access_provider.dart:89–103,520–555 resets the pending-attempt map in build() and records the signed write only in Riverpod memory. If the relay receives the write but the OK is lost and the app restarts, checkSave() sees no attempt and loads normally; channel_access_sheet.dart:240–264 offers new edits rather than readback/discard. A late prior write may override a later reviewed access/role change. This conflicts with VISION_MOBILE.md’s pending-action durability and the PR’s readback-only recovery contract. Author action: durably journal a scope-keyed pending attempt before dispatch, restore/fence it on restart, and clear only on verified outcome or explicit confirmed discard. Add a production-path regression for restart between signing and ambiguous OK followed by late acceptance; do not reissue an unconfirmed write.

  2. [P2, blocking] Re-confirm when Private-sharing consent is invalidated by a broader source policy. mobile/lib/features/channels/solo_share_sheet.dart:103–170 asks the user to approve a Private Solo chat becoming View only. At the pre-send recheck, a concurrent Private→Public change passes requireSource(current) and skips the only branch that compares the reviewed revision, then posts the link without renewed consent. Public permits broader contribution than the choice confirmed. mobile/test/features/channels/solo_access_recovery_cases.dart:301–326 changes metadata but not to Public, so it misses this interleaving. Author action: bind the confirmation to the exact source access revision/policy and abort for renewed review whenever the pre-send policy differs; regression-test Private→Public between confirmation and post, asserting no link is published.

Other traced behavior: contribution gating through channel/thread/forum composition, reactions, Canvas, huddle and message actions; Solo identity across visibility changes. No further material defect established in those reviewed paths.

Validation at this head: git diff --check passed on a clean exact-head checkout; GitHub Mobile Checks, three Mobile Tests shards and Android jobs passed. Independent local just mobile-install mobile-check mobile-test never reached analysis/tests (flutter pub get stalled under concurrent tooling); another local just mobile-check && just mobile-test attempt stalled during dart format. Native iOS/two-identity journey not run. These are reviewer/tooling confidence gaps, not author-actionable failures. The separate “Run Codex Security Review” check is reported failed by the PR check summary, but its job API conclusion is cancelled after 45 minutes; no PR-caused gate failure is established from it.

Verification owners: author for both fixes and focused regressions; reviewer/tooling for exact-new-head full mobile package gate and native/two-identity follow-up; CI owner for the cancelled security-review job. Any new head invalidates this verdict until the delta is checked. No approval or merge readiness is implied.

ebroderick added a commit that referenced this pull request Nov 13, 2026
## Summary

Mobile puts agent-created and shared Solo chats under Team because it
checks who created the chat. Show unarchived Solo chats the viewer
belongs to under Solo and exclude them from Team. Preserve membership
checks, guest read-only access, legacy chats, and owner-only composing.
This changes mobile classification; it needs no relay changes or data
migration.

**Desktop:**
<img width="557" height="695" alt="Screenshot 2026-11-11 at 10 00 07 AM"
src="https://github.com/user-attachments/assets/d338fa19-7b6f-4b52-a3a6-061025216ed3"
/>

**Mobile (missing solo chats created by agents):**

<img width="423" height="754" alt="Screenshot 2026-11-12 at 11 19 47 AM"
src="https://github.com/user-attachments/assets/18b5da75-38e9-4cca-906c-d0a949cc8cbb"
/>

### Code Changes

Separate Solo list and unread classification from owner-only composing.
Add regression coverage for shared and agent-created chats, Team
exclusion, membership/archive filters, legacy chats, and ordinary
sending from Solo.

### Related issue

Related: #8963 adds mobile access controls and Solo sharing. This PR
fixes the separate Solo/Team placement mismatch. No duplicate found in
searches for mobile Solo issues and PRs.

### Testing

Independent agent review found no blockers.

Device testing could not be completed. Android emulators stalled at
launch, iOS Simulator sign-in was blocked, and iPhone installation
required capabilities unavailable to the Personal Team. Shared Solo
placement and sending remain unverified in an authenticated app;
before/after screenshots remain pending.

Remaining manual checks:

- Have an agent create a Solo chat and include the viewer as a member.
- Confirm it appears once under Solo and is absent from Team.
- Open it, send a message, and confirm owner-only Solo settings are
absent.

Generated with Codex

---------

Signed-off-by: Evan Broderick <[email protected]>
Signed-off-by: Tom Brow <[email protected]>
Co-authored-by: coder <e509b66797ba43fd355dc12801a0c1ba376b06924147c65abdafa7ababcf8e2e@buzz.block.builderlab.xyz>
Co-authored-by: Tom Brow <[email protected]>
Co-authored-by: Tom Brow <[email protected]>
Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>

This branch was successfully deployed

No deployments
codex-review — 2a990250 Deployed Nov 5, 2026 by tellaho via Run Codex Security Review #12810
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.

5 participants