Commit 0449c63
`content/docs/automation/hook-bodies.mdx` claimed the write side had **no**
static checking at all, and called it an "accepted gap with no planned
closure". Since #4305 (`validateHookBodyWrites`) and #4344 (the action-side
sibling) that is false: `hook-body-write-unknown-field` and
`action-body-write-unknown-field` parse an L2 body, resolve its literal writes
against the target object's declared fields, and warn with a did-you-mean.
The mirror image of "declared ≠ enforced": here the capability shipped and the
docs still said it had not. An author who drops a real guardrail because the
docs said it does not exist pays the same price as one who trusts a guardrail
that does not.
- "Not statically checked: the write set" → "Write-set checking". Coverage
described accurately: the three literal patterns (tabulated per surface,
since an action's `ctx.input` is its params bag and only `api-crud-literal`
carries over), advisory `warning` that never gates, and the shapes the parser
must skip — computed keys, spreads, dynamic object names, wildcard
`ctx.input`, partial multi-target hits, cross-package targets, aliased input
— so the ABSENCE of a warning is not read as proof of correctness.
- #3700 (structured `writes`, closed as not planned) stays as accurate history,
but the "accepted gap" conclusion is retracted: the gap was closed from the
other end, by parsing the write set out of the source.
- Three now-stale cross-links in `hooks.mdx` follow the renamed anchor. The
wildcard bullet gets sharper rather than deleted — a wildcard hook's
`ctx.input` writes are exactly the shape the lint must skip.
Two claims were corrected against measured behaviour rather than restated:
- **Flow `update_record` has no unknown-field check.** The old advice
("prefer a flow node, they get the static checking hook bodies can't") is
now backwards on this axis. Verified on main: for the same undeclared field,
the hook body and action body each warn and the `update_record` node reports
nothing — `validateReadonlyFlowWrites` walks its `fields` but skips unknown
ones by design (`if (!meta) continue`). The recommendation is kept for what
is still true (structured diffing, the gating `flow-update-readonly-field`)
with the gap named.
- **"Silently never lands" is wrong in both directions.** The lint's own
message says the unknown column quietly vanishes. Measured: nothing strips
it — `applyMutationsToInput` is a plain `Object.assign`, `validateRecord`
walks declared fields only — so it reaches the driver. On SQL the whole write
FAILS (`table deal has no column named stagee`, zero rows stored); on memory/
MongoDB the stray key IS persisted. The doc's runtime paragraph was right and
is kept, now split by driver family. The lint's wording is tracked separately.
Docs only — no behaviour change, empty changeset.
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent a1b61e0 commit 0449c63
3 files changed
Lines changed: 53 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
119 | | - | |
| 119 | + | |
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | | - | |
| 127 | + | |
128 | 128 | | |
129 | | - | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
130 | 158 | | |
131 | | - | |
132 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
133 | 162 | | |
134 | 163 | | |
135 | 164 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | 38 | | |
39 | | - | |
40 | | - | |
41 | | - | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
42 | 45 | | |
43 | 46 | | |
44 | 47 | | |
| |||
84 | 87 | | |
85 | 88 | | |
86 | 89 | | |
87 | | - | |
88 | | - | |
89 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
90 | 94 | | |
91 | 95 | | |
92 | 96 | | |
| |||
179 | 183 | | |
180 | 184 | | |
181 | 185 | | |
182 | | - | |
183 | | - | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
184 | 189 | | |
185 | 190 | | |
186 | 191 | | |
| |||
0 commit comments