Skip to content

feat(channels): align create and edit forms with draft protection - #482

Merged
tellaho merged 9 commits into
mainfrom
tho/channel-form-parity
Oct 1, 2026
Merged

tellaho merged 9 commits into
mainfrom
tho/channel-form-parity

Conversation

@tellaho

@tellaho tellaho commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Category: improvement

User Impact: Creating and editing channels now use consistent controls for names, descriptions, privacy, and duration, with protection against accidentally discarding a draft.

Problem: Create and Edit presented the same channel settings differently, and closing a changed form could lose work without warning.

Solution: Share the field and duration controls while preserving each workflow's existing save and recovery ownership. Privacy changes use an in-dialog confirmation, and implicit dismissal of a changed draft offers a safe return to editing.

Changes

  • Unicode-aware Name/Description limits and near-limit counters; Description is immediately available and Create initially focuses Name.
  • Matching Ongoing/Temporary cards, draft-only 1-day / 7-day / 2-week controls, and left-aligned Private switches. Existing custom durations are preserved until explicitly adjusted.
  • Same-modal privacy confirmation in either direction, including a full-history warning when making a channel public. One device/account/community-scoped opt-out covers both directions across Create and Edit, and is remembered only after Continue.
  • Close, Escape, and backdrop dismissal protect changed drafts. Explicit Edit Cancel still discards immediately; Create/Save remain the write boundary.
  • Creation destination follows the sidebar entry point and appears in the group-specific title rather than a destination picker.
  • Explicit visibility and TTL changes use the existing narrowly validated details command. Unchanged values are omitted to avoid reopening a channel or resetting its cleanup deadline during a text-only edit.
  • Native signing/publication admission accepts the same visibility and bounded TTL change/clear shapes as the TypeScript command; malformed tags remain rejected.
  • Untouched durations adopt fresh remote values even after a failed conflict reload; a comparison-only baseline preserves explicit lifetime edits without retaining stale editing authority.
  • Existing permission checks, frozen creation retry, uncertain edit recovery, and the newer tabbed management panel are retained. This does not redesign channel lifecycle or member administration.
File changes

dev/relay-broker-api.test.mjs
Covers explicit public/private and TTL change/clear commands while preserving broker route and signing boundaries.

docs/channels.md
Documents the shared form contract, discard/privacy flows, group destination, and unchanged authority/recovery ownership.

src-tauri/src/relay/channel_writes.rs
Admits the exact details visibility/TTL shapes and covers signing, signed-publication validation, wrong signers/tampering, and malformed optional tags.

src/bundled/channel-templates/agent-selection.test.tsx
Updates the template selection journey for guarded form dismissal.

src/bundled/channels/ChannelDetailsEditor.test.tsx
Covers shared field behavior, privacy/duration drafts, discard protection, permissions, reload conflicts, and uncertain saves.

src/bundled/channels/ChannelDetailsEditor.tsx
Uses the shared fields and in-dialog confirmation steps without moving edit authority or save/recovery ownership.

src/bundled/channels/ChannelDurationField.module.css
Styles the shared duration cards and compact adjustment controls.

src/bundled/channels/ChannelDurationField.tsx
Shares duration selection and adjustment, retaining custom values and immediate reduced-motion/keyboard behavior.

src/bundled/channels/ChannelPrivacyConfirmation.test.tsx
Tests scope isolation, both-direction opt-out, legacy preferences, and unavailable/invalid storage behavior.

src/bundled/channels/ChannelPrivacyConfirmation.tsx
Shares consequence copy and the account/community-scoped privacy warning preference.

src/bundled/channels/ChannelSettingsPanel.test.tsx
Updates permission, loading, and editor integration expectations without relying on a non-actionable hint.

src/bundled/channels/ChannelSettingsPanel.tsx
Passes preference scope to Edit and keeps the Edit details label stable while loading.

src/bundled/channels/ChannelTextField.module.css
Styles the shared label-row character counter.

src/bundled/channels/ChannelTextField.tsx
Shares bounded Unicode editing, suffix preservation, counters, and connected validation errors.

src/bundled/channels/Channels.module.css
Aligns Edit's field and footer layout with Create.

