The data file nobody loads
TLDR
We built a feature against window.COMPONENT_SPECS, a lookup table that its own header comment said was "loaded only in electrical/index.html." A grep for the script tag found zero matches anywhere: the file existed, was maintained, was referenced by design docs, and was never loaded by any page. Every consumer had silently degraded to its fallback path. The fix is one script tag; the prevention is treating "is this asset actually loaded" as a checkable claim, not a comment.
The bug class
Script-tag codebases (no bundler, no import graph) have an invisible failure mode: a file's inclusion is asserted nowhere the machine can verify. With ES modules or a bundler, an unimported file is either dead code your tooling flags or a build error. With <script src> loading, a file can be:
- present in the repo,
- edited and improved over time,
- named in comments and architecture docs as "loaded by X",
<script> tag that would load it was never written, or was deleted in a refactor nobody connected to it.
The symptom is not an error. Consumers written defensively (window.COMPONENT_SPECS || {}) run fine with empty data. Features quietly do less than designed, forever.
The concrete instance
Our component spec table (pin counts, pin names, key parameters, typical values per symbol type) carried this header:
/* Component Specs โ Electrical Domain Lookup Table
Keyed by data-symbol attribute value.
Loaded only in electrical/index.html; other domains are unaffected. */
window.COMPONENT_SPECS = { resistor: { pinCount: 2, ... }, ... };
While wiring a new rule engine that needed pin counts, we checked where the file was included:
$ grep -rn "component-specs" --include='.html' --include='.js' .
(no results)
Nothing. The comment described an inclusion that did not exist, probably a page structure from an earlier layout that a later consolidation removed. An existing feature that read the specs (a pin-linting pass) had been running against undefined and taking its fallback branch the whole time.
The fix
One line in the page that hosts the editor, ordered before its consumers:
<script src="/assets/schema-editor/data/component-specs.js"></script>
<script src="src/js/features/ercEngine.js"></script>
And the stale claim in the file header should die with it, because a comment that asserts loading behavior is exactly the artifact that rotted here.
Preventing the class
Verify inclusion at the consumer, loudly, once. Defensive fallbacks (|| {}) are right for runtime, wrong as the only signal. Add a one-time dev-console warning when a designed-for dependency is absent:
if (!window.COMPONENT_SPECS) console.warn('[erc] COMPONENT_SPECS not loaded โ spec rules inert');
Grep before building on a global. Two greps, ten seconds: one for the definition, one for the script tag that loads it. We found this bug only because the new feature's author happened to run the second grep.
Prefer the machine-checked claim. Any file that can move to a real module import should, eventually, because an import is a loading assertion the toolchain enforces. Where script tags must stay (no-build constraints), a startup manifest check that asserts expected globals exist turns silent degradation into a visible warning.
The lesson
In a no-bundler codebase, "the file exists" and "the file runs" are unrelated facts, and only one of them is visible in a code review. Every window.X consumer is a claim that some HTML file loads X; treat that claim like the dependency it is and verify it in code, because comments about loading behavior are where the truth was, not where it is.