Skip to content

fix(client): getRuntimeStatus rows are the FlowRuntimeState contract - #23956

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23859-client-runtime-status-type
Oct 16, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23859-client-runtime-status-type

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23859

Clause-②: no

What changed

client.automation.getRuntimeStatus() declared its rows as a hand-typed { name, enabled, bound }. GET /automation/_status serves the automation engine's getFlowRuntimeStates() rows unchanged, and each row is the declared contract FlowRuntimeState (@objectstack/spec/contracts). The method now returns a Promise of { flows: FlowRuntimeState[]; total: number }, so an SDK caller reads status, triggerType, object, reason and unboundCause without a cast.

  • packages/client/src/index.ts: FlowRuntimeState joins the existing type-only @objectstack/spec/contracts import, in the group of contract types this SDK relays verbatim. The getRuntimeStatus return 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 reads reason, unboundCause (as FlowUnboundCause), status, triggerType and object through the client's own row type, each with the contract's optionality. A labelled green-in-both-states guard holds name, enabled and bound required.
  • .changeset/23859-client-runtime-status-type.md: @objectstack/client patch, 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-contract armedFrom / shadowed, and every other client method.

Mechanism assumptions, measured on base 0744f9436

  1. No caller breaks. name: string, enabled: boolean and bound: boolean are REQUIRED on FlowRuntimeState (packages/spec/src/contracts/automation-service.ts:616, :618, :626). In-repo TypeScript consumers of getRuntimeStatus are 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 no getRuntimeStatus. objectui at origin/main f78efdd has zero getRuntimeStatus hits, with a control: client.automation.* siblings hit apps/console/src/pages/developer/FlowRunsPage.tsx. objectui reads _status with a raw fetch (PackagedAutomationPage.tsx), so no SDK type change reaches it. unboundCause also has zero hits on objectui origin/main.
  2. The wire matches the contract. packages/runtime/src/domains/automation.ts:2816 answers deps.success({ flows, total: flows.length }) with flows = svc.getFlowRuntimeStates(), typed through Pick of IAutomationService. Pinned by packages/runtime/src/domain-handler-registry.test.ts:833 (full-shape pass-through, toEqual) and :855 (reason survives the door; absent on a row that has none).
  3. The .d.ts changes only here. @objectstack/client built at base and at head, dist/index.d.ts diffed: the contracts import gains FlowRuntimeState, the method's JSDoc gains five lines, and flows becomes FlowRuntimeState[]. Nothing else. index.d.mts is byte-identical to index.d.ts at head.

Verification at 67772f581

  • pnpm --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 --listFiles lists all 52 client test files, return-type-precision.test.ts among them, so the pin is compiled.
  • pnpm --filter @objectstack/client test: exit 0, Test Files 52 passed (52), Tests 671 passed (671).
  • Targeted vitest run --reporter=verbose over return-type-precision, meta-automation-descriptors, client.test: exit 0, 3 files, 221 tests. Both existing pins pass: getRuntimeStatus GETs the underscore-guarded _status route and declares no list.
  • pnpm exec eslint --no-inline-config over the two changed .ts files: exit 0. The repo-wide run is the Lint & Repo Gates check.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 63 commands from merge base 0744f9436. 61 exit 0. 2 exit 3 PREREQUISITE NOT MET, read as NOT MEASURED, not red: check:dual-build-cjs-loads needs a whole-tree build, and check:skill-examples (client SDK surface) needs fresh client / client-react declarations. --ran reconciliation: 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.mjs replaced the new signature with the pre-fix element type, rebuilt structurally from the contract so the import stays used: an array of Pick of FlowRuntimeState over name, enabled and bound. The anchor went from 1 hit to 0, and the blob from 9e5f53019589 to 955529918fc1. Under that mutation, pnpm check:test-typecheck went 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), and git diff HEAD is 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), not dist.

