[#177] Add story edit panel: cover image, genre, language, NSFW#178
Conversation
- Add uploadCoverImage() and updateStoryline() helpers in publish.ts using createOwsAccount for wallet signing with exact PlotLink message formats - Add POST /api/publish/upload-cover and /api/publish/update-storyline routes with file validation (500KB, image type) and wallet authentication - Add edit panel UI in PreviewPanel for published genesis files: cover image upload with preview, genre/language dropdowns, NSFW toggle - Wire walletAddress from StoriesPage to PreviewPanel for authorship check - Update AGENTS.md post-publishing guidance to reference in-app edit panel - Bump version to 1.1.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Initialize genre, language, and NSFW fields from the storyline's current values on PlotLink so saving with only a cover change doesn't silently overwrite existing metadata to defaults. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The signed upload/update helpers and route plumbing are in place, and CI is passing. However, the edit panel can silently overwrite existing storyline metadata with defaults during unrelated edits, so the feature is not safe to ship yet.
Findings
-
[high] Cover-only saves overwrite genre/language/NSFW with hard-coded defaults
- File:
app/web/components/PreviewPanel.tsx:47 - Suggestion: Do not initialize the edit metadata controls to global defaults unless those are the actual current story values. Either load the current PlotLink metadata before showing the panel, derive the initial values from stored publish metadata/structure where reliable, or send only fields the user explicitly changed. As written,
editGenre,editLanguage, andeditNsfwstart asRomance,English, andfalse, andhandleEditSavealways includes them in the update payload (app/web/components/PreviewPanel.tsx:184). A user who only uploads a cover for a Fantasy/Korean/NSFW story will unintentionally change its metadata.
- File:
-
[medium] Edit button is gated on wallet existence, not confirmed authorship
- File:
app/web/components/PreviewPanel.tsx:490 - Suggestion: Gate the UI on a stored/verified author address matching the current OWS wallet, or otherwise verify the selected published file was authored by the current OWS wallet. The current check only requires
walletAddressandstorylineId, so after wallet rotation or imported/local status data the panel can appear for stories the current OWS wallet cannot edit, which misses the acceptance criterion that the panel is visible only for published stories authored by the OWS wallet.
- File:
Decision
Requesting changes because the metadata overwrite bug can corrupt user-facing storyline details during a normal cover upload flow. lint-and-typecheck passed.
Store authorAddress in publish status when publishing. Edit button now only shows when the current wallet matches the stored author address (case-insensitive), with backwards compat for pre-existing published stories that lack the field. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minor version bump (1.1.0) requires T1 approval. Using patch bump for now; minor bump recommended for operator decision. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The authorship field and version bump fixes are moving in the right direction, but the metadata overwrite blocker is still not fully fixed. The edit panel still starts from defaults and can save before current metadata has loaded, or after the metadata fetch fails silently.
Findings
- [high] Metadata defaults can still overwrite current story values
- File:
app/web/components/PreviewPanel.tsx:218 - Suggestion: Track metadata loading/error state and prevent
Save Changesuntil current metadata is successfully initialized, or send only fields the user explicitly changed. The new effect fetches current metadata after the edit panel opens, but the controls remain initialized toGENRES[0],LANGUAGES[0], andfalse(app/web/components/PreviewPanel.tsx:48) andhandleEditSavestill always sends those values (app/web/components/PreviewPanel.tsx:185). Because the fetch is async and errors are ignored, a quick cover-only save, a failed/CORS-blocked fetch, or an unrecognized metadata value can still change the story to Romance / English / not NSFW.
- File:
Decision
Requesting changes because the main data-corruption risk from the first review remains possible in normal failure/race cases. Latest lint-and-typecheck was still pending when I rechecked.
Disable Save Changes button until the PlotLink metadata fetch completes successfully. Shows loading state and surfaces errors if the fetch fails, preventing race conditions where defaults could overwrite existing storyline metadata. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
The remaining metadata overwrite blocker is resolved: the edit form now disables saving until current PlotLink metadata loads successfully, and failed metadata loads surface an error while keeping save disabled. The authorship gating and version bump fixes are also in place.
Findings
- None.
Decision
Approving. Note: latest lint-and-typecheck was still pending when I rechecked the newest head, so I could not confirm the final CI result from the review CLI output.
Fixes #177
Summary
uploadCoverImage()andupdateStoryline()helpers inapp/lib/publish.tsusingcreateOwsAccountfor wallet signing with exact PlotLink message formatsPOST /api/publish/upload-coverandPOST /api/publish/update-storylineroute handlers with file validation (500KB max, image type check)PreviewPanelfor published genesis files: cover image upload with preview, genre/language dropdowns, NSFW toggle, save buttonwalletAddressfromStoriesPagetoPreviewPanelso edit button only shows for OWS wallet authorsTest plan
npm run typecheckandnpm run lintpass (confirmed)npm run app:buildsucceeds (confirmed)