镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Keep plugin manifests ASCII-only; add check_manifests_ascii guard - #578

Merged
ChuckBuilds merged 1 commit into
mainfrom
claude/manifest-ascii
Sep 29, 2026
Merged

ChuckBuilds merged 1 commit into
mainfrom
claude/manifest-ascii

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Eight manifests on main contained raw UTF-8: em dashes, plus baseball's up/down arrows. Every other manifest stores such characters as JSON \uXXXX escapes. This PR converts the eight to escapes and adds a guard so it doesn't happen again. Nothing on the display changes.

Why it matters

Anything that opens manifest.json without encoding= uses the platform's default encoding, which is cp1252 on Windows. That includes LEDMatrix cores before v3.4.0 (load_manifest, used by check_plugin.py) and the core's scripts/dev_server.py on main today. Under cp1252:

  • Most characters garble silently. An em dash reads as —.
  • Some abort the read. A character whose UTF-8 includes a byte cp1252 leaves undefined (81, 8D, 8F, 90, 9D) raises UnicodeDecodeError. A closing curly quote, U+201D, is one.

This has already happened: on-air's description and odds-ticker's 1.1.7 notes carry escaped mojibake (\u00e2\u20ac\u201d) from an earlier round trip. That repair is separate work.

Changes

  • The eight manifests: clock-simple, ledmatrix-weather, pomodoro-timer, and the baseball, basketball, football, lacrosse and soccer scoreboards. The scoreboard ones came in with scoreboards: require core 3.6.1; drop the bundled favourite-check and timezone code (stage 2 sunset) #570/soccer: use core's favourite-team check (2.37.0, requires core 3.6.2) #571. Each non-ASCII character becomes its JSON escape, with surrogate pairs above the BMP.

    • The substitution is text-level, so formatting, key order and line endings are unchanged. Each diff is one changed line per affected note, plus the version bump.
    • json.loads(before) == json.loads(after) was asserted for every file.
  • Versions: each plugin gets a PATCH bump with a new top versions[] entry. ledmatrix_min_version is copied from the previous top entry, and the notes explain the change. plugins.json was synced with update_registry.py.

    Plugin Version
    clock-simple 1.1.3
    ledmatrix-weather 2.7.9
    pomodoro-timer 1.3.9
    basketball-scoreboard 1.40.1
    football-scoreboard 3.17.1
    lacrosse-scoreboard 1.35.1
    soccer-scoreboard 2.38.1
    baseball-scoreboard 1.53.1
  • scripts/check_manifests_ascii.py (new guard): reads each plugins/*/manifest.json as raw bytes. It prints a FAIL line for every non-ASCII character, giving the line, column and escape to write. It also reports a BOM or a byte that isn't valid UTF-8. It fails if it finds fewer than 41 manifests, so a moved tree can't pass by finding nothing. Exit codes: 0 pass, 1 fail.

  • scripts/test_check_manifests_ascii.py (regression suite, 27 checks): runs the guard over the real tree, which is how CI's scripts/test_*.py glob enforces it. It also covers:

    • raw BMP and astral characters
    • BOM
    • cp1252-saved bytes
    • U+0085/U+2028/U+2029, which str.splitlines() would treat as line breaks
    • files other than manifest.json being ignored
    • the plausibility floor
    • that the suggested escapes parse back to the same text

Test plan

  • python scripts/check_manifests_ascii.py: PASS on this branch (46 manifests). Run against unfixed main, it lists all eight files by line and column.
  • python scripts/test_check_manifests_ascii.py: all 27 checks pass.
  • python update_registry.py --check: PASS.
  • python scripts/check_version_bump.py --base origin/main <the 8 ids>: all PASS.
  • python scripts/check_manifest_version_fields.py <the 8 ids>: OK.
  • The eight manifests validate against core main's schema/manifest_schema.json.
  • test_check_version_bump.py, test_update_registry.py, test_check_manifest_version_fields.py: pass.
  • Render harness: not run. Only manifest notes and version fields changed.

Notes for reviewer

  • Weather's registry entry on main read "2.7.8\r". Regenerating it clears the stray CR, which also appears in ten other latest_version values (from Remove code nothing calls (20 plugins) #560). A separate change fixes the rest and teaches update_registry.py --check to catch it, so that PR may conflict on the weather line.
  • Any open PR that bumps one of these five scoreboards will conflict on version.

🤖 Generated with Claude Code

Eight manifests on main carried raw UTF-8 (em dashes, and baseball's
up/down arrows): clock-simple, ledmatrix-weather, pomodoro-timer and five
scoreboards (baseball, basketball, football, lacrosse, soccer; added in
#570/#571). Tools that open manifest.json in the platform default
encoding -- cp1252 on Windows: cores before 3.4.0 and the core's
scripts/dev_server.py -- garble those bytes, or raise UnicodeDecodeError
on characters whose UTF-8 includes a byte cp1252 leaves undefined.
Every other manifest already stores such characters as JSON escapes.

- Rewrite the eight with a text-level substitution to JSON escape
  sequences (formatting, key order and line endings unchanged;
  json.loads before == after), and PATCH-bump each with a new top
  versions[] entry. plugins.json synced by update_registry.py.
- scripts/check_manifests_ascii.py: fails on any raw non-ASCII byte in
  plugins/*/manifest.json, naming line, column and the escape to write;
  also flags a BOM or a legacy-encoded byte, and fails if it finds 40 or
  fewer manifests.
- scripts/test_check_manifests_ascii.py: regression suite, which also
  runs the guard over the real tree so CI's scripts/test_*.py glob
  enforces it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 29, 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: Advanced

Run ID: a65349f3-b4b8-4cea-90a6-6ed5b93175a7


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 25 complexity

Metric Results
Complexity 25

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 8435880 into main Sep 29, 2026
5 checks passed
@ChuckBuilds
ChuckBuilds deleted the claude/manifest-ascii branch September 29, 2026 18:43
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