src/bundled/channels/ChannelsPage.tsx
Passes the active scope through the existing management panel composition.

src/bundled/channels/CreateChannelDialog.module.css
Aligns shared fields/footer and the fixed group destination heading.

src/bundled/channels/CreateChannelDialog.test.tsx
Covers field limits, privacy/duration changes, fixed destinations, discard protection, and frozen creation recovery.

src/bundled/channels/CreateChannelDialog.tsx
Uses shared fields and confirmation steps while preserving template setup and frozen retry ownership.

src/features/channel-navigation/ChannelSidebar.test.tsx
Updates sidebar integration for entry-point-owned destinations and confirmation steps.

src/features/relay/channel-creation-names.test.ts
Adds session-level canonical name and frozen-recovery regression coverage.

src/features/relay/channel-details-protocol.ts
Validates TTL metadata and narrowly encodes only changed visibility/duration, including explicit clearing.

src/features/relay/channel-details.test.ts
Covers visibility reversal, TTL parsing/writes/readback, omitted unchanged values, and authority/conflict boundaries.

src/features/relay/channel-details.ts
Preserves existing write/recovery ownership while confirming duration and allowing explicit public/private edits.

src/features/relay/session.ts
Uses the shared relay-compatible name canonicalization in creation, preflight, and recovery matching.

src/features/relay/work-sessions.test.ts
Tests canonical names at the existing ordinary-channel creation helper.

src/features/relay/work-sessions.ts
Applies the same canonicalization at that helper's input boundary.

src/shared/design-system/DESIGN.md
Documents opt-in dialog step motion and compact spacing.

src/shared/design-system/styles/overlays.css
Adds opt-in dialog step layout and spacing without changing default dialogs.

src/shared/design-system/ui/Dialog.tsx
Provides in-place animated steps with one backdrop/focus trap, inert outgoing content, and immediate keyboard/reduced-motion transitions.

src/shared/design-system/ui/compositions.test.tsx
Tests step accessibility, focus, motion behavior, and spacing while retaining mainline navigation-tab coverage.

tests/browser/agent-activity.spec.mjs
Keeps the details-read readiness barrier using aria-busy after removing the static permission hint.

tests/browser/navigation-sidebar.spec.mjs
Exercises visible Description, keyboard focus, privacy confirmation, backdrop discard protection, and focus return in the existing journey.

tests/browser/unread.spec.mjs
Retains the independent details-read completion barrier without using the removed hint as a locator.

Reproduction steps

  1. Open Create channel from the general Channels section, then from a saved group's add button. Confirm the destination/title follows the entry point and Name is focused.
  2. Enter a name/description near their 120/1,000-code-point limits. Paste into the middle and confirm the existing suffix is preserved and counters/errors remain connected to the fields.
  3. Select Temporary and adjust between 1 day, 7 days, and 2 weeks. Switch to Ongoing and back; the draft duration should remain selected.
  4. Toggle Private in either form. Confirm the same modal presents the consequence; Cancel restores the unchanged switch and Continue only stages the choice.
  5. Check “Don't show me this again” and Continue. Both privacy directions should subsequently skip confirmation for the same account/community on this device, without bypassing Create/Save.
  6. Change a field, then dismiss with Close, Escape, or the backdrop. Keep editing should preserve the draft; Discard changes should close it. Explicit Edit Cancel closes immediately.
  7. In a disposable test channel, save changed visibility/duration and verify readback. A text-only edit should omit visibility/TTL mutations; existing custom durations should remain unchanged unless adjusted.

Validation and remaining gates

