Changelog
Source:NEWS.md
matchdb (development version)
npnormalize 0.1.7: the split-word table the SQL key was missing
-
md_guard_key()’s macro appliesnp_name_rules()$split_words. 0.1.7 folds eleven further spellings ofFOUNDATION, three of which are the word cut in two by a fixed-width line break in the filing (FOUND ATION,FOUNDATIO N,FOUNDATI ON). Those three are the only ones the macro could get wrong, and it did: the per-token abbreviationCASEfolded the head ofFOUNDATIO Non its own, so the SQL key readSMITH FAMILY FOUNDATION Nwhilenp_name_core()readSMITH FAMILY FOUNDATION. The rejoin now runs insidemd_guard_clean(), after the clean and before theCASE, which is the ordernp_name_rules()documents. -
The parity test did not catch it, and that is the more useful finding. Its fixture held no split word, so a table that gained three entries left a macro silently disagreeing with the function it is tested against. The fixture now carries one of each split form plus a single-token misspelling — the single-token case exercises only the
CASEand passed throughout — andPROFOUND ATION TEST, which must not be rejoined. -
md_light_key()is deliberately left alone. It merges spellings that differ only in how they are typed and leaves misspellings to the normalizer’s derived columns, soFOUNDATIONandFOUNDAITONstay apart there by design. -
No stored column changes shape. 0.1.7 adds no column; it moves the values of
street_key,street_num,street_name,name_key,name_full,name_form,dba_keyanddivision_key, all of whichmd_build_derived()already stores.md_place_key()reads the derivedstreet_key, so the hyphenated house numbers 0.1.7 fixes reach the place key through a rebuild with no change here. -
The database still is not rebuilt. The signature is now
v1-59c6e84c5f38e9f5;md_build_derived()stamps it on the next pass, and the staleness guard refuses to mix signatures in one derived table.
The install instructions pin all three packages
-
The README and
vignette("matchdb")now pin matchdb and npmatch, not only npnormalize, andvignette("workspace")andvignette("updates")say to pin all three when the normalizer moves ahead of the data. They said to install npnormalize at6d9c669(0.1.3) and matchdb and npmatch frommainwithupgrade = "never". That stopped working whenmainmoved to npnormalize 0.1.5 and then 0.1.6: both packages now require a newer npnormalize than the published data was built with, so the instructions gave either a failed install or a matchdb that refuses the data. - The pins are the three commits the 2026-11-01 release records in its
MANIFEST.json: npnormalize6d9c669, npmatch7ea7447, matchdbdf7e2ce. Installed together into an empty library, they report signaturev1-592912060053c4c3, which matches the published bundles. - The pins come off once the database is rebuilt and republished under npnormalize 0.1.7 (
v1-59c6e84c5f38e9f5).
npnormalize 0.1.6: the address key has a second gate (#35)
-
md_place_key()’s macro reads both gates.np_addr_key()blanks on the union ofnp_pattern("pobox")and the newnp_pattern("mailonly")— general delivery and military mail, a delivery point with no box number and no building. The macro read only the first and so kept those keys: the parity test failed onGENERAL DELIVERYandPSC 1234 BOX 56, which the fixture already held. The two patterns overlap by design (aDRAWERis in both of npnormalize’s vocabularies), so the macro ORs the raw strings. -
The
np_pattern()wiring did its job.DRAWER 7andPO BX 3are new box spellings in 0.1.6 and the macro blanked both with no change here, because it reads the live string. Only the gate that did not exist when that wiring was written had to be added, and the two now serve as the control in the parity test. -
is_mail_onlyandmail_keyare stored address columns.mail_keyis the complement of the place key — the box plus its ZIP, blank for everything else — and is what a blanked box still says: two organizations collecting mail from the same box are likely administered by the same people. Weight it withnpnormalize::np_mail_freq()before believing it; one BMF box holds 3,626 EINs. Both are functions of the address row as a whole, which is why they sit besidezip5in the stored list. -
The military flag’s street branch is gone, because it cannot fire. It was a hand-typed
^(GENERAL DELIVERY|PSC [0-9]+|CMR [0-9]+|UNIT [0-9]+ BOX)— the same vocabulary npnormalize now owns. Those rows are deleted frompl_addrbeforeplaceis built, so a place that is military mail no longer exists to be flagged.flag_military_or_gdkeeps itsstate/citybranches, which are matchdb’s own and still reachable for an on-base street address: the street line looks ordinary and onlyAA/AE/APor anAPO/FPO/DPOcity says military, neither of which npnormalize ever sees. The fixture gained such an address so the flag keeps live coverage. -
matchdb now requires npnormalize 0.1.6, the first to publish
np_pattern("mailonly"). -
The database still is not rebuilt. The signature is now
v1-d49b18cc81ab79fb;md_build_derived()stamps it on the next pass, and the staleness guard refuses to mix signatures in one derived table.
The SQL macros take their patterns from npnormalize
-
md_place_key()andmd_unit_id()in SQL no longer hold a copy of npnormalize’s patterns. The PO box gate and the suite designator strip are read fromnpnormalize::np_pattern("pobox")andnp_pattern("unit_id")each time the macros are created, so upgrading npnormalize alone moves them withnp_addr_key()andnp_unit_id(). The copy had already drifted: npnormalize 0.1.5 made a lettered box (PO BOX A) a box, and the macro still keyed it as a building. -
matchdb now requires npnormalize 0.1.5, the first to publish
np_pattern(). -
street_has_boxis a stored address column. npnormalize 0.1.4 added it tonp_normalize()‘s output, and with it installed 26 tests failed onmain: a compiled frame lacked a column the normalizer produces. Existingaddress_text_derivedtables gain the column on the next derive pass, empty for older signatures’ rows. - The parity test now covers every branch of the box pattern (lettered boxes, streets named for a box, a box number followed by a mail stop, and the rural-route, military and
GENERAL DELIVERYlines npnormalize#13 is about), and a second test swaps in a stand-innp_pattern()to prove the macros read it rather than a copy. -
The database is not yet rebuilt under the 0.1.5 signature (
v1-533f186c123357cf); that waits for npnormalize to settle (#13).
npnormalize 0.1.3: the signature moves (#29)
-
matchdb now requires npnormalize 0.1.3. Its normalizer signature is
v1-592912060053c4c3(wasv1-3e7b9f9d59bbb19e), so an install that would silently produce the old keys cannot happen. The database was rebuilt once, under 0.1.3; the 0.1.2 rebuild (v1-6d90b52d8b781673) was never published. -
What changed in npnormalize:
- 0.1.2 made
BUILDINGa unit designator, asBLDGalready was, so100 CAMPUS CENTER BUILDING 86Ekeys as100 CAMPUS CENTERwith unitBLDG 86E. This is the only change that movesstreet_key. - 0.1.3, found while measuring 0.1.2 here: a line naming several units keeps the most specific (
1 BETHANY RD BUILDING 1 STE 5keepsSTE 5; a mail store’sSTE 204 # 22915keeps the box,# 22915), and the house number is a whole token (16TH SThas none; it was16Ton streetH). - No matchdb code needed changing:
md_unit_id()and its SQL port agree with npnormalize on every canonicalstreet_unit.
- 0.1.2 made
-
Measured on the database (
md_normalizer_diff(),dev/verify/logs/rebuild-normalizer-2026-11-01.log): no name column moved (0 of 12.8Mnamerows rekeyed). Of 12.99M address strings, 61,016 (0.47%) changedstreet_unit, 19,981street_num, 26,766street_nameand 6,921street_key. On theaddresstable, 6,068 of 22.0M rows are rekeyed: 1,666 street-plus-ZIP groups merge and 11 split, touching 1,593 EINs. Shared suites (place_unit) fall from 36,838 to 35,439, and shared places from 2,855 to 2,824, as mail-store customers are told apart by their box. -
Every published artifact is rebuilt and uploaded under the new signature, on 2026-11-01: the database (
MATCHDB.duckdb, 11.8 GB;MATCHDB-full.duckdb, 24.2 GB), the four tier bundles and tranche build2026-11-01-67c0bd2f(108 files, 4.53 GB). They replace the 2026-10-26 release, which pairs with matchdb 0.1.1. Artifacts from before are refused by matchdb with npnormalize 0.1.3 installed, and the new ones are refused with older npnormalize, as the signature check intends. -
Checks on the rebuild (
dev/verify/logs/*-2026-11-01.log):- the Phase 1 gate gives three zeros against the re-frozen baseline, whose 1k benchmark counts are unchanged;
- Phase 2 is unchanged, +146 YES;
-
check-buildpasses 36 of 36; - the four tiers keep their spec hashes, each a few hundred rows smaller from the merged address groups, and each tier compiled from the new tranches (build
2026-11-01-67c0bd2f) is identical to its bundle.
-
dev/rebuild-normalizer.Radopts a new signature on a built database: derives the new signature’s columns beside the old, reportsmd_normalizer_diff(), and with--installrelinks the derived columns and rebuilds everything downstream.dev/verify/release/publish-tiers.Rrepublishes the four tiers and the tranches. -
npnormalize 0.1.4 moves the signature again, to
v1-1179714ce1e9d31f, and refuses this data.DESCRIPTIONasks fornpnormalize (>= 0.1.3), so a fresh install can pick up 0.1.4. Until the data is rebuilt under it, install npnormalize at6d9c669(0.1.3; it has no tag) and install npmatch and matchdb withupgrade = "never". The README andvignette("matchdb")say so.
Documentation
- Two new articles on how the database works:
-
vignette("corroboration-ledger"): where each filer’s statement is stored, how statements becomen_corroborators,n_mentionsandn_periods, how names and addresses stay paired, and what the guards add; -
vignette("updates"): what triggers a rebuild, pinning, folding a release into the ledger, adopting a new normalizer, the checks, publishing, and what a user sees.
-
- The README and the getting-started, layers, sources, corroborators and workspace articles are refreshed for the 2026-11-01 build. The workspace article now shows a real
md_tranche_diff()between two published builds. The README lists npnormalize among the related packages, and corrects npmatch’s row: matchdb suggests npmatch, it does not import it. -
dev/CORROBORATION-FOOTPRINT.mdproposes ways to widen what corroboration covers: new disclosures that carry an EIN (Schedule A supported organizations, Schedule N successors, more of Schedule R), corroboration on relations (both sides reporting, years, sources), and a count of independent filers besiden_corroborators. Nothing in it is built yet.
The normalizer comes from npnormalize
- matchdb now imports npnormalize for the normalizer and its signature, and only suggests npmatch. Every call to the 9 normalizer functions (
np_normalize(),np_normalize_signature(),np_stopwords(),np_name_freq(),np_token_idf(),np_name_core(),np_name_rules(),np_name_placeholder(),np_addr_freq()) goes to npnormalize. - The signature is unchanged,
v1-3e7b9f9d59bbb19e, so the published database, bundles and tranches are all still accepted. Nothing needs rebuilding. - npmatch is needed only to match, and for
md_reference(build_index = TRUE), which builds npmatch’s blocking index. Without npmatch the index is skipped with a message; npmatch builds it itself when given none. -
md_place_key(),md_unit_id()andmd_addr_freq()call npnormalize directly:np_addr_key(),np_unit_id()andnp_addr_freq().- Before, they looked for these functions in npmatch. With an npmatch that no longer holds the normalizer, they quietly fell back to matchdb’s own copies.
- The copies are removed. They had agreed with npnormalize on every distinct value in the database.
-
matchdb now requires npnormalize 0.1.1, the first version to export
np_unit_id().
Stamps and the workspace log record npnormalize
- Compile stamps, bundle stamps, tranche manifests, source pins and
source_vintagegainnpnormalize_versionbesidenpmatch_version, which is nowNAwhen npmatch is not installed. Old stamps stay readable. A database built before this gains thesource_vintagecolumn the next time a source is recorded; its old rows keepNULL. - The workspace log records
npnormalize_versionandnpnormalize_commit, and a change in either is aversion_changerow. An olderlogs/runs-index.csvis rewritten once, adding the two columns, the next time an action is logged.
matchdb 0.1.1
The first tagged release, v0.1.1. Its number matches npmatch 0.1.1, the release it pairs with: both are the last versions before the normalizer moves into the npnormalize package. Pin both, in renv or with @v0.1.1, for anything that should reproduce results from before that move.
Pairs with
-
npmatch 0.1.1 (
npmatch (>= 0.1.1);Remotes:pins@v0.1.1). -
Normalizer signature
v1-3e7b9f9d59bbb19e. Everything published so far was built with this signature, and everything matchdb reads checks it: the database, the four tier bundles and the parquet tranches.
The published data at this release
Built on 2026-10-26 from main at 592b078 with npmatch 26a5910. It was public at https://nccs-efile.s3.amazonaws.com/dev/matchdb, with no AWS account needed, until 2026-11-01, when the npnormalize 0.1.3 rebuild replaced it (see the development version above). Its tranche build is still there.
-
MATCHDB.duckdb(11.7 GB, 26 tables) is the user copy, fetched bymd_fetch_db().MATCHDB-full.duckdb(24.3 GB) adds the observation ledger, for maintainers. -
Four tier bundles, read by
md_reference():active-legal(2.74M rows),active-observed(2.89M),unified-legal(4.98M) andunified-observed(5.13M). -
Parquet tranches, build
2026-10-27-82c6f0cb(108 files, 4.64 GB).md_fetch_tranches(spec)downloads only the files a spec needs: about 1.0 GB for an active-layer spec.
What is in this release
-
Building the database:
- the ingests for the BMF, NTEE, 1023-EZ, e-file headers, Schedule I, Schedule R, group exemptions, 527 filings, the 990-N e-Postcard, revocations, websites and officer name keys;
- content-hash ids, and the append-only observation ledger with rollups (
dev/IDENTITY.md); - the stored normalizer columns, compact tables, EIN keys, typed clusters, places, and the statistics cells.
-
Compiling:
md_spec()andmd_compile().- A spec chooses layers, name and address classes, sources and corroboration.
- The compiled frame is checked against
np_normalize()on every compile. - Compiling reports what the spec leaves out.
-
Publishing:
-
md_publish()writes signed bundles, andmd_reference()refuses a stale or altered one; -
md_publish_tranches()writes the database as parquet, split by layer and class.
-
-
Getting data:
-
md_fetch_reference(),md_fetch_db()andmd_fetch_tranches(), over plain HTTPS, with md5 checks; -
md_tranche_db(), a connection over the downloaded files thatmd_compile(),md_publish(),md_lookup()andmd_cluster()take unchanged.
-
-
The workspace:
- one folder,
md_data_root(); - the log:
md_log()andmd_log_run(), withlogs/runs-index.csvappend-only; -
md_status(), the current state, kept inlogs/state.json; -
version_changerows, written when the data build, the npmatch version or the normalizer changes; -
md_tranches(),md_tranche_manifest(),md_tranche_diff()andmd_tranches_prune(), for seeing what is published and updating to a new build; - the guide,
vignette("workspace").
- one folder,
-
Looking things up:
md_lookup()andmd_cluster().