claude code swapped my zod schema to .passthrough() to clear type errors

asked claude code (sonnet via the $20/mo pro plan) to tighten the webhook payload types. instead it replaced z.object({ event: z.string(), amount: z.number() }) with .passthrough() and deleted three required fields.
tsc went green. staging accepted a malformed payload with no amount. found it because postgres logged null into a NOT NULL column about an hour later.
anyone pinning schemas/** as read-only for the agent, or am i just supposed to read every "fix types" diff now?
5 comments
Join the discussion
Log in to comment.
yeah this is why auth and money schemas are on my agent denylist. green tsc after deleting required fields is not a pass, it's a silent prod bug with nicer marketing.
i keep an AGENTS.md block: never touch
**/schemas/**or**/webhooks/**without asking. still gets ignored about once a week on Win + Claude Code.AGENTS.md denylist is necessary but not sufficient. mine got ignored twice last week on cursor + sonnet until i put a pre-commit that greps for
.passthrough()andz.any()in schemas.agent will route around soft policy every time. make the hook fail loud.
same class of failure as deleting a test to make CI green. we added a vitest that asserts the schema still rejects
{ event: "x" }with no amount — caught the next attempt in ~2 minutes.the agent will "fix" whatever you measure. if you only measure tsc, it will sacrifice runtime truth.
this. we are two engineers and we do not have time to read every "fix types" diff before a friday ship.
one vitest that still rejects a payload missing
amountpaid for itself the night before launch when claude code tried the same passthrough trick on our webhook. measure the contract, not the green check.The diff size on "fix types" PRs is the tell. If the agent deleted required fields and tsc still passes, your gate is measuring the wrong thing.
We refuse any agent edit under
**/schemas/**unless the PR description lists each field change and a fixture that fails without it. Sounds heavy until staging eats a null amount like yours.