Skip to content

Commit 2dc0a77

Browse files
os-zhuangclaude
andauthored
docs(runtime,rest): name both causes of next: null in the state-introspection comments (#11591)
Both dispatchers compute `const next = from === undefined ? null : legalNextStates(schema, field, from);` so `next: null` has two causes -- no `state_machine` rule governs the field, and the caller omitted `?from=`. The comment immediately above each line named only the first. The `rest-server.ts` one was the sharper miss: it asserted a three-valued answer and justified the tri-state on the grounds that a UI must be able to tell the cases apart, directly above the line that folds a fourth input condition onto the same `null`. Both comments now match the semantics already asserted in `docs/qa/platform-checklist/areas/api-backend.json` and the prose in `content/docs/protocol/objectql/state-machine.mdx`. Comment text only -- every changed line is a `//` comment; no expression, return shape or observable behaviour moves. Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR Co-authored-by: Claude <noreply@anthropic.com>
1 parent 12e306a commit 2dc0a77

2 files changed

Lines changed: 17 additions & 6 deletions

File tree

packages/rest/src/rest-server.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6296,10 +6296,16 @@ export class RestServer {
62966296
});
62976297
return;
62986298
}
6299-
// `next: null` = no FSM governs the field; `next: []` =
6300-
// a declared dead end. Same three-valued answer the
6301-
// dispatcher gives, because a UI asking "where can this
6302-
// record go" must be able to tell those apart.
6299+
// Three answer values — `next: null`, `next: []` (a
6300+
// declared dead end), and the legal-next list — the same
6301+
// answer the dispatcher gives, because a UI asking "where
6302+
// can this record go" must tell those apart. But `null`
6303+
// is overloaded across TWO input conditions: no FSM
6304+
// governs the field, or the caller omitted `?from=` (no
6305+
// `from` => no transition table to answer with), which
6306+
// the line below folds onto the same `null` without
6307+
// consulting the rule. A UI therefore cannot read `null`
6308+
// as "no state machine" unless it passed a `from`.
63036309
const next = from === undefined ? null : legalNextStates(schema, field, from);
63046310
res.json({ object: name, field, from: from ?? null, next });
63056311
} catch (error: any) {

packages/runtime/src/domains/meta.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,13 @@ export async function handleMetadataRequest(deps: DomainHandlerDeps, path: strin
232232
// ADR-0020 D3.3 introspection: the legal next states declared by the
233233
// object's `state_machine` validation rule for `:field`. Lets UIs /
234234
// AI authors ask "from here, where can this record go?" instead of
235-
// hard-coding the transition table. Returns `next: null` when no FSM
236-
// governs the field, `next: []` for a declared dead-end state.
235+
// hard-coding the transition table. `next: []` is a declared
236+
// dead-end state. `next: null` has TWO causes: no FSM governs the
237+
// field, or the caller omitted `?from=` (no `from` => no transition
238+
// table to answer with) — the handler short-circuits on that before
239+
// it ever consults the rule. So a `null` answered to a call
240+
// that passed no `from` is not evidence the field has no state
241+
// machine; re-ask with `?from=`.
237242
if (parts.length === 4 && (parts[0] === 'objects' || parts[0] === 'object') && parts[2] === 'state' && (!method || method === 'GET')) {
238243
const name = parts[1];
239244
const field = parts[3];

0 commit comments

Comments
 (0)