fix(schema): tmdb.api_key is restart-required, not live — v0.46.0 - #35
Conversation
`schemas/server-settings.schema.json` declared `"restart": false` for `tmdb.api_key`, so the admin SPA promised a saved key applied immediately. That promise was false. TmdbProvider is registered as a PHP-DI `factory()`, and PHP-DI caches every resolved entry -- factories included -- in `Container::$resolvedEntries`, so the provider is a per-container singleton that captures the key BY VALUE at construction. One container is built per worker in `onWorkerStart`, and the `phlix-library-scan` worker resolves it eagerly at fork time (LibraryScanWorker -> LibraryMetadataMatcher -> TmdbProvider). With no TTL, no invalidation hook and no cross-worker propagation, a newly saved key stays inert until the workers are recycled. This is the same "Class (b) RESTART" shape already documented for the `server.rate_limit.*` keys in tests/Schema/ServerSettingsSchemaTest.php: a value frozen into DI at container-build time can never apply live, regardless of `SettingsRepository::getEffective()` doing an uncached SELECT per call. Also discloses the requirement in the key's admin-facing helpText, matching how the `process.<worker>.enabled` keys disclose their restart semantics. No key added or removed -- the hard-locked property count is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | 0 |
🟢 Coverage ∅ diff coverage · +0.00% coverage variation
Metric Results Coverage variation ✅ +0.00% coverage variation (-1.00%) Diff coverage ✅ ∅ diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (d82185a) 1016 829 81.59% Head commit (9af498a) 1016 (+0) 829 (+0) 81.59% (+0.00%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#35) 0 0 ∅ (not applicable) Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #35 +/- ##
=========================================
Coverage 81.29% 81.29%
Complexity 414 414
=========================================
Files 50 50
Lines 1160 1160
=========================================
Hits 943 943
Misses 217 217
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
What
Corrects
tmdb.api_keyinschemas/server-settings.schema.jsonfrom"restart": falseto"restart": true, discloses the requirement in the key'shelpText, and ships it as v0.46.0.Why
restart: falsewas factually wrongTmdbProvideris registered as a PHP-DIfactory(). PHP-DI caches everyresolved entry — factories included — in
Container::$resolvedEntries(
vendor/php-di/php-di/src/Container.php), so the provider is a per-containersingleton that captures the API key by value at construction.
onWorkerStart(start.php).phlix-library-scanresolves it eagerly at fork time(
LibraryScanWorker→LibraryMetadataMatcher→TmdbProvider).A newly saved key is therefore inert until the workers are recycled — while the
admin SPA rendered it as taking effect immediately.
This is the same "Class (b) RESTART" shape already documented for the
server.rate_limit.*keys intests/Schema/ServerSettingsSchemaTest.php("the limiters are factory() closures that capture max/window BY VALUE at
container-build time … frozen into DI and can never apply live"). The fact that
SettingsRepository::getEffective()itself does an uncachedSELECTon everycall is irrelevant once the value has been captured.
Scope
No key added or removed, so the suite's hard-locked property count is unchanged.
Verification
./vendor/bin/phpunitcomposer stancomposer csFollow-up (not in this PR)
An audit of the remaining 38
restart: falsekeys in this schema found 7 morein the same Class (b) shape, several of which contradict their own consuming
code's docblocks:
matching.noise_suffixes—factory()injected as aconstructorParameterinto
MediaScanner; its own comment says "computed once at construction".metadata.provider_priority,metadata.genres_mode— captured into thePriorityConfigfactory; comment says "resolved ONCE when first built(per worker cycle, not per request)".
lastfm.api_key,lastfm.shared_secret,lastfm.enabled— overlaid atroute-build time;
Application::applyLastfmOverrides()'s docblock literallyasserts "the
lastfm.*schema keys carry\"restart\": true\"", which thisschema contradicts.
port-forward.port_forwarding.upnp_enabled— read viaEffectiveConfig::file()at container-build time;
NetworkServicesProvider's comment says the values are"genuinely admin-controlled (on reload)".
Raised separately so this PR stays a single-key correction.
🤖 Generated with Claude Code