Review-fix head: 1330c83811cbff8ce5562bfb99de606f800c3d2e.

  • Reproduced both reported defects before fixing them. Native admission now covers 15 visibility/TTL combinations, real fixture signing and signed-publication validation, wrong-signer/tampering rejection, and 24 malformed-tag cases. Three new editor regressions cover changed, added and removed remote duration after conflict → failed reload → successful reload; the existing explicit-Ongoing regression remains.
  • Full Vitest on the fixed sources: 478 files / 5,927 tests passed. Final-head push hooks: TypeScript, 213 related files / 3,444 tests, design-system checks and workspace Clippy passed. No production/test changes after the full run; only documentation wrapping and commits.
  • Full local native library run: 197 passed, 1 failed, 6 ignored. Both new native boundary tests passed. The remaining failure, terminal::tests::real_spawn_fences_secrets_and_preserves_login_context, is blocked by an interactive security acknowledgement in this machine’s real login shell. No security prompt bypass or weakened test; this is not a green full native run.
  • Current hosted CI run 36810625166 is in progress at this head; DCO and native browser fixture passed at the recorded snapshot. Windows validation is intentionally skipped. Previous-head green checks do not validate these fixes.
  • Actual running app at 9ad6f6c8: exercised Create/Edit, privacy cancellation, draft-preserving back navigation, discard protection, and one opt-out skipping both directions. Captured desktop and 390px layouts. No channel writes were performed. These screenshots establish UI behavior/layout, not packaged-native Save/readback.
  • Browser case count: no cases added or removed. Existing journeys retain browser-only focus, backdrop, styling, and app-wiring coverage; state/protocol matrices remain in Vitest. Obsolete hidden-description/link-style assertions were replaced by visible Description and Tab-focus expectations. No separate fail-then-pass measurement was recorded for those assertion updates.
  • Historical baseline: CI run 36795682153 passed at 9ad6f6c8. One WebKit thread-unread relay timeout passed a single unchanged-head retry after the full browser file passed locally in both engines (10 cases). The intermittent timeout is not claimed fixed.
  • Remaining acceptance: packaged-native live Save/readback, human tryout, the separately requested independent adversarial review, and optional keyboard-focus inspection when a duration adjustment reaches a disabled limit. The PR remains ready for review at the author’s request; no approval or merge is implied.

Screenshots / demos

Actual running app at 9ad6f6c8, dark theme, neutral draft copy, cropped to the dialogs. These are no-write UI captures, not native Save/readback acceptance. The subsequent review fixes do not change their layout.

Create Edit
Create channel with shared fields and lifetime controls Edit channel with matching fields and lifetime controls
Make public Make private
Full-history warning before staging public visibility Membership warning before staging private visibility
Discard protection Narrow Edit at 390px viewport
Keep editing or explicitly discard an unsaved draft Edit channel at a narrow viewport

Implementation and PR description prepared with Carl (AI), under the author's direction.

@tellaho
tellaho marked this pull request as ready for review October 1, 2026 01:14
@tellaho
tellaho requested review from a team, comp615 and wesbillman as code owners October 1, 2026 01:14

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

Changes needed: the native Edit path rejects the new visibility/duration commands, and failed-reload recovery can overwrite an untouched duration (two inline findings).

Star Lord’s automated source review via Wes’s account. Head: 9ad6f6c8504fdccb25203d241b30dafcb56da011; base: 1a692d5d849145376be899fe0ecf7af195e3527c. Source-only; no tests or app execution. Hosted CI succeeded on this head (attempt 2), but native/live-write behavior and error/retry focus were not exercised. The public description has no attached screenshots; locally retained captures were not inspected.

Optional browser acceptance check: verify keyboard focus when a duration +/- button becomes disabled at its limit; this was not established as a defect by this source-only review.

Comment thread src/features/relay/channel-details-protocol.ts
Comment thread src/bundled/channels/ChannelDetailsEditor.tsx
@tellaho

tellaho commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

Both blockers are fixed and their inline threads resolved: native visibility/TTL admission in eba90c8 and untouched-duration recovery through failed reloads in 1330c83. The six actual-app screenshots are now embedded in the description and verified rendering.

Validation: full Vitest 5,927 passed on the fixed sources; final-head hooks passed TypeScript, 3,444 related tests, design checks and workspace Clippy. Native library: 197 passed / 1 local login-shell security-prompt failure / 6 ignored; both new boundary tests passed. New-head hosted CI is still in progress (DCO passed). Packaged-native live Save/readback and human acceptance remain outstanding.

— Carl (AI), acting under Taylor’s direction.

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

No further changes requested: both findings from the prior review are addressed—the native validator admits the intended visibility/TTL shapes, and failed reloads retain duration provenance without retaining edit authority.

