Skip to content

docs: name FLOW_INPUT_SCHEMA_INVALID in the four flow refusal-code enumerations - #13824

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-13720-flow-refusal-code-enumeration
Aug 31, 2026
Merged

docs: name FLOW_INPUT_SCHEMA_INVALID in the four flow refusal-code enumerations#13824
os-project-manager merged 1 commit into
mainfrom
claude/issue-13720-flow-refusal-code-enumeration

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes #13720

FlowRefusalCode gained a fourth member in packages/runtime/src/flow-dispatch-status.ts (b6d3d76b5), answered 422 and classified never-dispatched. Three pages were updated with it; four others enumerate the same union and were not — so each told a reader the enumeration was complete while a status they will really receive was absent.

The four edits

page line the row
content/docs/api/declarative-endpoints.mdx 103 the type: 'flow' delegation row
content/docs/api/plugin-endpoints.mdx 51 POST /automation/:name/trigger
content/docs/protocol/kernel/http-protocol.mdx 1228 the declared-endpoint type: 'flow' answer row
content/docs/ui/actions.mdx 349 the type: 'flow' over-REST row

Four lines, one code name added to each. No prose was rewritten, no schema moved, no runtime behaviour changed.

Placement was read off the runtime source, not inferred from the status

The four rows are not interchangeable, and one of them groups its enumeration by exactly the distinction this code turns on, so a copy-paste insertion would have been wrong there.

classifyFlowRefusal in packages/runtime/src/flow-dispatch-status.ts tests the new code inside the never-dispatched arm block:

// ── never dispatched: the producer says WHICH refusal (#9415, #10025) ──
if (result.code === 'FLOW_DISABLED')             -> 409
if (result.code === 'FLOW_NO_START_NODE')        -> 422
if (result.code === 'FLOW_INPUT_SCHEMA_INVALID') -> 422
// ── dispatched and rejected: the producer's lifecycle verdict (#9378) ──
if (result.status === 'failed')                  -> 400 FLOW_FAILED

The module header states the same thing in prose: the guard's verdict is "a pure function of the flow definition", the engine "refuses ONCE, never enters its retry loop", and the row is stamped with no status — the never-dispatched class.

So, per page:

  • declarative-endpoints.mdx, plugin-endpoints.mdx, http-protocol.mdx are flat status lists in engine order. The code is inserted after 422 FLOW_NO_START_NODE and before 400 FLOW_FAILED, which is the order classifyFlowRefusal evaluates.
  • ui/actions.mdx is the page that splits its enumeration into "a run that ran and was rejected" (400 FLOW_FAILED) versus "a dispatch that never happened" (404 / 409 / 422). The code joins the second group. Placing it beside FLOW_FAILED would have told a reader the run started, which the source says it did not.

Two codes now share 422

FLOW_NO_START_NODE and FLOW_INPUT_SCHEMA_INVALID both answer 422. Every entry on all four pages spells the status together with its code, so each stays a self-contained pair rather than a claim about what 422 alone means — an enumeration, not a contradiction. The discriminator is error.code, which is what http-protocol.mdx already tells readers to branch on in the same sentence ("Branch on the status and error.code, never on an inner success flag"). Per-code guidance and the retry semantics stay in the one full table, content/docs/automation/flows.mdx, which three of the four pages already link.

