Skip to content

fix(schema): correct 7 more Class (b) restart flags — v0.47.0 - #36

Merged
detain merged 1 commit into
masterfrom
fix/restart-flags-class-b
Jul 28, 2026
Merged

fix(schema): correct 7 more Class (b) restart flags — v0.47.0#36
detain merged 1 commit into
masterfrom
fix/restart-flags-class-b

Conversation

@detain

@detain detain commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Follow-up to #35. That PR corrected tmdb.api_key; this one closes out the audit it triggered.

Criterion

For every remaining restart: false key: is the value captured into a DI singleton's constructor, or read once at container / route build time? If so it cannot apply live, regardless of SettingsRepository::getEffective() doing an uncached SELECT on every call. Seven keys qualify.

Key Evidence
lastfm.api_key, lastfm.shared_secret, lastfm.enabled Overlaid at route-build time (once per worker) by Application::applyLastfmOverrides(), then frozen into LastfmApi's constructor-promoted readonly properties. That docblock already asserted these keys carry "restart": true — the schema simply disagreed with the code.
matching.noise_suffixes factory() injected as constructorParameter('noiseSuffixes', …) into MediaScanner at two wiring sites. Its own comment: "the value is computed once at construction."
metadata.provider_priority, metadata.genres_mode Captured into the PriorityConfig factory, injected as constructorParameter('globalPriority', …). Its own comment: "resolved ONCE when first built (per worker cycle, not per request)."
port-forward.port_forwarding.upnp_enabled Read at container-build time in NetworkServicesProvider::register(). See the caveat below.

Each also gains a helpText sentence disclosing the requirement, matching how tmdb.api_key and the process.<worker>.enabled keys disclose theirs.

port-forward.port_forwarding.upnp_enabled needed more than a flag flip

My first pass classified this as plain Class (b). Re-verifying before changing it showed that was wrong — the key is not merely restart-required, it is inert:

  • NetworkServicesProvider::register() computes $upnpEnabled at line 73 and the variable appears nowhere else in the file — it is passed to no definition.
  • PortForwardService::__construct() has no UPnP switch at all, and autoConfigure() calls $this->upnp->discoverGateway() unconditionally.
  • A repo-wide sweep finds no other consumer.

So an admin setting it to false got nothing — even across a restart. Flipping the flag alone would have swapped one false promise for another, exactly what this schema did with hwaccel.probe_timeout before it was deleted in v0.26.0.

The companion phlix-server PR wires it (PortForwardService::$upnpEnabled gates UPnP discovery and falls through to NAT-PMP, rather than disabling forwarding wholesale — that is what auto already does). restart: true is accurate only in combination with that change; the two should land together.

Note the existing InertSettingRepairsTest is not wrong about this — it states its own scope honestly: "This proves the value resolves and overlays; it does NOT by itself prove NetworkServicesProvider consumes that path." It never claimed the effect, and the effect was missing.

Left alone, deliberately

  • 23 keys verified correct as restart: false — each resolves through SettingsRepository at use time (per request / per call): the auth.* policy classes, EncodeSettings, ArtworkDownloadPolicy (whose docblock explicitly requires restart: false), DlnaAllowlistMiddleware, CastingEnabledMiddleware, TraktOperatorConfig (re-read per request), and others.
  • 8 keys have no use-time consumer found at alltranscoding.tone_mapping_mode, transcoding.prefer_hdr_output, newsletter.enabled, newsletter.send_hour, relay.reconnect_delay, relay.ping_interval, webhooks.enabled, stats.enabled. Their flags may be wrong in either direction, or they may be inert like upnp_enabled was. Left untouched pending a consumer trace rather than guessed at.

Scope

No key added or removed — property count unchanged at 72 (restart: true 34 → 41). The diff is exactly 14 lines changed across 7 keys (restart + helpText each), verified with git diff | grep -vc '"restart"|"helpText"'0 unintended lines.

Verification

Gate Result
./vendor/bin/phpunit OK — 1025 tests, 83028 assertions
composer stan [OK] No errors
composer cs clean — 59 files

🤖 Generated with Claude Code

Audited every remaining "restart": false key after tmdb.api_key was corrected
in 0.46.0, against one criterion: is the value captured into a DI singleton's
constructor, or read once at container/route build time? Seven were, and are
now "restart": true with the requirement disclosed in each helpText.

  * lastfm.api_key / .shared_secret / .enabled -- overlaid at route-build time
    (once per worker) by Application::applyLastfmOverrides(), then frozen into
    LastfmApi's constructor-promoted readonly properties. That docblock ALREADY
    asserted these keys carry "restart": true; the schema disagreed with it.
  * matching.noise_suffixes -- factory() injected as a constructorParameter into
    MediaScanner at two wiring sites. Its comment: "computed once at construction".
  * metadata.provider_priority / .genres_mode -- captured into the PriorityConfig
    factory, injected as constructorParameter('globalPriority'). Its comment:
    "resolved ONCE when first built (per worker cycle, not per request)".
  * port-forward.port_forwarding.upnp_enabled -- read at container-build time in
    NetworkServicesProvider::register().

The upnp key needed more than a flag flip: the provider computed the value into
a local that was never passed to any definition, and PortForwardService had no
UPnP switch at all, so an override changed nothing even across a restart. The
companion phlix-server change wires it; "restart": true is accurate only with
that change. Flipping the flag alone would have swapped one false promise for
another -- compare hwaccel.probe_timeout, deleted in 0.26.0 rather than
relabelled.

23 keys were verified CORRECT as "restart": false (each resolves through
SettingsRepository at use time) and are untouched. 8 more have no use-time
consumer found at all and are left alone pending a consumer trace rather than
guessed at in either direction.

No key added or removed; property count unchanged at 72 ("restart": true 34->41).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@codacy-production

codacy-production Bot commented Jul 28, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

🟢 Coverage ∅ diff coverage · +0.00% coverage variation

Metric Results
Coverage variation +0.00% coverage variation (-1.00%)
Diff coverage diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (0248d7d) 1016 829 81.59%
Head commit (f748964) 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 (#36) 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

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.29%. Comparing base (0248d7d) to head (f748964).

Additional details and impacted files
@@            Coverage Diff            @@
##             master      #36   +/-   ##
=========================================
  Coverage     81.29%   81.29%           
  Complexity      414      414           
=========================================
  Files            50       50           
  Lines          1160     1160           
=========================================
  Hits            943      943           
  Misses          217      217           
Flag Coverage Δ
phpunit 81.29% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@detain
detain merged commit d6d07ee into master Jul 28, 2026
11 checks passed
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