Star Lord’s automated source review via Wes’s account; head 1330c83811cbff8ce5562bfb99de606f800c3d2e, base 1a692d5d849145376be899fe0ecf7af195e3527c.

Source-only follow-up; no tests or app execution. Current-head hosted checks succeeded (Windows skipped), but the author-reported shell-gated native test failure and packaged-native Save/readback/human acceptance remain validation gaps; screenshots are prior-head, no-write evidence.

@tellaho
tellaho force-pushed the tho/channel-form-parity branch from 1330c83 to 38f9e39 Compare October 1, 2026 15:56

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

No further changes requested: the rebase preserves both previously resolved findings, and the updated backdrop test/docs match guarded Create/Edit dismissal.

Star Lord’s automated source review via Wes’s account; head 38f9e39f64e57fbcfbca10d1636117261dc586eb, base 0124f3fdfc9ece433d1ecb71aa43f2a378980f19.

Source-only follow-up; no tests or app execution. The description and all six prior-head screenshots were inspected. The hosted snapshot still had one WebKit shard running (Windows skipped); packaged-native Save/readback, browser error/retry focus behavior, and human acceptance remain unverified.

tellaho and others added 9 commits October 1, 2026 09:50
Share bounded text fields and duration controls, confirm privacy changes in the same dialog, and keep group placement tied to the creation entry point. Show the optional description field immediately while retaining initial name focus. Preserve separate save, authority, and frozen retry owners.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Allow backdrop dismissal for Create and Edit. Confirm implicit dismissal of changed drafts in the existing modal, keep explicit Cancel immediate, and preserve pending operations and frozen recovery.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Show visibility consequences in the confirmation body for Create and Edit. Allow opting out per direction and community/viewer on this device only after Continue, while retaining explicit writes and discard protection.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Opt Create and Edit privacy steps into an 8px body-to-footer gap. Preserve default spacing elsewhere and wait for the animated consequence copy before asserting visibility.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Share one privacy-warning opt-out across public/private choices in Create and Edit, honoring existing per-direction preferences. Remove the static permission hint without changing edit authority, and preserve browser readiness barriers via aria-busy.

Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Signed-off-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
Retain mainline backdrop cancellation coverage for untouched Create forms and require the explicitly requested confirmation for changed drafts. Preserve no-write assertions and document the Create/Edit exception to immediate cancellation.

Signed-off-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@buzz.block.builderlab.xyz>
@tellaho
tellaho force-pushed the tho/channel-form-parity branch from 38f9e39 to a710882 Compare October 1, 2026 16:55

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

No further changes requested in this bounded rebase follow-up: the earlier fixes remain intact, and I found no new actionable integration regression.

Star Lord’s automated source review via Wes’s account; head a710882ab0dfa564f933bad8bba84839a292b2dc, base e5a70460a9a3423464e7ee97dede8ccecfd69f10.

Source-only; no tests or app execution. The hosted snapshot still had JavaScript, Rust and browser checks running (Windows skipped); packaged-native Save/readback, error/retry focus behavior and human acceptance remain unverified.

@tellaho
tellaho merged commit c4df139 into main Oct 1, 2026
37 of 39 checks passed
@tellaho
tellaho deleted the tho/channel-form-parity branch October 1, 2026 18:07
bostonaholic added a commit to bostonaholic/buzz-app that referenced this pull request Oct 1, 2026
…page-icon

* origin/main:
  Count unread replies only in conversations you are part of (block#471)
  Animate the terminal welcome with a compact hex wordmark (block#508)
  Use top tabs in the new-tab picker (block#505)
  Polish media controls, panel headers, and menus (block#496)
  harden pinned browser CI setup and native fixture provenance (block#494)
  perf(relay): confirm membership hints with exact channel reads (block#486)
  test(browser): wait for menu and wheel completion (block#492)
  fix(links): render one hash on completed channel links (block#506)
  ci: publish Windows and Linux alongside macOS previews (block#491)
  fix(channels): keep conversations open through archive and restore (block#452)
  feat(channels): align create and edit forms with draft protection (block#482)
  Test provider connections before model selection (block#500)

Signed-off-by: Matthew Boston <mboston@squareup.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