fix: stop a film's save from erasing its custom field values - #761
Merged
helmerzNL merged 1 commit intoSep 3, 2026
Merged
Conversation
The edit form read its stored custom values from `detail.customValues`. `movie_detail_entity` attaches them as `detail.movie.custom_values`; `customValues` exists only on sync-mutation results and on the PUT response, and nothing ever sets it on a detail payload. So every input rendered empty on every load. That is not a display fault on its own. `collectMovieEditCustomValues` turns an empty input into a null, `replace_movie_custom_values` deletes the row for a null, and `saveMovieCustomValues` sends the whole collected map with every save. Opening a film, correcting its title and pressing save therefore erased every custom value on that film. Nothing errored, nothing logged, and the loss was only visible to whoever went looking for a value they had entered earlier. The two commits that introduced it are a pair: 8b91677 attached the values to the detail entity, fb19a1e read them back under a different name. No test touched the read path, so both halves looked finished. Both sides are now asserted, because a rename on either one alone restores the same silence: `test_next_custom_fields_ui.py` pins the accessor, and `test_next_custom_fields_routes.py` pins the payload key by writing a value and reading it back off `GET /api/next/movies/<id>`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PUwMZZ585LnTxaWMUuKVgT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A one-line accessor fix, and the tests that should have caught it. Saving any film currently deletes every custom field value that film had.
Why
renderMovieEditCustomFieldsreads its stored values fromdetail.customValues.movie_detail_entityattaches them asdetail.movie.custom_values; the keycustomValuesexists only on sync-mutation results (next_app.py:24749,:24794) and on thePUT /custom-valuesresponse (:38604), and nothing anywhere sets it on a detail payload.So every input renders empty on every load. On its own that is a display fault. It is not on its own:
collectMovieEditCustomValuesturns an empty input intonull.replace_movie_custom_valuesdeletes the row for anull— deliberately, so clearing a field works.saveMovieCustomValuessends the whole collected map on every save.Opening a film, correcting its title and pressing save therefore erased every custom value on that film. Nothing errored and nothing logged; the loss was visible only to whoever later went looking for a value they had entered.
The two commits that introduced it are a pair —
8b91677attached the values to the detail entity,fb19a1eread them back under a different name — and no test touched the read path, so both halves looked finished. Found while investigating #719, where @jeff363b mentions going into Edit to see what a custom field holds.How
detail?.customValues→detail?.movie?.custom_values.Tests
Both sides, because a rename on either one alone restores exactly the same silence:
tests/test_next_custom_fields_ui.py— the accessor reads the detail payload's own key, and does not read the key no detail payload carries.tests/test_next_custom_fields_routes.py— the round trip: write a value,GET /api/next/movies/<id>, and find it underdetail.movie.custom_valueswith nocustomValueson the detail object.Both fail on the previous code. Full backend suite green against a local PostgreSQL 16 with all migrations applied (3,458 tests, 2 skipped), as is
scripts/check_undefined_names.py.Impact on existing data
This stops the loss; it cannot undo it. Values erased by a save before this fix are deleted rows and are not recoverable except from a backup. Instances that have defined custom fields since 26.9.98 and edited films afterwards should expect gaps.
Deployment-file changes
No deployment-file changes in this PR.
Documentation
To be recorded in App-Guidance (
projects/discvault/specs/custom-fields.md) alongside the detail-page work that follows: values travel on the detail payload asmovie.custom_valuesand nowhere asdetail.customValues. Not documentation-neutral — the whole defect is a contract read under the wrong name.Translations
No new UI strings.
📦 Change Spec — release notes (fill at merge)
🤖 Generated with Claude Code
https://claude.ai/code/session_01PUwMZZ585LnTxaWMUuKVgT
Generated by Claude Code