Skip to content

fix(schemas): make 26 declared settings reachable in the config form - #299

Merged
ChuckBuilds merged 1 commit into
mainfrom
fix/property-order-coverage
Aug 19, 2026
Merged

fix(schemas): make 26 declared settings reachable in the config form#299
ChuckBuilds merged 1 commit into
mainfrom
fix/property-order-coverage

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Found while auditing for broken functionality and schema defects. This one is invisible by construction, which is why it lasted.

The mechanism

The web UI's config form iterates x-propertyOrder and nothing else:

{% set property_order = schema['x-propertyOrder']
                        if 'x-propertyOrder' in schema
                        else schema.properties.keys()|list %}
{% for key in property_order %}
    {% if key in schema.properties %}

A property the schema declares but that list omits is never rendered. No field, no error, no hint the setting exists. The value still validates on save and the plugin still reads it — so the only way to set one was to hand-edit config.json on the device.

What was unreachable

26 settings across 7 plugins:

plugin hidden
ledmatrix-flights flightaware_api_key, flight_plan_enabled, max_api_calls_per_hour, daily_api_budget, flight_plan_cache_ttl_hours, min_callsign_length, airline_callsign_prefixes, background_service
basketball-scoreboard scroll_card, background_service, both idle intervals
afl / nrl / soccer scroll_card, both idle intervals
masters-tournament player_card_duration, hole_display_duration, page_display_duration, scroll_card_width
f1-scoreboard customization.auto_scale

Two worth calling out:

These are omissions, not deliberate hiding

22 of the 26 already carry x-advanced: true — nobody flags a field "advanced" meaning "invisible". x-advanced is the supported way to de-emphasise a field, and it puts it in a collapsed Advanced Settings section. There is no supported way to hide a property, and no schema in the repo attempts one.

Why it went unnoticed

The two renderers disagree. app-shell.js sorts unlisted properties into an unorderedEntries list and still shows them; the server-rendered form drops them. The same schema looks fine in one and is unreachable in the other.

Confirmed on a live rig before changing anything: soccer-scoreboard's installed schema has 20 properties and 19 order entries, the odd one out is scroll_card, and scroll_card is absent from the 989 KB rendered page while display_duration appears four times.

Verification

Order-only change — verified per plugin that each schema is identical once x-propertyOrder is stripped, so nothing was added, renamed or retyped.

scripts/test_property_order_coverage.py guards it, and doesn't merely restate the rule: it lifts the ordering loop out of the shipped template, renders it against a two-property schema listing only one, and shows the other never reaches the form. If that loop is ever changed to append unlisted keys, the test notices.

Mutation-checked — dropping flightaware_api_key back out fails the check by name. All 52 test suites across the seven plugins exit 0.

Also checked, and clean

  • Every schema default validates against its own subschema, pattern and enum — 0 findings.
  • All 43 schemas pass Draft-7.
  • A config built purely from defaults validates for 42 of 43; youtube-stats requires api_key/channel_id with no defaults, which is the normal credentials pattern, not a defect.

🤖 Generated with Claude Code

https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW

The web UI's config form iterates x-propertyOrder and nothing else:

    {% set property_order = schema['x-propertyOrder']
                            if 'x-propertyOrder' in schema
                            else schema.properties.keys()|list %}
    {% for key in property_order %}
        {% if key in schema.properties %}

A property the schema declares but that list omits is therefore never
rendered. No field, no error, no hint the setting exists. The value still
validates on save and the plugin still reads it, so the only way to set one
was to hand-edit config.json on the device.

Twenty-six settings across seven plugins were in that state:

  ledmatrix-flights   flightaware_api_key + 7 more
  basketball          scroll_card, background_service, both idle intervals
  afl / nrl / soccer  scroll_card, both idle intervals
  masters-tournament  four duration/sizing settings
  f1-scoreboard       customization.auto_scale

Two of those deserve calling out. ledmatrix-flights' flightaware_api_key is
marked x-secret: true -- someone set up masking for a field that could not be
typed into. And the idle-poll intervals are the ones whose plumbing was fixed
in #295 so they would finally take effect; they still could not be set.

These are omissions, not deliberate hiding. Twenty-two of the twenty-six
already carry x-advanced: true, and nobody flags a field "advanced" meaning
"invisible" -- x-advanced is the supported way to de-emphasise one, and it
puts the field in a collapsed Advanced Settings section. There is no
supported way to hide a property and no schema in the repo attempts it.

What hid this for so long is an asymmetry between the two renderers: the
client-side one in app-shell.js sorts unlisted properties into an
unorderedEntries list and still shows them, while the server-rendered form
drops them. The same schema looks fine in one and is unreachable in the
other.

Order-only change: verified per plugin that the schemas are byte-identical
once x-propertyOrder is stripped, so nothing was added, renamed or retyped.

scripts/test_property_order_coverage.py guards it, and does not merely assert
the rule -- it lifts the ordering loop out of the shipped template, renders it
with a two-property schema listing only one, and shows the other never reaches
the form. Mutation-checked: dropping flightaware_api_key back out fails the
check by name. All 52 test suites across the seven plugins exit 0.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e5756c7b-db99-4ea9-8a4a-1c305b5f6d95


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.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 23 complexity

Metric Results
Complexity 23

View in Codacy

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.

@ChuckBuilds
ChuckBuilds merged commit ed90588 into main Aug 19, 2026
4 checks passed
@ChuckBuilds
ChuckBuilds deleted the fix/property-order-coverage branch August 19, 2026 22:39
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.

2 participants