From 89adc16e95c9e6a134a560a52b6f7d1589266d5f Mon Sep 17 00:00:00 2001 From: Devin Michael <110886466+next-devin@users.noreply.github.com> Date: Fri, 25 Sep 2026 18:04:40 +0700 Subject: [PATCH] docs: keep internal fleet detail out of the public changelog and TODOs Generalize the changelog's rationale, drop the two TODOs that describe internal tooling, and neutralize one test comment. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 2 +- TODOS.md | 14 +------------- tests/test_theme_contract.py | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bac44f8..ed37aa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ The GitHub release body is a summary, not a copy of the changelog section. Write ## Unreleased -- Every `theme-contract.json` requirement now carries a required `scope`, and `scripts/check-theme-contract.py` enforces it. `fleet` binds every Spark-derived store theme and is what a live check (`--store` + `--theme-id`) enforces by default; `spark` binds Spark's own working copy and is what a local check (`--root`, CI, `make contract`) enforces by default, on top of the fleet rules. `--scope fleet|spark` overrides either default, and the gate's output names the scope and how many requirements ran. `pixels` is the only fleet rule; the four runtime hooks #66 added in 1.5.0 without a changelog line (`cart-badge`, `mobile-nav-toggle`, `mobile-nav`, `cart-drawer`; the 1.5.0 entry below still describes the contract as `pixels` only) are scoped to Spark. The first fleet sweep against 1.5.0 reported nine of thirteen live Spark themes failing `mobile-nav` on the file rule alone, while four of those storefronts served `#mobile-nav` from another file: derived themes are forks that may carry a hook elsewhere, and a file-location rule against the fleet reports forks, not faults. Decided 2026-09-21. `docs/theme-contract.md` lists all five rules with their scope, the rule for promoting one to `fleet`, and the invocation for each case: a fork's working copy (`--root ../fork --scope fleet`), a derived live theme (default), and Spark's own copy on a dev store (`--scope spark`, since a live check otherwise assumes a derived theme). +- Every `theme-contract.json` requirement now carries a required `scope`, and `scripts/check-theme-contract.py` enforces it. `fleet` binds every Spark-derived store theme and is what a live check (`--store` + `--theme-id`) enforces by default; `spark` binds Spark's own working copy and is what a local check (`--root`, CI, `make contract`) enforces by default, on top of the fleet rules. `--scope fleet|spark` overrides either default, and the gate's output names the scope and how many requirements ran. `pixels` is the only fleet rule; the four runtime hooks #66 added in 1.5.0 without a changelog line (`cart-badge`, `mobile-nav-toggle`, `mobile-nav`, `cart-drawer`; the 1.5.0 entry below still describes the contract as `pixels` only) are scoped to Spark. 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/theme-contract.md` lists all five rules with their scope, the rule for promoting one to `fleet`, and the invocation for each case: a fork's working copy (`--root ../fork --scope fleet`), a derived live theme (default), and Spark's own copy on a dev store (`--scope spark`, since a live check otherwise assumes a derived theme). ## 1.5.0 - 2026-09-21 diff --git a/TODOS.md b/TODOS.md index cd9b800..4ccbf82 100644 --- a/TODOS.md +++ b/TODOS.md @@ -6,19 +6,7 @@ **Priority:** P1 **Effort:** S **What:** `scripts/check-theme-contract.py` masks only DTL comments (`{# #}`, `{% comment %}`, `{% verbatim %}`) before searching for a requirement's `must_contain`. A live theme carrying `` passes the `pixels` rule while the browser discards the rendered tracker iframes, so the storefront emits no events. Wrap the checker's mask with an HTML-comment mask (checker-side only; `check-templates.py`'s masking has other consumers) and add the negative test. `{% if False %}{% pixels %}{% endif %}` also passes and is not text-fixable; document it under "Verifying on a storefront". -**Why:** `pixels` is now the only fleet-scoped rule, so this is the whole fleet sweep's blind spot. Surfaced by the adversarial pass on the contract-scope PR, 2026-09-21. - -### Theme contract: harden the live check's transport -**Priority:** P2 -**Effort:** S -**What:** `read_remote_sources` uses the default `urllib` opener, so a 30x from the store forwards the `Authorization: Bearer` header to the redirect target, and `--store` accepts any URL scheme. Assert `https://` and install a non-following redirect handler. Also confirm the templates endpoint is unpaginated at the largest theme size (the checker reads `results` and never follows `next`), and quote remote template names in violation lines so a name containing a newline cannot fabricate a second `- [` line. -**Why:** Pre-existing, but the unattended fleet sweep runs this against every store twice a week with a real admin key. - -### Fleet sweep: pass `--scope fleet` explicitly and record the applied count (next-mind) -**Priority:** P2 -**Effort:** S -**What:** `next-mind/scripts/spark_fleet_check.py` invokes the checker with no `--scope`, discards stdout (where the "N of M requirement(s)" line goes), and turns any non-violation exit-1 (scope refusal, traceback on a malformed API entry) into a `failing_active` row. Pass `--scope fleet`, capture the applied count into the fleet JSON and ledger, and distinguish infrastructure errors from violations (a separate exit code from the checker would help). -**Why:** The sweep now depends on an implicit default that this repo changed under it; the ledger should say which rules ran. +**Why:** `pixels` is now the only fleet-scoped rule, so a commented-out tag is the one way a derived theme can pass the contract while serving no tracker. ### Preview mode placeholder suppression **Priority:** P2 diff --git a/tests/test_theme_contract.py b/tests/test_theme_contract.py index 4ae7d3a..7308d80 100644 --- a/tests/test_theme_contract.py +++ b/tests/test_theme_contract.py @@ -375,7 +375,7 @@ def test_fleet_scope_on_a_live_theme_matches_the_default(self): self.assertIn("fleet scope, 1 of 5 requirement(s)", result.stdout) def test_fleet_sweep_invocation_uses_env_key_and_sparks_own_contract(self): - # The next-mind fleet sweep runs exactly this: --store and --theme-id, + # A fleet sweep runs exactly this: --store and --theme-id, # the key in $NTK_APIKEY, no --contract and no --scope. It must land on # Spark's shipped contract at the fleet scope and pass a fork. with serve_theme(FORK_WITHOUT_SPARK_HOOKS) as base_url: