Skip to main content

max / makenotwork

Follow the Bespoke split, and say which of its regions owe a fill Seven of this server's nine opaque regions are `Handover`: the five tab panels, the version uploader, and the media transport. Each is a fill the app owes every host, so a renderer without one is looking at a hole and now says so instead of drawing an empty box. Two are `Ceded`: the analytics charts, on the ruling this repo already carries that a bar chart is not describable and should not be. Nothing is owed there and silence is the right drawing. The transport went `Handover` rather than `Ceded` on its own doc's argument: "a handover for now, a widget eventually", naming the media player as the first candidate to become one. A terminal shown nothing there is missing content the reader wants, which is the distinction `owed()` exists to carry.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-09-01 22:07 UTC
Signed with PGP, not checked
Commit: a77912ace2e29ede6deb165c9e6551a01ae52bc2
Parent: 76b2da2
16 files changed, +41 insertions, -36 deletions
@@ -18,7 +18,7 @@
18 18 # `makeover-tui` is the terminal renderer, and its `theme` feature is the
19 19 # intents-to-ratatui-colours mapping. No hex value is written in this crate.
20 20 makeover = "3.0"
21 - makeover-tui = { version = "0.42", features = ["theme"] }
21 + makeover-tui = { version = "0.43", features = ["theme"] }
22 22 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread", "time", "sync", "signal", "fs"] }
23 23 # `rustls-no-provider` rather than `rustls`: the latter is an alias for
24 24 # `__rustls-aws-lc-rs`, which links a C crypto backend. The provider is ring
@@ -15,7 +15,7 @@
15 15 # selection; `makeover-tui` is the terminal renderer, and its `theme` feature is
16 16 # the intents-to-ratatui-colours mapping. No colour is named in this crate.
17 17 makeover = "3.0"
18 - makeover-tui = { version = "0.42", features = ["theme"] }
18 + makeover-tui = { version = "0.43", features = ["theme"] }
19 19 tokio = { version = "1", features = ["full"] }
20 20 # `rustls-no-provider` rather than `rustls`: the latter is an alias for
21 21 # `__rustls-aws-lc-rs`, which links a C crypto backend. The provider is ring
M server/Cargo.lock +13 -13
@@ -5406,7 +5406,7 @@
5406 5406
5407 5407 [[package]]
5408 5408 name = "makeover-layout"
5409 - version = "0.42.0"
5409 + version = "0.43.0"
5410 5410
5411 5411 [[package]]
5412 5412 name = "makeover-timing"
@@ -10771,6 +10771,18 @@
10771 10771 name = "makeover-tui"
10772 10772 version = "0.42.0"
10773 10773
10774 + [[patch.unused]]
10775 + name = "kberg"
10776 + version = "0.1.0"
10777 +
10778 + [[patch.unused]]
10779 + name = "ops-status"
10780 + version = "0.1.0"
10781 +
10782 + [[patch.unused]]
10783 + name = "painhours"
10784 + version = "0.1.0"
10785 +
10774 10786 [[patch.unused]]
10775 10787 name = "quasi-immediate"
10776 10788 version = "0.97.0"
@@ -10786,15 +10798,3 @@
10786 10798 [[patch.unused]]
10787 10799 name = "quasi-tauri"
10788 10800 version = "0.97.0"
10789 -
10790 - [[patch.unused]]
10791 - name = "kberg"
10792 - version = "0.1.0"
10793 -
10794 - [[patch.unused]]
10795 - name = "ops-status"
10796 - version = "0.1.0"
10797 -
10798 - [[patch.unused]]
10799 - name = "painhours"
10800 - version = "0.1.0"
@@ -168,14 +168,14 @@
168 168 # rather than reached through quasi-router's re-export because a described
169 169 # screen names FieldKind and Tone directly; it has to track what quasi-router
170 170 # resolves or the two `layout::` paths are different crates.
171 - makeover-layout = "0.42"
171 + makeover-layout = "0.43"
172 172 # The webview renderer's field emitter, called directly by
173 173 # `quasi::rich_field` so one markdown editor's markup comes from the same
174 174 # place a whole described screen's would. Pinned here rather than reached
175 175 # through quasi-webview for makeover-layout's reason: two `form::` paths from
176 176 # two resolutions are two crates, and the `data-format="markdown"` rules in
177 177 # `static/layout.css` are generated from this one.
178 - makeover-webview = "0.71"
178 + makeover-webview = "0.72"
179 179 # For the request head the per-viewer state factory reads. axum re-exports it,
180 180 # but the factory's signature is quasi-axum's and names `http::request::Parts`.
181 181 http = "1.3.1"
@@ -254,7 +254,7 @@
254 254 # Emits static/geometry.css (makeover-geometry) and static/layout.css
255 255 # (makeover-webview). The same generator GO and BB run; only the output paths
256 256 # differ, since the server serves its stylesheets rather than bundling them.
257 - makeover-build = "0.64"
257 + makeover-build = "0.65"
258 258 # Read directly for the embeds' own copy of the spacing layer, which they need
259 259 # because an iframe cannot link a stylesheet. makeover-build does not re-export
260 260 # it, so the pin lives here and has to track the one makeover-build resolves.
@@ -70,7 +70,7 @@
70 70 //! - **Disclosure.** The Guide section groups into `<details open><summary>`
71 71 //! subsections. No node says that, so the described version flattens them.
72 72 //! - **The search box.** The input, its results container and `docs-search.js`
73 - //! are bespoke, so this screen needs a `Region::Bespoke` fill even though
73 + //! are bespoke, so this screen needs a `Region::Handover` fill even though
74 74 //! phase 0 rated it furniture. Worth noting for the sizing: "furniture" was
75 75 //! read off templates, and this one turned out to carry a fill.
76 76 //!
@@ -241,12 +241,14 @@
241 241
242 242 /// The audio player: the card, with the transport in a bespoke region.
243 243 ///
244 - /// **Bespoke for now, widgets eventually.** A play button, a scrub bar and an
244 + /// **A handover for now, a widget eventually.** A play button, a scrub bar and an
245 245 /// elapsed readout are a media transport, and the vocabulary names none of the
246 246 /// three on purpose — describing playback would
247 247 /// put scrub, rate and chapters into a core two of the three renderers could only
248 248 /// degrade. So this screen describes the chrome around the player and leaves the
249 - /// player alone, which is exactly what a [`RegionKind::Bespoke`] is for.
249 + /// player alone, which is exactly what a [`RegionKind::Handover`] is for: the
250 + /// fill is owed, and a renderer without one should say so rather than draw an
251 + /// empty box where the transport goes.
250 252 ///
251 253 /// The markup and the script that fills it are [`player_markup`], unchanged from
252 254 /// the template this replaces.
@@ -264,13 +266,13 @@
264 266
265 267 Screen::single(&view.title).with(slot).with(Slot::new(
266 268 PLAYER_REGION,
267 - RegionKind::Bespoke {
269 + RegionKind::Handover {
268 270 name: "media-transport".into(),
269 271 },
270 272 ))
271 273 }
272 274
273 - /// The bespoke region the transport is mounted in.
275 + /// The handover region the transport is mounted in.
274 276 pub const PLAYER_REGION: &str = "transport";
275 277
276 278 /// The player document: the described chrome, with the transport mounted.
@@ -15,7 +15,7 @@
15 15 //! cancel, a retry and an error surface, all of it client-side state.
16 16 //!
17 17 //! The table is described here. The upload machine stays markup, mounted as a
18 - //! [`RegionKind::Bespoke`] region, which is what bespoke regions are for and
18 + //! [`RegionKind::Handover`] region, which is what a handover is for and
19 19 //! what `super::user_analytics` already does with its chart. Describing a
20 20 //! progress machine is its own conversion with its own vocabulary questions,
21 21 //! and `138ad5ab`'s SCOPE says to split rather than widen. So it is split, and
@@ -216,7 +216,10 @@
216 216
217 217 // The upload machine, whatever state it is in. Below the table on an empty
218 218 // panel too, which is what "create your first version below" points at.
219 - slot = slot.with(Node::Region(Slot::bespoke(UPLOADER_SLOT, "version-upload")));
219 + slot = slot.with(Node::Region(Slot::handover(
220 + UPLOADER_SLOT,
221 + "version-upload",
222 + )));
220 223
221 224 Node::Region(slot)
222 225 }
@@ -190,7 +190,7 @@
190 190 .showing_one(shown);
191 191
192 192 for (at, tab) in tabs.iter().enumerate() {
193 - let mut region = Slot::bespoke(tab.panel, "item-panel").label(tab.label);
193 + let mut region = Slot::handover(tab.panel, "item-panel").label(tab.label);
194 194 if at != shown {
195 195 // Every panel here is an Askama route, so every one of them needs to
196 196 // be told where its answer goes: a route that names no region leaves
@@ -8,7 +8,7 @@
8 8 //! # The panels are not described and are not meant to be
9 9 //!
10 10 //! Max's ruling: describe the strip, leave the panels as routes. So every tab is
11 - //! a [`RegionKind::Bespoke`], a place and nothing else, and what lands in one
11 + //! a [`RegionKind::Handover`], a place and nothing else, and what lands in one
12 12 //! is whatever its route already answered with. That is the honest kind for a
13 13 //! region whose contents are Askama's, and it is what lets the five panel routes
14 14 //! in `routes::pages::public` stay untouched.
@@ -167,7 +167,7 @@
167 167 .showing_one(0);
168 168
169 169 for (at, tab) in shown.iter().enumerate() {
170 - let mut panel = Slot::bespoke(tab.panel, "library-panel").label(tab.label);
170 + let mut panel = Slot::handover(tab.panel, "library-panel").label(tab.label);
171 171 if at > 0 {
172 172 let mut call = Action::get(tab.route).awaiting();
173 173 // Described routes name their own region and must be left to;
@@ -145,7 +145,7 @@
145 145 /// Markup for the bespoke regions this request's screen describes.
146 146 ///
147 147 /// The seam between a handler and its renderer, and the reason it has to be
148 - /// here rather than in either of them: a `Region::Bespoke` is filled on the
148 + /// here rather than in either of them: a `Region::Handover` is filled on the
149 149 /// [`Webview`](quasi_webview::Webview), which quasi-axum builds *after* the
150 150 /// handler has answered, and the renderer factory is handed `&S` and the
151 151 /// answer. So the handler writes what it drew here and the renderer reads
@@ -124,7 +124,7 @@
124 124 } else {
125 125 // The description says only that there is a region here and what it is
126 126 // called; `drawn` puts the markup in it.
127 - Node::Region(Slot::bespoke(CHART_SLOT, "revenue-chart"))
127 + Node::Region(Slot::ceded(CHART_SLOT, "revenue-chart"))
128 128 });
129 129
130 130 out.push(Node::section("Top Performing Items"));
@@ -188,7 +188,7 @@
188 188 .showing_one(shown);
189 189
190 190 for (at, tab) in tabs.iter().enumerate() {
191 - let mut region = Slot::bespoke(tab.panel, "project-panel").label(tab.label);
191 + let mut region = Slot::handover(tab.panel, "project-panel").label(tab.label);
192 192 if at != shown {
193 193 // Every panel is an Askama route naming no region, so each is told
194 194 // where its answer goes or htmx swaps it into the pressed button.
@@ -259,7 +259,7 @@
259 259 .showing_one(shown);
260 260
261 261 for (at, section) in sections.iter().enumerate() {
262 - let mut region = Slot::bespoke(section.panel, "settings-panel").label(section.label);
262 + let mut region = Slot::handover(section.panel, "settings-panel").label(section.label);
263 263 if at != shown {
264 264 let mut call = Action::get(section.route).awaiting();
265 265 // A described route names its own region and must be left to. Same
@@ -24,7 +24,7 @@
24 24 //! 2. **A bar chart is not describable, and should not be.** makeover-layout
25 25 //! names no chart, and the admission test is that a node composes something
26 26 //! it already names. Inventing one there would be the layer naming a widget.
27 - //! So the chart is a [`quasi_router::RegionKind::Bespoke`] fill, which is
27 + //! So the chart is a [`quasi_router::RegionKind::Ceded`] fill, which is
28 28 //! exactly what bespoke regions are for, and it is the first one in the
29 29 //! tree. See [`chart_markup`].
30 30 //! 3. **A proportion bar inside a table cell is one site.** The comparison
@@ -278,7 +278,7 @@
278 278 } else {
279 279 // The chart's own markup arrives through the renderer. The description
280 280 // says only that there is a region here and what it is called.
281 - slot.with(Node::Region(Slot::bespoke(CHART_SLOT, "revenue-chart")))
281 + slot.with(Node::Region(Slot::ceded(CHART_SLOT, "revenue-chart")))
282 282 };
283 283
284 284 // One project is not a comparison, which is the condition the template
@@ -208,7 +208,7 @@
208 208 .showing_one(shown);
209 209
210 210 for (at, tab) in tabs.iter().enumerate() {
211 - let mut region = Slot::bespoke(tab.panel, "user-panel").label(tab.label);
211 + let mut region = Slot::handover(tab.panel, "user-panel").label(tab.label);
212 212 if at != shown {
213 213 let mut call = Action::get(format!("/dashboard/tabs/{}", tab.route)).awaiting();
214 214 // A described route names its own region and must be left to; an