Advance only when each pass condition is objectively true (reduces false positives on tea.Cmd and unsubstantiated blocking claims):
GatePass conditionG1 — Anti–false-positiveYou skimmed NOT Issues below or read references/elm-architecture.md before recording a finding about tea.Cmd returns, value receivers on Update, or nested child Update.G2 — Evidence for blocking / suspicious I/OEach Critical/Major finding names file path + line (or a short quoted snippet) showing the blocking call, huh.Form.Run in the wrong place, or other asserted anti-pattern—not a hypothetical.G3 — VerificationBefore publishing review output, you applied the review-verification-protocol to each proposed finding.
Issue TypeReferenceElm architecture, tea.Cmd as datareferences/elm-architecture.mdModel state, message handlingreferences/model-update.mdView rendering, Lipgloss stylingreferences/view-styling.mdComponent composition, Huh formsreferences/composition.mdBubbles components (list, table, etc.)references/bubbles-components.md
Read elm-architecture.md first! The most common review mistake is flagging correct patterns as bugs.
PatternWhy It's Correctreturn m, m.loadData()``tea.Cmd is returned immediately; runtime executes asyncValue receiver on Update()Standard BubbleTea pattern; model returned by valueNested m.child, cmd = m.child.Update(msg)Normal component compositionHelper functions returning tea.CmdCreates command descriptor, no I/O in Updatetea.Batch(cmd1, cmd2)Commands execute concurrently by runtime
PatternWhy It's Wrongos.ReadFile() in UpdateBlocks UI threadhttp.Get() in UpdateNetwork I/O blockstime.Sleep() in UpdateFreezes UI<-channel in Update (blocking)May block indefinitelyhuh.Form.Run() in UpdateBlocking call
tea.Cmd are NOT flagged as blockinggo
// BAD - mutates model
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.items = append(m.items, newItem) // mutation!
return m, nil
}
// GOOD - returns new model
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
newItems := make([]Item, len(m.items)+1)
copy(newItems, m.items)
newItems[len(m.items)] = newItem
m.items = newItems
return m, nil
}
go
// BAD - blocking in Update
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
data, _ := os.ReadFile("config.json") // blocks UI!
m.config = parse(data)
return m, nil
}
// GOOD - use commands
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, loadConfigCmd()
}
func loadConfigCmd() tea.Cmd {
return func() tea.Msg {
data, err := os.ReadFile("config.json")
if err != nil {
return errMsg{err}
}
return configLoadedMsg{parse(data)}
}
}
go
// BAD - creates new style each render
func (m Model) View() string {
style := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
return style.Render("Hello")
}
// GOOD - define styles at package level or in model
var titleStyle = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("205"))
func (m Model) View() string {
return titleStyle.Render("Hello")
}