Skip to content

fix(spec): approval node field help opens in business words - #28233

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-4phsso
Oct 30, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-4phsso

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Tesla · project thread

Fixes #27838

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:审批节点在 Studio 流程检查器里显示的字段说明全部改写为业务语言,每条第一句讲这个设置对审批请求起什么作用;“排除提交人”和审批人“组织”两条不再以 ADR 编号、库表字段名或枚举值开头,工程细节移到代码注释(JSDoc)。
  • 为什么改:Studio 把这些说明直接当作字段帮助显示,只露两行,超长折叠到“了解更多”;旧文案写给工程师,管理员看了不知道该怎么选。
  • 风险与回滚:只改说明文字,配置键、类型、默认值、可接受值都不变,旧的审批流程照常解析;回滚即 revert 本 PR。
  • 先看:packages/spec/src/automation/approval.zod.ts(excludeSubmitter、organization、onEmptyApprovers 三处 describe)、packages/spec/src/automation/approval-describe-business-words-27838.test.ts、content/docs/references/automation/approval.mdx(重新生成)。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/automation/approval-describe-business-words-27838.test.ts,预期 7 个用例全绿;或在 Studio 打开审批节点,看“Exclude Submitter”下的提示第一句是“Stops people approving their own requests”。
  • 需要你做的:无,席位落地。

What changes

The Studio flow inspector renders the approval node's property form from the engine-published JSON schema (getApprovalNodeConfigJsonSchema), and each property's description is the help line under the field, clamped to two lines behind "Learn more" (FLOW_HELP_CLAMP_CHARS = 120). Several of those descriptions opened with engineer detail: excludeSubmitter named submitter_id, onEmptyApprovers, admin_rescue, fallbackApprovers and quoted enum values; the approver organization opened with "ADR-0105 D9" and the $root / $parent tokens.

  • packages/spec/src/automation/approval.zod.ts: every .describe() / .meta({ description }) in the file now opens with one sentence in business words: what the setting does to the request, with no decision id, storage column, key or enum literal. The key or literal an author has to write (the onEmptyApprovers policy names, $root / $parent, the escalateTo address forms, the CEL roots) follows the first sentence, and the engineer detail moved to the JSDoc. Swept: the approver type, value, resolveAs, group and organization; the decision-output key, type, multiple and required; the escalation enabled, timeoutHours, action, escalateTo and notifySubmitter; the node's approvers, excludeSubmitter, behavior, minApprovals, lockRecord, approvalStatusField, onEmptyApprovers, fallbackApprovers, decisionOutputs, escalation and maxRevisions. Refusal messages (strictObject history/guidance, the pairing and escalation-target refusals) are not field help and are unchanged.
  • content/docs/references/automation/approval.mdx: regenerated (check:generated --fix, which named check:docs as the only stale artifact).
  • Measured: the describes feed no translation bundle (git grep of the old strings hits only the reference page and ui/ tests that carry their own fixtures), so no bundle is regenerated.
  • No key, type, default or accepted value changed: check:authorable-surface and check:api-surface are green on the built dist.

Tests

  • New approval-describe-business-words-27838.test.ts: walks every description in the published JSON schema (nested approver, escalation and decision-output shapes included, with path controls so a walk that stops at the top level reds) and asserts no first sentence carries a decision id, a backtick, a quoted enum literal, a snake_case or camelCase identifier, or an organization symbol. The prose itself is not pinned.
  • approval-exclude-submitter-25609.test.ts §5: the pins that required submitter_id in the describe and the "Segregation of duties" opening now assert the first sentence names no key, column or policy literal, that onEmptyApprovers and 'auto_approve' are still named, and that submitter_id stays in the JSDoc.
  • Existing pins kept unchanged and green: ApproverType.describe() still routes to approval-approvers-may-resolve-empty and names onEmptyApprovers; minApprovals still states the per-behavior default; onEmptyApprovers still names fallbackApprovers and 'fallback'.

Acceptance notes

  • Part 2 is out of scope here (outside domain:spec): the node descriptor descriptions in packages/services/service-automation/src/builtin/http-nodes.ts and packages/plugins/plugin-approvals/src/approval-node.ts. The exact strings and proposed business wording are in the os-dev report for the seat's follow-up card.
  • ui/packages/app-shell/src/views/metadata-admin/inspectors/FlowNodeInspector.escalationOff-11660.test.tsx quotes the old enabled describe in its header comment as "the governing text". Its meaning is kept (the engineer reading now sits in a comment above enabled in approval.zod.ts), but the quotation is stale; it is a ui/ comment, so it is left for a ui/ touch.
  • The Studio static fallback form (flow-node-config.ts) carries its own hand-written help strings for the approval node; it is only used when the engine publishes no configSchema, and it is a ui/ file.

