Skip to main content

max / makenotwork

server: the globals seal counts bare top-level functions Closes 82315c45. HIGH_WATER 106 -> 161, and that is a restatement, not a ratchet raise: the surface did not change, what the test can see did. Both existing rules match an assignment. A classic script does not need one -- a bare top-level `function foo() {}` becomes a property of the global object just by being declared. All 61 `<script src>` tags in templates/ are classic, none carry type="module", so all 55 of those declarations in static/*.js were globals this seal could not see. Found by deleting one. tab-item-sales.js declared exactly one function, was called by name from data-action, and went whole in 1ea96868. The seal did not move. Same false-progress failure as 7df1a7de, which matters here because this number is what S4 is judged by: a batch can retire real globals and report nothing. The rule is per tree and that is the point. A top-level function in an ES module under frontend/src is scoped to the module, so the new counter runs only over static/*.js while the window-assignment counter runs over both. Applying it everywhere would charge the typed tree for the surface it exists to remove. Column zero is the whole test for "top level". Every one of the 55 is written that way, and a declaration indented inside an IIFE is correctly not counted -- that is a function scope, not the global object. 161 verified exactly by forcing the seal to zero and reading the count back, not inferred from the arithmetic.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-26 23:39 UTC
Signed with PGP, not checked
Commit: 8ed9ad799f772bb5bd2f438f1c4af0fe7b119cba
Parent: fa70138
1 file changed, +103 insertions, -6 deletions
@@ -25,7 +25,32 @@
25 25 //! Both halves are fixed here: both trees are read, and an alias bound to
26 26 //! `window` in a file is followed within that file. `HIGH_WATER` was restated
27 27 //! once against the corrected measurement, which is not the same act as raising
28 - //! it. It has not moved since and must not.
28 + //! it.
29 + //!
30 + //! # The third gap, and the number moved a second time
31 + //!
32 + //! Problem `82315c45`, 2026-08-26. The two rules above both match an
33 + //! *assignment*, and a classic script does not need one: a bare top-level
34 + //! `function foo() {}` becomes a property of the global object just by being
35 + //! declared. Every `static/*.js` file is loaded by a plain `<script src>` --
36 + //! all 61 tags in `templates/`, none carrying `type="module"` -- so all 55 of
37 + //! those declarations were globals this test could not see.
38 + //!
39 + //! Found by deleting one. `static/tab-item-sales.js` declared exactly one
40 + //! function, was called by name from `data-action`, and went whole in
41 + //! `1ea96868`. The seal did not move, which is the same false-progress failure
42 + //! `7df1a7de` was about, wearing a different hat.
43 + //!
44 + //! **The rule is per tree, and that is the point.** A top-level function in an
45 + //! ES module under `frontend/src` is scoped to the module and is not a global,
46 + //! so [`count_script_globals`] runs only over `static/*.js` while
47 + //! [`count_globals`] runs over both. Applying it everywhere would have counted
48 + //! the typed tree's own functions as the surface the typed tree exists to
49 + //! remove.
50 + //!
51 + //! `HIGH_WATER` was restated a second time against this. Neither restatement
52 + //! raised the ratchet: both corrected what it can see. It must not move for any
53 + //! other reason.
29 54
30 55 use std::fs;
31 56 use std::path::{Path, PathBuf};
@@ -76,7 +101,11 @@
76 101 /// `saveLinkBtn` and `cancelLinkBtn` existed only because one template would
77 102 /// not include the other. The include is the whole fix; the row's surviving
78 103 /// verbs live in `actions-partials.js` and serve both paths.
79 - const HIGH_WATER: usize = 106;
104 + /// 161 on 2026-08-26, the second restatement and not progress. Problem
105 + /// `82315c45`: 55 bare top-level `function` declarations in `static/*.js` are
106 + /// globals in a classic script and had never been counted. 106 + 55 = 161. The
107 + /// surface did not change that day either; what this test can see did.
108 + const HIGH_WATER: usize = 161;
80 109
81 110 /// Every file whose global assignments count: the legacy scripts and the typed
82 111 /// modules that replaced them.
@@ -134,6 +163,28 @@
134 163 }
135 164 }
136 165
166 + /// Count bare top-level function declarations, in one CLASSIC-script file.
167 + ///
168 + /// `82315c45`. A `<script src>` with no `type="module"` shares the global
169 + /// scope, so `function foo() {}` at the top level of one lands `foo` on the
170 + /// global object without ever writing an assignment. Neither rule in
171 + /// [`count_globals`] can see that, and 55 of this server's globals are that
172 + /// shape.
173 + ///
174 + /// **Only for `static/*.js`.** The same declaration in an ES module under
175 + /// `frontend/src` is scoped to the module and is not a global, so counting it
176 + /// there would charge the typed tree for the surface it exists to remove.
177 + fn count_script_globals(src: &str) -> usize {
178 + // Column zero is the whole test for "top level", and it is enough because
179 + // every one of the 55 is written that way. A declaration indented inside an
180 + // IIFE is correctly not counted: that is a function scope, not the global
181 + // object. A regex cannot know the difference and does not have to.
182 + regex::Regex::new(r"(?m)^(?:async )?function [A-Za-z_][A-Za-z0-9_]*\s*\(")
183 + .unwrap()
184 + .find_iter(src)
185 + .count()
186 + }
187 +
137 188 /// Count assignments that land a name on `window`, in one file.
138 189 ///
139 190 /// Two forms, because the code uses two. The direct `window.foo = …` is what
@@ -144,6 +195,9 @@
144 195 /// The alias is followed only inside the file that binds it, and only when it
145 196 /// was bound to `window` itself, so a local named `w` holding anything else
146 197 /// contributes nothing.
198 + ///
199 + /// Runs over both trees, unlike [`count_script_globals`]: an assignment to
200 + /// `window` is a global wherever it is written.
147 201 fn count_globals(src: &str) -> usize {
148 202 // `=[^=]` matches an assignment `=` while excluding the first `=` of a
149 203 // comparison operator. The regex crate has no lookahead, so this is the
@@ -168,18 +222,61 @@
168 222 fn frontend_globals_do_not_grow() {
169 223 let count: usize = sources()
170 224 .iter()
171 - .map(|path| count_globals(&fs::read_to_string(path).unwrap_or_default()))
225 + .map(|path| {
226 + let src = fs::read_to_string(path).unwrap_or_default();
227 + // A bare top-level function is a global only in a classic script,
228 + // which is what `static/` holds and `frontend/src` does not. See
229 + // `count_script_globals`.
230 + let classic = path.parent().and_then(Path::file_name) == Some("static".as_ref());
231 + count_globals(&src)
232 + + if classic {
233 + count_script_globals(&src)
234 + } else {
235 + 0
236 + }
237 + })
172 238 .sum();
173 239
174 240 assert!(
175 241 count <= HIGH_WATER,
176 - "global assignments across static/*.js and frontend/src rose to {count} \
242 + "globals across static/*.js and frontend/src rose to {count} \
177 243 (HIGH_WATER {HIGH_WATER}). New frontend code must be a typed ES module in \
178 - frontend/src registered through the dispatcher, not a global. If you REMOVED \
179 - globals, lower HIGH_WATER to {count}."
244 + frontend/src registered through the dispatcher, not a global -- and note \
245 + that a bare top-level `function` in a classic script is one too. If you \
246 + REMOVED globals, lower HIGH_WATER to {count}."
180 247 );
181 248 }
182 249
250 + #[test]
251 + fn the_seal_sees_a_bare_top_level_function_in_a_classic_script() {
252 + // `82315c45`. The shape that was invisible until 2026-08-26: no assignment
253 + // anywhere, and `exportItemSalesCSV` was still a global the dispatcher
254 + // called by name.
255 + assert_eq!(
256 + count_script_globals("function exportItemSalesCSV() {\n}\n"),
257 + 1
258 + );
259 + assert_eq!(count_script_globals("async function loadThing(id) {}"), 1);
260 +
261 + // Two shapes that are NOT the global scope, and must not be counted.
262 + assert_eq!(
263 + count_script_globals("(function () {\n function inner() {}\n})();"),
264 + 0,
265 + "a declaration inside an IIFE is a function scope"
266 + );
267 + assert_eq!(count_script_globals("const f = function named() {};"), 0);
268 + }
269 +
270 + #[test]
271 + fn the_two_counters_do_not_double_count_one_name() {
272 + // A file that both declares and assigns is two globals by two routes, and
273 + // the seal should say two rather than collapsing them. The point is that
274 + // neither counter reaches into the other's shape.
275 + let src = "function draw() {}\nwindow.draw = draw;\n";
276 + assert_eq!(count_script_globals(src), 1);
277 + assert_eq!(count_globals(src), 1);
278 + }
279 +
183 280 #[test]
184 281 fn the_seal_sees_a_global_assigned_through_an_alias() {
185 282 // The hole `7df1a7de` names, as a unit. Without this the count is a