<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Derrick Zhou</title>
    <description>The latest articles on DEV Community by Derrick Zhou (@derrick_d15159abe0a5e6608).</description>
    <link>https://dev.to/derrick_d15159abe0a5e6608</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4109008%2Ffe1e4ac3-dc08-4c7a-b067-e49a7d4d09be.png</url>
      <title>DEV Community: Derrick Zhou</title>
      <link>https://dev.to/derrick_d15159abe0a5e6608</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/derrick_d15159abe0a5e6608"/>
    <language>en</language>
    <item>
      <title>We re-priced six weeks of our own AI coding-agent usage. The "obvious" saving was 5.5x too big.</title>
      <dc:creator>Derrick Zhou</dc:creator>
      <pubDate>Fri, 16 Oct 2026 16:17:37 +0000</pubDate>
      <link>https://dev.to/derrick_d15159abe0a5e6608/we-re-priced-six-weeks-of-our-own-ai-coding-agent-usage-the-obvious-saving-was-55x-too-big-3852</link>
      <guid>https://dev.to/derrick_d15159abe0a5e6608/we-re-priced-six-weeks-of-our-own-ai-coding-agent-usage-the-obvious-saving-was-55x-too-big-3852</guid>
      <description>&lt;p&gt;Over 46 days (35 of them active), one person's coding agent made &lt;strong&gt;61,955 requests&lt;/strong&gt;. There was no invoice for this exercise - a real client audit starts by reconciling to one - so we did what you do without one: we re-priced every request at the vendor's &lt;strong&gt;public, dated price sheet&lt;/strong&gt; (retrieved 2026-10-16) and asked where the money would go. Every dollar figure below is &lt;strong&gt;API-equivalent&lt;/strong&gt;, not what anyone was billed.&lt;/p&gt;

&lt;p&gt;The total came to &lt;strong&gt;$7,882&lt;/strong&gt;. Three things in it surprised us.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Almost all of it is re-reading
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;66% of the cost was cache reads&lt;/strong&gt;, and 99% of input-side tokens were cache hits. Output - the thing people optimise prompts for - was 12%. Spend is driven by &lt;em&gt;how long the context is x how many turns run on it&lt;/em&gt;, and one project accounted for 63% of it. The lever is context length and session hygiene, not a cleverer prompt.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost category&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cache reads (re-reading the existing context every turn)&lt;/td&gt;
&lt;td&gt;66%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1-hour cache writes&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output (incl. thinking)&lt;/td&gt;
&lt;td&gt;12%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-minute cache writes&lt;/td&gt;
&lt;td&gt;2%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fresh input&lt;/td&gt;
&lt;td&gt;~0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  2. The headline saving was 5.5x too big
&lt;/h2&gt;

&lt;p&gt;Newer model versions are cheaper per token. If you re-price every request that ran on an older version at the newer version's rates, you "save" &lt;strong&gt;$1,625 (20.6%)&lt;/strong&gt;. But most of those requests were made &lt;em&gt;before&lt;/em&gt; the newer version existed. Counting only requests made after it was available: &lt;strong&gt;$293 (3.7%)&lt;/strong&gt;. A saving you couldn't have taken at the time isn't a saving.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The expensive-looking setting was the right one
&lt;/h2&gt;

