Skip to content

The action taxonomy has no error-only signature, and no way to say an action is immediate-mode only #803

Open

Description

@David-Noble-at-work

Part of #799. Blocks #802.

docs/plans/action-interface-hierarchy.md proposes signature-based detection:

Return signature Action kind
(T, map[string]any, error) CompensableAction
(T, error) Action
(T) Action, wrapped with nil error

There is no row for (error). Every tier returns a T, because every tier assumes a caller —
which a diverging action does not have.

The table also needs a column it does not have: admissible dispatch mode. The three existing
kinds are admissible in both graph and immediate dispatch. A divergent action is immediate-only.
Adding the signature without the restriction would let it into a graph, which is the one place it
must never appear.

Naming

pkg/op/action.go is emphatic that these names classify a return signature — "a signature
cannot see effects"
— and its doc comments correct themselves twice for having implied effects. That
disqualifies the CQS family: Command, Effect, Procedure and SideEffect all name what
the method does to the world, the axis MethodClaims owns.

ResultlessAction is the obvious candidate and is wrong: it means returns normally, carrying
nothing
. This does not return. The established vocabulary is divergence — C's _Noreturn, C++'s
[[noreturn]], Rust's !, ⊥. DivergentAction states the contract.

But the ladder Action → Fallible → Compensable is one of increasing recoverability, and
divergence has none by construction. It may belong off the end rather than as a fourth rung — and
§8 of docs/architecture/3.6-method-classification.md is titled "Why the three tiers were
rejected."
That section should be read before any tier is added; the answer may be a directive
plus an existing tier, with no new interface.

Asserted, not inferred

§2 of the same document is "Why claims are asserted and not derived." Divergence should follow it:
a +devlore:diverges directive alongside +devlore:defaults and +devlore:struct_param, not
an inference from a bare (error) return. Inference would misfire anyway — a method returning only
error may be an ordinary fallible action with nothing to report.

Where the gate is enforced

Three candidates, not exclusive: codegen refusing to emit a graph binding for a +devlore:diverges
method; the graph assembler rejecting such a node; or Do refusing a non-nil-Graph activation.
The last is the cheapest backstop; the first turns it into a build error, which is better if the
claim is visible at generation time.

Plan and design documents

Kind Document
Plan not yet — the plan arrives when the branch does
Design draft in hand, uncommitted; lands with the first worktree

Epic: #815 · Feature: #799

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area:ArchitectureSystem architecture and designEpic:ProvidersThe provider surface: one feature per providertaskImplementation work item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions