Repository navigation
[Decision] os build cannot lower a job's handler into the new JobSchema.body as ruling E wrote it — withdraw the build lowering (C), or change the functions contract (A) or the job handler form (B)? #21540
Copy link
Copy link
Closed
Labels
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Oct 3, 2026 objectstack-fleet commented
on Oct 3, 2026 ContributorAuthorMore actionsRuling: batch #273 item 1 · letter C · maintainer 「同意c」 2026-10-03T12:01Z
Director seat, summon #32,
session_016tKoy8NJa35Yih1FdzrVmn. Written asobjectstack-fleet[bot]through the relay.- How it was ruled. Batch 🔗 Broken links detected in documentation #273 was presented in the live director chat with options C, A and B. The director recommended C, with fallback A. The maintainer answered 「同意c」.
- Freshness gate:
- this card has no comment;
- spec(system):
JobSchemagains a sandboxedbody, like hooks and script actions, so a job handler is declarable code that travels with a package (ruled on #21489, E) #21515 closedcompletedwhen PR spec(system): JobSchema gains a sandboxed L2bodyand deprecateshandler; a body job has one time limit #21538 landed (f1e4ae56ad), and its close note says this card carries the lowering; - [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489 is claimed by the
domain:cliseat (5967523158), and triage5966135682recorded that this card does not block it; origin/mainhas no text promising that the build lowers job handlers. Searchedcontent/**,packages/spec/src/**,.changeset/**anddocs/**: 0 hits.
The ruling
C: the build lowering is withdrawn. A job
bodyis authored as data.- How a job
bodyis written:{ language: 'js', source, capabilities }. Studio, an AI author and a JSON artifact all write this same form.os buildvalidates a jobbody. It never mints one from a function. - Ruling E (
5964305303on [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489) is amended in one clause only. "objectstack buildlowers inline job handlers into it" is struck. The rest of E stands:JobSchema.body(landed,f1e4ae56ad);handlerdeprecated;- the one binder schedules job bodies on every door ([Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489, in flight);
- install-local refuses an enabled job without a
body(E's C half).
handlerstays deprecated. A job still onhandlerkeeps working on a config or--artifactboot. Install-local refuses it loudly ([Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489).- The reverted lowering stays in branch history only (
4893a0b48b/781609d2f7, reverted inb7cf7f78b8). Nothing of it is re-landed. - The director's error, owned: E's lowering clause assumed that jobs have an inline handler form, as hooks do. This card's premise 1 measured that they never did.
Not taken:
- A: change the
functionscontract (z.function()→ an identity-preserving check) so the build can read the function. One function would then have to serve two contexts, in-process and the sandbox, and the documented({ jobId, ql, logger })form would still be refused. - B: add an inline function form to the deprecated
handlerkey. That adds an authoring form to a key being retired, plus runtime binding work that overlaps [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489. It has the same two-context trap.
四棱(本裁决新记录)
- ① 长远:应用包里的服务端代码只有一种可移植写法——沙箱代码体数据;构建不替作者从本机代码里抠代码体,与 ADR-0088「函数是代码、不是元数据」一致。
- ② 拉动:零——四仓只有
examples/app-showcase声明 job,且其函数在任何方案下都转不了。 - ③ 防 AI:严格 schema(仅 L2、超时一处、二选一必填)即全部契约,写错在解析时响亮拒收;没有「哪种函数可被转换」的隐含规则。
- ④ 不扩散:不加机制、不改
functions契约、不给弃用键加写法。 - 只看①选 C;②③④ 是否翻转:否。
Execution (ruled here; no further decision card)
- This card closes
completedin this act, citing this record. - spec(system):
JobSchemagains a sandboxedbody, like hooks and script actions, so a job handler is declarable code that travels with a package (ruled on #21489, E) #21515 is already closed. Its scope now reads "build lowering withdrawn", by this record. - [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489: its scope is unchanged. Its runtime half binds a job
bodyas data. The struck clause is recorded beside E on that card. - Docs: the jobs page already teaches the data form, so no docs change is owed.
- No
domain:clicard is filed.
Generated by Claude Code
- added a commit that references this issue
on Oct 7, 2026
Ruled: 5968961157 · letter C · 2026-10-03T12:02Z
This card carries #21515's scope item 2, the build lowering. #21515 keeps the spec half, which is draft PR #21538 (
Part of #21515).Filing gate: ② a maintainer decision. Executing ruling E (
5964305303on #21489, 「jobs同意」) falsified one of its premises, so the change of part of a recorded ruling goes back to the maintainer. Filed bydomain:specseat 2 (session_01YDt3PzwfrkuFzUBF89WPmM, seat post #18549), from the #21515 dev report5965564062(open_questions[0]). ⛔ Not a claim. Nothing waits on this card: the spec half lands without it, and #21489's runtime binder needs only the spec half.维护者速读
上一轮你批准「jobs 同意」(E):job 像 hook 一样带沙箱代码体
body,并由os build把 job 的处理函数自动转成body。spec 那一半已做完(PR #21538:JobSchema.body、handler标为弃用、超时只在一处声明)。自动转换这一半做不成:job 的处理函数写在defineStack({ functions })里,defineStack解析时会把每个函数包一层 zod 外壳,构建时拿到的是外壳、读不到作者源码;文档里 job 函数的标准写法({ jobId, ql, logger })即使读得到,转出来的body运行时也会报错,而且body优先,会顶掉原本能跑的函数。C=撤回自动转换:job 的body直接按数据写(和 Studio、AI、JSON 包写法一致),构建只校验;A=改functions的契约让构建读得到源码;B=给 job 加 hook 那样的内联函数写法。推荐 C。要不要撤回这一项?(C/A/B)Background
5964305303): "jobs gain a sandboxedbody, like hooks. The spec half is spec(system):JobSchemagains a sandboxedbody, like hooks and script actions, so a job handler is declarable code that travels with a package (ruled on #21489, E) #21515. Its scope:JobSchema.bodyreusing the hook body shape;handlerdeprecated;objectstack buildlowers inline job handlers into it." Facet ④: 「复用 hook 的体形与唯一绑定器,不另立机制」.bodyand deprecateshandler; a body job has one time limit #21538 (Clause-②: yes (widening), contract review owed):JobSchema.bodyisScriptBodySchemaby reference, L2 only. An L1 expression is refused atbody.languagewith a reason.handleris optional and DEPRECATED ("preferbody"), and a job with neither key is refused.body.timeoutMsis refused on a job, andJobSchema.timeoutMsis the one statement of the limit.bodyas data.4893a0b48b/781609d2f7, reverted inb7cf7f78b8. PR spec(system): JobSchema gains a sandboxed L2bodyand deprecateshandler; a body job has one time limit #21538 touches nopackages/clifile.Governing text:
handler, and why E exists.automation/flow-function.zod.ts:237: "z.function()wraps callables". The docblock says the CLI lowers callables BEFORE the stack is parsed, butdefineStackin the author's own config parses first (premise 2).Premises (each with its re-check, at
origin/main49161683fb)git grep -n "handler: z.string()" origin/main -- packages/spec/src/system/job.zod.ts→:193, 1 hit.functionsentry is zod's wrapper, not the author's function.git grep -n -E "z\.function\(" origin/main -- packages/spec/src/automation/flow-function.zod.ts→FlowFunctionDeclarationSchema.handler(:183) andFlowFunctionEntrySchema's first arm (:266).defineStack → normalizeStackInput → lowerCallables → ObjectStackDefinitionSchemaat781609d2f7. The parse succeeded,job.bodywasundefined, and the recorded extraction warning wasfree-identifiers [func, inst, parse]: zod's identifiers, not the author's.git grep -n "JobHandlerContext" origin/main -- content/docs/automation/jobs.mdx→:156to:170:async function sweepProjectHealth({ ql, jobId, logger }: JobHandlerContext).(async (ctx) => { … })withctx.api/ctx.log. A destructured{ ql, jobId, logger }extracts into a body reading unbound names. Becausebodywins overhandler, it would replace a working handler.git grep -l -E "^\s*jobs\s*:" origin/main -- 'examples/**/*.ts' 'packages/apps/**/*.ts'→examples/app-showcase/objectstack.config.tsonly. Its function uses module-scope helpers andql, so it would not lower under any option.The question
The ruled lowering cannot run as written. Should it be withdrawn, so that a job
bodyis authored as data, or kept by changing a public contract so the build can see the job's function?Options
bodyis written as data ({ language: 'js', source, capabilities }), the form Studio, an AI author and a JSON artifact all write.os buildonly validates.handlerstays deprecated until #21489 binds bodies.body. A job still onhandlerkeeps working onos start --artifact, and install-local refuses it loudly (C of the ruling, in #21489).FlowFunctionEntrySchema/FlowFunctionDeclarationSchema.handlerswitch fromz.function()to an identity-preserving function check (same accept set, no wrapper). The build mints a jobbodyfrom the named function behind a job-context guard (in branch history) and still refusesJobHandlerContext-shaped functions.ctxis converted. The documented({ jobId, ql, logger })form is refused at build, so the author rewrites it anyway. One function now serves two contexts, in-process and sandbox.JobSchema.handleralso accepts an inline function (DEPRECATED, as hooks). The build lowers it tobodyplus a ref, the runtime module bundles it, andAppPluginbinds inline functions on a config boot.Business meaning:
四维分析
os-decision-facets
body即数据,与 hook/动作的元数据形态一致,符合 ADR-0088「函数是代码、不是元数据」;A、B 都要让同一个函数同时满足进程内JobHandlerContext与沙箱ctx两种上下文,这是结构性陷阱,守卫只能拒绝、不能修复。examples/app-showcase声明 job,且其函数用模块作用域辅助函数与ql,任何方案都转不了;自动转换没有一个可被它服务的实测作者。body与一条拒绝路径,AI 要理解「何种函数可被转换」,出错面更大。Prior rulings read: job body,job handler,lowercallables,build lowering,inline handler,sandboxed body → 0 hits; none; thread: 1 ruling(s) (5964305303); repo: objectstack-ai/objectstack
推荐:C。 终态句:两年后,应用包里任何服务端代码(hook、动作、定时任务)都是作者写下的沙箱代码体数据,任何安装门都能跑;构建不替作者从本机代码里「抠」出代码体。只看①选 C;②③④ 是否翻转:否(②零拉动、③响亮拒收、④零新增,均同向)。回退: A,且须等 #21489 先决定进程内 job 处理函数是否获得
ctx.api/ctx.log,否则 A 转出的代码体与进程内函数仍是两套上下文。置信缺口: 前提 2 由 dev 的管线测试在781609d2f7实测,本席未独立复跑;仓外(cloud、hotcrm)无 job,由 E 裁决记录实测,本席未重测。After the ruling
completed, citing the ruling. spec(system):JobSchemagains a sandboxedbody, like hooks and script actions, so a job handler is declarable code that travels with a package (ruled on #21489, E) #21515 closes when PR spec(system): JobSchema gains a sandboxed L2bodyand deprecateshandler; a body job has one time limit #21538 lands, with its scope reading "build lowering withdrawn". The jobs docs already teach the data form. The dev's reverted lowering stays in history only.domain:speccard for thefunctionscontract change (identity-preserving check, its own contract review), then adomain:clicard for the guarded job lowering. Both are ordered after [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489 decides the in-process job handler context.domain:speccard for the inline job handler form, plus binding work folded into [Decision] install-local: a package's declared jobs are never scheduled — refuse the install, name them in the install answer, or make job handlers declarable bodies (the jobs half of #21322) #21489's runtime half.Related
Ruling E
5964305303· #21515 · PR #21538 · the dev report5965564062· #21489 (the runtime binder,domain:cli) · ADR-0088 ·automation/flow-function.zod.ts.Dedupe: the 100 most recently updated open issues here were listed by REST and grepped for
job body,lowerCallablesandjob handlerwithlower: the only hits are #21515, PR #21538 and #21489, the source. No card asks this question.Generated by Claude Code