How the database thinks about your records
Your office sends an export. What arrives is kept exactly as it arrived, then read against the parcels, owners, assessments, sales and buildings already on file, then against elevation, flood, wetlands and boundaries for the same ground. This page names the pieces.
It is written at the level of tables and functions, not columns. That is enough to have a real conversation about what is possible, and not enough to be a map for anyone else. The tool contract lives at /mcp.
The records
Nine families. Every answer PVAToday gives is assembled from these.
The parcel
The thing itself, and every version of it we have held.
| Table | What it holds |
|---|---|
parcel | One row per parcel as of the latest export: its number, where it is, how big, what class, which districts it falls in, and its map geometry. |
parcel_history | The same parcel as earlier exports described it. Nothing is overwritten; a correction becomes a new row and the old one stays readable. |
A parcel number is unique inside a county, not across counties. That is why every reply names its county, and why the record is being reshaped to carry a county code on every row.
Ownership
Who the roll says owns it, and who it said before.
| Table | What it holds |
|---|---|
parcel_owner | The owner of record for each parcel in the current export, with the deed reference that put them there. |
parcel_owner_history | Previous owners of record, as earlier exports carried them. This is what makes a chain of title readable without re-deriving it. |
Owner mailing addresses live in these tables. They are part of the public record and are served as such — see Posture, below.
Value
What the roll assessed, by year.
| Table | What it holds |
|---|---|
tax_assessment | Assessed value by parcel and tax year: land, improvements, the taxable total, property class and exemptions. |
tax_assessment_history | Prior-year values as previously delivered, so a restatement is visible as a restatement rather than a silent edit. |
tax_district | The districts a parcel can belong to, and what they are called. |
Transfers
Sales, with the honesty about which ones mean anything.
| Table | What it holds |
|---|---|
sale | Recorded transfers: date, price, deed book and page, and the validity code that says whether it was arms-length. |
Most rows in a sales table are not market sales — quitclaims between family, corrections, $1 transfers. Any question about market value has to filter on the validity code first. The valuation and ratio-study tools always do; the sales list does when asked for arms-length sales only.
Improvements
What is built on the land.
| Table | What it holds |
|---|---|
building | Structures by parcel: type, year built, size, condition, grade and value. A parcel may have many. |
The delivery record
Every export your office sent, and what changed between them.
| Table | What it holds |
|---|---|
pva_drop | One row per export received: its date, the roll it belongs to, and the stages it passed through. |
pva_unit | The individual files inside an export, each with the hash it arrived under. |
pva_change | What moved between one export and the next, per parcel and per field: transfers, value changes, new buildings, retirements. |
This is the part most record systems do not keep. It is what lets an answer say which export it came from, and what a question like "what changed since February" is answered out of.
As delivered, untouched
Your files, kept verbatim.
| Table | What it holds |
|---|---|
pva_raw.rows | Every delivered row, exactly as it arrived, with the file and line it came from. |
pva_raw.shape | The delivered map geometry, likewise unmodified. |
Nothing is loaded over the top of these. Any processed value can be traced back to the literal line of the literal file your office sent, which is the only way to settle a disagreement about what was delivered.
Normalised
The same records, made comparable.
| Table | What it holds |
|---|---|
pva_canon.parcel | Parcel rows with names, codes and formats regularised. |
pva_canon.assessment | Assessment rows, likewise. |
pva_canon.sale | Sale rows, likewise. |
pva_canon.building | Building rows, likewise. |
pva_canon.map | Map rows, likewise. |
Every county's export arrives in its own dialect. This layer is where a dialect becomes the shared vocabulary, without editing what arrived.
Who is who
Resolving the same owner across spellings. The main tables; the family has supporting ones too.
| Table | What it holds |
|---|---|
entity.owner_name_person | Owner names resolved to the individual people in them. |
entity.owner_name_parsed | Owner names broken into parts, so "SMITH JOHN A & MARY" is legible as people. |
entity.owner_entity | A canonical identity that several spellings can point at. |
entity.entity_candidate_pair | Two names that might be the same owner, with a score, awaiting judgement. |
entity.entity_relationship | How resolved identities relate to one another. |
This is the machinery behind "how much does this LLC own here" when the roll spells the name four ways. It is built and scoped to work across counties; it has not been run in anger yet.
What your records are read against
Around fifty reference layers for the region, refreshed on a schedule and held alongside the roll. A parcel answer can carry its flood zone, its terrain and its school district because these sit in the same place as the parcel.
Elevation and terrain
Two-foot LiDAR contours for the county, and derived slope and surface.
Aerial and oblique imagery
Three-inch orthoimagery, plus oblique frames with their flight geometry.
Flood
FEMA flood hazard layers.
Wetlands and water
National Wetlands Inventory, NHD hydrography, and watershed boundaries.
Weather history
Recorded tornado, hail and wind events.
Boundaries and districts
Census TIGER county, road and school district boundaries.
Public land and recreation
Protected areas, forest service roads, trails and designated areas.
Land cover
Cropland and land use.
Named places
Parks, schools, hospitals, churches, businesses and landmarks, with where they are. The list behind pva.today/mccracken/places.
The function inventory
26 functions live in the database (three of them in two versions). They are the questions it already knows how to answer, whether or not anything asks them yet.
11 of them are not called by anything. They were written, they work, and no product surface reaches them. If you are here to decide what to build next, that list is the shortest path from idea to working feature — the query already exists. One caution: some of them return owner mailing addresses, so none can be exposed until it goes through the same rule as everything else (see Posture, below).
Reachable through the MCP today
In useCalled by the tools any AI can use.
| Function | What it answers |
|---|---|
latest_owner | The owner of record for a parcel as of a given export. |
latest_assessment | The assessment in force for a parcel as of a given export. |
neighbor_analysis | What sits around a parcel, and how it compares. |
classify_owner_type | Whether an owner name reads as a person, a company, a government body or a trust. |
pva_canon_text | Regularises a delivered text value so it can be compared. The loader uses it too. |
Called by the county site
In useThe parcel pages and map at the county's own address. It also uses the four owner, assessment and neighbour functions above.
| Function | What it answers |
|---|---|
parcel_detail | Everything about one parcel, assembled in a single call. |
parcel_at_point | The parcel containing a point. Click the map, get the parcel. |
parcels_in_bbox | Every parcel inside a rectangle. A map viewport, essentially. |
search_parcels_text | Free-text search across parcels. |
search_by_owner_words | Find owners by the words in a name, not an exact string. |
get_portfolio | Everything one owner holds. The county site's owner view; the public MCP answers portfolio questions its own way. |
delinquent_summary | Delinquency rolled up by district and duration. |
Built, not yet wired to anything
IdleWorking code in the database that neither the MCP, the county site nor the loader calls. This is the interesting list.
| Function | What it answers |
|---|---|
search_parcels_nearby | Parcels near a point, filtered by a term, paged. |
search_owners_nearby | Owners near a point, likewise. |
search_assessments_nearby | Assessments near a point, likewise. |
search_parcels_with_owners_nearby | Both at once, with an owner filter. |
find_nearby_transfers | Recent transfers around a point, ranked by how recent the deed book is. Not filtered to arms-length sales. |
nearby_parcel_count | How many parcels within a radius. |
nearby_owner_count | How many owner rows within a radius. Not distinct owners: the count is of rows, and a parcel carries one per tax year. |
nearby_local_owner_count | How many of those rows carry a local (420xx) mailing ZIP. |
nearby_ex420_owner_count | The complement: rows whose mailing ZIP is outside 420xx, or absent. |
nearby_assessment_count | How many assessments within a radius. |
nearby_total_assessed | Total assessed value within a radius. |
Housekeeping
InternalInternal helpers, listed for completeness.
| Function | What it answers |
|---|---|
refresh_all_matviews | Rebuilds the precomputed summaries. The loader runs it after each export is published. |
_geo_point | Turns a latitude and longitude into a point. |
_miles_to_meters | Exactly that. |
Posture
What this page leaves out
Columns, types, keys, constraints and indexes. Naming a table is useful for talking about what is possible; publishing its exact shape is an attack surface and a promise about stability we are not making here.
Owner mailing addresses
They are in the record, because the roll carries them, and they are public record — the same information a county PVA publishes at the counter. What is not open to everyone is rolling one address up into every parcel behind it: serving a record and handing over a list are different acts, and the second needs a credential.
Nothing is overwritten
A correction adds a row; it does not replace one. Every answer can name the export it came from, and the delivered file and line behind it, which is what makes a disagreement about the record settleable.
One county is one county
A parcel number is unique inside a county and not across them. Every reply names its county, and the record is being reshaped so that a county code sits on every row rather than being implied by which database you opened.