dsh-warranty-calc — Warranty period and claim amount consistency check
dsh-warranty-calc reads one warranty claim register — the dealer header plus one row per claim — and checks that register's own arithmetic and period self-consistency: that each claim records its claim number or part name, that the claim date falls inside the warranty end date the register states, that the mileage at claim parses as a number and does not exceed the mileage cap the register states, that the claim amount equals quantity × unit price, that the sale date does not follow the claim date, and that claim numbers do not repeat.
What it looks like

Real output from this plugin over its own WC-003 test fixture — not a mock-up. The rule pack ships no invented quotations, so a finding names both the clause it applied and the fact that the clause text was not obtained.
What it answers
| You ask | What it answers |
|---|---|
| The register records no warranty end date. Does the claim-date check just pass? | No. WC-002 reports itself in skipped when the warranty end column is empty: it assumes no period and never works one out from the sale date. With the column filled it only checks that the claim date lies between the sale date and the end date you wrote, and a finding means the date disagrees with the period in your own register, not that the claim is out of warranty. |
| The claim amount does not equal quantity × unit price. Is that caught? | Yes. WC-005 reports the row when claimAmount differs from quantity × unitPrice by more than the 0.01 tolerance. It covers the parts amount only: if your register settles as parts + labour − deductible (laborHours, laborRate and deductible are separate columns), the rule will report a difference — repoint resultField at a parts-only column or disable it. It does not judge whether the unit price is reasonable or whether the part should have been replaced. |
The mileage column reads 48,600 公里. Is it still read, and what if it is above the cap? |
Yes. WC-003 takes the numeric part, so 48600 and 48,600 公里 both parse; only mileage it cannot parse is reported, and it does not judge whether the mileage is over the limit. WC-004 does that comparison, against the warrantyMiles cap your register states — no figure is built in — and its finding means “above the cap you recorded”, never “out of warranty” — time and mileage are independent limits, whichever comes first. |
| The same claim number appears on two rows. | WC-007 reports a repeated claimNo, ignoring whitespace, because a repeat double-counts the claim total and stops the manufacturer matching the line. Registering one claim on several lines for different parts is normal: distinguish them in the part name column. |
| A row has neither a claim number nor a part name. | WC-001 reports the row only when neither claimNo nor partName is filled: one of the two is enough. It checks that the minimum tracing information is present, not whether the claim falls inside warranty or should be accepted. |
| The sale date is later than the claim date. | WC-006 compares the two dates in the register and reports the row when saleDate follows claimDate. The start date is taken from your sale date column: the rule's clause names the invoice date and the delivery date as starting points and this rule does not pick one for you, and the actual start follows the manufacturer's commitment. A date it cannot parse is reported separately, not silently skipped. |
Standards it follows
| Document | Number | Cited by rules |
|---|---|---|
| 《家用汽车产品修理更换退货责任规定》 | 市场监管总局令第43号(2021 年 7 月 22 日公布,自 2022 年 1 月 1 日起施行) | WC-001, WC-003, WC-005, WC-006, WC-007 |
| 各厂商质保政策与三包规定(本机构配置) | 无统一标准(本条依据为台账写明的质保期) | WC-002 |
| 各厂商质保政策(本机构配置) | 无统一标准(本条依据为台账写明的里程上限) | WC-004 |
Boundary: this plugin checks a 质保索赔台账 for arithmetic and period self-consistency — that a claim records its number or part name, that the claim date falls inside the warranty end date the register states, that mileage parses and does not exceed the mileage cap the register states, that the claim amount equals quantity × unit price, that the sale date does not follow the claim date, and that claim numbers do not repeat. It does not decide whether a claim should be accepted, whether a failure is covered, or whether it was caused by misuse or normal wear.
⚠️ Warranty policy is the manufacturer's, and this pack does not pretend to quote one
Period length, mileage cap, labour rates and deductibles are set by each manufacturer's warranty policy and by the three-guarantee rules for the relevant product category. No unified standard exists, so every rule's
basissays exactly that and stays atwarnorinfo.Three consequences are worth knowing before trusting a finding:
- The plugin never derives a warranty end date. It does not compute "sale date + 36 months", because months vary in length and the period may start at delivery or at registration rather than at sale — a computed date would look precise while possibly being wrong. You work the date out under the applicable policy and record it in the 质保期截止日 column, and
WC-002compares against that.WC-004's mileage cap comes from the register too. No figure is built in, and a finding means "above the cap you recorded", never "out of warranty" — time and mileage are independent limits, whichever comes first, and policies differ on what happens past either.WC-005covers parts only. Real claim amounts often add labour and material and subtract a deductible, and this register has separate columns for those. A register settling as "parts + labour − deductible" will report a difference; repointresultFieldat a parts-amount column, or disable the rule.Every
excerptin the rule pack says, in so many words, that the clause text was not obtained. When the texts are in hand, replace eachexcerptwith the real clause and raisekindtodirect.
Compatibility
| Surface | Status |
|---|---|
| Harness | Peer range >=0.1.2-rc.1 <0.2.0 || >=0.2.0-0 <0.3.0 — verified to accept both 0.2.0-rc.2 and 0.2.1-alpha.1. engines.dsh is deliberately not declared: it has no reader and cannot reject a host |
| Node | `^22.19.0 |
| Platforms | All (plain ESM; no native code, no network, no model call) |
| Tool mode | Works in native, ptc and both; for a batch of claims use ptc |
What it does
Registers the warranty_calc tool. It reads one claim register — the dealer header plus one row per claim —
applies a versioned rule pack, and returns a report.
| Rule | Check | Severity | Basis kind |
|---|---|---|---|
WC-001 |
the claim records its number or part name | warn | direct |
WC-002 |
the claim date falls inside the recorded warranty end | info | local |
WC-003 |
mileage at claim parses as a number | warn | principle |
WC-004 |
mileage at claim does not exceed the recorded cap | info | local |
WC-005 |
the claim amount equals quantity × unit price | warn | direct |
WC-006 |
the sale date does not follow the claim date | warn | principle |
WC-007 |
claim numbers do not repeat | warn | principle |
Install
dsh plugin --profile <name> add dsh-warranty-calc
dsh --profile <name> --dump-config | grep 'dsh-warranty-calc'
Configuration
| Key | Type | Default | Description |
|---|---|---|---|
rulesFile |
string | rules/warranty-calc.yaml |
Rule-pack path, relative to the package root |
disabledRules |
string[] | [] |
Rule ids to stop running; each appears in skipped |
onlyRules |
string[] | [] |
Run only these rule ids; empty runs every rule |
skipNotes |
string | "" |
Note appended to every skipped reason |
timeoutMs |
number | 120000 |
Cooperative tool timeout budget |
Rule-level parameters worth knowing:
WC-002needs the register's 质保期截止日 /warrantyEndAtcolumn; without it the rule reports itself inskipped. The plugin never computes the date from a month count.WC-004needswarrantyMilesfrom the register. No mileage figure is built in.WC-005resultField/factorFields/tolerance— the parts arithmetic; repoint it if your settlement includes labour and a deductible.
Material format
The tool accepts JSON or YAML:
dealer: 某某服务站
manufacturer: 某某厂商
policyVersion: 2026 版质保政策
rows:
- { 索赔单号: SP-2026-0018, 配件名称: 前制动片, 销售日期: 2024-03-10,
索赔时里程: '48600', 质保期月数: '36', 质保里程: '100000',
质保期截止日: 2027-03-09, 索赔日期: 2026-03-05,
数量: '2', 单价: '180', 索赔金额: '360', 处理结论: 同意索赔 }
Column names are matched case-insensitively and ignoring spaces, underscores and hyphens; the register's own column names are kept, so a finding names the column it read.
Rule sources
Rule data lives in rules/warranty-calc.yaml. Because warranty policy is a manufacturer's instrument rather
than a standard, the pack's basis entries say so explicitly instead of citing one. The load-time guard still
requires a document, clause, excerpt and source per rule, and still forbids a locally configured check from
being error.
Troubleshooting
WC-002reports itself as skipped. The register records no warranty end date. The plugin will not compute one: months vary in length and the period may start at delivery or registration.WC-002fires although I believe the claim is covered. The recorded end date disagrees with the claim date. Recheck how the end date was worked out under the applicable policy.WC-004fires on a claim I consider covered. The mileage exceeds the cap you recorded — but time and mileage are independent limits, and this finding alone does not mean the claim is out of warranty.WC-005fires on a correct settlement. The amount probably includes labour and a deductible. PointresultFieldat a parts-only column, or disable the rule.WC-006fires on dates I can read. The reader accepts2026-03-05or2026-03-05 09:30;2026年3月5日is reported as unparseable on purpose.- The plugin installs but the tool never appears. Check that
mainresolves tolib/index.mjsand thatpnpm run buildproduced it; a wrongmainmakes the loader skip the entry silently. dsh plugin addrefuses the package as incompatible. The peer range covers0.1.xand0.2.x; if your runtime sits outside it, grant an explicit exemption:dsh plugin --profile <name> allow-version dsh-warranty-calc@0.1.0 --dsh-version <runtime> --accept-riskcheckreportsmanifest-peersas failed. The static checker compares against a hard-coded peer range that predates the 0.2 line. The runtime enforces peer compatibility at install time, so the declared range is the correct one; this is a known upstream issue indsh-plugin-dev.
Development
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm test # vitest, the shared table-plugin suite plus paired fixtures
pnpm run build # tsdown -> lib/index.mjs + lib/index.d.mts
node ../scripts/sync-shared.mjs dsh-warranty-calc # refresh src/shared from ../_shared
The plugin is data-only: src/model.ts declares the table shape, the shared kit supplies the reader and
the check engine, and the rule pack declares every check.
License
Apache License 2.0 © 2026 dsh-warranty-calc contributors.
No comments yet. Be the first to write one.