Verification

All readings at head fc57c565 on objectstack-ai/objectstack (merge base 3a2f4c00; origin/main has since moved by 3 commits that touch no file in this diff).

Tests
  • pnpm --filter @objectstack/spec test: Test Files 758/758, Tests 22559 passed, 1 todo; lock VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec typecheck: lock VERDICT command-exit 0.
  • Reverse verification: the committed fix in place, approval.zod.ts restored from 3a2f4c00 (on-disk count of the old "ADR-0105 D9 — organization" opening = 1), the two describe test files red 8 failed / 36 (all six first-sentence shapes plus the two new §5 pins); restored with git checkout HEAD --, git diff HEAD empty.
Gates
  • dispatch-gates --commands at fc57c565: 103 families, each run with stdin from /dev/null, exit codes recorded before any pipe. --ran: 103 derived, 103 run, 0 NOT MEASURED, 0 unrun, 0 red.
  • Seven families first answered exit 3 (prerequisite not met: unbuilt lint / formula / client / objectql dist, the full workspace dist for check:dual-build-cjs-loads, and a shallow clone for check-plugin-teardown-shape --self-test). Re-run after a workspace build (turbo run build, 116/116 tasks, lock VERDICT command-exit 0) and git fetch --unshallow, all exit 0.
  • pnpm --filter @objectstack/spec check:generated: after --fix, every artifact up to date.
  • The full CI farm (test:repo, the UI lanes) is CI's.

Generated by Claude Code

The approval node config's describe text is the field help the Studio flow
inspector renders. Rewrite every first sentence in approval.zod.ts to say
what the setting does to the request, with no decision id, storage column,
key or enum literal; the literal an author writes follows it, and the
engineer detail moves to the JSDoc. Pin the first-sentence shape across the
whole published JSON schema, and update the excludeSubmitter describe pins.

Claude-Session: https://claude.ai/code/session_01L9qibyR1YFTVfiVFt8svQ3
Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 7 documentable anchor(s).

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/approvals.mdx (via ApproverType (symbol, a top-level const object), admin_rescue (literal, a string literal in ApprovalNodeConfigSchema), auto_approve (literal, a string literal in ApprovalNodeConfigSchema))
  • content/docs/automation/flows.mdx (via auto_approve (literal, a string literal in ApprovalNodeConfigSchema))
  • content/docs/getting-started/common-patterns.mdx (via auto_approve (literal, a string literal in ApprovalNodeConfigSchema))

⛔ 4 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via ApproverType (symbol, a top-level const object))
  • content/docs/releases/v17/17-0.mdx (via admin_rescue (literal, a string literal in ApprovalNodeConfigSchema), auto_approve (literal, a string literal in ApprovalNodeConfigSchema))
  • content/docs/releases/v17/17-7.mdx (via ApprovalNodeConfigSchema (symbol, a top-level const))
  • content/docs/releases/v18/18-2.mdx (via admin_rescue (literal, a string literal in ApprovalNodeConfigSchema), auto_approve (literal, a string literal in ApprovalNodeConfigSchema))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 58 of 210 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 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 7c3cc889f7c64d465486bb94ded8c8ea558d6945 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 2cf717ba4396f18b01c45126faf9d384d67e0ca3 — the merge of head fc57c5652c4f1a1ed65f0d0126eba42246b5af45 into base 7c3cc889f7c64d465486bb94ded8c8ea558d6945, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 2cf717ba4396f18b01c45126faf9d384d67e0ca3 && git checkout 2cf717ba4396f18b01c45126faf9d384d67e0ca3
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7c3cc889f7c64d465486bb94ded8c8ea558d6945 fc57c5652c4f1a1ed65f0d0126eba42246b5af45 && git checkout -B drift-repro 7c3cc889f7c64d465486bb94ded8c8ea558d6945 && git merge --no-ff fc57c5652c4f1a1ed65f0d0126eba42246b5af45

node scripts/docs-audit/affected-docs.mjs --json 7c3cc889f7c64d465486bb94ded8c8ea558d6945

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 7c3cc889f7c64d465486bb94ded8c8ea558d6945 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#2 · os-tesla · session_01L9qibx5r5nhDMwpRs4SL6D

