Skip to content

refactor: make classmap data consistent, validated and generated - #16

Merged
afonsojramos merged 20 commits into
mainfrom
refactor/classmap-json-cleanup
Sep 29, 2026
Merged

afonsojramos merged 20 commits into
mainfrom
refactor/classmap-json-cleanup

Conversation

@afonsojramos

@afonsojramos afonsojramos commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Summary

Makes the published data consistent and machine-checked, and makes a new key something a person or an agent generates rather than hand-writes. No staged class changes for any key.

Data

  • Stock classes only. 27 leaves in 1020099 and 1030000 stored Spicetify css-map names (for example main-contextMenu-menuItemButton). Each is now the one stock hash that the css-map rewrites to that name and that is present in the stock 1.2.99.317 or 1.3.0.277 archive. 1030000 is byte-identical to 1030001 again.
  • One file name, one format. Every key uses classmap.json (the old hex suffix was a 1.2.94 build timestamp reused by four maps with different contents). All JSON has two-space indentation, sorted keys, and no empty placeholder groups. The unindexed 1020040 map, a strict subset of the indexed one, is removed.
  • META.json schema 2. A fixed field set: schema_version, classmap_key, spotify_version, status, generated, source, required_paths (enum statuses), stale_leaves, unverified_leaves, verified_classmap_sha256. Notes, statistics and verification runs move to each key's VERIFICATION.md. Contradictions fixed: 1020099 listed a leaf as both stale and unverified, and claimed stock 1.2.99 ships readable class names (it ships only hashes). The 1.3.0 history gets a correction: its Encore classes are in the stock CSS inside @layer encore, which the static verifier skipped until refactor(scripts): port the classmap capture tooling to TypeScript cli#3973.
  • expose.json records per-build hit counts as a hits object.

Tooling (TypeScript, Node 24.2+, pnpm check)

  • scripts/validate-classmaps.ts runs in CI. It checks layout, canonical form, and META claims against the files: leaves exist, lists agree with required_paths, inherited maps are byte-identical to their source in the same minor, no leaf stores a Spicetify name, and a map changed after verification fails its recorded digest.
  • pnpm publish-key publishes inherited and derived keys from the CLI reports. For a derived key it carries over the source's unchanged stale leaves and the leaves the migrate report kept with a vanished hashed class. It counts a path missing from the stock CSS as observed only through its stock class. It takes --stale, --drop-required, --note and --replace, validates the key and every key inheriting from it, and rolls back the key and index.json on failure.
  • pnpm fix formats every JSON file and rebuilds the index; pnpm fix FILE formats a candidate map.
  • AGENTS.md records the conventions the code doesn't make obvious. The README describes the full pipeline for unchanged patches, changed classes, and fixes to published keys.

Compatibility

  • Shipped CLIs read status, spotify_version, classmap_key and stale_leaves from META and file names from index.json. All are kept, and the index field names are unchanged. Unknown META and patch fields are ignored.
  • The Rust and Go CLIs and the module kit all prefer classmap.json.
  • The module kit needs no change: building every module in spicetify/modules against the old and new 1030001 maps gives byte-identical output (375 files).

Verification

  • pnpm check (tsc, index, validator, expose, 57 tests) passes at every commit.
  • I ran the Rust CLI's own fetch, file selection, stale handling, remap and css-map staging against this branch and against main, both served locally. For every leaf of all 13 keys the staged class is identical, and a cache upgraded from main equals a fresh install.
  • The new JSON renderer reproduces the previous Python output byte for byte for every published file.
  • I ran the documented derived pipeline on real 1.3.0 → 1.3.1 archives (migrate, flatten, verify, publish). Migrate reproduced the published map byte for byte, and the publisher reached the same stale and unverified result as 1030001. For the CDP step I reused a recorded 1.3.1 run with its digest rebound, because I didn't launch a live client.

Merge order

  1. This PR.
  2. chore: follow the spicetify/classmaps schema 2 layout cli#3972, which syncs the CLI's embedded expose.json. Its release gate compares against this repo's published digest.
  3. refactor(scripts): port the classmap capture tooling to TypeScript cli#3973, which ports the CLI's capture tooling to TypeScript.

