From a79683a374fbd63c6d366e3679d66d5e9b71a31a Mon Sep 17 00:00:00 2001 From: Rod Vince Date: Fri, 11 Sep 2026 04:01:59 -0600 Subject: [PATCH 1/2] fix(welcome): the house derives its design-system URLs and types the prefix once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The page's `` spelled `/design/milpa-tokens.css`, `/design/milpa-fonts.css` and `/design/milpa-app-icon.svg`, and the plugin spelled `/design/` twice more in its route declarations. `DesignTokens::urls()` (live-web 0.27.0) takes a prefix and returns the whole set, including the `fonts/` segment `milpa-fonts.css` asks for relatively β€” a host that flattens that serves a stylesheet whose every `src` is a 404, which shows up as missing type rather than as an error. 🚨 THIS HOUSE IS THE EVIDENCE FOR WHY THE TYPING MATTERED. `/design/` was invented here in the same afternoon that `/webauthn/`, `/admin/assets/` and `/live/` already existed β€” by me, and I could not see the other three from where I was writing, because nothing this page imports mentions them. Four prefixes and nobody chose four. A prefix PER HOST is not the defect: it is a decision written where it is made (`DesignTokens::iconLink()` β€” each host serves these from its own asset route with its own cache policy), because a plugin whose pages work the moment it is installed cannot depend on another plugin's routes being mounted. `HelloPlugin::designPrefix()` now says it once, and the filenames come from the authority. The route PATTERNS stay local and should: one catch-all `{file}` here, five named routes in the passkey door, both right for their host. Only the prefix and the filenames moved. Control: `testItLinksTheSystemThisHouseServes` still asserts the three literal hrefs and passes untouched β€” the page's output did not move, its authority did. 170 tests (168 before), same 66 skips. And the new guard was probed with a regression in a form it was NOT written against β€” the prefix split from the filename by `sprintf('%s/milpa-wordmark-light.svg', '/design')`. Both halves fired. A guard is worth exactly one probe, and the probe has to differ from the thing the guard was written against. Refs: greenhouse decisions/0308 --- composer.json | 2 +- .../Controllers/HomeController.php | 27 +++- src/Plugins/HelloPlugin/HelloPlugin.php | 20 ++- .../TheHouseDerivesItsDesignUrlsTest.php | 123 ++++++++++++++++++ 4 files changed, 165 insertions(+), 7 deletions(-) create mode 100644 tests/Plugins/TheHouseDerivesItsDesignUrlsTest.php diff --git a/composer.json b/composer.json index 4a02727..c153c37 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "milpa/tool-runtime": ">=0.13 <1.0", "nyholm/psr7": "^1.8", "nyholm/psr7-server": "^1.1", - "milpa/live-web": ">=0.26.1 <1.0" + "milpa/live-web": ">=0.27 <1.0" }, "conflict": { "milpa/agent": "<0.5", diff --git a/src/Plugins/HelloPlugin/Controllers/HomeController.php b/src/Plugins/HelloPlugin/Controllers/HomeController.php index becff47..57264a0 100644 --- a/src/Plugins/HelloPlugin/Controllers/HomeController.php +++ b/src/Plugins/HelloPlugin/Controllers/HomeController.php @@ -20,8 +20,10 @@ use Milpa\Live\Components\CodeBlockComponent; use Milpa\Live\Contracts\Component\ComponentDefinitionInterface; use Milpa\Live\Contracts\Rendering\ComponentRendererInterface; +use App\Plugins\HelloPlugin\HelloPlugin; use Milpa\Live\Rendering\BrandMarkHtmlRenderer; use Milpa\Live\Rendering\CodeBlockHtmlRenderer; +use Milpa\Live\Support\DesignTokens; use Milpa\Live\ValueObjects\ComponentContext; use Milpa\Live\ValueObjects\RenderRequest; use Milpa\Live\ValueObjects\RenderTarget; @@ -223,12 +225,30 @@ private function elsewhere(): string return $html; } + /** + * The design system's tags, from the authority rather than from typing. + * + * The three filenames used to be spelled here, a fourth time in this family, and the prefix a + * fourth WAY β€” which is how `/design/` came to exist next to `/webauthn/`, `/admin/assets/` and + * `/live/` without anyone choosing four. {@see HelloPlugin::designPrefix()} owns the prefix and + * {@see DesignTokens::urls()} owns the filenames; this method owns neither + * (greenhouse decisions/0308). + */ + private static function designLinks(): string + { + $design = DesignTokens::urls(HelloPlugin::designPrefix()); + + return '' + . '' + . DesignTokens::iconLink($design[DesignTokens::APP_ICON]); + } + private function html(): string { $assets = self::assets(); return \str_replace( - ['__GREETING__', '__MARK__', '__DOOR__', '__WAYS_OUT__', '__ELSEWHERE__', '__STYLES__', '__SCRIPTS__'], + ['__GREETING__', '__MARK__', '__DOOR__', '__WAYS_OUT__', '__ELSEWHERE__', '__DESIGN__', '__STYLES__', '__SCRIPTS__'], [ htmlspecialchars($this->greeting, \ENT_QUOTES, 'UTF-8'), // READY, not `sown`: the mark reports what the surface is doing, and this page has @@ -238,6 +258,7 @@ private function html(): string self::door(), self::waysOut(), $this->elsewhere(), + self::designLinks(), $assets->styleTag(), $assets->scriptTag(), ], @@ -248,9 +269,7 @@ private function html(): string Milpa is running - - - + __DESIGN__ __STYLES__