max / makenotwork
- Co-Authored-By
- Claude Opus 5 (1M context) <noreply@anthropic.com>
44 files changed,
+309 insertions,
-1651 deletions
| @@ -50,10 +50,3 @@ | |||
| 50 | 50 | # script reads the same value as CAPTURE_BUYER_PASSWORD. See src/seed/buyer.rs. | |
| 51 | 51 | # TESTNOT_BUYER_PASSWORD= | |
| 52 | 52 | ||
| 53 | - | # Optional: the wave-2 conversion switch. A comma-separated list of screens that | |
| 54 | - | # serve from the quasi description layer instead of Askama; `*` converts | |
| 55 | - | # everything, which is a local-work setting. Unset means every screen serves | |
| 56 | - | # Askama, which is where every deployment stays until a screen's parity test is | |
| 57 | - | # green and Max flips it. A name that matches nothing is inert, so a typo | |
| 58 | - | # disables a screen rather than enabling the wrong one. See wiki look-wave-2. | |
| 59 | - | # QUASI_SCREENS= |
| @@ -494,7 +494,21 @@ | |||
| 494 | 494 | /// template in this repo. Nothing about this server changed; what changed is | |
| 495 | 495 | /// that the check can now see the half of the vocabulary it was blind to. | |
| 496 | 496 | /// It tightens as screens convert, exactly as the lines above did. | |
| 497 | - | const DEAD_VOCABULARY_HIGH_WATER: usize = 44; | |
| 497 | + | /// 44 to 45, 2026-08-26, and this one LOOSENS -- the first line here that does. | |
| 498 | + | /// `64b33b26` deleted the seven Askama renderings the description replaced, and | |
| 499 | + | /// `.form-label` lost its last two spellings with them (both in | |
| 500 | + | /// `partials/tabs/user_ssh_keys_tab.html`). The class is not gone and is not | |
| 501 | + | /// unused: makeover-webview's field emitter still writes it, on the described | |
| 502 | + | /// screen that replaced that template. It is dead only in the sense this check | |
| 503 | + | /// can measure, which is "no markup in this repo spells it", and the markup | |
| 504 | + | /// that spells it is now Rust in a dependency. | |
| 505 | + | /// | |
| 506 | + | /// So a rising number here is not automatically a regression. Read it against | |
| 507 | + | /// what moved: markup deleted in favour of a description will raise it, and a | |
| 508 | + | /// class that genuinely lost its writer will too. The list the failure prints | |
| 509 | + | /// is what tells them apart -- if a name on it is one this server still means | |
| 510 | + | /// to render, that is the bug. | |
| 511 | + | const DEAD_VOCABULARY_HIGH_WATER: usize = 45; | |
| 498 | 512 | ||
| 499 | 513 | /// The scripts this build script generates into `static/`. | |
| 500 | 514 | /// |
| @@ -1053,7 +1053,6 @@ | |||
| 1053 | 1053 | access_gate: crate::config::AccessGate::Open, | |
| 1054 | 1054 | sso: None, | |
| 1055 | 1055 | rate_limits: crate::constants::RateLimits::production(), | |
| 1056 | - | quasi_screens: crate::config::QuasiScreens::default(), | |
| 1057 | 1056 | build: BuildConfig { | |
| 1058 | 1057 | trigger_token: None, | |
| 1059 | 1058 | host_linux: None, | |
| @@ -1140,7 +1139,6 @@ | |||
| 1140 | 1139 | access_gate: crate::config::AccessGate::Open, | |
| 1141 | 1140 | sso: None, | |
| 1142 | 1141 | rate_limits: crate::constants::RateLimits::production(), | |
| 1143 | - | quasi_screens: crate::config::QuasiScreens::default(), | |
| 1144 | 1142 | build: BuildConfig { | |
| 1145 | 1143 | trigger_token: None, | |
| 1146 | 1144 | host_linux: None, |
| @@ -84,68 +84,6 @@ | |||
| 84 | 84 | /// Rate-limit profile the router is built with. Production everywhere that | |
| 85 | 85 | /// is not a test; see [`crate::constants::RateLimits`]. | |
| 86 | 86 | pub rate_limits: crate::constants::RateLimits, | |
| 87 | - | /// Which screens serve from the quasi description layer instead of Askama | |
| 88 | - | /// (`QUASI_SCREENS`). See [`QuasiScreens`]. | |
| 89 | - | pub quasi_screens: QuasiScreens, | |
| 90 | - | } | |
| 91 | - | ||
| 92 | - | /// The wave-2 conversion switch, one screen at a time. | |
| 93 | - | /// | |
| 94 | - | /// Per screen and not global: a global flag means the first screen converted | |
| 95 | - | /// cannot ship until the last one is, which turns a hundred-screen conversion | |
| 96 | - | /// into one release. Per screen, each conversion ships the moment its parity | |
| 97 | - | /// test is green and reverts by editing an env var rather than by a deploy. | |
| 98 | - | /// | |
| 99 | - | /// Read from `QUASI_SCREENS` as a comma-separated list of screen names. Unset | |
| 100 | - | /// means empty means every screen still serves Askama, which is the state this | |
| 101 | - | /// is meant to be in everywhere until Max flips one: | |
| 102 | - | /// | |
| 103 | - | /// ```text | |
| 104 | - | /// QUASI_SCREENS=user_account,item_pricing | |
| 105 | - | /// QUASI_SCREENS=* # everything, for local work | |
| 106 | - | /// ``` | |
| 107 | - | /// | |
| 108 | - | /// The names are the conversion's own, matching the screen inventory in wiki | |
| 109 | - | /// `look-wave-2`. Nothing validates them against a registry: a typo disables a | |
| 110 | - | /// screen rather than enabling the wrong one, which is the safe direction, and | |
| 111 | - | /// a registry would have to be kept in step with a list that is still moving. | |
| 112 | - | #[derive(Clone, Debug, Default, PartialEq, Eq)] | |
| 113 | - | pub struct QuasiScreens { | |
| 114 | - | all: bool, | |
| 115 | - | names: std::collections::HashSet<String>, | |
| 116 | - | } | |
| 117 | - | ||
| 118 | - | impl QuasiScreens { | |
| 119 | - | /// Parse the comma-separated form. Blanks and stray whitespace are ignored. | |
| 120 | - | #[must_use] | |
| 121 | - | pub fn parse(raw: &str) -> Self { | |
| 122 | - | let mut all = false; | |
| 123 | - | let mut names = std::collections::HashSet::new(); | |
| 124 | - | for part in raw.split(',') { | |
| 125 | - | match part.trim() { | |
| 126 | - | "" => {} | |
| 127 | - | "*" => all = true, | |
| 128 | - | name => { | |
| 129 | - | names.insert(name.to_owned()); | |
| 130 | - | } | |
| 131 | - | } | |
| 132 | - | } | |
| 133 | - | Self { all, names } | |
| 134 | - | } | |
| 135 | - | ||
| 136 | - | /// Whether this screen serves from the description layer. | |
| 137 | - | #[must_use] | |
| 138 | - | pub fn enabled(&self, screen: &str) -> bool { | |
| 139 | - | self.all || self.names.contains(screen) | |
| 140 | - | } | |
| 141 | - | ||
| 142 | - | /// Whether any screen is converted. For the startup log line: a server | |
| 143 | - | /// serving one screen differently from every other deployment is worth | |
| 144 | - | /// saying out loud rather than discovering. | |
| 145 | - | #[must_use] | |
| 146 | - | pub fn any(&self) -> bool { | |
| 147 | - | self.all || !self.names.is_empty() | |
| 148 | - | } | |
| 149 | 87 | } | |
| 150 | 88 | ||
| 151 | 89 | /// Native build pipeline configuration (`BUILD_*`, `GIT_*`). | |
| @@ -597,7 +535,6 @@ | |||
| 597 | 535 | access_gate, | |
| 598 | 536 | sso, | |
| 599 | 537 | rate_limits: crate::constants::RateLimits::production(), | |
| 600 | - | quasi_screens: QuasiScreens::parse(&std::env::var("QUASI_SCREENS").unwrap_or_default()), | |
| 601 | 538 | build: BuildConfig { | |
| 602 | 539 | trigger_token: build_trigger_token, | |
| 603 | 540 | host_linux: build_host_linux, | |
| @@ -1167,7 +1104,6 @@ | |||
| 1167 | 1104 | access_gate: AccessGate::Open, | |
| 1168 | 1105 | sso: None, | |
| 1169 | 1106 | rate_limits: crate::constants::RateLimits::production(), | |
| 1170 | - | quasi_screens: QuasiScreens::default(), | |
| 1171 | 1107 | build: BuildConfig { | |
| 1172 | 1108 | trigger_token: None, | |
| 1173 | 1109 | host_linux: None, |
| @@ -596,10 +596,7 @@ | |||
| 596 | 596 | }); | |
| 597 | 597 | let csrf_routes = csrf_routes.finalize(); | |
| 598 | 598 | let app = Router::new() | |
| 599 | - | .merge(page_routes( | |
| 600 | - | state.config.rate_limits, | |
| 601 | - | &state.config.quasi_screens, | |
| 602 | - | )) | |
| 599 | + | .merge(page_routes(state.config.rate_limits)) | |
| 603 | 600 | .merge(sso_routes()) | |
| 604 | 601 | .merge(csrf_routes) | |
| 605 | 602 | .merge(git_routes()) |
| @@ -142,17 +142,6 @@ | |||
| 142 | 142 | let config = Config::from_env().expect("Failed to load configuration"); | |
| 143 | 143 | tracing::info!("Configuration loaded"); | |
| 144 | 144 | ||
| 145 | - | // A box serving some screens from the description layer and the rest from | |
| 146 | - | // Askama is worth saying out loud. The failure this guards against is a | |
| 147 | - | // QUASI_SCREENS left set on a host nobody meant to convert, which otherwise | |
| 148 | - | // looks exactly like the site behaving oddly for one page. | |
| 149 | - | if config.quasi_screens.any() { | |
| 150 | - | tracing::warn!( | |
| 151 | - | screens = %std::env::var("QUASI_SCREENS").unwrap_or_default(), | |
| 152 | - | "QUASI_SCREENS is set: these screens serve from the description layer, not Askama" | |
| 153 | - | ); | |
| 154 | - | } | |
| 155 | - | ||
| 156 | 145 | // Create database connection pool with health checks and lifecycle limits. | |
| 157 | 146 | // - test_before_acquire: validates connections before use (catches stale/broken conns) | |
| 158 | 147 | // - max_lifetime: rotates connections to prevent long-lived session issues |
| @@ -37,12 +37,14 @@ | |||
| 37 | 37 | /// 50 across 33 files on 2026-08-20, the measurement the task was written | |
| 38 | 38 | /// against and unchanged since. | |
| 39 | 39 | /// | |
| 40 | - | /// Three of the fifty are not this program's to remove and will be the last to | |
| 41 | - | /// go: `partials/ssh_keys_list.html`, `partials/git_tokens_list.html` and | |
| 42 | - | /// `partials/tabs/library_contacts.html` back screens that are already | |
| 43 | - | /// described, and are still live Askama structs because the conversions are | |
| 44 | - | /// dual-serve while `QUASI_SCREENS` serves nobody. They leave with the templates | |
| 45 | - | /// when the switch ships, which is task `64b33b26`. | |
| 40 | + | /// Three of the fifty were called out as not this program's to remove: | |
| 41 | + | /// `partials/ssh_keys_list.html`, `partials/git_tokens_list.html` and | |
| 42 | + | /// `partials/tabs/library_contacts.html`, all backing screens that were already | |
| 43 | + | /// described and dual-serving while the switch served nobody. `64b33b26` shipped | |
| 44 | + | /// the switch's deletion and took `library_contacts.html` with it, which is the | |
| 45 | + | /// 47 to 46 below. The other two stay: they are not tab renderings but the | |
| 46 | + | /// fragments `routes::api::ssh_keys` and the git-token routes answer with, and | |
| 47 | + | /// the described screens still call those. | |
| 46 | 48 | /// | |
| 47 | 49 | /// 48 on 2026-08-22, and the first two that left without their screens. The | |
| 48 | 50 | /// identical "Delete this blog post?" button in `tabs/project_content.html` and | |
| @@ -64,7 +66,7 @@ | |||
| 64 | 66 | /// progress: the seal counts template source, so deduplicating two templates | |
| 65 | 67 | /// lowers it without describing anything. The surviving site is still blocked | |
| 66 | 68 | /// on the `closest .link-row` target above. | |
| 67 | - | const HIGH_WATER: usize = 47; | |
| 69 | + | const HIGH_WATER: usize = 46; | |
| 68 | 70 | ||
| 69 | 71 | /// Every template, recursively. Walked rather than listed for the reason the | |
| 70 | 72 | /// frontend-globals seal walks `frontend/src`: a fence that has to be told about |
| @@ -1,4 +1,4 @@ | |||
| 1 | - | //! Tests for the parity harness, and for the per-screen conversion switch. | |
| 1 | + | //! Tests for the parity harness. | |
| 2 | 2 | //! | |
| 3 | 3 | //! The harness is what every phase-3 conversion trusts, so it is tested on both | |
| 4 | 4 | //! sides: that it ignores what it claims to ignore, and that it still fails on | |
| @@ -12,7 +12,6 @@ | |||
| 12 | 12 | #[path = "harness/parity.rs"] | |
| 13 | 13 | mod parity; | |
| 14 | 14 | ||
| 15 | - | use makenotwork::config::QuasiScreens; | |
| 16 | 15 | use parity::Parity; | |
| 17 | 16 | ||
| 18 | 17 | // --- what it forgives ------------------------------------------------------- | |
| @@ -172,49 +171,14 @@ | |||
| 172 | 171 | } | |
| 173 | 172 | ||
| 174 | 173 | // --- the per-screen switch -------------------------------------------------- | |
| 175 | - | ||
| 176 | - | #[test] | |
| 177 | - | fn no_screen_is_converted_by_default() { | |
| 178 | - | // The state every deployment is in until Max flips one. | |
| 179 | - | let screens = QuasiScreens::default(); | |
| 180 | - | assert!(!screens.enabled("item_pricing")); | |
| 181 | - | assert!(!screens.any()); | |
| 182 | - | } | |
| 183 | - | ||
| 184 | - | #[test] | |
| 185 | - | fn an_unset_variable_converts_nothing() { | |
| 186 | - | let screens = QuasiScreens::parse(""); | |
| 187 | - | assert!(!screens.enabled("item_pricing")); | |
| 188 | - | assert!(!screens.any()); | |
| 189 | - | } | |
| 190 | - | ||
| 191 | - | #[test] | |
| 192 | - | fn screens_are_named_one_at_a_time() { | |
| 193 | - | let screens = QuasiScreens::parse("user_account,item_pricing"); | |
| 194 | - | assert!(screens.enabled("user_account")); | |
| 195 | - | assert!(screens.enabled("item_pricing")); | |
| 196 | - | assert!(!screens.enabled("project_content")); | |
| 197 | - | assert!(screens.any()); | |
| 198 | - | } | |
| 199 | - | ||
| 200 | - | #[test] | |
| 201 | - | fn whitespace_and_blanks_in_the_list_are_ignored() { | |
| 202 | - | let screens = QuasiScreens::parse(" user_account , , item_pricing ,"); | |
| 203 | - | assert!(screens.enabled("user_account")); | |
| 204 | - | assert!(screens.enabled("item_pricing")); | |
| 205 | - | assert!(!screens.enabled("")); | |
| 206 | - | } | |
| 207 | - | ||
| 208 | - | #[test] | |
| 209 | - | fn a_star_converts_everything_for_local_work() { | |
| 210 | - | let screens = QuasiScreens::parse("*"); | |
| 211 | - | assert!(screens.enabled("anything_at_all")); | |
| 212 | - | assert!(screens.any()); | |
| 213 | - | } | |
| 214 | - | ||
| 215 | - | #[test] | |
| 216 | - | fn a_typo_disables_a_screen_rather_than_enabling_another() { | |
| 217 | - | // The safe direction, and the reason nothing validates against a registry. | |
| 218 | - | let screens = QuasiScreens::parse("item_pricng"); | |
| 219 | - | assert!(!screens.enabled("item_pricing")); | |
| 220 | - | } | |
| 174 | + | // | |
| 175 | + | // Six tests lived here until 2026-08-26, covering `QuasiScreens::parse`: the | |
| 176 | + | // default converting nothing, an unset variable, naming screens one at a time, | |
| 177 | + | // whitespace and blanks, `*` for local work, and a typo disabling a screen | |
| 178 | + | // rather than enabling another. `64b33b26` deleted the switch, so they have no | |
| 179 | + | // subject. | |
| 180 | + | // | |
| 181 | + | // The normalizer above is untouched and is the half worth keeping: a phase-3 | |
| 182 | + | // conversion still wants to compare its described rendering against the Askama | |
| 183 | + | // one it replaces. What it cannot do any more is serve both from one binary and | |
| 184 | + | // diff them over a request, because there is no flag to serve the old one. |
| @@ -43,7 +43,8 @@ | |||
| 43 | 43 | use super::Viewer; | |
| 44 | 44 | use crate::db; | |
| 45 | 45 | ||
| 46 | - | /// The conversion switch's name for this screen. `QUASI_SCREENS=buyer_contacts`. | |
| 46 | + | /// This screen's name. Was the `QUASI_SCREENS` switch name until `64b33b26` | |
| 47 | + | /// deleted the flag; it survives as the marker the tab strips read. | |
| 47 | 48 | pub const SCREEN: &str = "buyer_contacts"; | |
| 48 | 49 | ||
| 49 | 50 | /// The address this screen answers, and the one the Askama route gives up. |