Skip to content

fix(publish): deliver overflowing waves and deck threads to the composer#1237

Merged
feruzm merged 2 commits into
developfrom
bugfix/waves-overflow-publish-handoff
Jul 24, 2026
Merged

fix(publish): deliver overflowing waves and deck threads to the composer#1237
feruzm merged 2 commits into
developfrom
bugfix/waves-overflow-publish-handoff

Conversation

@feruzm

@feruzm feruzm commented Jul 24, 2026

Copy link
Copy Markdown
Member

When a wave or a deck thread goes past its character limit, the form builds the content with its attachments, stashes it, and opens /publish so it can become a post instead.

It stashed it under the submit page's local draft key (ecency_local_draft). Nothing on /publish reads that key, so the content was silently dropped and the composer opened empty.

The write was also partial: setLocalDraft({ ...localDraft, body: content }) over a localDraft that defaults to {}. That left the key holding a draft with neither title nor tags, which the submit page passed straight into applyTitle -> value.slice(...), crashing every later visit to /submit (ECENCY-NEXT-1GJC).

Change

  • New usePublishHandoffWriter / usePublishHandoff pair on a dedicated one-shot key (ecency_pub_handoff), consumed and cleared on composer mount.
  • use-wave-submit and the deck threads form stage content through the writer instead of writing into the submit draft.
  • The publish page seeds both publish state and the editor, matching what the import flow already does, since the editor prefills from publish state only if it initialises after the handoff runs.

ecency_local_draft is now written only by the submit page, which always writes a complete PostBase.

Notes

  • The entry paired with fix(submit): handle missing title in local drafts #1236, which guards the read side so users who already have the malformed draft in localStorage stop crashing. This one stops it being written.
  • Tests cover staging, one-shot delivery, empty and missing entries, the round trip, and that staging leaves an in-progress submit draft untouched.
  • pnpm --filter @ecency/web test 240 files / 2332 tests pass, typecheck clean, lint shows no new warnings.

Summary by CodeRabbit

  • New Features

    • Added seamless handoff of oversized thread and wave content to the Publish composer.
    • Preserves attached content during the handoff and opens it in a new tab for editing.
    • Automatically pre-fills the Publish composer with handed-off content.
  • Bug Fixes

    • Prevents oversized content from overwriting local drafts.
    • Ensures handed-off content is delivered only once and then cleared.
  • Tests

    • Added coverage for handoff persistence/delivery, draft preservation, and empty or invalid handoff handling.

A wave or deck thread past its character limit wrote its content into the
submit page's local draft key and opened /publish. Nothing on /publish reads
that key, so the content was silently dropped.

The write was also partial ({ ...localDraft, body } over a localDraft that
defaults to {}), so it left that key holding a draft with neither title nor
tags. The submit page fed those straight into applyTitle, crashing every
later visit to /submit (ECENCY-NEXT-1GJC).

Both surfaces now stage content on a dedicated one-shot key that the publish
composer consumes on mount, so the handoff arrives and the submit draft is
left to the submit page.
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71dd9407-ff4e-4d7b-971a-6fed5f582642

📥 Commits

Reviewing files that changed from the base of the PR and between 4875c68 and b47949b.

📒 Files selected for processing (2)
  • apps/web/src/app/publish/_hooks/use-publish-handoff.ts
  • apps/web/src/specs/app/publish/publish-handoff.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/app/publish/_hooks/use-publish-handoff.ts
  • apps/web/src/specs/app/publish/publish-handoff.spec.ts

📝 Walkthrough

Walkthrough

Oversized deck-thread and wave content now uses a one-shot local-storage handoff to populate the publish composer. The publish page consumes the handoff into both editor states, replacing the prior local-draft flow.

Changes

Publish handoff

