picatz / picatz/flowstate

proto/server: 88 Connect errors carry a message and no detail, `RunResponse.Error.kind` is a free string, and `MutationResult` is a CLI document living in the RPC package

Open
#1,665 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

cli design engine kind/decision
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

Observed behavior

At eb8172f, pkg/flowstate/v1/server/*.go has 88 connect.NewError sites (56 InvalidArgument, 11 PermissionDenied, 10 Internal, 7 FailedPrecondition) and none attaches an error detail. connect.NewErrorDetail appears only in the plugin SDK (plugin/sdk/errors.go:212,248), so the plugin protocol has typed refusals and the public control plane has prose. A client cannot distinguish "input failed declaration binding" from "size limit exceeded" from "tenant not addressable" without parsing a sentence, which is what cmd/flow and the MCP layer do today, and what #1552 is fixing on the CLI side one refusal at a time.

Validate and Compile return DiagnosticReport in the success body, which is right. Run refuses a bad spec with a bare InvalidArgument string, so the same class of problem reaches a caller two ways. RunResponse.Error.kind (service.proto:155) is deliberately an un-enumerated string mirroring a Go type, so a caller branching on it is matching text against Go source.

MutationResult (service.proto:1332-1400) is defined in the service package and returned by no RPC: every constructor is in cmd/flow (lifecycle.go:45,99, signals.go:393, schedule.go:271-385), and Cancel, Terminate and Signal still return empty messages. The proto comment cites #374 for the richer responses.

Desired outcome

  • One flowstate.v1.ErrorDetail message attached to every refusal the server produces: a stable code (the Diagnostic code vocabulary where the refusal is about a file, a small closed set otherwise), an optional field path, and an optional Diagnostic when the refusal is a compile-class problem. RunResponse.Error.kind becomes an enum projected from ErrorKind.
  • The CLI and the MCP layer render from the detail, so #1552's per-refusal typing collapses to one renderer.
  • Cancel, Terminate, Signal, and the schedule mutations return the MutationResult the CLI already prints, produced by the server, so the document a script indexes is the server's word rather than the client's inference.

Acceptance criteria

  • A test asserts every connect.NewError returned by a WorkflowService handler carries an ErrorDetail; the count of sites without one is zero and pinned.
  • flow run -o json on a refused submit prints a document with code and no prose trailer (#1552's acceptance).
  • flow cancel -o json prints the server's MutationResult unchanged.

Constraints and dependencies

  • Additive: kind stays a string until the enum lands beside it, per the repo's carry-both rule.
  • Adjacent: #184 (the error pipeline), #1552, #374, #1647 (diagnostic codes for type errors).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading service.proto and the handlers under pkg/flowstate/v1/server/*.go, then inspect the existing MutationResult constructors in cmd/flow. Search all connect.NewError sites and the relevant CLI JSON output paths; done means every WorkflowService refusal has an ErrorDetail and the run and cancel acceptance cases expose the server-produced fields unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.