diff --git a/docs/consultations/gemini-build-pipeline-2026-04-13.md b/docs/consultations/gemini-build-pipeline-2026-04-13.md new file mode 100644 index 0000000..0e7cc40 --- /dev/null +++ b/docs/consultations/gemini-build-pipeline-2026-04-13.md @@ -0,0 +1,169 @@ +# Gemini Consultation: ModpackChecker Build Pipeline Fragility + +**Date:** April 13, 2026 (late night) +**From:** Michael (The Wizard) + Claude (Chronicler #84 — The Meridian) +**To:** Gemini (Architectural Partner) +**Re:** build.sh is causing production incidents — we need a bulletproof deployment pipeline + +--- + +## Hey Gemini! 👋 + +It's very late and we just had a production incident. We're deploying ModpackChecker v1.1.0 on a live Pterodactyl panel and the new React widget caused the server info card to disappear entirely for users. We had to emergency-revert. The root cause is our build.sh doing too many things in one shot with no safety net. We need your help designing a bulletproof deployment pipeline before we try again. + +--- + +## The Product + +ModpackChecker is a Blueprint extension for Pterodactyl Panel 1.12.2. It has: +- **PHP backend** — Laravel artisan commands, API controllers, services +- **Admin Blade view** — PHP/Blade template for the admin settings page +- **React TSX frontend** — Two components: + - `ModpackVersionCard.tsx` — injected into the server console page + - `UpdateBadge.tsx` — injected into the dashboard server list + +Blueprint extensions install via `blueprint -install modpackchecker`, which copies files and then calls our `build.sh`. + +--- + +## The Current build.sh (Full Source) + +```bash +#!/bin/bash +# Runs during blueprint -install from Pterodactyl root + +# 1. Detect Node version, set NODE_OPTIONS for Node 17+ +NODE_MAJOR_VERSION=$(node -v | grep -oE '[0-9]+' | head -1) +if [ "$NODE_MAJOR_VERSION" -ge 17 ]; then + export NODE_OPTIONS=--openssl-legacy-provider +fi + +# 2. Copy wrapper.tsx → ModpackVersionCard.tsx +EXT_DIR=".blueprint/extensions/modpackchecker" +cp "$EXT_DIR/views/server/wrapper.tsx" resources/scripts/components/server/ModpackVersionCard.tsx + +# 3. Inject import + component into AfterInformation.tsx (only if not already there) +AFTER_INFO="resources/scripts/blueprint/components/Server/Terminal/AfterInformation.tsx" +if ! grep -q "ModpackVersionCard" "$AFTER_INFO"; then + sed -i '/\/* blueprint\/import \*\//a import ModpackVersionCard from "@/components/server/ModpackVersionCard";' "$AFTER_INFO" + sed -i 's|{/\* blueprint/react \*/}|{/* blueprint/react */}\n |' "$AFTER_INFO" +fi + +# 4. Copy UpdateBadge.tsx + inject into ServerRow.tsx +cp "$EXT_DIR/views/dashboard/UpdateBadge.tsx" resources/scripts/components/dashboard/UpdateBadge.tsx +if ! grep -q "UpdateBadge" resources/scripts/components/dashboard/ServerRow.tsx; then + sed -i '1i import UpdateBadge from "@/components/dashboard/UpdateBadge";' resources/scripts/components/dashboard/ServerRow.tsx + sed -i 's|{server.name}

|{server.name}

|' resources/scripts/components/dashboard/ServerRow.tsx +fi + +# 5. Copy PHP files (services, controllers, commands) +cp "$EXT_DIR/app/Services/LicenseService.php" app/Services/ +cp "$EXT_DIR/app/Services/ModpackApiService.php" app/Services/ +cp "$EXT_DIR/app/Console/Commands/CheckModpackUpdates.php" app/Console/Commands/ +cp "$EXT_DIR/app/Console/Commands/ValidateLicense.php" app/Console/Commands/ +cp "$EXT_DIR/app/Http/Controllers/ModpackAPIController.php" app/Http/Controllers/ + +# 6. Overwrite Blueprint's auto-generated admin controller +cp "$EXT_DIR/admin/controller.php" "app/Http/Controllers/Admin/Extensions/modpackchecker/modpackcheckerExtensionController.php" + +# 7. Clear caches +php artisan optimize:clear + +# 8. yarn build:production (2-5 minutes) +yarn build:production +``` + +--- + +## What Happened Tonight + +We shipped v1.1.0 with a redesigned React widget. During deployment: + +1. We ran `blueprint -install modpackchecker` — SUCCESS, copied the new TSX +2. We then manually re-ran `bash build.sh` to ensure the PHP files were copied +3. Step 2 **overwrote** `ModpackVersionCard.tsx` with the new widget correctly +4. `yarn build:production` compiled successfully +5. BUT: the compiled bundle caused the server info card to disappear entirely + +The new widget rendered nothing (or threw a silent React error that unmounted the whole card). We emergency-reverted to the old widget by writing the old TSX directly and rebuilding yarn. + +**The result:** We now have v1.1.0 backend deployed (new DB columns, new endpoints, better detection) but v1.0.0 frontend widget still in production. The product is half-upgraded. + +--- + +## The Problems + +### Problem 1: No Staging / Safety Check +The build runs directly on the production panel. There's no way to verify the compiled output renders correctly before it goes live. The only test is "does the panel explode." + +### Problem 2: Build.sh Does Too Many Things +It copies files AND injects into Pterodactyl source AND compiles frontend in one atomic step. If anything goes wrong mid-way, the panel is in an inconsistent state. + +### Problem 3: Multiple Deployment Paths Create Drift +We have two deployment patterns that fight each other: +- `blueprint -install modpackchecker` (calls build.sh automatically) +- Manual: copy individual PHP/TSX files + run yarn build separately + +When we mix these, files get overwritten at different points and the final state is unpredictable. + +### Problem 4: The `*/6` Docblock Keeps Coming Back +Our PHP file `CheckModpackUpdates.php` has `*/6` in a docblock comment which PHP sometimes parses as end-of-comment + stray tokens. We've patched it THREE times on the server because build.sh keeps copying from a repo file that still has it (fixed in one copy, not the other). + +### Problem 5: No Rollback +When the panel broke tonight, there was no "undo" — we had to manually reconstruct the previous TSX from memory and rebuild yarn. A 90-second compile to fix something that took 10 seconds to break. + +### Problem 6: Blueprint's Auto-Generated Controller Gets Overwritten +Blueprint generates its own controller at `app/Http/Controllers/Admin/Extensions/modpackchecker/`. Our build.sh overwrites it with our version (which has LicenseService DI). But `blueprint -install` runs first and generates the file BEFORE our build.sh overwrites it — so the sequence is correct, but fragile. If Blueprint ever changes when it calls build.sh, we break. + +--- + +## Our Constraints + +1. **We're selling this on BuiltByBit** — customers install via `blueprint -install modpackchecker`. We cannot require them to do complex post-install steps. +2. **We cannot assume SSH access** on customer panels — some customers are on managed hosting. +3. **Pterodactyl 1.12.2 + Blueprint beta-2026-01** — these are fixed targets. +4. **yarn build:production takes 90 seconds to 3 minutes** — on every install, every update. +5. **Node.js version varies** — we handle this with `--openssl-legacy-provider` for Node 17+. +6. **We have one source of truth** (`firefrost-services` git repo) but multiple deployment surfaces (Dev Panel, Live Panel, customer panels). + +--- + +## Specific Questions + +1. **How should we structure the build pipeline to separate "copy files" from "compile frontend"?** + Right now it's all in build.sh. Should there be a separate `install.sh` (file operations) and `compile.sh` (yarn build), called in sequence? How do other Blueprint extensions handle this? + +2. **Is there a way to validate a React component compiles without breaking the production bundle?** + Before we run `yarn build:production` on a live panel, can we do a dry-run or type-check that would catch errors? `tsc --noEmit` perhaps? Or a simple syntax check? + +3. **How should we handle the "new widget breaks the panel" failure mode?** + Tonight the new TSX caused the server card to disappear entirely with no console error we could see. React swallowed the error silently. Should we wrap our component in an `ErrorBoundary`? What's the right defensive pattern for injected Blueprint components? + +4. **What's the cleanest way to handle the multiple deployment paths (blueprint -install vs manual)?** + We need one canonical deploy procedure that works whether the Chronicler is deploying to a customer panel OR to our own panels during development. How do we eliminate the "drift" problem? + +5. **The `*/6` docblock problem** — is there a pre-commit hook or linting check that would catch PHP syntax errors like this before they reach the repo? We keep fixing it manually on the server. + +6. **Should we ship a pre-compiled JS bundle instead of requiring yarn build on the customer's panel?** + Gemini previously rejected this (it would overwrite Pterodactyl's `public/assets/main.js` and break other extensions). But is there a safe way to do it — like a separate bundle entry point that doesn't conflict with the main bundle? Or inject via a `