فهرست منبع

Document prototype hardening lessons

Tom McKenzie 1 ماه پیش
والد
کامیت
f8715c9381
1فایلهای تغییر یافته به همراه36 افزوده شده و 0 حذف شده
  1. 36 0
      docs/blog/2026-09-19-hardening-the-lever.md

+ 36 - 0
docs/blog/2026-09-19-hardening-the-lever.md

@@ -0,0 +1,36 @@
+---
+date: 2026-09-19
+title: Hardening the lever without sanding off the fun
+---
+
+# Hardening the lever without sanding off the fun
+
+The first prototype proved the loop. The second pass proved that the loop must own its rules on the server, not only in the screen that happens to call it.
+
+## The browser is a view, not a referee
+
+The original client hid actions after lock, but the API still accepted them. It also trusted chip counts because the buttons only sent `1` and `-1`. Direct requests could veto after lock, store a string as a chip count, or pull a hand without joining it.
+
+The fix was small: normalize input at the Worker boundary, validate it again where the hand owns the state, and make every operation state its membership and phase rules. The UI can now stay playful without carrying the integrity of the game.
+
+## Safe templates did not require a framework rewrite
+
+Standalone lit-html kept the plain-JavaScript shape and the existing template-literal feel. Dynamic names, questions, options, and Jev values now enter the DOM as text bindings instead of parsed HTML. Event handlers are functions, lists are templates, and a state update patches the existing tree.
+
+This removed the stored-script path without introducing components, Shadow DOM, or a new application architecture.
+
+## One object still has asynchronous races
+
+A Durable Object is the right owner for a hand, but an external Jev request yields control. A newer chip move can finish its Jev call before an older one and then be overwritten by stale odds.
+
+Each odds request now carries the hand revision and request number that produced it. Only the latest matching result can land. Pulling also cancels the pending debounce, requests fresh odds once, and runs as a single flight.
+
+## Consensus is a different game mode
+
+The smoke run reproduced the important product bug: both players put every chip on Thai, Jev selected `one_tap`, and sampling still let a 17 percent option win.
+
+`one_tap` now confirms the highest-weight real option. Craps and reels still sample. The next live run returned Thai and the dealer line, “Unanimous. Boring. Go eat.” The guardrail preserved the joke instead of flattening it.
+
+## Keep the sharp edge visible
+
+The dependency audit is down from three high and four moderate findings to one moderate transitive finding in drizzle-kit's retired esbuild loader. The affected development server is not used by this app, and the current package has no patched upgrade path. It stays visible rather than forcing a breaking downgrade.