Skip to content

Scope theme-contract requirements: pixels binds the fleet, runtime hooks bind Spark - #71

Merged
next-devin merged 3 commits into
mainfrom
contract-scope
Sep 25, 2026
Merged

next-devin merged 3 commits into
mainfrom
contract-scope

Conversation

@next-devin

@next-devin next-devin commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Scopes the theme contract so pixels is the only rule that binds Spark-derived themes, and the four runtime hooks #66 added bind Spark's own copy only.

Contract scope

  • Every theme-contract.json requirement now carries a required scope: fleet (every Spark-derived store theme) or spark (Spark's own working copy). A missing, empty, or unknown scope is a load error, never a default.
  • scripts/check-theme-contract.py enforces it: a live check (--store + --theme-id) defaults to fleet rules, a working-copy check (--root, CI, make contract) defaults to all rules, and --scope fleet|spark overrides either. The output names the scope and how many requirements ran (fleet scope, 1 of 5 requirement(s)), and a scope that selects nothing refuses rather than passing.
  • Why: derived themes are forks that may carry a hook in a different file, so a file-location rule applied to them reports forks, not faults.

Docs

  • docs/theme-contract.md lists all five rules with their scope, explains the two scopes and the rule for promoting one to fleet, and shows the command for a fork's working copy (--scope fleet), a derived live theme (default), and Spark's own copy on a dev store (--scope spark). The Makefile contract comment says the same.

Bookkeeping

  • CHANGELOG.md Unreleased entry (no version bump: Spark moves its version only in release PRs).
  • TODOS.md: mask HTML comments in the checker's needle search (P1), so a commented-out {% pixels %} cannot pass.

Tests

tests/test_theme_contract.py 23 → 33 tests: scope load errors (missing / empty / unknown / wrong case), both defaults, both overrides, empty-selection refusal, fleet-scope checks local and remote, spark-only files absent on a live theme, and report lines carrying scope and count. The remote tests use a stub admin API that rejects the wrong path or key, so a URL or header regression fails instead of passing.

Test plan

  • python3 -m unittest discover -s tests: 128 tests OK
  • make verify-theme: css-check + tests + contract gate passed (spark scope, 5 of 5 requirement(s))
  • python3 scripts/check-templates.py / check-settings-parity.py: both CI gates pass
  • Negative control: stub API with the wrong key or theme id → checker exits 1 with "could not read theme"

🤖 Generated with Claude Code

next-devin and others added 3 commits September 21, 2026 22:21
…n copy

Every requirement in theme-contract.json now carries a required `scope`.
`fleet` binds every Spark-derived store theme; `spark` binds Spark's own
working copy only. check-theme-contract.py validates the field, enforces
only fleet rules by default for a live theme (--store/--theme-id) and all
rules by default for a working copy (--root), and takes --scope to
override either. The gate's output names the scope and how many
requirements ran, and a scope that selects nothing refuses rather than
passing.

`pixels` is the only fleet rule. The four runtime hooks #66 added
(cart-badge, mobile-nav-toggle, mobile-nav, cart-drawer) are scoped to
Spark: the first fleet sweep reported nine of thirteen live themes failing
mobile-nav on the file rule while four of them served #mobile-nav from
another file. Derived themes are forks; a file-location rule against the
fleet reports forks, not faults.

Tests cover both defaults, both overrides, the load errors, the empty
selection, the block-override rule at fleet scope, and the exact
invocation the next-mind fleet sweep makes, against a stub admin API that
rejects the wrong path or key.
theme-contract.md lists all five rules with their scope, explains why the
runtime hooks bind Spark only, states the rule for promoting one to fleet,
and shows the command for a fork's working copy, a derived live theme, and
Spark's own copy on a dev store. The Makefile contract target's comment
says the same.
Unreleased entry for the scope field. TODOs for the three findings the
pre-landing adversarial pass surfaced and this change does not take on:
HTML-comment masking in the needle search, live-check transport hardening,
and the fleet sweep passing --scope fleet explicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kilo-code-bot

kilo-code-bot Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Reviewed all 7 changed files against the PR's stated scope (split theme-contract.json requirements into fleet and spark scopes, plumb --scope through the checker, document and test both defaults plus both overrides). The change introduces one new module-level symbol set (SCOPE_FLEET/SCOPE_SPARK/SCOPES), one new function (select_requirements), a report() signature change, a check_sources() signature change, and a main() defaults/empty-selection block. The JSON gains a required scope field on each of the five requirements, the docs gain a scope column and a ## Two scopes section, and the Makefile/CHANGELOG gain scope-related guidance.

Walked every changed file and the test file (10 new tests cover scope load errors, both defaults, both overrides, empty-selection refusal, block-override at fleet scope, the exact next-mind fleet-sweep invocation, and stderr shape) and confirmed:

  • load_contract rejects missing, empty, unknown, and wrong-case scope values with a message that names the valid scopes, matching test_unknown_scope_error_names_the_valid_scopes.
  • select_requirements raises on an unknown scope (rather than degrading) and returns the filtered list per scope; the spark branch returns all rules (including fleet) so Spark's own copy is held to the fleet standard.
  • The empty-selection check fires before the network call, which test_live_theme_with_no_fleet_rules_refuses_before_reading_the_store verifies via a discarded-port store URL.
  • The report() output names the scope and the N of M count; the stderr line shape (- [id] detail) is preserved for the next-mind parser per test_fleet_sweep_sees_only_fleet_violations_on_stderr.
  • The stub admin API rejects wrong paths (404) and missing/wrong Bearer keys (401), so checker URL/header regressions surface as could not read theme rather than a false pass.

The three concerns the author flagged and deferred in TODOS.md (HTML-comment masking in the needle search, live-check transport hardening, fleet sweep passing --scope fleet explicitly) are pre-existing outside this PR's scope; not raised here as new findings.

Files Reviewed (7 files)
  • CHANGELOG.md
  • Makefile
  • TODOS.md
  • docs/theme-contract.md
  • scripts/check-theme-contract.py
  • tests/test_theme_contract.py
  • theme-contract.json

Reviewed by minimax-m3 · Input: 0 · Output: 0 · Cached: 0

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