Skip to main content

Zero-PHI source-assurance CLI for healthcare's public data inputs

Project description

SourceLock

Every answer comes with a receipt, and your build fails when the source moves.

SourceLock reads the public data healthcare software runs on — CMS coverage policy, NPPES and PECOS, ICD-10-CM and HCPCS releases, CMS-HCC risk models, the OIG LEIE — and returns, with every answer, the release it came from, the SHA-256 of the raw bytes behind it, when those bytes were retrieved, and what the answer does not prove. hc-source lock init pins those sources in a source-lock.json; hc-source doctor verifies that pin and fails CI the day one of them changes underneath you.

Install

git clone https://github.com/writtenonwater99/sourcelock
cd sourcelock
pipx install .

Python 3.11 or newer. There is no PyPI release yet, so pip install sourcelock does not work and this file does not pretend it does — see RELEASING.md for what publishing takes.

See it work, offline, right now

hc-source valid-on E11.9 2026-07-01

No network, no credentials, no lockfile. The release tables are vendored, so that command answers in under a second on a plane:

{
  "code": "E11.9",
  "code_nodot": "E119",
  "code_system": "ICD-10-CM",
  "date": "2026-07-01",
  "valid": true,
  "description": "Type 2 diabetes mellitus without complications",
  "release": "fy2026-april",
  "release_effective_from": "2026-04-01",
  "release_effective_to": "2026-09-30"
}

followed by the receipt — source, route, release, effective window, retrieval time, upstream status, the hash of the bytes the answer was derived from, the transform version, and whether a mirror answered — and then the part most tools leave out. Four non-claims, printed in full; the first line of each:

does not prove:
  - PHI_NOT_EXPECTED: this tool accepts only public typed parameters.
  - DOES_NOT_INCLUDE_CPT_DESCRIPTORS: no HCPCS Level I (CPT) record and no ADA
  - DOES_NOT_PROVE_COVERAGE: a code being valid for a date of service says
  - DOES_NOT_PROVE_CURRENCY: answers come from the release train vendored at

The real output does not wrap and does not trail off: the CPT one runs to a paragraph naming all seventeen CMS descriptions that quote a CPT number, because that is what an AMA licence question actually needs. These four are what codes.valid_on claims it cannot tell you — every one of them, not a representative sample, and nothing this product does not actually print.

What it is for

If you are building AI or automation over revenue-cycle data, you have run into some version of this:

  • A model cited a code set and nobody can say which release. Every answer here carries source_version, effective_from/effective_to, and raw_sha256. That is an audit trail, not a log line.
  • A pipeline broke because CMS renamed something. NPPES retired its V1 bulk filenames on 2026-03-03; jobs that still generated them got silent 404s. hc-source lock init pins 23 cheap checks across six sources and hc-source doctor fails the build the day one moves — with the fix, not a stack trace.
  • An agent will confidently answer from a stale cache. Receipts distinguish when bytes were retrieved from when upstream last confirmed them, a canary that read out-of-date data is not allowed to report ok, and a source that could not be read is never reported as unchanged.
  • Your reference data is not all public. Sources are plugins. Your licensed AMA CPT tables can be a first-class adapter without forking anything.
  • PHI must not end up in a tool call. Parameters are public and typed, no receipt or log carries a payload, and a guard refuses input shaped like a patient record. It is a structural best-effort refusal, not a HIPAA control: hc_source/guard.py states exactly what it detects and, just as plainly, which evasion classes it does not close.

The six sources

source what it answers
codes ICD-10-CM / HCPCS Level II validity on a date of service, release trains
hcc CMS-HCC V24/V28 mapping, hierarchies, community continuing-enrollee scoring
provider NPI Registry lookups, NPPES bulk-file cadence, PECOS enrollment snapshot
coverage CMS coverage policy: NCDs, LCDs and articles, MCD weekly snapshot identity
leie OIG LEIE exclusion checks by NPI, candidate search, monthly refresh status
demo packaged reference adapter used in tests and examples

codes and hcc answer offline from vendored release data. The rest read live CMS and OIG endpoints.

Everyday commands

hc-source valid-on E11.9 2026-07-01                     # offline
hc-source hcc score --dx E11.9,I50.9 --model v28 --year 2026 --age 72 --sex F
hc-source lookup-npi 1003000126                         # NPPES
hc-source check-npi 1003000126                          # OIG LEIE screen
hc-source tools                                         # every route, with its parameters
hc-source call coverage.lookup_ncd --param section=30.3 # the general form
hc-source mcp                                           # serve it all to an agent over MCP

call reaches every route, including ones provided by adapters you installed; the named commands are shorthand for the four questions people arrive with.

Pin your sources and fail the build when they move

hc-source lock init      # observe all six sources, write source-lock.json
hc-source doctor         # re-check upstream against the lockfile
hc-source init --ci      # scaffold the GitHub Actions workflow

Commit source-lock.json and review its diffs like any other lockfile. A green run ends with:

23 ok, 0 drift, 0 unreachable, 0 schema_changed, 0 unpinned, 0 stale, 0 error