维护者速读

  • 改了什么: 审批节点设置的 23 条字段说明(Studio 流程节点检查器里显示的帮助文字)改成业务语言:第一句说这个设置对审批请求有什么作用,不再以 ADR 编号、内部字段名或枚举值开头;工程细节挪进代码注释,没有丢。
  • 为什么改: 18.3.0 RC 走查时管理员看到的帮助像工程文档(如 “ADR-0105 D9 —”、submitter_id、admin_rescue),看不懂该怎么设。
  • 风险与回滚: 只改说明文字,没有改任何键、类型、默认值或行为。回滚即 revert。
  • 先看: packages/spec/src/automation/approval.zod.ts。
  • 两分钟验证: pnpm --filter @objectstack/spec exec vitest run src/automation/approval-describe-business-words-27838.test.ts,预期全绿(它扫描发布出去的 JSON Schema,旧文案下有 8 条红)。
  • 需要你做的: 无。不属于受管面,纯文案,由席位落地。HTTP 节点和审批节点在节点面板里的描述在别的包里,另开为 Flow node palette help in business words: the HTTP and approval node descriptions #28234。
  • 席位意见: ACCEPT,可落地。

席位核对 · ACCEPT · domain:spec seat 2 (#18549) · 2026-10-30T18:42Z

Head fc57c5652c4f1a1ed65f0d0126eba42246b5af45. Card #27838 (Part 1), claim 6528717388.

  • Shape: draft to main, made by the relay; Fixes #27838; Clause-②: no, Metadata-protocol: none (describe copy only). Changeset @objectstack/spec patch.
  • Contract review: none owed. No key, type, default or accept set moves; the reference page is the regenerated describe text.
  • Diff read by the seat: every changed .describe() opens with what the setting does to the request in business words (who can approve, the deadline and what happens when it passes, send-backs, record lock); the engineer detail (onEmptyApprovers pairing, ADR-0105 tokens) is kept in JSDoc. The new sweep test reads the published JSON Schema and was reverse-verified red on the old copy; the excludeSubmitter §5 pins moved with the copy. No translation bundle is fed by these describes (measured by the card thread).
  • Follow-ups filed: Flow node palette help in business words: the HTTP and approval node descriptions #28234 (Part 2: the HTTP and approval node descriptor descriptions, outside domain:spec, with proposed wording).
  • Acceptance notes: the Docs Drift Check lists approvals.mdx, flows.mdx and common-patterns.mdx for naming admin_rescue / auto_approve; no behaviour changed, so those pages stay. The stale quotation of the old escalation describe in a ui test header comment is noted, not filed.
  • Gates: check-runs on this head 41 success, 9 skipped, 0 red. mergeable_state clean. check-governed-merges --branch: NOT governed, 5 paths, +238/−97.
  • Authority: maintainer standing go-ahead 「按 pm-dispatch 审过的pr你可以自主落地」 (2026-10-30T14:20Z, project thread).
  • Landing: pr_ready + automerge_enable in this act.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 30, 2026 18:43
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 30, 2026 18:43
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#2 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract-review-claim: session_01L9qibw58ehQ2gRHP2h2Puz · head fc57c5652c4f1a1ed65f0d0126eba42246b5af45 · 2026-10-30T18:46Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#2 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: fc57c5652c4f1a1ed65f0d0126eba42246b5af45
Local-runs: none
Scope: packages/spec/src/automation/approval.zod.ts + packages/spec/src/automation/approval-describe-business-words-27838.test.ts (new sweep), packages/spec/src/automation/approval-exclude-submitter-25609.test.ts (section 5 pins), content/docs/references/automation/approval.mdx (regenerated), .changeset/27838-approval-help-business-words.md; read for the claims: the JSON schema walk getApprovalNodeConfigJsonSchema the sweep test reads, scripts/check-doc-authoring.mjs Rule 3 (tracker ids in spec strings)

Inputs: card #27838 (body, claim 6528717388, os-dev-report 6530217232), PR body, the 5-file diff against merge base 3a2f4c0, the head's check-runs (read 2026-10-30T18:47Z: 51 check-runs, all completed: 42 success, 9 skipped (path-filtered), 0 failed, 0 cancelled. Success: Auto Label, Build & E2E UI, Build Core, Build Docs, Build UI Deps, Check Changeset, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Flag docs affected by code changes, Governed Surface Queue Guard, Lint & Repo Gates, Lint · CI, release & engine gates, Lint · ESLint, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Lint · scoped · tooling self-tests, Live E2E UI, PR-body guards (claim · duplicate · Part-of · single-writer path), Plan Test Core shards, Spec property liveness, Test Core, Test Core (all 8), Test UI, Type Check UI, Type Check · consumer gates, Type Check · debt ledger, Type Check · source gates, Type Check · workspace, TypeScript Type Check, filter. Skipped: 18.x upgrade harness (opt-in), Dogfood Regression Gate (matrix shard/3), Dogfood Verify CLI, Lint UI, Packed-tarball smoke (opt-in), Schedule gate · skip when a green push run covers the commit, Temporal Conformance (live PG + MySQL), Test UI (matrix shard/16), UI Published Artifacts.). Author user.login is objectstack-fleet[bot], so no login note is owed. The reviewer is not the drafter (session_01L9qibyR1YFTVfiVFt8svQ3).

① Derived judgments

  • The diff is describe copy only. Every hunk in approval.zod.ts rewrites a .describe() or .meta({ description }) string or adds a JSDoc / line comment; no key, type, .default(), .min(), enum member, xRef annotation, superRefine or refusal message moves. Checked line by line on the 23 strings the report names: ApproverType, approver value / resolveAs / group / organization, decision-output key / label (unchanged) / type / multiple / required, escalation enabled / timeoutHours / action / escalateTo / notifySubmitter, node approvers / excludeSubmitter / behavior / minApprovals / lockRecord / approvalStatusField / onEmptyApprovers / fallbackApprovers / decisionOutputs / escalation / maxRevisions.
  • Against the card's Wanted (first sentence in business words, no decision id, internal field name or enum literal; engineer detail may stay in JSDoc): each new first sentence says what the setting does to the request; the keys and literals an author must write (onEmptyApprovers, 'auto_approve', $root / $parent, the escalateTo address forms, the CEL roots) follow in a later sentence; submitter_id, admin_rescue, the route names and the ADR-0105 D9 id moved into the JSDoc above the rows. The strings stay free of tracker ids (check-doc-authoring Rule 3 posture, which the ApproverType comment already records).
  • Tests hold it in both directions: the new sweep walks every description in the published node JSON schema (path controls for a node key, an approver column, an escalation field and a typed output, so a top-level-only walk reds) and refuses six engineer shapes in the first sentence; the spec(automation): an approval step's excludeSubmitter option, default off — the protocol half of #25573 (ruling 6377731715, letter B) #25609 section 5 pins are re-cut so they no longer demand submitter_id or the "Segregation of duties" opening, still require onEmptyApprovers and 'auto_approve' to be named, and now require that submitter_id is absent from the string. The PR's reverse verification (old describes restored, 8 failed / 36) matches that shape.
  • Reference page regenerated from the describes; measured by the PR that no translation bundle carries these strings (ui tests hold their own fixtures), so no bundle move is owed.
  • Changeset @objectstack/spec patch, Clause-②: no, Metadata-protocol: none: the right grade for copy that changes no accepted shape (the fix(spec): the permission-set form's Name help says when the name is filled from the label, and when to type it #28229 precedent).

② Semver level

patch. The authored protocol does not move: check:authorable-surface and check:api-surface are unchanged on the built dist per the PR body and the Governed Surface Queue Guard / Spec property liveness runs are green on the head; the JSON schema the Studio renders changes only in its description values.

③ Boundary flags

  • No ui/**, no governed path, no skill or ADR in the diff; the strings that were cut carry a decision id only in JSDoc now.
  • Should-fix (not blocking, for the seat's follow-up cards): (a) Part 2, the node descriptor descriptions in service-automation http-nodes.ts and plugin-approvals approval-node.ts, is out of domain:spec and still reads as engineer copy; the report carries the proposed wording. (b) Two ui/ leftovers the PR names: the Studio static fallback form flow-node-config.ts keeps its own hand-written approval help (used only when the engine publishes no configSchema) and now diverges in tone from the describes, and the header comment of FlowNodeInspector.escalationOff-11660.test.tsx quotes the old enabled describe as "the governing text". Both belong on the domain:ui half.
  • Note: onEmptyApprovers's first sentence lists all four outcomes in words and the second sentence restates the four literals; the sweep allows that by design (literals after the first stop), and the restatement is what an author typing the value needs.

④ Design judgment

The change holds against the surface it is read on and the scenario it is accepted against. The reader is the Studio flow inspector, which renders each property's description as the help line clamped to about two lines behind Learn more (PR #27832), so the first sentence is the whole message for most admins; putting the business meaning there and the engineer facts in JSDoc is the right split, and it keeps the describe as the single source for the generated reference page. The sweep pins the shape rather than the prose, so later copy edits stay free while the regression the card found (a decision id or storage column leading the help) cannot come back silently. The two rows the card singled out read correctly against their code: excludeSubmitter says the request goes to the administrators or the named backups and is never approved automatically, which is exactly what the ADR-0105 D9 / #25635 pairing refusal and the admin_rescue default enforce; organization says "another organization of the same group" and names the symbols after, matching APPROVER_ORG_SYMBOLS and the group-posture refusal recorded in its JSDoc. Scope discipline is right: Part 2 and the two ui/ touches are left to their lanes with the wording recorded.

Implemented-by: claude/project-thread-4phsso
Reviewed-by: session_01L9qibw58ehQ2gRHP2h2Puz

VERDICT: PASS

Merged via the queue into main with commit 1ea3fe9 Oct 30, 2026
51 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-4phsso branch October 30, 2026 19:26
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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flow node help in business words: approval config describe text and node palette descriptions are written for engineers (#27356 row 15, #27521 row 39)

1 participant