feat(product): remove crm_product.tax_rate — declared, read by nothing, ruled removed 2026-08-17 (#1198) - #1588
Merged
Conversation
The field was declared on an apiEnabled object, absent from the product form, and read by nothing: no view column, no formula, no hook, no flow. Enforcing it was measured wrong (a stamped rate makes a quote total disagree with the sum of its own line totals and double-taxes a rep who also fills the quote's Tax amount), so the maintainer ruled removal on 2026-08-17. Removes the field, its four crm_product locale rows, and the twelve product-doc sites across the three faces. Fixes two comment cross-references the deletion makes false, and updates the validator transcript in docs/STATUS.md from 334 to 333 fields, which test/docs-declared-versions.test.ts pins against the stack. The quote line item's own tax_rate and the quote's manual Tax amount are untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TezFG8ZMrNH6n5VTNpPpdH
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-zhuang
marked this pull request as ready for review
September 5, 2026 15:20
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.
Fixes #1198
Executes the maintainer ruling of 2026-08-17 (#1198 (comment), verbatim 「其他接受你的所有建议」; restored on 2026-08-31 in #1198 (comment) after the 08-22 re-escalation was found to have been made without reading the record): remove
crm_product.tax_rate— the field, its fourcrm_productlocale rows, its docs surface. Published-field deletion is authorised explicitly by that ruling.The blocker that stopped the R32 round is gone: #1580 retired
test/field-consumer-scan.test.tsandscripts/scan-field-consumers.tson 2026-09-05, so the fixture collision no longer exists. This branch is cut from021db549, the merge commit of that retirement.The third option is not taken and not foreclosed. Making a product rate drive the quote-level tax figure remains a possible future design; it gets one sentence in the changeset and nothing else here.
Why the field goes
Declared on an
apiEnabledobject, absent from the product form (so only the REST API could ever set it), and read by nothing — no view column, no formula, no hook, no flow. Enforcing it was measured wrong on the real engine: stamping the product rate onto a line makes the quote's total 200 lower than the sum of its own line totals, and double-taxes a rep who also fills in the quote's manualtaxamount. The card carries the full measurement.What changed
Metadata (1 field, 4 locale rows)
src/objects/product.object.ts— thetax_rate: Field.percent({...})block and its// Tax & billingcomment, which covered only this field. Thepricingfield group survives onlist_price/cost.src/translations/{en,es-ES,ja-JP,zh-CN}.ts— one row each. Each deletion was made by line number after printing the enclosing object key, so the fourcrm_quote_line_item.tax_raterows (a different object's live field, read by the line'stotal_priceformula) are untouched. Verified after the fact: each pack went from 2tax_rateoccurrences to 1, and the survivor is insidecrm_quote_line_item.Docs — the 12 sites across the three faces (
products.mdx,products.zh-Hans.mdx,products.zh-Hant.mdx, 4 sites each)description, which ended "SKUs and tax rates" / 「SKU 和税率」 / 「SKU 和稅率」;| **Pricing** | List price, cost, SKU, tax rate |);⛔ Not touched, and still true: the sales-rep tip "Tax is not filled in: enter it on the quote" is about quote-level tax. Each face keeps its own locale convention — the zh-Hant page continues to spell console navigation in English per the #1368 ruling, and nothing unrelated was "fixed" on these pages.
Two comment cross-references this deletion makes false
src/objects/quote_line_item.object.ts:60— "andcrm_productkeepstax_ratethere too" is dropped; the rest of the field-group rationale is unchanged.src/objects/opportunity_line_item.object.ts:63— "crm_quoteandcrm_productboth keep every money field — tax included — inpricing" attributed a tax field tocrm_productthat no longer exists. Re-attributed tocrm_quote'stax, which is where it is true. This one is outside the dispatched surface and is declared as an in-place fix: same defect class as the clause above, mechanical, comment-only, no new verification surface, and no other claim holds the file.One documented figure, protected by a pin
docs/STATUS.md:22transcribes whatpnpm validateprints;test/docs-declared-versions.test.ts(#1011) compares every figure in that transcript against the registered stack.Data: 18 Objects 334 Fieldsbecomes333 Fields. That is the pin doing its job, not a pin being adjusted — proven by ablation: with the figure left at 334 the test fails with "docs/STATUS.md transcribes figures that are not the current ones" (Tests 1 failed | 18 passed); restored to 333 it passes, and the restore was verified by blob hash againstHEAD, not by an exit code.Changeset —
.changeset/remove-product-default-tax-rate.md,minor. Notmajor, and the title drops the!: the comparable precedent in this repo is the enforce-or-remove sweep that deleted nine inert published fields, released under Minor Changes (540e488inCHANGELOG.md), and the onlymajorentry in the current changelog is a behaviour-breaking data-model change. It states that any value written tocrm_product.tax_ratethrough the REST API is dropped, that no seeded catalog product ever carried one (all 13 sit at the0default), and that the product-driven quote tax remains a possible future design.Gates — the repo's own chain, each command run separately, exit code captured by redirect before any pipe
pnpm validate✓ Validation passed·Data: 18 Objects 333 Fieldspnpm typechecktsc --noEmit, no outputpnpm lint90 warning(s), 12 suggestion(s)— no errorspnpm lint:i18n-gate✓ i18n lint gate: 0 i18n/missing-* issuespnpm hygiene✓ source hygiene cleanpnpm hygiene:tokens✓ source token ratchet clean— business semantics ~84,018 / ceiling ~85,000; authored total ~135,789 / ceiling ~140,000. No ceiling raised; the deletion lowers the count.pnpm buildArtifact: dist/objectstack.json (2011.4 KB)pnpm testTest Files 159 passed (159)·Tests 3380 passed, 1 skipped (3381)Reverse verification. Before the edit, on
021db549:pnpm validateexit 0 atData: 18 Objects 334 Fields,pnpm testexit 0 at159 passed / 3380 passed, 1 skipped. After: validate exit 0 at 333 Fields — exactly one field fewer, the positive control that validate re-read the tree — and the same 159 files / 3380 tests green with the one documented figure updated. No test needed adjusting; no pin went red for any reason other than the figure above.The four locale packs keep identical
crm_productfield key sets after the deletion (13 direct field keys each, symmetric difference againstenempty), which is why the i18n gate stays at 0 missing-key issues.Generated by Claude Code