Acceptance notes

  • objectui hand-types its own _status row (packages/app-shell/src/views/setup/packagedFlows.ts, FlowRuntimeStateRow: every field unknown and optional, plus an index signature) and reads it through raw fetch. That is a deliberate lenient projection on the objectui side, and nothing here changes it. Noted, not filed; no carrier.
  • @objectstack/client does not re-export FlowRuntimeState. 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.
  • Other hand-typed client.automation answers checked against their routes: toggle ({ name, enabled }, route :2914) and delete ({ name, deleted: true }, route :3675) match. No other divergence was seen.
  • main moved 12 commits past the base before this PR opened. None touch packages/client, packages/spec/src/contracts or the automation route (git diff --name-only over those paths is empty), and git merge-tree is clean, so main was not merged in. The merge queue rebuilds on current main.

Generated by Claude Code

`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>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling labels Oct 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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): node scripts/docs-audit/affected-docs.mjs --json 98ba1bf1d28d44bddd18b3dcff5db2502e8ad6a9 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · #23859 · domain:cli seat 2 · os-tesla · session session_018t6a5rvqPRvEDMCVVW9kYT · 2026-10-16T14:08Z · reviewed head 67772f581f, against GitHub and the branch, not against the report's prose. Holder of claim 6215777713; report on #23859.

  1. Shape. Draft, base main, assignee os-tesla. Line 1 is Fixes #23859, the one closing keyword. Clause-②: no is at line start. 3 files, +60 / −1. check-governed-merges --pr 23956: NOT governed. git merge-tree is clean against origin/main.
  2. The change, read in the diff.
    • getRuntimeStatus's return type is now Promise<{ flows: FlowRuntimeState[]; total: number }>.
    • FlowRuntimeState is added to the existing type-only @objectstack/spec/contracts import.
    • The method's JSDoc gains the [#23859] note.
    • Nothing else in packages/client/src/index.ts moves.
  3. Mechanism assumptions, measured.
    • (1) name, enabled and bound are required in FlowRuntimeState; this seat read it at automation-service.ts :616–:626. So every caller that read them still compiles. The in-repo consumers are client.test.ts :1231 and meta-automation-descriptors.test.ts :108. objectui origin/main f78efdd has 0 getRuntimeStatus hits, with a control showing that sibling client.automation.* calls do hit.
    • (2) The route serves getFlowRuntimeStates() rows unchanged. domain-handler-registry.test.ts :833 and :855 pin that.
    • (3) The .d.ts diff from base to head is the import, the JSDoc and the element type, nothing else.
  4. Pins.
    • returnTypePrecisionPins23859 holds the answer equal to the contract. It also reads reason, unboundCause (FlowUnboundCause), status, triggerType and object through the row type.
    • The three required-field lines are labelled as green in both states, so they guard compatibility and are not evidence.
    • Reverse verification put the pre-fix element back. check:test-typecheck then reported 6 type errors, exactly the six RED-BEFORE lines. The restore was proven by blob.
  5. Changeset, sentence by sentence. @objectstack/client patch, Clause-②: no. The "what was wrong" paragraph matches the route and the contract. "name, enabled and bound stay required" matches the contract. "The request, the route and the values on the wire are unchanged" matches the diff.
  6. Contract review: none is owed. The paths decide no face, and Clause-②: no carries no arm. The claim's Basis line gives the reason: typing the SDK to an already-published contract does not touch Clause ② (「拉回已声明契约不触它」). This seat's read is the review.
  7. Gates, pinned to the head. Check-runs on 67772f581 read at this stamp, latest run per name: 40 names, 34 success, 6 skipped, 0 failure, nothing running. The successes include Build Core, Test Core 1–6/6, TypeScript Type Check and the four Type Check · lanes, all eight Lint · lanes, Lint & Repo Gates, Check Changeset and Governed Surface Queue Guard. The 6 skips are roster names: Build Docs, Console Pin Gate, Dogfood Regression Gate (matrix), Dogfood Verify CLI, Packed-tarball smoke, Temporal Conformance. The dev's local subset at this head: 62 of 63 derived gate commands run with exit 0. One is NOT MEASURED: check:dual-build-cjs-loads, which needs a whole-tree build that CI's Lint lanes have. @objectstack/client: typecheck 0, 52 files / 671 tests.
  8. Accepted deviations: no merge of origin/main before opening (12 commits, none in the client, the contract or the route; merge-tree clean); one lock queue-timeout re-run; one self-stopped queued ablation before it took the lock (nothing mutated).

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 MERGED.


Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

2 participants