You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(runtime): action body 被丢弃的 ctx.record 写在调用时可见 (#4345) (#4357)
* feat(runtime,lint,spec): an action body's ctx.record writes are reported, not silently discarded (#4345)
`ctx.record` in an L2 action body is a pre-fetched snapshot that nothing writes
back, so every assignment to it was dropped — a correctly spelled, fully
declared field exactly like an unknown one — while the action returned success.
No diagnostic anywhere: the #4001 "silent no-op manufactures false completion"
shape, one layer below the unknown-column drop #4271 covers.
The snapshot stays read-only. An action's output is its return value and its
write channel is `ctx.api`; making the snapshot writable would raise questions
this bug does not answer (write back to what, under whose permissions, what
`requiresRecord: false` means). What was wrong was the silence.
Runtime: the sandbox installs a set/deleteProperty/defineProperty proxy over
the snapshot, behind an accessor so a wholesale `ctx.record = {…}` cannot swap
the recorder out, and reports the touched keys as
`ScriptResult.droppedRecordWrites`. `actionBodyRunnerFactory` warns naming the
discarded fields and the `ctx.api.object(...).update(...)` remedy. Writes still
work inside the VM, so a body using the snapshot as scratch keeps its reads
coherent — only the silence is removed. As a run-time trap it sees the computed
keys, `Object.assign` and aliases static analysis cannot, and it covers
metadata authored through Studio or the API, which no lint inspects. Hooks
carry no `record` and install no proxy.
Lint: new advisory rule `action-body-record-write-discarded`
(`validateActionRecordWrites`) in REFERENCE_INTEGRITY_RULES, so `os validate`,
`os lint` and `os compile` all report it. It never consults declared fields and
offers no did-you-mean — the field name is not the bug — and it dedupes
defineStack's merged action copies by value, not identity, so one authored
action reports once. Advisory because a body may use the snapshot as local
scratch, which no analysis short of data-flow tells from an intended persist.
Docs: `ScriptContext.record`, `ActionSchema.body`, `ScriptBodySchema`,
`content/docs/ui/actions.mdx` and `content/docs/automation/hook-bodies.mdx` now
state the read-only semantics and name the `ctx.input` analogy as the trap it
is.
Verified on the showcase app: zero findings before, exactly one after planting
the issue's repro — naming both declared fields and proposing the very
`ctx.api` call it replaced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(actions): 说明两端都只报到不了库的写;活写模式保持安静 (#4345)
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
0 commit comments