Deliberately not touched

  • content/docs/releases/v17.mdx — it carries the same short enumeration and is out of scope for two independent reasons: release notes are never edited in a code PR (AGENTS.md Documentation Guardrails; the file is the repo's hottest conflict magnet), and that page is a historical record of what v17 shipped rather than a live contract page.
  • content/docs/permissions/system-context.mdx — the card body names it as having been correctly updated, but that page names none of the flow refusal codes and makes no completeness claim, so it is not a fifth omission and nothing was added to it. Verified by grep on this branch: zero hits for any union member.
  • content/docs/references/api/contract.mdx and references/api/error-code-ledger.mdx — both already carry the code and both are head-bannered AUTO-GENERATED. There is no generator half to this change.
  • The docs-drift blindness that let this through is docs-drift: bounded history sweep over the 91 enumeration-carrying pages — measure the real rate of uncaught vocabulary widenings (#11817 ruling) #11995 and is untouched here; that card remains open and is not addressed by this PR.

Verification

Final commit 1974fb160. All gate results below were run on that exact tree (working tree clean, no commits after).

Gate families derived mechanically from the real change set rather than from a recalled list: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack -> 36 families (22 pnpm, 14 direct node), harvested runnably with --commands.

35 of 36 green, 1 not measurable locally. Exit codes were captured before any pipe.

Named in the dispatch, with each gate's own verdict line:

pnpm --filter @objectstack/spec run check:docs      exit=0
  "230 generated files in sync with packages/spec"
  "import examples resolve against api-surface/ (60 accepted gap(s) in the baseline)"

pnpm check:doc-anchors                              exit=0
  "check-doc-anchors: 290 internal #fragment link(s) across 409 source file(s)
   all resolve to a real heading"

pnpm check:doc-authoring                            exit=0
  "doc authoring guard: 393 files clean — no bare metadata literals."

Also green: check:corpus-claim-drift, check:docs-single-h1, check:docs-audit-scope, check:docs-redirects, check:published-readme-links, check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:liveness, check:empty-state, check:variant-docs, check:strictness-ledger, check:yaml-examples, check:role-word, check:react-page-adapter-contract, check:cross-package-test-inputs, check:objectui-changeset, check:pm-half-states, check:changeset-gate-self-tests, plus the 13 direct-node gates including check-empty-changeset, check-adr-0087-registration, check-changeset-no-major, check-doc-frontmatter, check-doc-route-spelling, check-docs-section-name, check-section-landing-index.

node scripts/check-test-completeness.mjs is recorded NOT MEASURED, not red: it exits 3 with PREREQUISITE NOT MET because it grades a saved turbo run test log that only CI produces, and its own output says so.

Three gates first reported PREREQUISITE NOT MET on unbuilt packages (@objectstack/formula, @objectstack/lint, @objectstack/client-react); all three ran green after turbo run build for those packages. @objectstack/spec and its dependency closure were built before any gate ran, since check:docs reads built output rather than source.

Repo-wide ESLint (pnpm lint) was narrowed, and the narrowing is proved rather than assumed. ESLint's own configuration declares no .mdx or .md population — every files glob in eslint.config.mjs is a TypeScript/JavaScript extension set. Asked directly about the five changed paths, ESLint answers for each: File ignored because no matching configuration was supplied. Counted from --format json: 5 results, 0 files actually linted, 0 errors. Since no path in this diff is in ESLint's input set, the repo-wide verdict is identical to origin/main's for every file, touched and untouched alike.

No test changes: this diff contains no executable code.

Zone 2 assumptions

  • A2.1 confirmed — the four rows are differently shaped, and ui/actions.mdx really does split its enumeration into two groups. A single copy-paste sentence would have been wrong there.
  • A2.2 confirmed by the sourceFLOW_INPUT_SCHEMA_INVALID sits in the never-dispatched arm block, above the status === 'failed' arm. The PM's reading was right; nothing was falsified.
  • A2.3 handled — see "Two codes now share 422" above.
  • Premise re-verified on current origin/main (4bc18e542, moved from the 0a8ebf33d the pre-flight used). The union-member census still returns 7 non-generated pages, 5 of which omit the code; four are this card's and the fifth is the release page. All four line numbers still hold.

Generated by Claude Code

…umerations

Four pages enumerate the flow trigger-refusal status contract and each still
listed exactly the three pre-widening codes, stating the enumeration as complete
while `FLOW_INPUT_SCHEMA_INVALID` (422, never-dispatched) was missing.

Placement was read off `packages/runtime/src/flow-dispatch-status.ts`:
`classifyFlowRefusal` tests the code in the never-dispatched arm block, above the
`status === 'failed'` arm that answers 400 FLOW_FAILED. `ui/actions.mdx` is the
one page that groups its enumeration by that distinction, so the code joins its
"a dispatch that never happened" group there.

Every entry spells the status together with its code, so the two codes now
sharing 422 each stay a self-contained pair.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pk26oZ12t5N1hwGW1m1MgC
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 33403513351 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/6) — 失败步骤: Run this shard's tests

    @objectstack/client:test:  FAIL  src/envelope-caller-census.test.ts > #13079 §3 — every call site is classified > the mechanical enumeration and the hand ledger agree, site for site
      ↳ 失败原因: @objectstack/client:test: AssertionError: expected { …(13) } to deeply equal { …(12) }
    @objectstack/client:test:  FAIL  src/envelope-caller-census.test.ts > #13079 §3 — every call site is classified > ⭐ THE NUMBER: zero call sites in this repo would break SILENTLY
      ↳ 失败原因: @objectstack/client:test: AssertionError: expected [ { …(5) }, { …(5) } ] to deeply equal []
    @objectstack/client:test:  FAIL  src/envelope-caller-census.test.ts > #13079 §3 — every call site is classified > records the split: 13 loud pin sites, 6 result-insensitive, 1 not-SDK
      ↳ 失败原因: @objectstack/client:test: AssertionError: expected 21 to be 19 // Object.is equality
    

↳ 失败原因 是判读的关键:超时Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 7 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

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 tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: four pages enumerating the flow refusal codes still omit FLOW_INPUT_SCHEMA_INVALID after #13371

2 participants