Layer / File(s) Summary
Handoff channel
apps/web/src/app/publish/_hooks/*
Adds the publish handoff payload, storage key, writer hook, receiver hook, and hook re-export.
Producer and composer integration
apps/web/src/app/decks/..., apps/web/src/features/waves/..., apps/web/src/app/publish/_page.tsx
Stages over-length thread and wave content, then consumes it to initialize the publish editor.
Handoff behavior validation
apps/web/src/specs/app/publish/publish-handoff.spec.ts
Tests storage isolation, delivery, one-time consumption, no-op cases, cleanup, and round-trip content preservation.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DeckThreadsForm
  participant useWaveSubmit
  participant PublishHandoffStorage
  participant PublishPage
  DeckThreadsForm->>PublishHandoffStorage: Stage oversized thread content
  useWaveSubmit->>PublishHandoffStorage: Stage oversized wave content
  PublishPage->>PublishHandoffStorage: Read and remove staged body
  PublishHandoffStorage-->>PublishPage: Deliver body
  PublishPage->>PublishPage: Set content and editor content
Loading

Suggested labels: patch

Poem

I’m a rabbit with a parcel to send,
Through publish’s door, the drafts now wend.
Stored just once, then cleared away,
The editor blooms with words today.
Hop, hop—content finds its way!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: routing overflowing waves and deck threads to the publish composer.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/waves-overflow-publish-handoff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/app/publish/_hooks/use-publish-handoff.ts`:
- Around line 39-49: Update the useMount logic in use-publish-handoff.ts to
remove the staged handoff immediately when processing begins, before checking
whether handoff?.body is deliverable; add a ref-based guard so the same staged
entry is consumed only once across later mounts, while preserving onReceive for
non-empty bodies. In apps/web/src/specs/app/publish/publish-handoff.spec.ts
lines 64-70, add coverage asserting entries with an empty body are removed and
not delivered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b7d220d9-f0a1-457b-9326-ac15ceaea2e1

📥 Commits

Reviewing files that changed from the base of the PR and between bd002e8 and 4875c68.

📒 Files selected for processing (6)
  • apps/web/src/app/decks/_components/deck-threads-form/index.tsx
  • apps/web/src/app/publish/_hooks/index.ts
  • apps/web/src/app/publish/_hooks/use-publish-handoff.ts
  • apps/web/src/app/publish/_page.tsx
  • apps/web/src/features/waves/hooks/use-wave-submit.ts
  • apps/web/src/specs/app/publish/publish-handoff.spec.ts

Comment thread apps/web/src/app/publish/_hooks/use-publish-handoff.ts
@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a dedicated one-shot handoff channel (ecency_pub_handoff) for passing oversized wave and deck thread content to the publish composer, replacing the broken approach of writing a partial object into the submit page's own draft key. Both use-wave-submit and deck-threads-form now call usePublishHandoffWriter instead of mutating ecency_local_draft, and the publish page seeds both setContent and setEditorContent on mount to cover the editor's lazy-load timing.

  • use-publish-handoff.ts: new writer/consumer hook pair on a dedicated key; the consumer unconditionally removes the entry before inspecting the body, so malformed or empty entries are cleaned up on first visit rather than persisted forever.
  • _page.tsx: seeding both publish state and the editor directly covers the race between useMount and the dynamically-imported PublishEditor component.
  • publish-handoff.spec.ts: six tests cover staging, one-shot delivery, empty body cleanup, missing entries, and the full round-trip.

Confidence Score: 5/5

Safe to merge — the fix is narrowly scoped to the handoff path, does not touch the submit page's own draft key, and every edge case (empty body, missing entry, re-visit after delivery) is covered by the new tests.

The handoff key is isolated from the submit draft, the consumer removes the entry unconditionally before inspecting its contents (preventing stale-key accumulation), and the dual seed in the publish page correctly handles the lazy-load timing of the editor. The six new tests exercise all the cases called out in the PR description and the previous review thread, including the empty-body cleanup path that was the subject of those earlier comments.

No files require special attention.

Important Files Changed

Filename Overview
apps/web/src/app/publish/_hooks/use-publish-handoff.ts New hook pair implementing the one-shot handoff; unconditionally removes the localStorage entry before checking body, correctly preventing stale entries.
apps/web/src/app/publish/_page.tsx Adds usePublishHandoff to seed both publish state and editor content on mount; useCallback dependency array is correct (Zustand setters are stable).
apps/web/src/features/waves/hooks/use-wave-submit.ts Replaces the partial write to ecency_local_draft with stageForPublish; change is minimal and correct.
apps/web/src/app/decks/_components/deck-threads-form/index.tsx Replaces the partial write to ecency_local_draft with stageForPublish; symmetric change to use-wave-submit, correct.
apps/web/src/specs/app/publish/publish-handoff.spec.ts Six tests covering staging, one-shot delivery, empty body cleanup, missing entry, and round-trip; explicitly asserts localStorage state after each relevant case.
apps/web/src/app/publish/_hooks/index.ts Re-exports the new hook; no issues.

Sequence Diagram

sequenceDiagram
    participant User
    participant WaveForm as Wave / DeckThreadsForm
    participant LS as localStorage
    participant PublishPage as /publish (_page.tsx)
    participant Editor as PublishEditor (lazy)

    User->>WaveForm: "Submit content > char limit"
    WaveForm->>LS: "setHandoff({ body }) → ecency_pub_handoff"
    WaveForm->>PublishPage: window.open("/publish", "_blank")

    PublishPage->>PublishPage: mount → usePublishHandoff fires (useMount)
    PublishPage->>LS: read ecency_pub_handoff
    PublishPage->>LS: removeHandoff() — cleared before use
    alt body present
        PublishPage->>PublishPage: setContent(body)
        PublishPage->>PublishPage: setEditorContent(body)
    end

    PublishPage->>Editor: lazy load completes
    Editor->>PublishPage: reads publish state (content already seeded)
    Editor-->>User: composer pre-filled with overflowing content
Loading

Reviews (2): Last reviewed commit: "fix(publish): drop a staged handoff befo..." | Re-trigger Greptile

Comment thread apps/web/src/app/publish/_hooks/use-publish-handoff.ts
Comment thread apps/web/src/specs/app/publish/publish-handoff.spec.ts Outdated
An entry whose body was empty or unreadable hit the early return before
removeHandoff ran, so it stayed in local storage and was re-examined on
every later visit to the composer without ever being consumed. No caller
writes such an entry today, since the overflow guard requires content, but
the hook promised one-shot consumption and did not deliver it.
@feruzm
feruzm merged commit a534641 into develop Jul 24, 2026
9 checks passed
@feruzm
feruzm deleted the bugfix/waves-overflow-publish-handoff branch July 24, 2026 15:01
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.

1 participant