Repository navigation
fix(refusals): name fields and stages by their labels when a converted lead or a closed deal's line items refuse an edit (#2338 items 14–15) - #2354
Merged
Conversation
…d lead or a closed deal's line items refuse an edit Part of #2338 (items 14 and 15). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjXujUz9ErJ5BBgVDx
…ad lock's label table Part of #2338 (item 14). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjXujUz9ErJ5BBgVDx
Part of #2338 (item 14). Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjXujUz9ErJ5BBgVDx
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Author
席位核对Verdict: ACCEPT ·
Generated by Claude Code |
This was referenced Oct 28, 2026
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.
Requested by Irene · project thread
Part of #2338 (items 14–15). Items 1–13 landed in #2346 and #2347; the card can close once this lands.
维护者速读
company、closed_won这类 API 名。RECORD_LOCKED/ 409 不变;给日志和 API 调用方的诊断message原样保留(含 API 名与尝试修改的字段),给用户看的句子走userMessage。回滚即还原本 PR。src/sales/objects/lead.hook.ts(转化线索锁的FIELD_LABELS表与用户句),src/revenue/objects/opportunity_line_item.hook.ts(STAGE_LABELS),test/lead-duplicate-management.test.ts(源码扫描守卫只剥离那一张标签表)。pnpm vitest run test/refusal-labels.test.ts test/converted-lead-guard.test.ts test/opportunity-line-freeze.test.ts,预期全部通过;或在控制台编辑一笔 Closed Won 商机的行项目数量并保存,预期提示 "…is closed (Closed Won), so its line items can no longer be added, changed or removed."。Type of Change
What changes
Item 14: converted-lead lock (
lead_automation)messageis unchanged:Cannot edit converted lead Ada Lovelace - Acme (attempted: company). Make changes on the converted records instead.test/converted-lead-guard.test.tspins the attempted API keys on purpose, and they stay.refuse()now passes a labeluserMessage:Cannot change Company on converted lead Ada Lovelace - Acme; only its Description and Notes can still be edited. Make changes on the converted records instead.Several fields read "Email and Lead Score".crm_leadfield outside itsALLOWEDset, so the body carries aFIELD_LABELStable with one entry per held field (35). A lowered body cannot read object metadata, so the labels are written out, the same route item 12 took.test/refusal-labels.test.tsreads that table out of the lowered body. It asserts that the keys are exactly thecrm_leadfields outsideALLOWEDand that each label equals the object's label. A field added, relabelled or dropped without the table turns it red.Item 15: closed-deal line-item freeze (
opportunity_line_item_freeze)closed (closed_won). TheuserMessagereadsOpportunity Globex Training Package is closed (Closed Won), so its line items can no longer be added, changed or removed.STAGE_LABELSis held tocrm_opportunity.stage's option labels bytest/refusal-labels.test.ts.Pins extended
test/refusal-envelope.test.ts: both sites are added on the shipped path (lowered body, QuickJS) and on the in-process path, withuserWording. The pin says the marked channel carries the label sentence and differs from the diagnostic.test/opportunity-line-freeze.test.ts: every refusal it checks now also pinsuserMessage(in-process, shipped, and the RESTDELETEenvelope).test/converted-lead-guard.test.tshas one new case.test/lead-duplicate-management.test.ts(claim extended by the seat): its source scan asserted thatlead.hook.tsnever containsdisqualification_reason, and that field is one the lock holds and now labels. The scan strips exactly the oneconst FIELD_LABELSliteral, which has no nested brace. It asserts that the literal matched exactly once, and keeps a positive control that it still reads the lock sentence. Any other read of the field still turns it red (ablation A3 below).src/sales/objects/_refusal.ts: the note "Two sites do since Browser pass #2320 on 18.2.0 — HotCRM-side defects (13 items: dashboards shown to personas with no access, a dead-end case close, campaign editors who cannot edit, a toolbar action that always fails, …) — list card, split per item at dispatch #2338" now says four (claim extended by the seat).Tests
pnpm verifyon946467d(this branch merged withorigin/main1f1ea12): validate ✓, typecheck ✓,lint --strict✓, hygiene ✓, token ratchet ✓, build ✓;pnpm test: Test Files 236 passed (236) · Tests 4548 passed | 1 skipped (4549),VERIFY_EXIT=0.An earlier full run on
38a41befailed one test, thelead-duplicate-managementsource scan described above. It was fixed in9ef687fand tightened in00fff87.Ablations (one-shot, each restored from HEAD; git diff HEAD empty and hash-object equal to the HEAD blob afterwards)
userMessageargument removed.converted-lead-guardwent red,ABL_EXIT=1, 1 failed of 20 (tells the user the same refusal in field labels).userMessageargument removed.opportunity-line-freezewent red,ABL_EXIT=1, the closed-deal cases failed.if (input.disqualification_reason === 'duplicate') return;was injected in the lock, outside the table. Thelead-duplicate-managementscan went red,ABL_EXIT=1, so the strip does not widen.Each mutation was confirmed on disk with
grep -cFbefore the run.Verification
Browser, on a dev server booted from this branch's built artifact (
dist/objectstack.json, so the lowered hook bodies ran), 18.2.0, as admin:Opportunity Globex Training Package is closed (Closed Won), so its line items can no longer be added, changed or removed.Screenshot: project filesissue-2338-p4/15-line-item-refusal.png.PATCH /api/v1/data/crm_opportunity_line_item/IDanswered 409 withcode: RECORD_LOCKED,errorholding the diagnostic(closed_won)anduserMessageholding(Closed Won).refusal-envelope, and the console readsuserMessagethe same way for every hook.Acceptance notes
src/revenue/objects/quote.hook.ts:105, answersQuote QTE-… is accepted, so its line items can no longer be added, changed or removed., which shows the raw status (accepted/expired).test/quote-line-freeze.test.ts:103pins that sentence. No other hook refusal shows an API value. I read everyrefuse(call undersrc/, and the rest name labels, record titles, counts or dates.38a41becarries the fleet bot as git author through a local override. The later commits use the container's default identity. The squash merge decides the landed author either way.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01J8VVAjXujUz9ErJ5BBgVDx