Repository navigation
Commit 5363e2d
feat(spec,service-automation): a flow run's result carries the flow's authored label as flowLabel (#20633)
Part of #20318 — stage 1 of 2 (the served authored label). Stage 2, the
objectui reader of `flows.FLOW.label` in the runner header and
completion toast, stays open on the card; this PR does not flip the
ledger row.
Clause-②: yes (widening: `AutomationResult` gains `flowLabel`)
## What changes
`AutomationResult` (`@objectstack/spec/contracts`) gains one optional
member, `flowLabel?: string`: the flow definition's authored `label`,
copied verbatim by `service-automation` at the same exits that copy
`successMessage` / `errorMessage`. `TriggerFlowResponseSchema.data`
(`@objectstack/spec/api`) mirrors it, which its compile-time parity
guard with `AutomationResult` requires. The generated automation API
reference is regenerated. `translateFlow`'s docblock now says where the
fallback label comes from and that the translation key is still unread.
This is option (b) of seat 4's fork, taken by the claim from standing
text: the result already carries flow-level strings copied from the
definition for a runner's benefit.
## The served shape (for the stage-2 sub-issue)
- **Field:** `flowLabel`, type `string`, optional, on `AutomationResult`
and on `TriggerFlowResponse.data`.
- **Set** on every result of an evaluation of a registered flow:
- `status: 'paused'` (first attempt, a retry attempt, a resume that
pauses again, a subflow chain that pauses again);
- terminal success with no `status`, including the two skip exits
(`condition_not_met`, `reentrancy_loop_guard`);
- `'failed'` (the trigger exit and the exhausted-retry exit),
`'stranded'`, `'refused'`;
- a resumed parent whose delegated subflow child failed (no `status`,
`success: false`).
- **Absent** on every refusal that carries a `code` (`FLOW_DISABLED`,
`FLOW_NO_START_NODE`, `FLOW_INPUT_SCHEMA_INVALID` and all six resume
refusals, a nested child's screen refusal included), and when the flow
is not registered.
- **Subflow rule:** always the label of the run the caller addressed,
which is the parent. The child that supplied the screen never lends its
label. Decided from what the runner displays: `ScreenFlowState.flowName`
is the launched flow, and the delegated pause answers with the parent's
`runId`.
- **Verbatim:** `FlowSchema` requires `label`, so the member is always
present on the set above and is always what the author wrote, an empty
string included. It is never replaced by the API name.
- **At the wire:** both runner doors relay the result verbatim on a
`200`, so `data.flowLabel` arrives on `POST
/api/v1/automation/NAME/trigger` (paused, finished, refused or skipped
launch) and on `POST /api/v1/automation/NAME/runs/RUN_ID/resume` (a
further pause, the completion, a refusal). A `400 FLOW_FAILED` answer
does not carry it: the trigger door and `classifyResumeResult` build
`error.details` from their own key set (`errorMessage`, `summary`, and
on resume the stranded verdict), in `packages/runtime`, and this PR
leaves that set alone. See the open question below.
## Premise, verified before the first edit (on `origin/main` c1d8051)
1. Every `successMessage` / `errorMessage` copy site is in `engine.ts`
and reads the local parsed `flow`, whose `label` is a required string.
The one exception, `retryExecution`'s exhausted exit, receives
`flow.errorMessage` as a parameter from `execute()`, which holds `flow`;
the label is now passed beside it. The hits in `subflow-node.ts` /
`map-node.ts` are comments; node executors return a
`NodeExecutionResult`, never an `AutomationResult`.
2. `respondToFlowTrigger` answers the paused arm and the terminal arm
with `deps.success(result)`, the resume door answers every `success !==
false` result the same way, and the dispatcher's `success()` is `{
success: true, data, meta }` with nothing projected. The `400
FLOW_FAILED` arms project `details` from their own key set (above).
## Verification (at `01cd34c7e4`)
- `service-automation`: new `flow-label-on-result.test.ts`, 16 tests
(every PRESENT arm, the subflow chain, verbatim `''`, and the ABSENT
refusals). Full package `vitest run`: 152 files, 1867 tests passed.
`typecheck`: exit 0, test layer 0 debt.
- Ablation, three legs through `scripts/ablation-replace.mjs` (anchor
must hit, restore proved by blob == HEAD): blanking the 13 direct stamps
turned 10 tests red and left 6 green (the refused, retry-exhausted and 4
absent tests), as predicted; blanking the refused chokepoint turned
exactly the refused test red; blanking the retry-exhausted exit turned
exactly that test red.
- Reverse type check: `flowLabel: 42` at the refused chokepoint makes
`service-automation`'s `tsc --noEmit` red with TS2322 at
`engine.ts:9060`, so it reads the rebuilt spec `.d.ts`. Renaming the
mirror member in `automation-api.zod.ts` makes spec's test typecheck red
with 3 errors in `automation-api.zod.test.ts`, so the mirror is
load-bearing.
- `spec`: the touched test files (3 files, 340 tests) pass, `typecheck`
exit 0, `check:generated --fix` regenerated only
`content/docs/references/api/automation-api.mdx`.
- Wire, `@objectstack/verify` (the one package depending on both the
doors and the engine): new `automation-trigger-flow-label.test.ts` plus
the four sibling automation suites, 5 files, 17 tests passed. The
existing paused-run parity test still deep-compares the two routes'
bodies, now with `flowLabel` on both.
- Pin sweep: no test deep-compares an engine `AutomationResult` outside
this package. Consumer suites run green: `plugin-approvals` (791),
`trigger-record-change` (101), `trigger-schedule` (150).
- Gates: `dispatch-gates --commands` derived 111; `--ran` reconciles 109
run and 2 NOT MEASURED. `check:liveness` exit 0.
- NOT MEASURED: `check:dual-build-cjs-loads`, reason: its prerequisite
is every package built (33 had no dist), which is CI-owned.
- NOT MEASURED: `check:type-check-debt`, reason: `--re-measure` re-runs
tsc for every debt-ledger entry repo-wide, none of which is a package
this diff touches, and a 300s ceiling fired. `check:type-check-coverage`
ran green.
## Acceptance notes
- **Surface beyond the claim's list, declared:**
`packages/spec/src/api/automation-api.zod.ts` (+ its test and the
regenerated reference page) is the trigger transport's declared response
schema, bound to `AutomationResult` by `TriggerFlowDataMatchesContract`,
and its `z.object` strips undeclared keys, so a client parsing the
response would drop the label.
`packages/verify/src/automation-trigger-flow-label.test.ts` is the route
pin the dispatch asked for. It lives in `verify` because nothing else
depends on both packages.
- **Two stamped exits no test observes:** `reentrancy_loop_guard` (needs
a same-record re-entrant dispatch) and `executeWithoutRetry`'s failed
exit (the retry loop consumes it and answers from the exhausted exit).
Both are stamped, and the first ablation leg blanked them.
- **The wire file was not ablated at `dist` level.** Its PRESENT
assertions are `toBe(label)`, which an absent member cannot satisfy, and
the engine-side legs above already show the mutation reds the equivalent
pins.
- `seedRunVariables` still writes `$flowLabel` as `flow.label ??
flowName`. The `??` arm is unreachable because `label` is required.
Noted only.
- Read, not measured: the resumed-parent exit for a delegated child
failure carries no `errorMessage`. The contract says `errorMessage` is
set on failure, so a runner would show the raw subflow error there
instead of the parent author's text. The probe at the resume door never
got the shared verify lock, so this stays a note and no card is filed.
Carrier: none.
- The `translations.mdx` bullet, the ledger flip and the `authorWarn`
drop ride the stage-2 reader, per the claim.
`packages/spec/liveness/translation.json` is unchanged: no note names a
missing producer, and nothing in it became false.
## Open question for the seat
Should the `400 FLOW_FAILED` details carry `flowLabel`? My
recommendation is no. No runner surface names the flow on a failure: the
failure toast shows the error text, and the `Flow "NAME" failed`
fallback is built client-side before the request. Widening an ADR-0112
details set in `packages/runtime` with no reader is outside this claim.
---
_Generated by [Claude
Code](https://claude.ai/code/session_014EJ1ED8X4MMrT18BhVx4tx)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4d04b6b commit 5363e2d
9 files changed
Lines changed: 585 additions & 8 deletions
File tree
- .changeset
- content/docs/references/api
- packages
- services/service-automation/src
- spec/src
- api
- contracts
- system
- verify/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
642 | 642 | | |
643 | 643 | | |
644 | 644 | | |
| 645 | + | |
645 | 646 | | |
646 | 647 | | |
647 | 648 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5364 | 5364 | | |
5365 | 5365 | | |
5366 | 5366 | | |
5367 | | - | |
| 5367 | + | |
| 5368 | + | |
| 5369 | + | |
| 5370 | + | |
5368 | 5371 | | |
5369 | 5372 | | |
5370 | 5373 | | |
| |||
5411 | 5414 | | |
5412 | 5415 | | |
5413 | 5416 | | |
5414 | | - | |
| 5417 | + | |
5415 | 5418 | | |
5416 | 5419 | | |
5417 | 5420 | | |
| |||
5568 | 5571 | | |
5569 | 5572 | | |
5570 | 5573 | | |
| 5574 | + | |
| 5575 | + | |
| 5576 | + | |
| 5577 | + | |
5571 | 5578 | | |
5572 | 5579 | | |
5573 | 5580 | | |
| |||
5631 | 5638 | | |
5632 | 5639 | | |
5633 | 5640 | | |
| 5641 | + | |
5634 | 5642 | | |
5635 | 5643 | | |
5636 | 5644 | | |
| |||
5780 | 5788 | | |
5781 | 5789 | | |
5782 | 5790 | | |
5783 | | - | |
| 5791 | + | |
| 5792 | + | |
| 5793 | + | |
5784 | 5794 | | |
5785 | 5795 | | |
5786 | 5796 | | |
| |||
5833 | 5843 | | |
5834 | 5844 | | |
5835 | 5845 | | |
| 5846 | + | |
5836 | 5847 | | |
5837 | 5848 | | |
5838 | 5849 | | |
| |||
6532 | 6543 | | |
6533 | 6544 | | |
6534 | 6545 | | |
| 6546 | + | |
| 6547 | + | |
| 6548 | + | |
| 6549 | + | |
6535 | 6550 | | |
6536 | 6551 | | |
6537 | 6552 | | |
| |||
6593 | 6608 | | |
6594 | 6609 | | |
6595 | 6610 | | |
6596 | | - | |
| 6611 | + | |
6597 | 6612 | | |
6598 | 6613 | | |
6599 | 6614 | | |
| |||
7007 | 7022 | | |
7008 | 7023 | | |
7009 | 7024 | | |
| 7025 | + | |
7010 | 7026 | | |
7011 | 7027 | | |
7012 | 7028 | | |
| |||
7097 | 7113 | | |
7098 | 7114 | | |
7099 | 7115 | | |
7100 | | - | |
| 7116 | + | |
7101 | 7117 | | |
7102 | 7118 | | |
7103 | 7119 | | |
| |||
7256 | 7272 | | |
7257 | 7273 | | |
7258 | 7274 | | |
| 7275 | + | |
7259 | 7276 | | |
7260 | 7277 | | |
7261 | 7278 | | |
| |||
8970 | 8987 | | |
8971 | 8988 | | |
8972 | 8989 | | |
| 8990 | + | |
| 8991 | + | |
8973 | 8992 | | |
8974 | 8993 | | |
8975 | 8994 | | |
| |||
9038 | 9057 | | |
9039 | 9058 | | |
9040 | 9059 | | |
| 9060 | + | |
9041 | 9061 | | |
9042 | 9062 | | |
9043 | 9063 | | |
| |||
11252 | 11272 | | |
11253 | 11273 | | |
11254 | 11274 | | |
11255 | | - | |
| 11275 | + | |
| 11276 | + | |
11256 | 11277 | | |
11257 | 11278 | | |
11258 | 11279 | | |
11259 | 11280 | | |
11260 | 11281 | | |
11261 | 11282 | | |
11262 | 11283 | | |
| 11284 | + | |
11263 | 11285 | | |
11264 | 11286 | | |
11265 | 11287 | | |
| |||
11332 | 11354 | | |
11333 | 11355 | | |
11334 | 11356 | | |
| 11357 | + | |
11335 | 11358 | | |
11336 | 11359 | | |
11337 | 11360 | | |
| |||
11627 | 11650 | | |
11628 | 11651 | | |
11629 | 11652 | | |
11630 | | - | |
| 11653 | + | |
11631 | 11654 | | |
11632 | 11655 | | |
11633 | 11656 | | |
| |||
11730 | 11753 | | |
11731 | 11754 | | |
11732 | 11755 | | |
| 11756 | + | |
11733 | 11757 | | |
11734 | 11758 | | |
11735 | 11759 | | |
| |||
11802 | 11826 | | |
11803 | 11827 | | |
11804 | 11828 | | |
| 11829 | + | |
11805 | 11830 | | |
11806 | 11831 | | |
11807 | 11832 | | |
| |||
0 commit comments