Research: state verification for actions — 'can't archive an archived card' #24

Open
opened 2026-08-07 03:28:01 +00:00 by ginjiruu · 0 comments
Owner

Question

What projects/specs let an app declare state-dependent action availability ("can't archive an archived card", "can't reorder a single column") — and which, if any, fits the toolbelt?

Ticket #11 settled that HATEOAS actions are permission-only: generated can_* relations answer "may this user do X", and state conditionals are the renderer's job. This ticket reopens the state side as its own decision: is there a declarative, server-enforced way to write "this action is only valid in this state", beyond imperative aggregate guards?

Candidates to evaluate:

  • OpenFGA conditional relationships (CEL condition on tuples, context passed to Check/BatchCheck) — already in-platform: embeddedfga runs openfga v1.18.1, the model bootstrapper loads Conditions (model_bootstrapper.go:320), and maxConditionEvaluationCost is set (server.go:232). But authz.Check/embeddedfga.Check take Tuple{User, Relation, Object} with no condition context today. Verify the exact supported surface and what plumbing the absorbed authz needs to pass state context.
  • OPA/Rego, AWS Cedar — standalone policy engines; cost of running a second authorization system alongside OpenFGA.
  • XState / statecharts — interaction-level state machines; client-side affordance logic, not server enforcement.
  • Event-sourced aggregate guards — the toolbelt-native enforcement point (command layer reads the aggregate and refuses); imperative Go, not a spec.

Deliverable: a recommendation and, if OpenFGA conditions win, the exact model + context plumbing for the post-map rewrite. Resolve via a /research subagent on a throwaway branch.

Child of: "Toolbelt glue absorption — map: what the toolbelt absorbs from duplicated consumer glue" (#1).

## Question What projects/specs let an app declare state-dependent action availability ("can't archive an archived card", "can't reorder a single column") — and which, if any, fits the toolbelt? Ticket #11 settled that HATEOAS actions are **permission-only**: generated `can_*` relations answer "may this user do X", and state conditionals are the renderer's job. This ticket reopens the *state* side as its own decision: is there a declarative, server-enforced way to write "this action is only valid in this state", beyond imperative aggregate guards? Candidates to evaluate: - **OpenFGA conditional relationships** (CEL `condition` on tuples, context passed to Check/BatchCheck) — already in-platform: `embeddedfga` runs openfga v1.18.1, the model bootstrapper loads `Conditions` (`model_bootstrapper.go:320`), and `maxConditionEvaluationCost` is set (`server.go:232`). But `authz.Check`/`embeddedfga.Check` take `Tuple{User, Relation, Object}` with no condition context today. Verify the exact supported surface and what plumbing the absorbed `authz` needs to pass state context. - **OPA/Rego, AWS Cedar** — standalone policy engines; cost of running a second authorization system alongside OpenFGA. - **XState / statecharts** — interaction-level state machines; client-side affordance logic, not server enforcement. - **Event-sourced aggregate guards** — the toolbelt-native enforcement point (command layer reads the aggregate and refuses); imperative Go, not a spec. Deliverable: a recommendation and, if OpenFGA conditions win, the exact model + context plumbing for the post-map rewrite. Resolve via a `/research` subagent on a throwaway branch. **Child of:** "Toolbelt glue absorption — map: what the toolbelt absorbs from duplicated consumer glue" (#1).
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ginjiruu/toolbelt#24
No description provided.