| #988 graduation 500 | Story + root cause: §A above | — | #983 retro comment 2026-06-30; PR #991 closed unmerged; 9b99005 ✓ | rebuild tracked on #988; method rewrite #992 (live state: re-verify) | AGENTS.md done-rule; spec/graduate/conformance skills; gate-spec-signoff.mjs |
| #523/#457 zero-migration scaffold | Fresh scaffold ships zero migrations, silently; first deploy fails (fix: diagnostics-index) | db:generate needs the built schema.mjs; the CLI ran it bare | Fix e4d92da ✓ (2026-06-20): build-first generation in packages/crouton-cli/lib/utils/generate-migrations.ts; prints manual steps instead of shipping nothing | Fixed | Build-first migration generation; fail loudly or print the recipe (mechanics: db-migrations skill) |
#138 --config path-doubling (pre-shallow) | Staging D1 migrate: "No migrations present" though migrations exist (fix: diagnostics-index) | wrangler resolved the relative migrations_dir against the passed config's dir. Was latent in the scaffolder template too — triage dodged it by reusing a pre-migrated DB (folded back via #135) | PR #138 body (GitHub only) | Fixed; rule enshrined in root CLAUDE.md | Wrangler resolves relative paths against the config file's dir; a template "working" on app A can carry a latent bug A merely dodges |
#624 maplibre CJS crash (aftershock of the #538 Mapbox→MapLibre swap, 48ef1b8 ✓) | Maps forms crash the page in dev — named-import failure against raw CJS (mechanics + fix: diagnostics-index) | maplibre-gl v5 is CJS-only and was in build.transpile | Fix 9cc0d4c ✓; caught by the with-maps e2e fixture (#549) | Fixed | The provider-swap skill was minted from #538; a swap is only proven when a fixture exercises it in a browser |
| #680/#685/#700 translations_ui 500 | Fresh app admin 500: no such table: translations_ui (fix: diagnostics-index) | The rejected fix is the story: PR #685 shipped the migration from the package — verified closed unmerged (merged:false). Rejection reason (commit 9515df1 ✓ body, verbatim): "NuxtHub applies package-layer migrations BEFORE the app's own (directory order), so a package translations_ui migration ALWAYS ran first and collided with existing apps' non-idempotent migration ('table already exists') — unfixable by renaming" | Actual fix: graceful degradation (mechanics: diagnostics-index); chain 9515df1 ✓ → 6ddb699 → merge #700 | Fixed | Packages must not ship D1 migrations for infra tables consumed by pre-existing apps; optional-table reads degrade, don't crash. Sanctioned package-owned-table pattern: db-migrations skill |
| #740→#745 devtools deploy cache corruption (3 rounds) | POC deploy fails at nuxt prepare: "Could not load @fyit/crouton-devtools" (symptom row: diagnostics-index) | R1 094ae41: symptom-workaround (removed the module). R2 7b77d47: always build devtools dist. R3 7d781bf ✓ — the real bug: the shared layer-dist cache was keyed on a static version, so a cache hit restored a dist set missing packages across apps building different package sets | Fix: key the cache on the resolved build-set identity; proof 034a42a ✓ restored the review overlay | Fixed | A shared build cache keyed without build-set identity corrupts across consumers; a "fix" that bumps a cache version papers over it |
| #133/#110 cross-env cookie/data leakage (pre-shallow) | __Secure-better-auth cookie collisions — staging logins leaking into production; sibling #110: a fanfare PR preview could read/write real till data (shared prod DB) | One registrable domain for both envs; shared bindings | Epic #133 (closed 2026-06-15, GitHub only) | Fixed structurally: prod → <app>.friendlyinter.net, staging → <app>.pmcp.dev — separate registrable domains; per-env D1/KV ids (bindings don't inherit across wrangler envs) | Prefer structural impossibility over convention — the repo's signature move (also #347: a push event can never set environment=production) |
| #552–#556 day-one red-team auth findings | Within days of the red-team agent shipping (#540) | (a) Invitation-resend born-broken: getOrganizationMembershipDirect used a bare member symbol never imported → ReferenceError, plus call-site args swapped vs the (organizationId, userId) signature — verified in f9219b4 ✓ body; failed closed since PR #248, so nobody ever successfully resent an invitation. (b) Scoped-access mint trusted the token role from the request body while only checking the caller was any member → member could mint an elevated token | Fixes f9219b4 ✓ (#552), 19e4c30 ✓ (#556, admin/owner only), b692d5b ✓ (#554 refresh hardening) | Fixed | "Fails closed" can hide being completely broken; never trust role/privilege fields from the request body; adversarial review pays immediately on auth surfaces |
| #108 Workers→Pages→Workers boomerang (pre-shallow) | N/A — a platform decision, not a breakage | Apps ran on Workers, moved to Pages (commit ee2946ed, 2026-01-18, "simplify hub.db config") — then Wrangler auto-provisioning (4.45+) killed exactly the friction that motivated the move, so #108 moved back to Workers, piloted on throwaway three-demo first | Epic #108 (closed 2026-06-15, GitHub only); root CLAUDE.md "not Pages — ignore older docs/commits that say Pages" | Settled: Workers is the standard | Platform decisions are timestamped simplifications, not doctrine — re-litigate when the underlying constraint dies |