Repository navigation
fix(client): getRuntimeStatus rows are the FlowRuntimeState contract - #23956
Conversation
`client.automation.getRuntimeStatus()` declared its rows as a hand-typed
`{ name, enabled, bound }`, narrower than what `GET /automation/_status`
serves: the engine's `getFlowRuntimeStates()` rows, unchanged, typed by the
declared contract `FlowRuntimeState` in `@objectstack/spec/contracts`. The
optional `status`, `triggerType`, `object`, `reason` and `unboundCause` were
therefore invisible to SDK callers.
The return type is now `{ flows: FlowRuntimeState[]; total: number }`, with
`FlowRuntimeState` added to the existing type-only contracts import. A
type-level pin in return-type-precision.test.ts holds the answer equal to the
contract and reads the five optional fields through the client's row type.
Patch changeset for @objectstack/client. Card 23859.
Claude-Session: https://claude.ai/code/session_018t6a5rvqPRvEDMCVVW9kYT
Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 16 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
席位核对ACCEPT · #23859 ·
Landing: once every check on the head is green or an expected skip, this seat flips the PR ready and arms auto-merge through the relay, then follows it to Generated by Claude Code |
Fixes #23859
Clause-②: no
What changed
client.automation.getRuntimeStatus()declared its rows as a hand-typed{ name, enabled, bound }.GET /automation/_statusserves the automation engine'sgetFlowRuntimeStates()rows unchanged, and each row is the declared contractFlowRuntimeState(@objectstack/spec/contracts). The method now returns aPromiseof{ flows: FlowRuntimeState[]; total: number }, so an SDK caller readsstatus,triggerType,object,reasonandunboundCausewithout a cast.packages/client/src/index.ts:FlowRuntimeStatejoins the existing type-only@objectstack/spec/contractsimport, in the group of contract types this SDK relays verbatim. ThegetRuntimeStatusreturn type and its JSDoc change. No other method changes.packages/client/src/return-type-precision.test.ts:returnTypePrecisionPins23859, a type-level pin in this file's existing style. It holds the answer EQUAL to{ flows: FlowRuntimeState[]; total: number }and readsreason,unboundCause(asFlowUnboundCause),status,triggerTypeandobjectthrough the client's own row type, each with the contract's optionality. A labelled green-in-both-states guard holdsname,enabledandboundrequired..changeset/23859-client-runtime-status-type.md:@objectstack/clientpatch,Clause-②: no. Typing the SDK to an already-published contract does not touch Clause ②.Hold-offs kept, as the claim names them:
packages/cli/src/commands/serve.ts(its feature-detected local annotation), the engine's off-contractarmedFrom/shadowed, and every other client method.Mechanism assumptions, measured on base
0744f9436name: string,enabled: booleanandbound: booleanare REQUIRED onFlowRuntimeState(packages/spec/src/contracts/automation-service.ts:616,:618,:626). In-repo TypeScript consumers ofgetRuntimeStatusare the two client tests only (git grep; the other hits are prose, the route ledger's string and a migration sentence). The scoped client has nogetRuntimeStatus. objectui atorigin/mainf78efddhas zerogetRuntimeStatushits, with a control:client.automation.*siblings hitapps/console/src/pages/developer/FlowRunsPage.tsx. objectui reads_statuswith a rawfetch(PackagedAutomationPage.tsx), so no SDK type change reaches it.unboundCausealso has zero hits on objectuiorigin/main.packages/runtime/src/domains/automation.ts:2816answersdeps.success({ flows, total: flows.length })withflows = svc.getFlowRuntimeStates(), typed throughPickofIAutomationService. Pinned bypackages/runtime/src/domain-handler-registry.test.ts:833(full-shape pass-through,toEqual) and:855(reasonsurvives the door; absent on a row that has none)..d.tschanges only here.@objectstack/clientbuilt at base and at head,dist/index.d.tsdiffed: the contracts import gainsFlowRuntimeState, the method's JSDoc gains five lines, andflowsbecomesFlowRuntimeState[]. Nothing else.index.d.mtsis byte-identical toindex.d.tsat head.Verification at
67772f581pnpm --workspace-concurrency=2 --filter '@objectstack/client^...' build: exit 0.pnpm --filter @objectstack/client build: exit 0.pnpm --filter @objectstack/client typecheck: exit 0.check:test-typecheck: OK ... 0 file(s) / 0 error(s).tsc -p tsconfig.test.json --listFileslists all 52 client test files,return-type-precision.test.tsamong them, so the pin is compiled.pnpm --filter @objectstack/client test: exit 0,Test Files 52 passed (52),Tests 671 passed (671).vitest run --reporter=verboseoverreturn-type-precision,meta-automation-descriptors,client.test: exit 0, 3 files, 221 tests. Both existing pins pass:getRuntimeStatus GETs the underscore-guarded _status routeanddeclares no list.pnpm exec eslint --no-inline-configover the two changed.tsfiles: exit 0. The repo-wide run is theLint & Repo Gatescheck.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 63 commands from merge base0744f9436. 61 exit 0. 2 exit 3 PREREQUISITE NOT MET, read as NOT MEASURED, not red:check:dual-build-cjs-loadsneeds a whole-tree build, andcheck:skill-examples(client SDK surface) needs freshclient/client-reactdeclarations.--ranreconciliation:63 derived famil(ies) accounted for — 61 run, 2 NOT-MEASURED, exit 0. CI runs both on this PR.Reverse verification (one-off, no permanent file)
The fix was committed first. Then
scripts/ablation-replace.mjsreplaced the new signature with the pre-fix element type, rebuilt structurally from the contract so the import stays used: an array ofPickofFlowRuntimeStateovername,enabledandbound. The anchor went from 1 hit to 0, and the blob from9e5f53019589to955529918fc1. Under that mutation,pnpm check:test-typecheckwent red:src/return-type-precision.test.ts: 6 type error(s), exit 1. Six is exactly the six RED-BEFORE lines: the equality and the five optional-field reads. The three compatibility guards produced none. The restore leg is proven: blob after restore == HEAD (9e5f53019589), andgit diff HEADis empty. The gate is green again on HEAD (check:test-typecheck: OK). No build step is involved: the pin reads the client through./index(source), notdist.Acceptance notes
_statusrow (packages/app-shell/src/views/setup/packagedFlows.ts,FlowRuntimeStateRow: every fieldunknownand optional, plus an index signature) and reads it through rawfetch. That is a deliberate lenient projection on the objectui side, and nothing here changes it. Noted, not filed; no carrier.@objectstack/clientdoes not re-exportFlowRuntimeState. A caller that wants to name the row type imports it from@objectstack/spec/contracts, a dependency the client already has, or reads it off the method's return type. Adding a re-export would widen the published surface, so it stays outside this card.client.automationanswers checked against their routes:toggle({ name, enabled }, route:2914) anddelete({ name, deleted: true }, route:3675) match. No other divergence was seen.mainmoved 12 commits past the base before this PR opened. None touchpackages/client,packages/spec/src/contractsor the automation route (git diff --name-onlyover those paths is empty), andgit merge-treeis clean, somainwas not merged in. The merge queue rebuilds on currentmain.Generated by Claude Code