Skip to main content

max / makenotwork

Park the CSS seal and fold the duplicated copy and toast helpers The seal: hand-written CSS is 340 KiB against a sealed 337, and the test asserts equality, so it fires on a decrease as well as an increase. Mid conversion that means re-baselining every batch, which measures nothing. Parked with #[ignore] rather than deleted, CSS_KIB_HIGH_WATER kept as the record of where the conversion started, and the exit condition written down: the conversion finished and the duplicated CSS gone. the_two_lists_agree stays active, since bytes moving to an unweighed sheet is a different failure. Max, 2026-08-18. Six copy buttons hand-rolled the label revert that core/clipboard.ts already does through its resetMs parameter. They now call it through the legacy bridge. Durations preserved per site, including the one that waits 2000ms where the others wait 1500: which is right is a question for the semantic-timing work, not for a consolidation pass. The error toast in htmx-glue carried a verbatim copy of toast.ts's dismissal timers. Extracted as autoDismiss(toast, lifetimeMs), with the lifetime still the caller's: 3000 for an ordinary toast, 6000 for one carrying a Retry button. The audit's fourth claim does not hold: there is one debounce helper (core/tabs.ts), not four. The other four are timer handles named debounce, used inline. Left alone, since folding them would add a global to a bridge whose purpose is to lose entries. GoingsOn mnw-server 2d01900f, 033c722f.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-18 18:16 UTC
Signed with PGP, not checked
Commit: 4c2fd4e2fe125f703a4c1d597b09d8acb56eae9f
Parent: 6d9f5ea
6 files changed, +76 insertions, -27 deletions
@@ -97,7 +97,7 @@
97 97 };
98 98
99 99 window.copyKeyCode = function (code) {
100 - navigator.clipboard.writeText(code); this.textContent = 'Copied!'; setTimeout(() => this.textContent = code, 1500);
100 + window.copyWithFeedback(this, code, 'Copied!', 1500);
101 101 };
102 102
103 103 window.toggleContextMenuBtn = function (itemId) {
@@ -130,11 +130,14 @@
130 130 };
131 131
132 132 window.copyElementText = function (id) {
133 - navigator.clipboard.writeText(document.getElementById(id).textContent).then(() => { this.textContent = 'Copied'; setTimeout(() => this.textContent = 'Copy', 1500); });
133 + window.copyWithFeedback(this, document.getElementById(id).textContent, 'Copied', 1500);
134 134 };
135 135
136 + // 2000ms here rather than the 1500 every other copy button uses. Preserved as
137 + // found: which of the two is right is a question for the semantic-timing work,
138 + // not for a consolidation pass.
136 139 window.copyFeedUrl = function () {
137 - navigator.clipboard.writeText(document.getElementById('feed-url').value).then(() => { this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy URL', 2000); });
140 + window.copyWithFeedback(this, document.getElementById('feed-url').value, 'Copied!', 2000);
138 141 };
139 142
140 143 // --- user_media.html ---
@@ -29,21 +29,13 @@
29 29 btn.className = className;
30 30 btn.textContent = 'Copy';
31 31 btn.addEventListener('click', function () {
32 - navigator.clipboard.writeText(text).then(function () {
33 - btn.textContent = 'Copied';
34 - setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
35 - });
32 + window.copyWithFeedback(btn, text, 'Copied', 1500);
36 33 });
37 34 return btn;
38 35 }
39 36
40 37 window.syncKitCopyKey = function (event, key) {
41 - navigator.clipboard.writeText(key).then(function () {
42 - var btn = event.target;
43 - var orig = btn.textContent;
44 - btn.textContent = 'Copied';
45 - setTimeout(function () { btn.textContent = orig; }, 1500);
46 - });
38 + window.copyWithFeedback(event.target, key, 'Copied', 1500);
47 39 };
48 40
49 41 window.syncKitRegenKey = function (appId) {
@@ -5,11 +5,7 @@
5 5 var itemTitle = cfg.dataset.itemTitle;
6 6
7 7 window.copyEmbed = function(btn) {
8 - const code = btn.previousElementSibling.textContent;
9 - navigator.clipboard.writeText(code).then(() => {
10 - btn.textContent = 'Copied!';
11 - setTimeout(() => btn.textContent = 'Copy', 1500);
12 - });
8 + window.copyWithFeedback(btn, btn.previousElementSibling.textContent, 'Copied!', 1500);
13 9 };
14 10
15 11 window.switchCardLayout = function(layout) {
@@ -7,6 +7,14 @@
7 7 //! and that is currently the largest standing cost of the conversion, paid on
8 8 //! every page load by every visitor including signed-out ones.
9 9 //!
10 + //! # Parked, 2026-08-18
11 + //!
12 + //! The ratchet below is `#[ignore]`d by Max's ruling until the conversion is
13 + //! finished and the duplicated CSS is gone. Everything this doc argues still
14 + //! holds and none of it is retracted; see the test's own doc comment for why the
15 + //! enforcement was suspended anyway, and for what turns it back on.
16 + //! `the_two_lists_agree` is unaffected and still runs.
17 + //!
10 18 //! # Why this seal exists rather than a note saying the same thing
11 19 //!
12 20 //! The conversion's payoff is the hand-written sheet shrinking. Without a
@@ -83,7 +91,42 @@
83 91 (each.iter().map(|(_, bytes)| bytes).sum(), each)
84 92 }
85 93
94 + /// Parked by Max on 2026-08-18, and the module doc above argues against parking
95 + /// it, so the argument gets answered rather than ignored.
96 + ///
97 + /// What the doc says: a guard people edit rather than read is not a guard, and
98 + /// without a number "we converted a screen" and "we removed its cost" are the
99 + /// same claim. Both points stand. What they do not survive is the assertion
100 + /// pair below: this test fails on any decrease as well as any increase, so mid
101 + /// conversion it fires on work going in the direction it exists to reward, and
102 + /// the number gets re-baselined every batch. A seal that is re-baselined on
103 + /// schedule measures nothing, and it teaches exactly the editing habit the doc
104 + /// warns about.
105 + ///
106 + /// So the number is kept and the enforcement is suspended, rather than the seal
107 + /// being quietly lowered batch by batch. `CSS_KIB_HIGH_WATER` stays at 337
108 + /// because it is the record of where the conversion started, and it is what the
109 + /// finished conversion gets measured against.
110 + ///
111 + /// WHAT BRINGS IT BACK: the conversion complete and the duplicated CSS removed.
112 + /// At that point the number stops moving in both directions, and the decision
113 + /// deferred with it becomes worth taking: seal the minified size rather than raw
114 + /// bytes, which is what Max ruled earlier the same day. `lightningcss` is
115 + /// already a dependency of this repo, so that costs no new dependency.
116 + ///
117 + /// STATE AT PARKING, measured 2026-08-18:
118 + ///
119 + /// static/style.css 324,648 (322,102 at the 2026-08-15 baseline)
120 + /// static/wizard.css 13,459
121 + /// static/media-player.css 8,953
122 + /// static/no-js.css 1,212
123 + /// total 348,272 = 340 KiB against the sealed 337
124 + ///
125 + /// Red on the grow assertion by 3 KiB, which is what prompted the ruling.
126 + ///
127 + /// GoingsOn mnw-server `2d01900f`.
86 128 #[test]
129 + #[ignore = "parked by Max 2026-08-18 until the conversion is finished and the duplicated CSS is gone: see this test's doc comment"]
87 130 fn hand_written_css_does_not_grow() {
88 131 let (total, each) = measure();
89 132 let kib = total / 1024;
@@ -4,7 +4,7 @@
4 4
5 5 import { resolveHtmxLoadingButton } from './loading.ts';
6 6 import { csrfHeaders } from './net.ts';
7 - import { showToast } from './toast.ts';
7 + import { autoDismiss, showToast } from './toast.ts';
8 8
9 9 interface HxDetail {
10 10 elt: HTMLElement;
@@ -78,10 +78,9 @@
78 78 toast.appendChild(closeBtn);
79 79
80 80 container.appendChild(toast);
81 - setTimeout(() => {
82 - toast.classList.add('fade-out');
83 - setTimeout(() => toast.remove(), 300);
84 - }, 6000);
81 + // 6000 rather than the 3000 an ordinary toast gets: this one carries a Retry
82 + // button, so it has to outlive a glance.
83 + autoDismiss(toast, 6000);
85 84 });
86 85
87 86 // Loading button on request start; restore on every terminal event.
@@ -9,6 +9,25 @@
9 9 type?: string;
10 10 }
11 11
12 + /** How long the fade-out animation runs before the node is removed. Matches the
13 + * `.fade-out` transition in the stylesheet, so shortening it here drops the
14 + * toast mid-animation. */
15 + const TOAST_FADE_MS = 300;
16 +
17 + /** Fade `toast` out after `lifetimeMs`, then remove it.
18 + *
19 + * Extracted because `initHtmxGlue`'s error toast had its own verbatim copy of
20 + * the same two nested timers. The lifetime stays the caller's business: this
21 + * renderer's toasts live 3000ms and an error toast lives 6000ms, and which of
22 + * those is right is a question for the semantic-timing work rather than for a
23 + * helper that only exists to stop the dismissal being written twice. */
24 + export function autoDismiss(toast: HTMLElement, lifetimeMs: number): void {
25 + setTimeout(() => {
26 + toast.classList.add('fade-out');
27 + setTimeout(() => toast.remove(), TOAST_FADE_MS);
28 + }, lifetimeMs);
29 + }
30 +
12 31 /** Fire a toast. Rendered by the delegated listener installed by `initToasts`. */
13 32 export function showToast(message: string, type = 'error'): void {
14 33 document.body.dispatchEvent(new CustomEvent<ToastDetail>('showToast', { detail: { message, type } }));
@@ -28,9 +47,6 @@
28 47 toast.className = 'toast toast-' + (detail.type || 'info');
29 48 toast.textContent = detail.message || 'Action completed';
30 49 container.appendChild(toast);
31 - setTimeout(() => {
32 - toast.classList.add('fade-out');
33 - setTimeout(() => toast.remove(), 300);
34 - }, 3000);
50 + autoDismiss(toast, 3000);
35 51 });
36 52 }