Skip to content

fix(spec,runtime): functions: [{ name, handler }] 数组形扛得住 objectstack build (#6238) - #6651

Merged
qq9340100 merged 1 commit into
mainfrom
claude/issue-6238-functions-array-lowered
Aug 8, 2026
Merged

fix(spec,runtime): functions: [{ name, handler }] 数组形扛得住 objectstack build (#6238)#6651
qq9340100 merged 1 commit into
mainfrom
claude/issue-6238-functions-array-lowered

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes #6238

同一条缝第三次裂开(#4343 教 union 认裸 lowered ref、#4976 认 lowered declaration,都只动了 map 成员)。完整叙事与读数见分支 head commit;要点:

前提复核 —— 分诊机制假设实测证实

真实流水线四格读数(defineStacknormalizeStackInputlowerCallables → parse):map 两格 ACCEPT,数组两格同栽在同一个 union 成员上 —— 一次加宽同收 bare/declared 两种拼写(数组条目 effect 本就 optional),不需要 #4976 式的第二成员,故未照抄其派生模式。

改动

  1. stack.zod.ts 数组成员的 handler 收下 lowered 字符串 ref —— 四格全部 round-trip;
  2. 连带一处装载缝(runtime/load-artifact-bundle.ts):本次加宽让数组形 bundle 首次可达 mergeRuntimeModule,其数组分支掉进 map 重建丢 effect: 'writes' —— A script node's function is contractually pure, but nothing enforces it — a function that writes makes its run under-report #4396 修掉的静默 un-declaring 换门重进。改前/改后读数在 commit;⚠️ 此 hunk 越出 issue 字面范围,若需拆分可单独摘出(带其两条测试)。

验收与逆向

changeset:spec minor + runtime patch。

交付通道注记

云端工头 G(session_01QBmSqXovE79wARsbwc2Kib)无 GitHub 工具,走交付降级通道:dev push 分支,PM(session_011M7UwH25Unfi73UHim7ajY)代开本 PR 并跟进 CI 至合并。


Generated by Claude Code

…ck build` (#6238)

顶层 `functions` 的数组形通不过它自己的 build。`lowerCallables` 一直在降级数组
分支(把 `handler` 和 `name` 双双改写成 ref),但 `stack.zod.ts` 里 `functions`
union 的数组成员仍然只收 `handler: z.function()`。于是 `objectstack build` 亲手
产出 `[{ name: 'syncBilling', handler: 'syncBilling', effect: 'writes' }]`,再由
自己拒收:`invalid_union: Invalid input`,路径止步于 `functions`,不点名条目、
不点名键、不给原因。

同一条缝第三次裂开,前两次修复正是这次看着小的原因。#4343 教会 union 认裸
lowered ref;#4976 教会它认 lowered *declaration*。两次都只动了 **map** 成员 ——
数组成员是另一条内联记录(数组条目自带 `name`,还有可选 `packageId`,因此不可能
是 `FlowFunctionEntrySchema` 装进列表),加宽其一从不加宽其二。

## 前提复核(实测,非推断)

分诊的机制假设「对称加宽 `handler` 即足」**实测证实**。改动前跑真实流水线
(`defineStack` → `normalizeStackInput` → `lowerCallables` → parse)的四格读数:

| 格 | 降级产出 | parse |
|---|---|---|
| map / bare | `{"scoreLead":"scoreLead"}` | ACCEPT |
| map / declared | `{"syncBilling":{handler,effect}}` | ACCEPT |
| array / bare | `[{"name","handler":"scoreLead"}]` | **REJECT** `invalid_union` @ `functions` |
| array / declared | `[{name,handler,effect}]` | **REJECT** |

两个数组格栽在**同一个**成员上,所以一次加宽同时收两种拼写 —— 这点与 map 形不同:
数组条目的 `effect` 本就 optional,bare 与 declared 只差这个键在不在,不需要
#4976 那样的第二个成员。未照抄 #4976 的派生模式,因为两者结构确实不同。

## 改动

1. **`packages/spec/src/stack.zod.ts`** —— 数组成员的 `handler` 在原有 callable
   之外收下 lowered 字符串 ref。四格全部 round-trip。

2. **`packages/runtime/src/load-artifact-bundle.ts`** —— 本次加宽**让其可达**的装载
   缝。`mergeRuntimeModule` 的数组分支会掉进 map 重建(`bundle.functions` 是数组时
   `existing` 恒为 `{}`),于是合并后的 bundle 变成裸 `{ name: callable }` map,
   `effect: 'writes'` 被丢弃。函数照样注册、照样运行,写入却被计为零 —— 正是 #4396
   修掉的静默 un-declaring 换了扇门进来,也正是让 #4354 broken-sweep 告警对最需要它
   的那次 run 保持沉默的状态。实测读数:

       改前 [ARRAY] collected: {"syncBilling":{handler, effect:"pure"}}   ← 声明丢失
       改后 [ARRAY] collected: {"syncBilling":{handler, effect:"writes"}} ← 与 map 形一致

   数组形在 parse 这关被拒之前,没有任何构建产物到过这条分支;与其把它当作活陷阱
   一起发布,不如同一次改掉。保留数组形状、按条目 `name` 挂回 callable;产物未声明
   条目的模块函数照旧注册(map 分支就是这么做的,数组分支不该比 bundle 构建时少发
   函数)。⚠️ 这一处越出 issue 字面范围,PM 若要拆分可单独摘出该 hunk 与其两条测试。

## 验收(= 扩展 #4976 的跨界 round-trip pin)

`packages/cli/src/utils/lower-callables.test.ts` 的参数化正是 #4976 预留的槽位
(原文:「SCOPE: the map form … Filed as #6238; extend the parametrisation below
when it lands」)。现覆盖 map/array × bare/declared 全四格,外加 packageId 与多条目:
**24 passed(原 18)**。数组格由整栈 parse 钉住(数组成员内联于
`ObjectStackDefinitionSchema`,无导出的单条目 schema),与 build 实际做的断言一致。

## 逆向验证(方向先判后跑,真实读数)

- 撤回 union 新成员 → 预判「恰好 6 条数组行转红」→ 实测 **6 failed | 18 passed**,
  红的正是 5 条数组整栈 parse + 1 条数组产物断言;map 行全绿。恢复后 24/24 绿。
- 撤回 runtime 数组分支 → 预判「恰好 2 条新增 #6238 runtime 测试转红」→ 实测
  **2 failed | 2 passed**,既有两条不受影响。恢复后 4/4 绿。

## 验证读数

- `@objectstack/spec` 测试 **8808 passed / 343 files**;`@objectstack/cli` **983 /
  94**;`@objectstack/runtime` **1613 / 111**。
- typecheck:spec、cli、runtime 三包干净。
- `check:generated` **✓ All 10 generated artifacts are up to date**(10/10,无生成物漂移)。
- `check:spec-parsed-alias` 通过(18 self-test + 1443 别名核对)。
- `pnpm lint` 干净。
- 三个示例应用 `validate` 全部 **exit=0**(crm / showcase / todo;输出中的告警为既有,
  与 `functions` 无关)。
- 已 merge 最新 origin/main(82397b6)后重跑 pin、runtime 测试与 check:generated,均绿。

## 未做 / 留给裁决

数组形在本仓库**零作者**(examples/apps/packages 无一处以数组形书写)。但它是 spec
里第一等的公开形状 —— `stack.zod.ts` 文档注释明列、`lowerCallables` 与
`collectBundleFunctionEntries` 都专门支持、`composeStacks` 还为 map/array 冲突
报错,且 #4976 的测试文件亲自预留了本次修复的槽位。因此按「修」而非「退役」处理;
退役属 ADR-0087 全套,另一个 program,未在此静默删除。

changeset:`@objectstack/spec` minor(接受面加宽)+ `@objectstack/runtime` patch。
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 8, 2026 8:41am

Request Review

@github-actions github-actions Bot added the size/m label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/runtime, @objectstack/spec.

118 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/tenancy-modes.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 8, 2026
@qq9340100
qq9340100 enabled auto-merge August 8, 2026 08:41
@qq9340100
qq9340100 added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit c8d6f6e Aug 8, 2026
26 checks passed
@qq9340100
qq9340100 deleted the claude/issue-6238-functions-array-lowered branch August 8, 2026 09:16
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.

functions: [{ name, handler }] (the array form) cannot survive objectstack build either — #4343/#4976 both fixed only the map form

2 participants