Exit codes are the contract: 0 everything matched, 1 drift or schema change, 2 a source was unreachable or an adapter broke, 3 a canary was observed but nothing pinned it, 4 everything matched but something reported that what it read is out of date. 3 and 4 exist because a missing source-lock.json used to report 23 ok, 0 drift at exit 0 — a build that verified nothing, reporting green. Full CI setup, per-canary severity, and the on-unreachable / on-stale policies: docs/ci.md.

Watch it catch drift, in 90 seconds

You do not have to wait for CMS to change something. NPPES really did retire its V1 bulk-file names on 2026-03-03. The repo carries a recording of what the listing page would look like if that class of change happened again:

hc-source lock init
HC_SOURCE_PROVIDER_NPPES_FILES_URL="file://$PWD/tests/fixtures/provider/npi_files_v1_only.html" \
  hc-source doctor --source provider

Doctor exits 1, marks provider.nppes_v2_files as drift, and prints:

provider.nppes_v2_files [drift]: NPPES retired the V1 bulk files on 2026-03-03; only
*_V2.zip names are published now (V2 extends the First Name and Legal Business Name
field lengths). The listing this canary just read carries a V1-style name with no _V2
suffix, which means the page has regressed, a stale mirror is being served, or
something upstream renamed the grammar again. Fix: open
https://download.cms.gov/nppes/NPI_Files.html, read the 'Important Information' block
(where CMS announced the V1 retirement), confirm the current version suffix, make sure
nothing in your pipeline still generates V1 filenames
(NPPES_Data_Dissemination_<Month>_<YYYY>.zip silently 404s), then re-pin with
`hc-source lock init`.

Run it again without the override and it goes back to green. That is the whole product: pin what your build depends on, and get told — with an instruction, not a stack trace — the moment upstream moves.

For agents

hc-source mcp serves every discovered tool over MCP stdio: one MCP tool per route, the same typed parameters, the same receipts, the same PHI refusals as the CLI. It refuses to start if any adapter failed to import, because an agent that sees a short tools/list reads it as the whole product.

Responses are cached on disk and revalidated conditionally — an entry is stored only if the response carried an ETag or a Last-Modified, and a hit is a request that came back 304, so cached bytes are ones the source confirmed a moment ago. A cache hit still reports when its bytes were retrieved, with a cache_hit flag, rather than claiming a fresh read.

How much it helps depends entirely on whether upstream sends validators, and that varies a lot. Measured here against live sources, median of five runs each:

command cold warm
hc-source call leie.check_npi --param npi=… (15.5 MB OIG file) 2.78s 0.90s
hc-source doctor (23 canaries) ~6s ~6s (no reliable difference)

The LEIE file is served with a Last-Modified, so the warm run revalidates it in one round trip instead of re-downloading 15.5 MB. doctor gets no measurable benefit: its canaries are cheap by design, so the round trip already dominates what a cache could save. Every path under api.coverage.cms.gov/v1/ and the NPPES NPI Registry API sends neither an ETag nor a Last-Modified, so they are re-fetched every time by design — storing a body with no way to re-confirm it is exactly the shortcut this product exists not to take. hc-source cache info lists the endpoints in that state rather than leaving you to wonder why the entry count is low.

hc-source cache info|clear; HC_SOURCE_CACHE_DIR moves or disables it.

Adding your own source

Three homes, one contract: ship it in the package, publish it as a distribution advertising the sourcelock.adapters entry point, or drop a file in ./.sourcelock/adapters/ and switch that directory on with HC_SOURCE_LOCAL_ADAPTERS=1 (off by default: loading a file from it means executing it, so it is never on where a pull request could add one). A third-party adapter gets the same validation, the same PHI guard, and the same receipts — and cannot claim a built-in source id.

ADAPTER_GUIDE.md is the contract; examples/sourcelock-example-adapter/ is a working skeleton with four marked places to change.

More

  • ADAPTER_GUIDE.md — writing a source adapter
  • docs/ci.md — the GitHub Action, severity, and CI policy
  • RELEASING.md — publishing to PyPI
  • hc_source/guard.py — what the PHI guard detects, and what it does not

License

MIT. See LICENSE. Source data carries its own terms; each adapter records them in its SourceContract.license_notes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sourcelock-0.1.0.tar.gz (1.9 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sourcelock-0.1.0-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file sourcelock-0.1.0.tar.gz.

File metadata

  • Download URL: sourcelock-0.1.0.tar.gz
  • Upload date:
  • Size: 1.9 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sourcelock-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b73d323d0e259d9b1c399643c4d7945440c842ff8b3404addbe1f46e1e6fe276
MD5 ded20889707f628e5e770bf24c585f77
BLAKE2b-256 63765e6124b1326a4e5b70a830a644e7db26044591d5fe32d4099a7b60603db8

See more details on using hashes here.

Provenance

The following attestation bundles were made for sourcelock-0.1.0.tar.gz:

Publisher: release.yml on writtenonwater99/sourcelock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sourcelock-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sourcelock-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sourcelock-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8035a9c48d37bf4c96accd26cefb357d891ac03a4862efb29ae22426979373e1
MD5 1a890fd74a6df8ee077552287a953399
BLAKE2b-256 b181bc6ed18c7a5a8f1163ecf8de0e64b953bfe4d50e8111174ce0d3ff3739b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for sourcelock-0.1.0-py3-none-any.whl:

Publisher: release.yml on writtenonwater99/sourcelock

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page