Filed by the domain:spec execution seat from the contract review of PR #17608 (card #15117), 2026-09-11T05:07Z. finding only — no domain:*, no priority; triage grades it.
The finding
examples/app-todo/src/actions/task.handlers.ts:44-50, read by state at 8c90c0b0f3:
/**
* Mark a single task as complete.
*
* [#7036] `status` only. `completed_date` is `readonly` — server-owned — so a
* caller's write to it is stripped from the payload before the record is
* validated, and sending it here made this action refuse itself against
* `todo_task`'s `completed_date_required` rule. The stamp belongs to the
* `beforeUpdate` leg of `src/objects/task.hook.ts`, which runs on the
* transition and whose write the strip lets through.
*/
Both mechanism sentences are false, and in the direction that makes a reader less safe. PR #17608 has just removed the identical prose from content/docs/ui/actions.mdx after a contract review established, at the sites the conclusion depends on:
action-execution.ts:1420-1422 — a handler's ctx.engine is bound with { ...base, isSystem: true }, unconditionally.
engine.ts:12213 — the read-only strip is inside if (!opCtx.context?.isSystem), so on a handler's write it does not run at all. The pre-hook withholding of caller readonly keys is gated the same way (:11466).
- Therefore "stripped from the payload before the record is validated" is wrong (nothing is stripped), "made this action refuse itself against
completed_date_required" is wrong (the rule passes on a payload carrying a value), and "whose write the strip lets through" is wrong about why — the strip lets the hook's write through because it never ran, not because it made an exception for it.
The corrected page now says the opposite conclusion: what a handler names, lands — a server-owned field is more dangerous in a handler than in a form PUT, not less.
Why this is worth a card rather than a note
This exact sentence is the demonstrated origin of the falsehood that just cost PR #17608 three review rounds: the docs page copied it from here. Left standing, it is a live source for the next copy. It is shipped example code that both human and AI authors read as a pattern, not a test comment — which is the line I have been holding all session for what earns a card.
One correction to the adopted verdict
The review's card entry says the site is "untouched by this PR, and outside its diff". Half of that is wrong and a future handler needs the accurate version: the lines are untouched (they appear only as context), but the file is squarely in PR #17608's diff — examples/app-todo/src/actions/task.handlers.ts, +32/-24, one of its six files. The round rewrote the block immediately above (lines 14-44, replacing the local ActionContext copy with the published ActionHandlerContext).
That matters because the review offered two dispositions and made one conditional: "a one-line follow-up under the example, or fold it in only if the round is already touching the file." The round is touching the file, so the fold-in branch was in fact available and I want the record to say so.
Why the seat did not fold it in
Deliberate, and the reasoning should be auditable rather than assumed:
So: land #17608, discharge this here as its own narrow change. ⚠️ It must be serialised after #17608 lands — same file, and the hard same-file serialisation rule applies.
Acceptance
Replace the two false mechanism sentences with the true one, in the example's own voice, consistent with the corrected content/docs/ui/actions.mdx. Check the same file for any other survival of the pre-#3914 story before calling it done — ⛔ do not fix only the lines this card quotes and assume they were the only ones; grep the file by state and report the count with a lit control.
Refs: card #15117 · PR #17608 · adopted verdict #17608 (comment)
Generated by Claude Code
Filed by the
domain:specexecution seat from the contract review of PR #17608 (card #15117), 2026-09-11T05:07Z.findingonly — nodomain:*, no priority; triage grades it.The finding
examples/app-todo/src/actions/task.handlers.ts:44-50, read by state at8c90c0b0f3:Both mechanism sentences are false, and in the direction that makes a reader less safe. PR #17608 has just removed the identical prose from
content/docs/ui/actions.mdxafter a contract review established, at the sites the conclusion depends on:action-execution.ts:1420-1422— a handler'sctx.engineis bound with{ ...base, isSystem: true }, unconditionally.engine.ts:12213— the read-only strip is insideif (!opCtx.context?.isSystem), so on a handler's write it does not run at all. The pre-hook withholding of caller readonly keys is gated the same way (:11466).completed_date_required" is wrong (the rule passes on a payload carrying a value), and "whose write the strip lets through" is wrong about why — the strip lets the hook's write through because it never ran, not because it made an exception for it.The corrected page now says the opposite conclusion: what a handler names, lands — a server-owned field is more dangerous in a handler than in a form PUT, not less.
Why this is worth a card rather than a note
This exact sentence is the demonstrated origin of the falsehood that just cost PR #17608 three review rounds: the docs page copied it from here. Left standing, it is a live source for the next copy. It is shipped example code that both human and AI authors read as a pattern, not a test comment — which is the line I have been holding all session for what earns a card.
One correction to the adopted verdict
The review's card entry says the site is "untouched by this PR, and outside its diff". Half of that is wrong and a future handler needs the accurate version: the lines are untouched (they appear only as context), but the file is squarely in PR #17608's diff —
examples/app-todo/src/actions/task.handlers.ts, +32/-24, one of its six files. The round rewrote the block immediately above (lines 14-44, replacing the localActionContextcopy with the publishedActionHandlerContext).That matters because the review offered two dispositions and made one conditional: "a one-line follow-up under the example, or fold it in only if the round is already touching the file." The round is touching the file, so the fold-in branch was in fact available and I want the record to say so.
Why the seat did not fold it in
Deliberate, and the reasoning should be auditable rather than assumed:
Clause-②: yes, so any head move re-hangs the contract-review gate and buys a fifth review for six lines of prose.So: land #17608, discharge this here as its own narrow change.⚠️ It must be serialised after #17608 lands — same file, and the hard same-file serialisation rule applies.
Acceptance
Replace the two false mechanism sentences with the true one, in the example's own voice, consistent with the corrected
content/docs/ui/actions.mdx. Check the same file for any other survival of the pre-#3914 story before calling it done — ⛔ do not fix only the lines this card quotes and assume they were the only ones; grep the file by state and report the count with a lit control.Refs: card #15117 · PR #17608 · adopted verdict #17608 (comment)
Generated by Claude Code