Files
pad/internal/server
xarmian 22f6342794 fix(mcp): bundle BUG-1081 + BUG-1082 + TASK-1076 — three small MCP-UX fixes from dogfooding (#387)
All three caught in Claude Desktop's second-round review against the
deployed cloud build. Independent file surfaces, but they all polish
the same MCP-tool-call user experience so they ride together.

## BUG-1081: star/unstar return structured JSON instead of 204

internal/server/handlers_stars.go — `handleStarItem` and
`handleUnstarItem` previously returned 204 No Content. RESTfully
fine, but the MCP HTTPHandlerDispatcher passes through whatever the
handler wrote — empty body + 204 → empty MCP tool result. Agents
had no signal whether the operation landed. BUG-989's earlier fix
touched the CLI's text output via the JSON branch but missed the
API endpoint itself.

Fix: both endpoints now return 200 OK with `{ref, starred: bool}`.
Mirrors the shape Claude's review requested + the broader "return
enough info to be the next source of truth" pattern note/decide
adopted.

New test pins the wire shape including content-type. Negative
control verified — reverting the handler fails the test with
"expected 200, got 204" on the first assertion.

## BUG-1082: suggested_next surfaces orphans, not just plan-children

internal/server/handlers_dashboard.go — the candidate loop only
walked items that are children of an active plan. Workspaces
without active plans (or with in-progress / high-priority items
outside their active plans) got an empty suggested_next, even
when the obvious answer was "continue your one in-progress task."

BUG-990's earlier fix added in-progress to the active-plan scope
but kept the orphan branch in scope-creep territory. Real
dogfooding showed it's the common case for new workspaces.

Fix: add a second pass that scans all items for in-progress (any
priority — continuation always beats priority) and high/critical-
priority open items not already in the active-plan candidates.
Orphans rank lower than plan-children so existing plan-driven
behavior is preserved when both are present. Reason text drops
the plan-name reference for orphans.

Two existing tests pinned the OLD "no suggestions when no active
plans" behavior — that was pinning the bug. Updated to the new
correct behavior. Added two new tests pinning the in-progress-
beats-priority gating and the rank-below-active-plan ordering.

## TASK-1076: workspace auto-default from OAuth allow-list

internal/mcp/dispatch_http.go + internal/mcp/dispatch_http_advanced.go
— the dispatcher's preprocess flow now calls `maybeInjectWorkspace`
after the existing --assign / --role resolution. When:

  - input["workspace"] is set    → caller wins (no override)
  - d.Lister is nil              → no-op (tests + non-OAuth paths)
  - lister returns 1 workspace   → inject input["workspace"] = slug
  - lister returns 0 or N        → no-op (caller must pass explicitly;
                                   route mapper's existing "missing
                                   required input" error surfaces if
                                   the route needs workspace)

The lister already encodes the right policy (PAT auth → all the
user's workspaces; wildcard token → same; specific allow-list →
intersection with memberships) so we reuse it instead of building
a parallel resolver. Auto-defaulting only when the resolved set
collapses to one is the unambiguous case; multi-workspace tokens
still require explicit choice (silently picking one would be a
real audience-confusion hazard for write operations).

Caller-passed workspace ALWAYS wins — agents that pass an explicit
slug never see it silently overridden by the default. Lister error
falls through to no-op (don't poison input on transient store hiccup).

Tests pin all four matrix cases from the task spec plus three
operational corner cases (nil lister, lister error, copy-on-write
non-mutation).

## Combined CI surface

`make check` clean across lint + tests + web. The test surface
gained:
- TestStarUnstar_ReturnsStructuredJSON (server)
- TestDashboardSuggestedNextOrphan_InProgressBeatsPriority (server)
- TestDashboardSuggestedNextOrphan_RanksBelowActivePlan (server)
- TestMaybeInjectWorkspace_* (mcp, 7 cases)
- TestDashboardSuggestedNextNoPlans + TestDashboardSuggestedNextFromPlannedPlan
  reframed from pin-the-old-bug to pin-the-new-correct-behavior
2026-05-02 21:31:48 -04:00
..