&lt;p&gt;85% of cache-write tokens used the 1-hour prompt cache, which costs more to write than the 5-minute cache. We tested the opposite: if every cache write had used the 5-minute cache, anything idle for more than five minutes would have to be re-written at write prices. Only 2.5% of cache-read tokens came after such a gap, but those requests carried very large contexts. Net result: the 5-minute cache would have cost &lt;strong&gt;$1,781 more (+22.6%)&lt;/strong&gt;. Keep the 1-hour cache. (And moving subagent work to a cheaper model saved $62 - not worth the quality risk.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is, and isn't
&lt;/h2&gt;

&lt;p&gt;It is a re-pricing from token counters, not realised savings. We did not evaluate output quality. Subagent streams were merged when measuring idle gaps, so those gaps look shorter than they were. The aggregated CSVs in the repo let you check the totals, and the scripts reproduce them from your own usage logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it on your own logs
&lt;/h2&gt;

&lt;p&gt;The scripts are open source (MIT), deterministic, and make no LLM or network calls:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/zbl1998-sdjn/llm-spend-audit-toolkit" rel="noopener noreferrer"&gt;https://github.com/zbl1998-sdjn/llm-spend-audit-toolkit&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;extract per-request usage (token counters only) from your coding-agent logs&lt;/li&gt;
&lt;li&gt;price it by category from a dated public price sheet&lt;/li&gt;
&lt;li&gt;test "move to the newer model" with an available-at-the-time check&lt;/li&gt;
&lt;li&gt;test the 5-minute vs 1-hour cache counterfactual&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How we'd do this for your bill
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Export-only.&lt;/strong&gt; Billing/usage exports - no API keys, no prompts, no production access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic analysis&lt;/strong&gt; - scripts on your numbers, not a model reading your data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconcile first&lt;/strong&gt;: recomputed spend must match your invoice within +/-3% before any saving is counted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only conservative, de-duplicated, available-at-the-time findings&lt;/strong&gt; - a lower bound, with the formula next to each number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you spend $3,000+/month on LLM APIs and want a second pair of eyes: &lt;a href="mailto:hello@currawongweb.com"&gt;hello@currawongweb.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: the analysis scripts and this write-up were produced with AI assistance (Claude Code).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Measuring China's Company Registry from the Outside: A Technical Writeup</title>
      <dc:creator>Derrick Zhou</dc:creator>
      <pubDate>Mon, 07 Sep 2026 05:55:09 +0000</pubDate>
      <link>https://dev.to/derrick_d15159abe0a5e6608/measuring-chinas-company-registry-from-the-outside-a-technical-writeup-2kh8</link>
      <guid>https://dev.to/derrick_d15159abe0a5e6608/measuring-chinas-company-registry-from-the-outside-a-technical-writeup-2kh8</guid>
      <description>&lt;p&gt;&lt;em&gt;How we designed paired-control experiments to measure government registry accessibility — and what the data shows.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you've ever built a tool that queries a government database, you know the pain: no API, no docs, no SLA. Now imagine that database is China's national company registry, serves 160 million business records, and actively distinguishes between human browsers and everything else.&lt;/p&gt;

&lt;p&gt;We run &lt;a href="https://currawongweb.com" rel="noopener noreferrer"&gt;Currawong Web&lt;/a&gt;, a supplier verification service. Over the past few months we ran controlled experiments measuring what happens when you try to access Chinese government registries from outside China. We published 20 datasets on &lt;a href="https://dataverse.harvard.edu/" rel="noopener noreferrer"&gt;Harvard Dataverse&lt;/a&gt; — all CC-licensed, all reproducible. Here's the technical story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: a registry that fights back
&lt;/h2&gt;

&lt;p&gt;China's national company registry (国家企业信用信息公示系统, or NECIPS) holds the canonical registration data for every company in the country. It's the source of truth for business licence details, legal representative, registered capital, and operational status.&lt;/p&gt;

&lt;p&gt;It also serves a JavaScript challenge to every visitor.&lt;/p&gt;

&lt;p&gt;This isn't a simple cookie check. The challenge evaluates your client environment — we observed different outcomes depending on browser fingerprint characteristics even from the same IP address. The system appears to use these signals to decide whether to serve data or return an empty response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment design
&lt;/h2&gt;

&lt;p&gt;We wanted to measure this systematically, not just anecdote our way through it. So we designed a paired-control experiment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Variables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client profile matrix&lt;/strong&gt;: 5 distinct browser fingerprint configurations, ranging from a vanilla Chrome profile to headless configurations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry point matrix&lt;/strong&gt;: direct URL, search-engine referral, and portal navigation paths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network location&lt;/strong&gt;: 2 mainland China networks + 1 overseas comparison point&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Protocol:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 rounds per combination&lt;/li&gt;
&lt;li&gt;Same target company in each round&lt;/li&gt;
&lt;li&gt;Record: HTTP status, JS challenge presence, data payload presence, time to response&lt;/li&gt;
&lt;li&gt;Control: a known-accessible domestic business portal queried in the same session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gave us a structured matrix of observations rather than a single pass/fail answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the JS challenge actually does
&lt;/h2&gt;

&lt;p&gt;We're deliberately not publishing bypass methods — that would undermine a legitimate anti-scraping system. But the technical observation is worth documenting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial page load&lt;/strong&gt; returns a minimal HTML shell with an inline script&lt;/li&gt;
&lt;li&gt;The script performs &lt;strong&gt;environment checks&lt;/strong&gt; — we observed it probing properties that differ between headless and headed browsers&lt;/li&gt;
&lt;li&gt;On passing, a &lt;strong&gt;cookie is set&lt;/strong&gt; and the page reloads with actual content&lt;/li&gt;
&lt;li&gt;On failing, the page either loops or returns empty content — no error message, no HTTP error code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The subtlety is that this isn't binary. Some client profiles pass the challenge but receive degraded results. The registry appears to have multiple tiers of trust, not just allow/block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results: what works and what doesn't
&lt;/h2&gt;

&lt;p&gt;From our 106-company English-name lookup dataset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end success rate was low.&lt;/strong&gt; Most failures occurred before the verification step — at the name-matching stage, not the access stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network location matters&lt;/strong&gt;, but less than client profile. A well-configured browser from overseas performed better than a poorly configured one from inside China.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificate registries vary wildly.&lt;/strong&gt; We tested 8 official sources (CCC, CQC, CFDA, and others) with 240 observations. Some answer reliably from any location. Others are effectively unreachable without a China-side session.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The registration-change problem
&lt;/h2&gt;

&lt;p&gt;One dataset tracked 264 manufacturers classified as national "Little Giant" firms (专精特新"小巨人"). We compared registration snapshots over time and found that key fields — operational status, registered capital, business scope — shift more frequently than most due-diligence processes assume.&lt;/p&gt;

&lt;p&gt;A supplier check from 6 months ago may already be outdated. This isn't a data-quality issue — it's a feature of a dynamic registry system that reflects real corporate changes. The implication for anyone building verification tooling is that you need a freshness model, not a cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alibaba vs. 1688: identity field comparison
&lt;/h2&gt;

&lt;p&gt;We also compared supplier identity fields between Alibaba.com (international) and 1688.com (domestic) for 94 companies present on both platforms. The registered company names, addresses, and representative details don't always match — not because of fraud, but because of legitimate differences in how companies present themselves for international vs. domestic trade.&lt;/p&gt;

&lt;p&gt;This matters for entity resolution. If your verification system tries to match a supplier's Alibaba profile against the government registry using the English trade name, you'll get a different result than matching via the Chinese registered name on 1688.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons for builders
&lt;/h2&gt;

&lt;p&gt;If you're building tools that interact with government data sources — in any country — a few patterns from this work apply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure access, don't assume it.&lt;/strong&gt; We started with the assumption that the registry was accessible. The data showed a more nuanced picture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design for failure tiers&lt;/strong&gt;, not binary up/down. A system that returns empty content with HTTP 200 is harder to handle than one that returns 403.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client fingerprint matters more than you think.&lt;/strong&gt; We saw different outcomes from the same network with different browser configurations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a freshness model.&lt;/strong&gt; Government records change. Your verification is a snapshot, not a permanent fact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate name-matching from access.&lt;/strong&gt; Our biggest source of failure wasn't "can't reach the registry" — it was "can't find the company by its English name."&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data availability
&lt;/h2&gt;

&lt;p&gt;All 20 datasets are on Harvard Dataverse with DOIs and CC licences. Download them, reproduce the experiments, challenge the methodology. That's the point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dataverse.harvard.edu/" rel="noopener noreferrer"&gt;Currawong Web research datasets on Harvard Dataverse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://currawongweb.com" rel="noopener noreferrer"&gt;currawongweb.com&lt;/a&gt; — our supplier verification service&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Derrick Zhou builds supplier verification tools at Currawong Web. Previously worked in cross-border trade operations.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>data</category>
      <category>security</category>
    </item>
    <item>
      <title>How China's company registration code uses ISO 7064 check digits (and why it matters for importers)</title>
      <dc:creator>Derrick Zhou</dc:creator>
      <pubDate>Fri, 04 Sep 2026 04:31:33 +0000</pubDate>
      <link>https://dev.to/derrick_d15159abe0a5e6608/how-chinas-company-registration-code-uses-iso-7064-check-digits-and-why-it-matters-for-importers-1312</link>
      <guid>https://dev.to/derrick_d15159abe0a5e6608/how-chinas-company-registration-code-uses-iso-7064-check-digits-and-why-it-matters-for-importers-1312</guid>
      <description>&lt;p&gt;If you've ever sourced products from China, you've probably seen an 18-character code on your supplier's business licence. It looks something like this:&lt;/p&gt;

&lt;p&gt;91440300MA5FJK2W30&lt;/p&gt;

&lt;p&gt;This is the Unified Social Credit Identifier (USCI) — China's equivalent of a company registration number. And buried in its last character is a check digit based on ISO 7064 Mod 31-3.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the code tells you
&lt;/h2&gt;

&lt;p&gt;The 18 characters encode specific information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Position 1: Registration authority type&lt;/li&gt;
&lt;li&gt;Position 2: Organization category&lt;/li&gt;
&lt;li&gt;Positions 3-9: Regional code (maps to province/city/district)&lt;/li&gt;
&lt;li&gt;Positions 10-17: Organization identifier&lt;/li&gt;
&lt;li&gt;Position 18: Check digit (ISO 7064 Mod 31-3)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The check digit math
&lt;/h2&gt;

&lt;p&gt;The validation uses a weighted sum mod 31, with weights cycling through powers of 3. Here's a JavaScript implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateUSCI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0123456789ABCDEFGHJKLMNPQRTUWXY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CHARS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: USCI uses a custom character set — no I, O, S, V, Z (to avoid visual confusion with 1, 0, 5, U, 2).&lt;/p&gt;

&lt;h2&gt;
  
  
  How well does it work?
&lt;/h2&gt;

&lt;p&gt;I ran an exhaustive test: for every position in every sample code, I substituted every possible character and checked whether the check digit caught the error.&lt;/p&gt;

&lt;p&gt;Result: 100% detection of single-character substitutions across 2.9 million simulated errors.&lt;/p&gt;

&lt;p&gt;For comparison, the US VIN (Vehicle Identification Number) check digit only catches 92.5% of single-character errors.&lt;/p&gt;

&lt;p&gt;The full dataset is on Zenodo: &lt;a href="https://zenodo.org/records/15589531" rel="noopener noreferrer"&gt;https://zenodo.org/records/15589531&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;If a supplier sends you a business licence with a typo in the registration code — or a completely fabricated code — the check digit catches it instantly, before you spend time on a manual lookup.&lt;/p&gt;

&lt;p&gt;Some other findings from our research:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;42.5% of NHTSA-registered Chinese manufacturers can't be found by English name alone in China's registry&lt;/li&gt;
&lt;li&gt;25.4% of China's "little giant" manufacturers don't have import/export in their registered business scope&lt;/li&gt;
&lt;li&gt;53.4% of those manufacturers have changed their company name at least once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built a free tool that does this validation plus a manual cross-reference against official Chinese registry data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://currawongweb.com/verify/" rel="noopener noreferrer"&gt;https://currawongweb.com/verify/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The research papers and datasets are all open access. Happy to answer questions about the methodology.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>data</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
