Conversation
recipes/apps/chat.md's tutorial described a framework that does not exist. It
showed:
func (s *ChatState) Change(ctx *livetemplate.ActionContext) error {
switch ctx.Action {
case "send":
ctx.Bind(&data)
There is no ActionContext, no Change-with-a-switch dispatch, and no ctx.Bind.
It also defined a Init() error method that nothing calls, put the mutex and the
users map on the state struct when both live on the controller, and passed an
undefined `controller` variable to Handle. Someone following the page could not
have produced a running program.
The real examples/chat/main.go uses the controller pattern: a ChatController
singleton holding the shared data behind a mutex, a per-connection ChatState,
and named action methods dispatched by name.
Steps 2-4 are now rebuilt from that file through `include=` rather than
retyped, so they cannot drift again. The extension snippets under "Things to
add" got the same treatment — persistence now puts the store on the controller
where it belongs, and rate limiting keys on ctx.GroupID() instead of a
per-connection field a second tab would reset.
Two smaller corrections that came out of reading it closely: step 3 of "How it
works" named a SendMessage method (it is Send), and the summary claimed four
methods (there are eight).
CONTRIBUTING.md gains the rule that would have caught this — include code, do
not retype it — and a pointer to VOICE.md. That guidance used to live in
livetemplate/examples/CONTRIBUTING.md, but that repo is archived and read-only,
so this file is now the only place it can live.
Verified: voice-check green (it caught a load-bearing and four passives in my
own new prose first), tinkerdown validate 98/98 which resolves every include,
e2e green, sweep 194/196, and the rendered page read back in a real browser to
confirm the controller API appears and no trace of the invented one does.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0166MK1arBYbVZq6wfm8EsQZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
recipes/apps/chat.md's tutorial described a framework that does not exist. I flagged this in #137 rather than folding it into a prose PR; this is that fix.What it claimed
There is no
ActionContext, noChange-with-a-switch dispatch, and noctx.Bind. The page also:func (s *ChatState) Init() error, which nothing callssync.RWMutexand theusersmap on the state struct — both live on the controller, and a mutex on state is copied per connection and guards nothingcontrollervariable toHandleSomeone following the page could not have produced a running program.
What the app actually does
examples/chat/main.gouses the controller pattern — aChatControllersingleton holding shared data behind a mutex, a per-connectionChatState, and named action methods dispatched by name (Mount,OnConnect,Join,Send,NewMessage,Leave, plus the two peer handlers).Steps 2–4 are now built from that file with
include=rather than retyped, so they cannot drift again. Same for the "Things to add" snippets:ctx.GroupID()instead of a per-connection field that opening a second tab would resetTwo smaller corrections
Reading it closely turned up that "How it works" step 3 named a
SendMessagemethod (it isSend), and the summary claimed four methods where there are eight. Both were mine, from #137.CONTRIBUTING
Adds the rule that would have caught this — include code, don't retype it — plus a pointer to
VOICE.md. That guidance previously lived inlivetemplate/examples/CONTRIBUTING.md; that repo is archived and read-only, so this file is now the only place it can live. Worth knowing separately, sincecontent/contributing/examples.mdstill mirrors from it.Verification
scripts/voice-check.shgreen — it caught aload-bearingand four passives in my own new prose before I noticed themtinkerdown validate content/98/98, which resolves everyinclude=include=line range checked to land on a clean function boundarygo test ./e2e/...green uncached against the prod imagemake sweep194/196 — the 2 are the pre-existing 4.9 MBlarge-tabletimeoutsActionContext/switch ctx.Action/ctx.Bind/Change/Init/SendMessage/Auto-broadcastdoes🤖 Generated with Claude Code
https://claude.ai/code/session_0166MK1arBYbVZq6wfm8EsQZ