Skip to content

feat(spec): CloneFlowResponseSchema declares an optional data.noticeCode beside notice - #29779

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-30noxg
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-30noxg

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread

Fixes #29758

Clause-②: yes (widening)
Metadata-protocol: none

This is the contract-first half of #29727 and unblocks it: the server half (sending the code from the flow clone door) stays on #29727.

维护者速读

  • 改了什么:流程「新建相似」(clone) 接口的响应 schema 在 notice 旁新增可选字段 noticeCode,用一个稳定代码标识这句提示。
  • 为什么改:notice 是服务端写死的英文句子,控制台无从得知是哪一句,中文界面只能原样显示英文;有了代码,控制台可以换成自己的译文。
  • 风险与回滚:仅为可选键,旧服务端不发它时照常解析,notice 仍必填、仍是英文兜底;回滚即撤掉该键,无数据迁移。
  • 先看:packages/spec/src/api/automation-api.zod.ts(CloneFlowResponseSchema 的 noticeCode 与其说明),packages/spec/src/api/automation-api.zod.test.ts(四条 pin),.changeset/29758-clone-flow-notice-code.md。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/api/automation-api.zod.test.ts,预期 72/72 通过。
  • 需要你做的:无,席位落地(键名 noticeCode 在否决窗口内,有异议请在本 PR 说)。