The hex suffix was a 1.2.94 build timestamp reused by maps with different contents; index.json already records each file and its digest. Drops the unindexed 1020040 map, a strict subset of the indexed one.
…y to VERIFICATION.md

META.json now has a fixed schema_version 2 field set. required_paths uses one status vocabulary, source replaces inherited_from, and notes, statistics, guards and verification runs move to each key's VERIFICATION.md. 1020099 no longer lists its stale upgrade button as unverified, and its notes no longer claim that stock 1.2.99 ships readable class names.
… 2 layout

promote_inherited.py writes META.json and VERIFICATION.md and runs the validator on the new key before publishing it.
Per-build match counts move from prose notes into a hits object. Shipped CLIs ignore unknown patch fields.
publish_key.py replaces promote_inherited.py. A derived key takes a candidate map and overlay, with --stale and --note for the decisions the reports can't make, and gets the same report checks, generated META.json and VERIFICATION.md, validation and index rollback.
@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 0e541dc0-72a0-4284-916e-e197a3a9d36e

📥 Commits

Reviewing files that changed from the base of the PR and between 603e296 and f869d95.

📒 Files selected for processing (48)
  • .github/workflows/index.yml
  • .gitignore
  • 1020038/classmap-1718192021222.json
  • 1020038/classmap.json
  • 1020040/classmap-1906ea8d2e9.json
  • 1020040/classmap-190747c4b8f.json
  • 1020040/classmap.json
  • 1020045/classmap-191b119b48e.json
  • 1020045/classmap.json
  • 1020084/META.json
  • 1020084/VERIFICATION.md
  • 1020084/classmap.json
  • 1020092/META.json
  • 1020092/VERIFICATION.md
  • 1020092/classmap.json
  • 1020094/META.json
  • 1020094/VERIFICATION.md
  • 1020094/classmap.json
  • 1020095/META.json
  • 1020095/VERIFICATION.md
  • 1020095/classmap.json
  • 1020096/META.json
  • 1020096/VERIFICATION.md
  • 1020096/classmap.json
  • 1020097/META.json
  • 1020097/VERIFICATION.md
  • 1020097/classmap.json
  • 1020098/META.json
  • 1020098/VERIFICATION.md
  • 1020098/classmap.json
  • 1020099/META.json
  • 1020099/VERIFICATION.md
  • 1020099/classmap.json
  • 1030000/META.json
  • 1030000/VERIFICATION.md
  • 1030000/classmap.json
  • 1030001/META.json
  • 1030001/VERIFICATION.md
  • 1030001/classmap.json
  • README.md
  • expose.json
  • index.json
  • scripts/build_index.py
  • scripts/promote_inherited.py
  • scripts/test_promote_inherited.py
  • scripts/test_validate_classmaps.py
  • scripts/validate_classmaps.py
  • scripts/validate_expose.py
💤 Files with no reviewable changes (4)
  • 1020040/classmap-1906ea8d2e9.json
  • 1020045/classmap-191b119b48e.json
  • 1020040/classmap-190747c4b8f.json
  • 1020038/classmap-1718192021222.json

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The PR standardizes published classmap files and metadata, adds classmap validation to the workflow and promotion tooling, updates release classmaps and verification records, and stores exposure-patch hit counts in structured fields with stricter validation.

Changes

Classmap publication

