LearnNewsExamplesServices
Frontmatter
id17900
titleThe build-once, watch-before-editing theme workflow is undocumented
stateClosed
labels
documentationaibuild
assigneesneo-opus-grace
createdAtAug 31, 2026, 1:04 AM
updatedAtAug 31, 2026, 8:31 AM
githubUrlhttps://github.com/neomjs/neo/issues/17900
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 31, 2026, 8:31 AM

The build-once, watch-before-editing theme workflow is undocumented

Closed v13.2.0/archive-v13-2-0-chunk-17 documentationaibuild
neo-opus-grace
neo-opus-grace commented on Aug 31, 2026, 1:04 AM

RESTATED 2026-08-31 — the original shape was wrong and @tobiu killed it correctly. This was filed as "expose the freshness inspector as a standalone npm run check-themes". That premise does not survive one question. The command, its spec, its package script and its Contract Ledger are all withdrawn; what remains is the documentation gap, which is the only part that was ever real. Original framing preserved below the fold for the record.

Context

Neo's development mode serves JS from source (native ES modules, always current) and CSS from a built dist/ (only as fresh as the last theme build). A stale build therefore renders current JS against an older stylesheet — confidently wrong, and the first suspect is always product code.

That has cost real diagnosis time three times: twice on 2026-07-21 (recorded in #15666's Context) and again in #17890, where eight candidate causes were eliminated in source before the build was suspected.

The Problem — it is a documentation gap, not a tooling gap

There is a workflow that makes the stale state impossible, and it was never written down:

  1. npm run build-themes on a fresh checkout, and after any pull or branch switch that brings someone else's SCSS — the compiled CSS is gitignored, so it never travels.
  2. npm run watch-themes before editing SCSS, left running — it recompiles what you touch, so the build cannot fall behind your sources.

Measured, both directions:

tree state npm run watch-themes
stale throws — names every stale/missing output and prints DEVELOPMENT_THEME_BUILD_COMMAND, non-zero exit (assertThemeWatcherReady)
fresh starts watching

So on the case that matters, watch-themes already is the freshness check, with the same information and the same remedy. All three incidents were people who did not know the workflow — including the agent diagnosing the third.

Why the original prescription was withdrawn

It proposed a standalone read-only query on the premise that "there is no way to ask the inspector a question without starting a server, a watcher, or a test suite." Literally true; practically irrelevant. Nobody needs to ask the question, because the workflow prevents the state. A diagnostic for a state that should not exist is worse than none — it implies the state is expected, and it competes with the habit that actually prevents it.

#15585 (watchThemes: handle add/rename/delete events) is CLOSED/COMPLETED, so the watcher now handles rename as well as change; the July limitation that would have argued for a separate query no longer holds either.

The Fix

Document the workflow in learn/guides/uibuildingblocks/StylingAndTheming.md §3, where the build-vs-source mental model forms. No new command, no new script, no new detection logic.

Acceptance Criteria

  • The theming guide states that the browser reads a build, not your SCSS, and gives the two-step workflow — build-themes on a fresh checkout and after incoming SCSS, watch-themes before editing.
  • It explains that a watcher refusing to start against a stale build is the feature, not a bug.
  • It records that the server-start freshness warning is a dev-server feature no other static host provides.
  • It records that a green test suite is not evidence about your browser — e2e and component materialize their own assets, the visual suite refuses to run, and neither says anything about your dist/.
  • Every factual claim above is anchored to a file:line in the checkout at PR time.

Out of Scope

  • Any new command. That was the error this restatement corrects.
  • Changing how themes are built, or making a server rebuild automatically.
  • Wiring theme materialization into the unit suite — it renders nothing and has no globalSetup.

Avoided Traps

  • Building a detector for a state a workflow prevents. The tooling was complete; the habit was undocumented. Asking "what workflow makes this not happen?" before "what detects it?" would have produced this ticket directly.
  • Sweeping only GitHub for prior art. A dup sweep over issues found #15666 and correctly avoided a duplicate ticket — but the operator's workflow rationale lived in Memory Core, never in a ticket. A GitHub sweep answers does a ticket exist; an MC sweep answers what did we decide, and why. The second one was skipped.

Related

  • #15666 — dev-server warning (CLOSED/COMPLETED).
  • #15585 — watcher add/rename/delete coverage (CLOSED/COMPLETED).
  • #15449 — materialize fresh development themes before source-mode e2e.
  • #17890 — the third occurrence and the worked example.

Origin Session ID: 56bc214a-5b55-41a2-848a-cdfa372abbcd

Retrieval Hint: "build-themes once then watch-themes before editing scss; stale dist renders old CSS against new JS"

tobiu referenced in commit 07941f6 - "docs(theming): teach the build-once, watch-before-editing workflow (#17900) (#17902) on Aug 31, 2026, 8:31 AM
tobiu closed this issue on Aug 31, 2026, 8:31 AM