What changes

  • CloneFlowResponseSchema.data (packages/spec/src/api/automation-api.zod.ts) declares noticeCode: z.string().optional() beside notice, described as a stable code naming the notice sentence: a client maps a code it knows to its own translated sentence and falls back to notice verbatim for an unknown or absent code. No code values are enumerated; the vocabulary is the server's (runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727). notice and its describe are unchanged. The schema's TSDoc gains one sentence saying the same.
  • Name: noticeCode, the seat's call under the veto window. A key named THING + Code for the code of a sibling sentence follows declaredCode in packages/spec/src/api/contract.zod.ts.
  • Generated: content/docs/references/api/automation-api.mdx (via gen:docs) is the only artefact the member moves. check:authorable-surface, check:api-surface, check:export-origins, check:declaration-map and check:strictness-ledger stayed green with no regeneration: the authorable-surface shard lists api/CloneFlowResponse:data and nothing below it, and no export was added.
  • Changeset: @objectstack/spec patch, not the minor the dispatch named. Metadata-protocol: none (a REST answer shape is nothing a metadata author writes, and no authorable-surface shard moved), and scripts/check-changeset-no-major.mjs refuses a minor beside none; a non-protocol widening ships patch and keeps Clause-②: yes (widening). @objectstack/client gets no entry: automation.clone() returns CloneFlowResponse['data'] imported from @objectstack/spec (a dependency, external to the client's tsup build), so its emitted types do not change.

Why

The Console prints data.notice verbatim, so the flow "New similar" notice shows English under zh-CN (#29706 row 1). Nothing in the answer named which sentence it was. A code beside it lets the Console translate it, contract-first, before the server sends one.

Tests

packages/spec/src/api/automation-api.zod.test.ts, new describe('CloneFlowResponseSchema — data.noticeCode names the notice sentence'):

  1. accepts a string noticeCode beside notice and keeps it on the parsed value;
  2. an answer without noticeCode still parses;
  3. notice is still required (one issue, invalid_type at data.notice);
  4. a non-string noticeCode is refused (one issue, invalid_type at data.noticeCode).

Ablation, once, on the committed head d419dc32 through scripts/ablation-replace.mjs (the test imports ./automation-api.zod from source, so no dist leg): renaming the key to noticeCodeAblated landed on disk (anchor 1 → 0, blob 767587bb7ef0 → c06b7927ece5); pins 1 and 4 went red (2 failed, 70 passed); restored to blob 767587bb7ef0 with git diff HEAD empty.

Acceptance notes

Consumers of CloneFlowResponse, read on origin/main c9c68288:

packages/metadata-protocol/src/protocol.ts is not touched (freeze).

Verification

All readings on head be18e3d1 (objectstack-ai/objectstack, merge base c9c68288).

Local runs
  • pnpm --filter @objectstack/spec build under the verify lock: VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec check:generated: first run named one stale artefact (content/docs/references/**), regenerated with gen:docs; re-run "All 14 generated artifacts are up to date", exit 0.
  • pnpm --filter @objectstack/spec typecheck under the lock: VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 (the whole spec suite) under the lock: VERDICT command-exit 0, Test Files 892 passed (892), Tests 25326 passed, 1 todo.
  • pnpm lint (eslint . --no-inline-config): exit 0.
  • node scripts/pm/dispatch-gates.mjs --commands: 102 derived families. Run with exit codes recorded before any pipe, then --ran: "102 derived famil(ies) accounted for — 101 run, 1 NOT-MEASURED". Six first exited 3 on missing builds; after turbo run build for @objectstack/lint..., @objectstack/objectql, @objectstack/formula and @objectstack/client-react..., five re-ran at exit 0. NOT MEASURED: check:dual-build-cjs-loads (needs every package's dist; left to CI).
  • node scripts/check-changeset-no-major.mjs --base c9c68288d --event EVENT with this body: exit 0, "LEVEL AXIS: clause-② yes (widening) and metadata-protocol none … a non-protocol change at patch".

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

Card thread session session_01JQwxbWyGo9rhjNEzeo5Ujt, dispatched by domain:server#1.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbWyGo9rhjNEzeo5Ujt


Generated by Claude Code

…ode beside notice

A stable code naming the clone notice sentence, so a client can show its own
translation and fall back to the English notice for an unknown or absent code.

Claude-Session: https://claude.ai/code/session_01JQwxbWyGo9rhjNEzeo5Ujt
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling labels Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/concepts/metadata-lifecycle.mdx (via /api/v1/automation/:name/clone (route, bridged from symbol CloneFlowResponseSchema — its route source's handler names it))

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

  • content/docs/releases/v17/17-6.mdx (via /api/v1/automation/:name/clone (route, bridged from symbol CloneFlowResponseSchema — its route source's handler names it))
  • content/docs/releases/v17/17-7.mdx (via /api/v1/automation/:name/clone (route, bridged from symbol CloneFlowResponseSchema — its route source's handler names it))

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 61 of 218 client-bound route-ledger rows — the other 157 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 157: 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; 102 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 7ba8b11f52215f945ef1fd417d38b1fb00d8c20e → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 019790643f1f1b0e503b71d2b007ac36b29ccc2d — the merge of head be18e3d1b06da2c7fbdadcb3c1382dd046c449ba into base 7ba8b11f52215f945ef1fd417d38b1fb00d8c20e, 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 019790643f1f1b0e503b71d2b007ac36b29ccc2d && git checkout 019790643f1f1b0e503b71d2b007ac36b29ccc2d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7ba8b11f52215f945ef1fd417d38b1fb00d8c20e be18e3d1b06da2c7fbdadcb3c1382dd046c449ba && git checkout -B drift-repro 7ba8b11f52215f945ef1fd417d38b1fb00d8c20e && git merge --no-ff be18e3d1b06da2c7fbdadcb3c1382dd046c449ba

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

⚠️ 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 7ba8b11f52215f945ef1fd417d38b1fb00d8c20e → 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:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G

Contract-review-claim: session_01JQwxbXsK9j25sd7eVwW96G · head be18e3d · 2026-11-03T04:20Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: be18e3d1b06da2c7fbdadcb3c1382dd046c449ba
Local-runs: none
Scope: packages/spec/src/api/automation-api.zod.ts + packages/spec/src/api/contract.zod.ts (the declaredCode precedent the key name cites), packages/spec/src/automation/flow.zod.ts (FlowSchema, the data.flow member the pins' fixture must satisfy), packages/client/src/index.ts (automation.clone, first consumer of CloneFlowResponse['data']), packages/runtime/src/domains/automation.ts and packages/runtime/src/flow-clone.ts (the serving side and FLOW_CLONE_NOTICE), packages/runtime/src/route-ledger.ts (the clone row naming the schema), packages/runtime/src/domains/automation-flow-clone-custom-package.test.ts (parses the served answer through the schema), packages/spec/authorable-surface/api.json (the shard the level axis reads), scripts/check-changeset-no-major.mjs and scripts/pm/clause2-line.mjs (the gate that enforces the level rule), AGENTS.md §3 of the Human Minimum (the level rule). Read, not reviewed. Remainder of the diff (the changeset, the regenerated mdx, the test file) is the lane seat's ACCEPT at TIER_DEFAULT.

① Derived judgments

  • Accept set of CloneFlowResponseSchema.data widens by one optional member noticeCode: z.string().optional(). Every answer that parsed on main ({ flow, packageId, notice }) still parses; an answer carrying a string noticeCode now parses where main's z.object would have stripped it silently (the object is not .strict(), so on main the key was accepted-and-dropped, never refused). Widening, no narrowing. Right.
  • notice stays z.string() required, its describe byte-identical to main. Right.
  • Public type surface: CloneFlowResponse (z.input) and CloneFlowResponseParsed (z.infer) each gain noticeCode?: string. No export added or removed: api-surface/api.json, declaration-map/api.json, export-origins/api.json, json-schema.manifest/api.json unchanged on the head, and check:api-surface / check:export-origins / check:declaration-map are not owed a regeneration. Right.
  • authorable-surface/api.json lists api/CloneFlowResponse:data and its three siblings on both main and the head, nothing below data; a nested key of a REST answer is not an authorable key, so the shard does not move and Metadata-protocol: none is a true reading of the tree. Right.
  • packages/client automation.clone() returns CloneFlowResponse['data'] imported as a type from @objectstack/spec/api; the return type gains the optional key with no source change in the client, and nothing in the client reads data.notice or data.noticeCode, so it type-checks against the widened shape by construction. No client changeset owed: the client publishes nothing it did not publish before. Right.
  • packages/runtime clone handler answers deps.success({ flow, packageId, notice: FLOW_CLONE_NOTICE }) with no noticeCode; the key is optional, so the served answer still parses, and automation-flow-clone-custom-package.test.ts (CloneFlowResponseSchema.safeParse(answer.body).success === true, answer.data.notice === FLOW_CLONE_NOTICE) stays green by construction. Serving the code is runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727's half. Right.
  • route-ledger.ts clone row's note still spells data as { flow, packageId, notice }. Stale by one optional key, prose only, and the PR body names it for runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727 to update when the server sends the code. Not a finding on this PR's hits; noted for runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727.
  • Generated: only content/docs/references/api/automation-api.mdx moves (the data summary row and a new noticeCode nested-shape row). check:generated is answered by CI; see ② for the check-run state.

② Semver level

Changeset .changeset/29758-clone-flow-notice-code.md: '@objectstack/spec': patch, body carries Clause-②: yes (widening) and Metadata-protocol: none; PR body carries the same two lines. Patch is the level the repo's rules require; the triage audit's "spec minor" is superseded by ruling A and is not a finding against the PR.

  • AGENTS.md Human Minimum §3: "The level follows the kind alone: a kind takes at least minor on a package the diff moves, none takes patch; a non-protocol change, widening or breaking, ships patch and keeps its BREAKING banner and ADR-0087 disposition." A key added to a served REST answer changes nothing a metadata author can write, so the kind is none and the level is patch.
  • scripts/check-changeset-no-major.mjs, "The LEVEL axis ([finding] No gate answers whether a changeset's LEVEL fits the surface — Check Changeset is green on patch and on minor for the same diff #16055)", ruling A (maintainer, 2026-10-21, on changeset levels: minor only when the metadata protocol changes (added / narrowed / semantic), patch otherwise; release notes grouped by what the reader must do (maintainer ruling A, 2026-10-21) #25105): "none grades every introduced entry patch"; "A non-protocol widening (REST) or narrowing (a driver, a posture) ships patch"; "none beside a minor is the half of the ruling with teeth ... refused whatever the package, moved or not". The judgeLevel branch if (declared.protocol === 'none') { if (moved.length) none-baseline-moved; if (minors.length) none-minor; none-clean } refuses a minor under none outright. The self-test pins the exact pairing this PR uses: armVerdict('Clause-②: yes (widening)\nMetadata-protocol: none\n') === 'none-clean' ("a yes (widening) with none beside it (a REST widening) ships patch").
  • So the dev's deviation is the rule, not a workaround: a minor here would have been refused by Check Changeset, and correctly so. The gate is right; the triage line "a spec minor" restated the pre-ruling-A coupling of Clause-②: yes to minor.
  • Consistency of the lines: Clause-②: yes (widening) names the accept-set widening ① confirms; Metadata-protocol: none names the unchanged authorable surface ① confirms; patch is what none grades. The two contradiction checks in the gate (added under no, narrowed without the (narrowing) arm) are not engaged. Consistent.
  • Check-runs on the head at the time of this record: Check Changeset success (the level axis on this body and changeset is none-clean), Governed Surface Queue Guard success, PR-body guards success, Check PR Size success, Spec property liveness success, Lint · PM dispatch-gates success, Lint · scoped · tooling self-tests success, Check Documentation Links success, Dogfood Regression Gate success; 7 skipped by design (opt-in and conditional jobs). Still in progress on two reads: Build Core, Build UI Deps, Build Docs, Test Core 1/8 through 8/8, Live E2E UI, Type Check · workspace / source gates / consumer gates / debt ledger, Lint · ESLint / docs & code guards / repo & tooling gates / CI, release & engine gates / scoped · query-options erasure / scoped · slot lookup & corpus. No failure on any completed run. The landing rule (landing-operations.md: all PR checks green, not the required subset) is still owed by those runs; this record does not stand in for them.

③ Boundary flags

  • Dev flag (deviation): "Changeset is @objectstack/spec patch, not the minor the order named." Answered in ②: patch is required by AGENTS.md §3 and ruling A; no action.
  • Dev flag (deviation): "No @objectstack/client entry." Answered in ①: the client's source does not move and its return type follows the spec type by import; no changeset owed.
  • Dev flag (deviation): "The schema TSDoc also gained one sentence naming noticeCode." Read: the TSDoc sentence matches the describe (stable code, console shows its own translation, falls back to notice for an unknown or absent code). No action.
  • open_questions: []. None to answer.
  • Author: PR user.login is objectstack-fleet[bot], so no human login to name.
  • Triage 6594892213 named "a spec minor" and "regenerated artifacts" as binding. The level point is resolved against the repo's written rule in ②; the regeneration point is met (the one artefact the member moves is regenerated, and the ledgers that did not move are shown in ① not to be owed). Escalation not needed: a seat does not out-rule AGENTS.md, and triage's line is the older coupling, not a maintainer ruling.
  • Name veto window: noticeCode stays the seat's call. Precedent read in ④.

④ Design judgment

packages/spec/src/api/automation-api.zod.ts against card #29758's Wanted list, ADR-0126 §9 (no clone lineage, the notice is the stated fact), declaredCode in contract.zod.ts, and the first consumers (packages/client automation.clone, the runtime clone handler, #29706's Console mapping):

  • Optional, string, located beside notice. noticeCode: z.string().optional() sits in data after notice; notice: z.string() is required and its describe is unchanged. An answer with no noticeCode parses; notice absent is refused with exactly one issue at data.notice; a non-string noticeCode is refused with exactly one issue at data.noticeCode. The pins' fixture flow (name matching /^[a-z_][a-z0-9_]*$/, label, type: 'autolaunched', status: 'obsolete' which is in the FlowSchema status enum, two nodes, one edge) satisfies FlowSchema's required members, so the "exactly one issue" assertions are sound against the live FlowSchema. Holds.
  • The describe tells a client what to do. "a client maps a code it knows to its own translated sentence, and falls back to notice verbatim for a code it does not know or when this key is absent (an older server sends none). The values are the server's; notice stays the English fallback." That is the card's Wanted sentence, and it is the whole contract Studio: zh-CN first screens stop mixing English: the clone notice, the new package form, the flow rail group #29706 needs: map known, fall back otherwise, never drop notice. Holds.
  • No values enumerated. The schema is z.string(), not an enum or literal; the describe names no code. The vocabulary stays with the server (runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727). This is the right side of the line: an enum here would make every new notice a spec release and would break the fallback story (an unknown code must parse, not be refused). Holds.
  • Regenerated mdx matches the describe. The nested-shape row for noticeCode in content/docs/references/api/automation-api.mdx carries the describe text verbatim, typed string, marked optional; the data summary row reads { flow: object; packageId: string; notice: string; noticeCode?: string }. Holds.
  • Key name against precedent. declaredCode (contract.zod.ts) is the nearest: a THING + Code key, z.string().optional(), naming an open, producer-owned code beside a required sibling (code there, notice here). The other two *Code keys in packages/spec/src/api (statusCode, authorizationCode in documentation.zod.ts) are HTTP-shaped and not a closer fit. noticeCode reads as "the code of the notice beside it", which is what it is. Holds; the name stays under the veto window as the card says.
  • Attempt to break it. (a) An empty string '' parses as a noticeCode; the describe's "a code it does not know" covers it, so a client falls back to notice; declaredCode has the same latitude, and tightening to .min(1) here would diverge from that precedent for no consumer gain. Not a finding. (b) A server sending noticeCode without notice is refused, which is correct: the English fallback is the contract. (c) main's schema silently stripped an unknown noticeCode; a server that ships the code before this spec lands would have had it dropped at a parsing client, which is why the contract-first order (automation-api: CloneFlowResponseSchema declares an optional noticeCode beside notice, so the Console can translate the flow "New similar" notice #29758 then runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727) is right. (d) Transport: CloneFlowResponse is z.input, so a consumer typing an answer in hand may omit the key; CloneFlowResponseParsed is z.infer, where the key is string | undefined. Both are what an optional key should type to. No must-fix, no should-fix.

Implemented-by: claude/project-thread-30noxg
Reviewed-by: session_01JQwxbXsK9j25sd7eVwW96G

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G

席位核对

ACCEPT · domain:server#1 · head be18e3d1b06da2c7fbdadcb3c1382dd046c449ba · 2026-11-03T04:44Z · contract review PASS 6595431256 at CONTRACT_REVIEW_TIER (schema face: packages/spec/src/api/automation-api.zod.ts, fable subagent, independent of the dev); remainder (test file, regenerated mdx, changeset) read by the seat at TIER_DEFAULT

  1. Shape: draft, base main, Fixes #29758. 4 files, +79/-2: CloneFlowResponseSchema.data gains noticeCode: z.string().optional() beside the unchanged required notice, with 4 pins in automation-api.zod.test.ts, the regenerated automation-api.mdx, and one changeset (@objectstack/spec patch, Clause-②: yes (widening), Metadata-protocol: none). The card was taken on the cross-lane channel 「接手无主阻塞项」 (triage 6594892213). Not governed, under 3000 lines.
  2. Premise measured: the clone answer carries only the English notice, so the Console cannot translate it (Studio: zh-CN first screens stop mixing English: the clone notice, the new package form, the flow rail group #29706 row 1). The ablation reds the accept and refusal pins (report 6595350768).
  3. Gates on this head: check-runs pinned to be18e3d1: 65 total, 57 success, 8 skipped, 0 failed. Dev local: dispatch-gates --ran 102 derived, 101 exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads, which CI runs); spec 892/892 files, typecheck 0, pnpm lint 0.
  4. Accepted deviations: the changeset is patch, not the minor named in the triage audit. The review traced AGENTS.md Human Minimum §3 ("a non-protocol change, widening or breaking, ships patch") and scripts/check-changeset-no-major.mjs, which refuses minor beside Metadata-protocol: none. authorable-surface/api.json does not move, so none is a true reading of the tree. Key name noticeCode is the seat's call under the veto window, following the declaredCode precedent.
  5. Out of scope: serving the code from the runtime and the permission-set door is runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727 (seat 3). The review noted that the packages/runtime/src/route-ledger.ts clone row still spells data as { flow, packageId, notice }; that is passed to runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727, with no new card.
  6. Landing: not governed and under 3000 lines ⇒ the seat lands it (pr_ready + automerge_enable). At MERGED: landing record on automation-api: CloneFlowResponseSchema declares an optional noticeCode beside notice, so the Console can translate the flow "New similar" notice #29758 (closed by Fixes), pm:dispatched + pm:blocking removed; seat 3 told that runtime: the flow and permission-set "New similar" clone notices carry a code, so the Console can translate them (zh-CN shows English today) #29727 is unblocked.

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

Development

Successfully merging this pull request may close these issues.

automation-api: CloneFlowResponseSchema declares an optional noticeCode beside notice, so the Console can translate the flow "New similar" notice

1 participant