fix(hooks): freeze-guards skip system/seed writes — 23 boot errors + closed-won probability (2.2.2)#462
Merged
Conversation
…ors + closed-won probability (2.2.2) Closes #459. The opportunity_lifecycle and quote freeze-guards ran on every write to a closed/accepted record. The seed re-applies rows on each reboot, and its `close_date: daysAgo(15)` / quote dates re-evaluate to a *new* date every boot, so the re-seed genuinely changes a guarded field on an already-closed record — which the guard rejected. Result: 23 `BodyRunner` errors per boot, and the seed could never set closed-won `probability` to 100 (it fell back to the field default 10). Both guards now fire ONLY for genuine user edits (`ctx.user?.id` present). System / seed / backfill writes (no user) pass — matching this repo's system-write convention (case/lead hooks) and the guards' own stated intent. A user editing a closed opportunity / accepted quote via the UI is still blocked. Verified: reboot on the existing (persisted) DB — the exact 23-error scenario — now logs 0 BodyRunner errors, and all closed_won opps report probability 100 (open stages keep their stage-derived values). verify (validate/build/test 17/17) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #459. Highest-severity finding from the v2.2.1 QA dogfood; fixing before the ObjectStack 16 marketplace release.
Root cause
The
opportunity_lifecycleand quote freeze-guards rejected any changed business field on a closed/accepted record. The seed re-applies rows on every reboot, and its dates (close_date: daysAgo(15), quote dates) re-evaluate to a new day each boot, so a re-seed legitimately changesclose_dateon already-closed opps → guard throws. Effects:BodyRunnererrors on every reboot (log noise, looks broken to ops).probabilitystuck at the field default10— the guard blocked the seed from writing 100.Fix
Both guards now fire only for genuine user edits (
ctx.user?.idpresent). System / seed / backfill writes (no user) pass — matching this repo's system-write convention (case/leadhooks) and the guards' own intent ("only user edits to business fields"). A user editing a closed opportunity / accepted quote through the UI is still blocked (unchanged).Verification
Rebooted on the existing persisted DB — the exact 23-error scenario:
BodyRunnererrors: 23 → 0 (opportunity + quote).closed_wonopps now reportprobability100 (open stages keep stage-derived 25/40/60/80); confirmed via/api/v1/data/crm_opportunity.verify(validate + typecheck + build + vitest 17/17) green.🤖 Generated with Claude Code