Layer / File(s) Summary
Validate classmap releases
scripts/validate_classmaps.py, scripts/test_validate_classmaps.py, .github/workflows/index.yml, .gitignore
Adds validation for release files, classmap structure, canonical JSON, metadata, inheritance, and CSS overlays. The workflow runs the validator, and tests cover valid and invalid releases.
Generate and promote published keys
scripts/build_index.py, scripts/promote_inherited.py, scripts/test_promote_inherited.py, index.json, README.md
Index generation and inherited promotion use shared helpers and canonical JSON. Promotion writes schema-versioned metadata and a verification report, then validates the staged release.
Normalize earlier classmap files
1020038/*, 1020040/*, 1020045/*
Replaces digest-suffixed classmap files with classmap.json in three releases.
Update releases 1020084–1020094
1020084/*, 1020092/*, 1020094/*
Updates classmaps and metadata, and adds verification reports describing checks, mappings, and publication results.
Update releases 1020095–1020098
1020095/*, 1020096/*, 1020097/*, 1020098/*
Reorganizes classmaps, updates per-path metadata, and adds verification reports with publication counts and test observations.
Update releases 1020099–1030000
1020099/*, 1030000/*
Updates selectors and classmaps, records required-path statuses, and adds verification reports for published builds and verification runs.
Update release 1030001
1030001/*
Updates inherited-source metadata and verification records, and changes modal and sort-box selectors in the classmap.

Exposure-patch hit counts

Layer / File(s) Summary
Store and validate hit counts
expose.json, scripts/validate_expose.py, README.md
Moves measured per-build counts from note text into hits objects. The README documents the fields, and the validator checks build keys, count values, notes, and JSON formatting.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant Actions as GitHub Actions
  participant Validator as validate_classmaps.py
  participant Releases as Key release files
  Actions->>Validator: Run classmap validation
  Validator->>Releases: Scan keys and read published files
  Releases-->>Validator: Return classmaps and metadata
  Validator-->>Actions: Return validation status and errors
Loading

Merge Risk: ⚪ Minimal · up to f869d

The canonical filename migration preserves every published release, with consistent metadata and index checksums. No merge-blocking issue was identified; merge after the remaining normal CI checks pass.

Security Architecture Review

Security architecture risk: 🔵 Low · up to f869d

The reviewed changes strengthen consistency checks without establishing a new security weakness. Risk remains low rather than minimal because compatibility with the external client and recovery from interrupted or concurrent publication are not fully demonstrated.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The documented distribution boundary can affect downstream client rewriting: classmaps are selected by client version, while exposure patches are shared across builds. Actual client acceptance and fallback behavior remain bounded by documentation because the consumer implementation was not supplied.

Trust Boundaries and Controls

  • observed — Index entries bind named release files to SHA-256 digests. Promotion additionally compares operator-supplied verification reports to the source map digest and expected source identity. These consistency checks predate the PR; they do not independently authenticate report authors or the publisher.
  • observed — The new publication checks reject semantic Spicetify names in stock classmap leaves and inconsistent inherited bytes. CI scans release directories independently, while promotion applies the same validation to the staged target before publication.

Resilience and Maintainability Implications

  • observed — Separate release publication and index generation, with exception-based rollback, already existed at the base revision. The PR adds staged-content validation but does not introduce transaction-wide locking or interruption recovery; those existing limitations are not retained as newly introduced concerns.

Hardening Proposals

  • proposed — If concurrent publishers or process interruption are supported operational conditions, serialize publication and add atomic index replacement plus recovery reconciliation so downstream consumers receive a coherent release/index pair.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 47 functions across 6 files. (38 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: classmap consistency, validation, and generation. It is concise and specific.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 47 functions across 6 files. (38 skipped: 38 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

A rabbit checks each map with care
Then hops through keys from here to there
The counts now sit in fields aligned
Each release leaves its notes behind
The validator gives a nod
And bounds along the garden sod.

Comment @coderabbitai help to get the list of available commands.

Node 24 runs the scripts directly, pnpm check runs tsc and every data check, and CI installs the pinned toolchain. The JSON renderer is byte-identical to the Python one for every published file.
renderJson sorts keys by code point, integer-like keys included. Files must be valid UTF-8, a null onMiss is rejected as the CLI would, Rust-style named groups and leading flags compile, each check reports its own failure, and pnpm fix FILE formats a single file. The scripts require Node 24.2 for import.meta.main.
… to their verified map

A derived key keeps its source's unchanged stale leaves and the migrate leaves whose hashed classes left the stock CSS. A path missing from that CSS counts as observed only through its stock class. --drop-required, --replace and --overlay cover the remaining decisions, and META.json records verified_classmap_sha256 so a map edited after verification fails validation. VERIFICATION.md records the classmap, overlay and target CSS digests.
@afonsojramos afonsojramos changed the title refactor: make classmap data consistent and validated refactor: make classmap data consistent, validated and generated Sep 29, 2026
@afonsojramos
afonsojramos merged commit 2198fa6 into main Sep 29, 2026
3 checks passed
@afonsojramos
afonsojramos deleted the refactor/classmap-json-cleanup branch September 29, 2026 23:23
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