Pivot
Pivot is a high-performance real time analytics database on open data formats.
The history Philadelphia's public systems throw away. Every Active + Expired rental license, diffed daily. 25,946 §9-3902 violations archived since 2010.
Translation pending
DataHTML · PythonGitHub @thumpersecureOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
📊 Daily append-only change log of Philadelphia Active/Expired rental licenses (public open data from phl.carto.com). Proof-of-concept history tracker.
Taken from the repository README
Loading the full README.
Read the full README ↗Every Active + Expired rental license, diffed daily. Every §9-3902 violation since 2010.
A rental license expires. Months pass. The landlord renews. Every trace that it ever lapsed — silently disappears.
When a landlord renews a lapsed rental license, the City overwrites the expiration date. After the renewal, there is no longer any public record online that the license was ever expired — or on what dates.
That is a serious problem for tenants. A tenant in a dispute — often months later, in court — may need to prove the landlord's rental license was expired during their tenancy. But if they didn't screenshot it at the time, those expired dates are gone from every City system.
This log fixes that. It records every Active → Expired and Expired → Active transition the day it happens, permanently — before the City erases it — so anyone can look up, after the fact:
This license was expired on
[date], renewed on[date], and lapsed for[N]days.
This project is designed so you never have to ask the person who built it to vouch for the data. Every daily log is anchored to the Bitcoin blockchain via OpenTimestamps, which lets anyone independently prove the log's contents existed, unaltered, on a given date. A tenant can therefore cite these dates in court as tamper-evident evidence — no need for the maintainer to appear, explain how the data was retrieved, or attest to its authenticity. The Bitcoin proof does that on its own, forever.
Philadelphia publishes rental license data across four public surfaces. Every one shows only the license's current state:
| Surface | Expiration? | Renewal date? | Status history? |
|---|---|---|---|
🗺️ Atlas atlas.phila.gov | ❌ no column | ❌ | ❌ |
📋 Property History li.phila.gov | ❌ no row | ❌ | ❌ |
🏢 eCLIPSE eclipse.phila.gov | ✅ | ⚠️ partial | ❌ |
🔌 Carto API phl.carto.com | ✅ | ✅ (hidden field) | ❌ |
When L&I cites a property for operating without a valid rental license, that record does not get erased by a later renewal. It keeps its case number, its dates, its resolution — and a link to the official Notice of Violation PDF.
That enforcement history reaches back to 2010.
| Question | Answer |
|---|---|
| Was this license expired on a given past date? | ❌ Not available — overwritten |
| When was it last renewed? | ✅ Available — mostrecentissuedate |
| Was the property cited for operating unlicensed, and when? | ✅ Permanent — since 2010 |
[!WARNING] The gap that remains. Not every lapse produces a violation. A license that expires and is renewed before an inspector visits leaves no enforcement record and no status history. Those lapses are invisible in every public system — which is exactly what the daily license log exists to catch.
phl.carto.com ─▶ daily pull ─▶ diff ─▶ append-only log ─▶ OpenTimestamps ─▶ git commit
(public) (deltas) (Bitcoin anchor) (+ .ots proof)
| Log | What | Coverage |
|---|---|---|
| 📜 License log | 99,348 Active/Expired rental licenses, diffed daily | Forward from 2026-08-21 |
| ⚖️ Violations archive | 26,817 §9-3902 rental-license citations | 2010 → present |
Every update is a timestamped Git commit, and GitHub's Activity log records every push — including any force-push — with compare links, visible to anyone with read access. That push history is outside the maintainer's control, which is what makes it worth citing. See REWRITE_LOG.md for a full account of any history changes.
A git commit date is only as trustworthy as the person (or platform) who wrote it — it can be back-dated, and GitHub could in principle be compelled to rewrite history. So the daily job does one more thing: it anchors each change log to the Bitcoin blockchain using OpenTimestamps.
Here's what that means in plain terms:
.ots file (e.g. changes.ndjson.ots) and committed to the repo. These proofs are self-validating — once a .ots carries its Bitcoin attestation, anyone can verify it with nothing but a Bitcoin node, even if this repo, GitHub, and every calendar server disappear.[!NOTE] Why this matters here: the whole point of this project is that Philadelphia's systems overwrite history. A back-datable git log would be a weak answer to that. A Bitcoin anchor is not — it proves the log's contents on a given day to anyone, forever, without asking you to trust GitHub or the maintainer.
# one-time: install the client (no account, no API key)
pipx install opentimestamps-client # or: pip install opentimestamps-client
# grab a log and its proof
curl -O https://thumpersecure.github.io/phl-rental-license-log/changes.ndjson
curl -O https://thumpersecure.github.io/phl-rental-license-log/changes.ndjson.ots
ots info changes.ndjson.ots # shows the SHA-256 + which Bitcoin block(s) it's anchored in
ots verify changes.ndjson.ots # confirms the file matches the proof and the block timestamp
ots info lists the Bitcoin block heights the hash is committed to; ots verify recomputes the hash of your copy of changes.ndjson and checks it against the block. If someone hands you an altered log, the hash won't match and verification fails.
Proof files carried in the repo: changes.ndjson.ots, violations_changes.ndjson.ots, and the current month partition (changes/YYYY-MM.ndjson.ots). Each is refreshed the moment its data file changes, so the committed proof always anchors the current contents; every past state keeps its own confirmed proof in git history at that day's commit.
[!NOTE] Timestamping is best-effort and additive — it never blocks or gates a daily data update. If a calendar server is briefly unreachable, that day's stamp is simply retried on the next run; the data log is unaffected.
Short answer: indefinitely, with a light human touch roughly every year or two — not "5 months," and not honestly "forever with zero hands." Here's the real accounting, because the honest version is more useful than a slogan.
What costs nothing and never expires (the machinery is durable):
| Component | Status |
|---|---|
| GitHub Actions minutes | Free and unmetered for public repos — one run/day is nothing |
| GitHub Pages hosting | No inactivity expiry; usage is far under every limit |
| The Actions token | Auto-issued fresh each run, self-renewing — nothing to rotate |
| Existing Bitcoin timestamps | Self-validating forever, independent of GitHub and of OpenTimestamps' own servers |
| Data source | phl.carto.com — public, no auth, no key to expire |
The two things that eventually need a human:
GitHub's 60-day scheduled-workflow rule. GitHub auto-disables a scheduled (cron) workflow "when no repository activity has occurred in 60 days" in a public repo. This job commits every day, so it should keep resetting that clock and run unattended — but GitHub's docs do not explicitly state whether a commit made by the workflow's own bot counts as "activity," and their answer to that is undocumented. If bot commits count, this runs untouched for years. If they don't, the workflow would pause at day 60 and need one click ("Enable workflow") or any manual commit to resume. Either way the data is never lost — a paused job just stops adding new days until you nudge it. This is the one thing worth glancing at once every couple of months.
Pinned action / runtime decay. The workflow pins versioned actions (actions/checkout, actions/setup-python, actions/cache). GitHub retires the underlying runner Node runtimes on a schedule and eventually removes them rather than grandfathering old pins, so about every 1–2 years those pins need a version bump. It's a two-line edit when it comes due; ignoring it indefinitely is the thing that would ultimately break an otherwise-immortal job.
Bottom line: the infrastructure has no built-in expiry and no recurring cost, so there's no fixed lifespan — but "runs itself forever with nobody ever looking" isn't truthful. The accurate promise is years of hands-off daily operation, punctuated by a ~1–2-year maintenance touch (an action-version bump) and a possible one-click re-enable if GitHub's 60-day rule turns out not to count bot commits. Design-wise it's built to survive neglect: a missing state cache just self-re-baselines, a flaky calendar server just retries next day, and every timestamp already earned stays valid no matter what happens to this repo.
curl -O https://thumpersecure.github.io/phl-rental-license-log/changes.ndjson
One JSON object per line. No parsing ceremony.
grep '"licensenum":"602204"' changes.ndjson | jq .
jq -c 'select(.diff.licensestatus.to == "Expired")' changes.ndjson
jq -c 'select(.diff.licensestatus.from == "Expired" and
.diff.licensestatus.to == "Active")' changes.ndjson
curl -O https://thumpersecure.github.io/phl-rental-license-log/violations_changes.ndjson
jq -c 'select(.new.violationcode | startswith("9-3902"))
| {case:.new.casenumber, addr:.new.address,
issued:.new.violationdate, resolved:.new.violationresolutiondate}' \
violations_changes.ndjson
grep '"address":"315-23 N 12TH ST"' violations_changes.ndjson | jq '.new.publicnov'
Each record carries publicnov — a direct link to the City's official Notice of Violation PDF.
curl -s https://thumpersecure.github.io/phl-rental-license-log/latest.json | jq .
The log is append-only and timestamp-anchored, so it is never rewritten — bad City data is annotated, not deleted. Known events:
updated records that are not real changes. The search page labels them as a feed outage.Full counts, verification steps and a Carto query: ANOMALIES.md.
| File | What it is |
|---|---|
changes.ndjson | 🔒 Append-only. One line per detected change. The whole point. |
violations_changes.ndjson | ⚖️ Violations archive. §9-3902 citations, 2010–present. |
violations_latest.json | 📊 Summary of the most recent violations run. |
state.json | 📸 Last-known state of every tracked license (the diff basis). |
latest.json | 📊 Summary of the most recent run. |
index.html | 🌐 The public page. |
// a license changed
{"ts":"…","licensenum":"602204","change":"updated",
"diff":{"licensestatus":{"from":"Expired","to":"Active"},
"expirationdate":{"from":"2026-02-28…","to":"2027-02-28…"}},
"new":{…}}
// first time we ever saw it
{"ts":"…","licensenum":"000001","change":"initial","new":{…}}
// left the Active/Expired set entirely
{"ts":"…","licensenum":"…","change":"left_set","last":{…}}
Licenses — licensestatus · expirationdate · mostrecentissuedate (renewal) · inactivedate · address · opa_account_num · zip
Violations — violationcode · violationcodetitle · violationstatus · violationdate · violationresolutiondate · casestatus · underappeal · publicnov
| Source | https://phl.carto.com/api/v2/sql — public, no auth |
| Scope | Rental licenses (Active/Expired) + §9-3902 violations, citywide |
| Volume | 99,348 licenses · 26,817 violations |
| Schedule | Daily, 08:15 UTC (~4:15 AM ET) |
| Storage | Changelog-style — only deltas are written |
| Load | A handful of paginated API calls per day |
[!IMPORTANT] The violations archive is complete history — every §9-3902 citation issued since 2010. The license log is forward-capturing: it records status changes from
2026-08-21onward and cannot reconstruct a license's status before that date.
[!NOTE] Independent project. Not affiliated with, endorsed by, or operated by the City of Philadelphia. All data is the City's own public open data.
Built with public data · Because the record should outlive the refresh.