Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/32379-api-flow-inner-refusal-any-node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/skills': patch
---

skills(objectstack-api): a flow door's `FLOW_FAILED` `details.innerRefusal` is the refusal any node met, not only a write's

The flow-door paragraph described `innerRefusal` as the refusal "a node's write was refused with" and listed three codes as if they were the set. On `main` it is filled by a data node's refused read or write (any declared 4xx, its code the `ErrorCode` member a record save of the same call answers) and by a `script` node whose function name is ambiguous or outside its package's reach (`RESOURCE_CONFLICT`). The paragraph now says so and gives the codes as examples. The "Choosing between `apis:` and a code handler" table now links the `script` node row to objectstack-automation's package rule (silently-wrong item 3) for which function runs, without restating it.

Clause-②: no
Metadata-protocol: none
9 changes: 5 additions & 4 deletions skills/objectstack-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ policy layer over an existing pipeline, never a second execution dialect.
| Use | When |
|:---|:---|
| **`defineStack({ apis })`** | The endpoint is a *projection* of something the platform already executes: query/return records, or trigger a flow. No code, no deploy artifact, publish-gated. **Prefer this.** |
| **A flow that runs your code** | The endpoint needs real handler CODE: point a `type: 'flow'` endpoint at a flow whose `script` node names a stack function (`defineStack({ functions })`), or whose `connector_action` node calls a declared connector (outbound). The URL stays declarative; the code runs where the automation surface already runs it. |
| **A flow that runs your code** | The endpoint needs real handler CODE: point a `type: 'flow'` endpoint at a flow whose `script` node names a stack function (`defineStack({ functions })`; which one runs: [objectstack-automation](../objectstack-automation/SKILL.md#valid-but-silently-wrong-passes-build-fails-at-runtime) item 3), or whose `connector_action` node calls a declared connector (outbound). The URL stays declarative; the code runs where the automation surface already runs it. |

An inbound webhook is a `type: 'api'` flow (objectstack-automation →
**Inbound webhook (`api`) triggers**): it verifies ObjectStack's own
Expand Down Expand Up @@ -357,9 +357,10 @@ A flow door — `POST /api/v1/automation/{name}/trigger`, resume, `/actions`, a
declared `type: 'flow'` endpoint — answers a failed run with `400 FLOW_FAILED`;
its `error.details` is `FlowFailureDetailsSchema` (`api/automation-api.zod.ts`):
`errorMessage?` (the flow author's text), `summary?` (which node failed) and
`innerRefusal?`, the `{ code, message }` a node's write was refused with, `code`
in its wire spelling (`UNIQUE_VIOLATION`, `VALIDATION_FAILED`,
`PERMISSION_DENIED`). Render it as a record form renders a refused save:
`innerRefusal?`, the `{ code, message }` refusal a node met (a data node's read
or write, a `script` node's function name), `code` an `ErrorCode` member in wire
spelling (e.g. `UNIQUE_VIOLATION`, `PERMISSION_DENIED`, `RESOURCE_CONFLICT`).
Render it as a record form renders a refused save:
top-level `userMessage`, then `details.innerRefusal`, then `message`. Absent
keys mean the run produced none — never invent an empty.

Expand Down
Loading