PTAXSIM

R-CMD-check test-coverage lint pre-commit codecov

⚠️ NOTE: PTAXSIM relies on a separate SQLite database to function correctly. You must download and decompress the database before using this package! See Database installation for details.

Link to PTAXSIM database (DB version: 2022.0.0; Last updated: 2024-01-19 04:40:35)

PTAXSIM is an R package/database to approximate Cook County property tax bills. It uses real assessment, exemption, TIF, and levy data to generate historic, line-item tax bills (broken out by taxing district) for any property from 2006 to 2022. Given some careful assumptions and data manipulation, it can also provide hypothetical, but factually grounded, answers to questions such as:

PTAXSIM can generate hundreds, or even millions, of tax bills in a single function call, which enables complex tax analysis on a municipality or even whole-county level. PTAXSIM is accurate (within $10 of the real bill) for >99% of historic property tax bills. However, it is currently an experimental tool only and is not recommended for critical use. See Notes and Disclaimer for more information.

For detailed documentation on included functions and data, visit the full reference list or the introduction vignette.

For examples of PTAXSIM’s functionality and usage, click one of the questions above or see the vignettes page.

FAQs

Q: Who is the target audience for PTAXSIM?

PTAXSIM is a currently a developer and researcher-focused tool. Its intended audience is academics and policymakers interested in tax policy analysis or the history of the property tax system. It is not intended to predict or explain individual bills. In the future, we plan to make PTAXSIM more accessible via a web frontend and/or API.

Q: I got my Assessment Notice with a new assessed value. Can I input the new assessed value into PTAXSIM to predict next year’s property tax bill?

No. Assessments sent by the Assessor are not final. A property’s assessed value can change at multiple stages: at the Assessor’s Office due to a reassessment, at the Assessor’s Office due to an appeal, and at the Board of Review due to an appeal. Assessments are not finalized until these stages are complete/certified, and only finalized assessments are used to calculate bills.

Additionally, an increased assessed value does not necessarily result in an increased bill. There are many other factors that contribute to a property’s tax bill – including the assessed value of other properties.

Q: I know my property’s final assessed value. Can I input the final assessed value into PTAXSIM to predict next year’s property tax bill?

No. Even if you know your property’s final assessed value with certainty, precisely predicting a future tax bill in Cook County is difficult because tax rates stem from multiple agencies (and the numbers they produce each year). These agencies include various taxing districts (typically 10 to 14 per property, including school districts, municipal/township/city governments, and Cook County), multiple Cook County property tax offices (Assessor, Board of Review, and Clerk), and the Illinois Department of Revenue (IDOR).

It is true, however, that PTAXSIM is technically capable of predicting bills. To do this, you must have technical competency in the R programming language, and must make explicit predictions for each of the numeric inputs listed in the table below.

Q: I can code in R. What other numbers, besides assessed value, do I need to input into PTAXSIM to generate predictions?

To predict next year’s bill for one property (PIN), you must predict the PIN’s taxable value (EAV), as well as what will happen to the individual levies and tax bases of all taxing districts associated with the PIN. The table below lists each input, along with some complications and options:

Input What this means Complications and possible implementation option(s)
The PIN’s taxable value The PIN’s Equalized Assessed Value (EAV), which incorporates the assessed value, exemptions, and IDOR’s equalizer. Complications: In a tax year, AVs can change at the Assessor’s Office and at the Board of Review. Also, IDOR calculates a new equalizer every year.

Option: Predict what you think is an accurate AV, apply what exemptions you qualify for, and use past equalizers issued by IDOR.
Tax extensions, also called levies, for each taxing agency associated with that PIN’s tax code (typically, 10-14 agencies) The total extension is the total dollar amount each taxing agency decides to collect from property owners within the boundaries of its district. Complication: Each agency sets their own tax levy.

Option: For each agency associated with that PIN’s tax code, you might use the past year extension, and apply a percentage increase or decrease.
Tax bases for each taxing agency associated with that PIN’s tax code (typically, 10-14 agencies) For each agency, the tax base equals the sum of the EAVs of all properties in its district, except for any region of the agency that is in a TIF (where the base is frozen). Complication: Even after a township has been reassessed, many agencies span across township boundaries. (For example: the taxing district of the City of Chicago is divided up into eight assessment townships, but property tax bills for Chicagoans depend on assessments throughout all eight townships).

Option: For each agency associated with that PIN’s tax code, you might use the past year total EAV, and apply a percentage increase or decrease.

Installation

Package installation

You can install the released version of ptaxsim directly from GitHub with one of the following commands:

# Using remotes
remotes::install_github("ccao-data/ptaxsim")

# Using renv
renv::install("ccao-data/ptaxsim")

# Using pak
pak::pak("ccao-data/ptaxsim")

# Append the @ symbol for a specific version
remotes::install_github("ccao-data/ptaxsim@0.6.0")

⚠️ NOTE: Windows users may need to install Rtools in order to build and use this package. Please follow the instructions here to install Rtools for your version of R. Once Rtools is installed, installation can proceed normally using the code above.

Database installation

PTAXSIM relies on a separate SQLite database to function correctly. This database contains the information about properties, taxing districts, and TIF districts necessary to calculate tax bills. To use this database:

  1. Download the compressed database file from the CCAO’s public S3 bucket. Link here.
  2. (Optional) Rename the downloaded database file by removing the version number, i.e. ptaxsim-2022.0.0.db.bz2 becomes ptaxsim.db.bz2.
  3. Decompress the downloaded database file. The file is compressed using bzip2.
    • On Windows, you can easily decompress bzip2 files using 7-Zip.
    • On *nix systems, bzip2 is typically installed by default and can be used via the command line i.e. bzip2 -d ptaxsim.db.bz2. If bzip2 is not installed, use the package manager on your system (brew, apt, etc.) to install it first.
  4. Place the decompressed database file (ptaxsim.db) in a convenient location, preferably at the root of your R project.
  5. At the beginning of your project, instantiate a DBI connection to the database file with the name ptaxsim_db_conn. The PTAXSIM R functions look for this connection object name by default. If you wish to change the name, you can pass the custom named object to the conn argument of each PTAXSIM function. Below is a sample DBI connection:
library(ptaxsim)

# Create the DB connection with the default name expected by PTAXSIM functions
ptaxsim_db_conn <- DBI::dbConnect(RSQLite::SQLite(), "./ptaxsim.db")

Usage

PTAXSIM has a single primary function - tax_bill() - with two required arguments:

  1. year_vec - A numeric vector of tax years
  2. pin_vec - A character vector of Property Index Numbers (PINs)

The output is a data.table containing the tax amount directed to each taxing district, by PIN and year. By default, tax_bill() can only generate historic tax bills; it cannot generate future or counterfactual bills. To generate future/counterfactual bills, you must provide additional data to tax_bill() via its secondary arguments. See the introduction page for more details.

Single bill, single year

The simplest use of tax_bill() is to calculate a single bill for a single year:

single_bill <- tax_bill(year_vec = 2020, pin_vec = "17341020511001")
single_bill
#>     year            pin class tax_code    av   eav agency_num
#>  1: 2020 17341020511001   299    76037 11568 37288  010010000
#>  2: 2020 17341020511001   299    76037 11568 37288  010020000
#>  3: 2020 17341020511001   299    76037 11568 37288  030210000
#>  4: 2020 17341020511001   299    76037 11568 37288  030210001
#>  5: 2020 17341020511001   299    76037 11568 37288  030210002
#>  6: 2020 17341020511001   299    76037 11568 37288  030210529
#>  7: 2020 17341020511001   299    76037 11568 37288  043030000
#>  8: 2020 17341020511001   299    76037 11568 37288  044060000
#>  9: 2020 17341020511001   299    76037 11568 37288  050200000
#> 10: 2020 17341020511001   299    76037 11568 37288  050200001
#> 11: 2020 17341020511001   299    76037 11568 37288  080180000
#>                      agency_name     agency_major_type agency_minor_type
#>  1:               COUNTY OF COOK           COOK COUNTY              COOK
#>  2: FOREST PRESERVE DISTRICT ...           COOK COUNTY              COOK
#>  3:              CITY OF CHICAGO MUNICIPALITY/TOWNSHIP              MUNI
#>  4: CITY OF CHICAGO LIBRARY F... MUNICIPALITY/TOWNSHIP           LIBRARY
#>  5: CITY OF CHICAGO SCHOOL BL... MUNICIPALITY/TOWNSHIP              MISC
#>  6: TIF - CHICAGO - BRONZEVIL... MUNICIPALITY/TOWNSHIP               TIF
#>  7: CHICAGO COMMUNITY COLLEGE...                SCHOOL         COMM COLL
#>  8:           BOARD OF EDUCATION                SCHOOL           UNIFIED
#>  9:        CHICAGO PARK DISTRICT         MISCELLANEOUS              PARK
#> 10: CHICAGO PARK DISTRICT AQU...         MISCELLANEOUS              BOND
#> 11: METRO WATER RECLAMATION D...         MISCELLANEOUS             WATER
#>     agency_tax_rate final_tax
#>  1:         0.00453     57.57
#>  2:         0.00058      7.37
#>  3:         0.01580    200.79
#>  4:         0.00140     17.79
#>  5:         0.00166     21.10
#>  6:         0.00000   1698.69
#>  7:         0.00151     19.19
#>  8:         0.03656    464.62
#>  9:         0.00329     41.81
#> 10:         0.00000      0.00
#> 11:         0.00378     48.04

To compare this output to a real tax bill, we can reorder the rows and keep only the columns that appear on an actual printed bill.

library(dplyr)

single_bill %>%
  select(agency_name, final_tax, agency_tax_rate) %>%
  mutate(agency_tax_rate = agency_tax_rate * 100) %>%
  arrange(-row_number()) %>%
  setNames(c("Agency", "2020 Tax", "2020 Rate")) %>%
  knitr::kable("html", digits = 3)
Agency 2020 Tax 2020 Rate
METRO WATER RECLAMATION DISTRICT OF GREATER CHICAGO 48.04 0.378
CHICAGO PARK DISTRICT AQUARIUM & MUSEUM BONDS 0.00 0.000
CHICAGO PARK DISTRICT 41.81 0.329
BOARD OF EDUCATION 464.62 3.656
CHICAGO COMMUNITY COLLEGE DISTRICT 508 19.19 0.151
TIF - CHICAGO - BRONZEVILLE 1698.69 0.000
CITY OF CHICAGO SCHOOL BLDG & IMP FUND 21.10 0.166
CITY OF CHICAGO LIBRARY FUND 17.79 0.140
CITY OF CHICAGO 200.79 1.580
FOREST PRESERVE DISTRICT OF COOK COUNTY 7.37 0.058
COUNTY OF COOK 57.57 0.453

Here’s the real 2020 tax bill for this PIN for comparison:

There are some minor differences between PTAXSIM and the real bill. The taxing district names may not be identical. Additionally, PTAXSIM aggregates the different Cook County agencies (Public Safety, Health Facilities, and County of Cook) into a single line-item (COUNTY OF COOK).

Single bill, multiple years

We can also look at a single property over multiple years, in this case broken out by taxing district. To do so, pass a vector of multiple years to the year_vec argument of tax_bill():

multiple_years <- tax_bill(2010:2021, "14081020210000")
multiple_years
#>      year            pin class tax_code    av    eav agency_num
#>   1: 2010 14081020210000   206    73001 69062 227905  010010000
#>   2: 2010 14081020210000   206    73001 69062 227905  010020000
#>   3: 2010 14081020210000   206    73001 69062 227905  030210000
#>   4: 2010 14081020210000   206    73001 69062 227905  030210001
#>   5: 2010 14081020210000   206    73001 69062 227905  030210002
#>  ---                                                           
#> 122: 2021 14081020210000   206    73105 70000 210189  043030000
#> 123: 2021 14081020210000   206    73105 70000 210189  044060000
#> 124: 2021 14081020210000   206    73105 70000 210189  050200000
#> 125: 2021 14081020210000   206    73105 70000 210189  050200001
#> 126: 2021 14081020210000   206    73105 70000 210189  080180000
#>                       agency_name     agency_major_type agency_minor_type
#>   1:               COUNTY OF COOK           COOK COUNTY              COOK
#>   2: FOREST PRESERVE DISTRICT ...           COOK COUNTY              COOK
#>   3:              CITY OF CHICAGO MUNICIPALITY/TOWNSHIP              MUNI
#>   4: CITY OF CHICAGO LIBRARY F... MUNICIPALITY/TOWNSHIP           LIBRARY
#>   5: CITY OF CHICAGO SCHOOL BL... MUNICIPALITY/TOWNSHIP              MISC
#>  ---                                                                     
#> 122: CHICAGO COMMUNITY COLLEGE...                SCHOOL         COMM COLL
#> 123:           BOARD OF EDUCATION                SCHOOL           UNIFIED
#> 124:        CHICAGO PARK DISTRICT         MISCELLANEOUS              PARK
#> 125: CHICAGO PARK DISTRICT AQU...         MISCELLANEOUS              BOND
#> 126: METRO WATER RECLAMATION D...         MISCELLANEOUS             WATER
#>      agency_tax_rate final_tax
#>   1:         0.00423    964.04
#>   2:         0.00051    116.23
#>   3:         0.00914   2083.05
#>   4:         0.00102    232.46
#>   5:         0.00116    264.37
#>  ---                          
#> 122:         0.00145    225.36
#> 123:         0.03517   4984.70
#> 124:         0.00311    483.37
#> 125:         0.00000      0.00
#> 126:         0.00382    593.71

The tax_bill() function will automatically combine the years and PIN into their Cartesian product. The result is a tax amount per taxing district, per PIN, per year. We can collapse these amounts and then plot them to see how a single PIN has changed over time:

multiple_years_summ <- multiple_years %>%
  group_by(year, agency_minor_type) %>%
  summarize(final_tax = sum(final_tax)) %>%
  mutate(
    agency_minor_type = factor(
      agency_minor_type,
      levels = c(
        "TIF", "BOND", "COOK", "LIBRARY", "MUNI", "PARK",
        "UNIFIED", "COMM COLL", "WATER", "MISC"
      )
    )
  )
Click here to show plot code
library(ggplot2)

# Plot the amount of taxes going to each district over time
multiple_years_plot <- ggplot(data = multiple_years_summ) +
  geom_area(aes(x = year, y = final_tax, fill = agency_minor_type)) +
  geom_vline(xintercept = 2016, linetype = "dashed", alpha = 0.3) +
  annotate(
    "text",
    x = 2015.8,
    y = 12500,
    label = "RPM TIF enacted",
    hjust = 1
  ) +
  scale_y_continuous(
    name = "Total Tax Amount",
    labels = scales::dollar,
    expand = c(0, 0)
  ) +
  scale_x_continuous(name = "Year", n.breaks = 7) +
  scale_fill_manual(values = scales::hue_pal()(10)) +
  theme_minimal() +
  guides(fill = guide_legend(title = "District Type"))

For more advanced usage, such as counterfactual analysis, see the vignettes page.

Data

The PTAXSIM backend database contains cleaned data from the Cook County Clerk, Treasurer, and Assessor. The database is updated whenever all the data necessary to calculate a new tax year becomes available. Typically this occurs roughly a year after assessments are mailed i.e. 2019 bill data was available in mid-2020.

Data sources

Table Name Source Agency Source Link Ingest Script Contains
agency Clerk Tax Extension - Agency Tax Rate Reports data-raw/agency/agency.R Taxing district extensions, limits, and base EAV
agency_info Clerk + imputed Tax Extension - Agency Tax Rate Reports data-raw/agency/agency.R Taxing district name, type, and subtype
agency_fund Clerk Tax Extension - Agency Tax Rate Reports data-raw/agency/agency.R Funds and line-items that contribute to each district’s extension
agency_fund_info Clerk Tax Extension - Agency Tax Rate Reports data-raw/agency/agency.R Fund name and whether the fund is statutorily capped
cpi IDOR History of CPI’s Used for the PTELL data-raw/cpi/cpi.R CPI-U used to calculate PTELL limits
eq_factor Clerk Tax Extension - Agency Tax Rate Reports data-raw/eq_factor/eq_factor.R Equalization factor applied to AV to get EAV
pin Clerk + Treasurer CLERKVALUES and TAXBILLAMOUNTS internal SQL tables data-raw/pin/pin.R PIN-level tax code, AV, and exemptions
tax_code Clerk Tax Extension - Tax Code Agency Rate Reports data-raw/tax_code/tax_code.R Crosswalk of tax codes by district
tif Clerk TIF Reports - Cook County Summary Reports data-raw/tif/tif.R TIF revenue, start year, and cancellation year
tif_crosswalk Clerk Manually created from TIF summary and distribution reports data-raw/tif/tif.R Fix for data issue identified in #39
tif_distribution Clerk TIF Reports - Tax Increment Agency Distribution Reports data-raw/tif/tif.R TIF EAV, frozen EAV, and distribution percentage by tax code

Database diagram

Click here to show full database diagram
erDiagram

  agency {
    int     year              PK
    varchar agency_num        PK
    boolean home_rule_ind
    int     agg_ext_base_year
    bigint  lim_numerator
    bigint  lim_denominator
    double  lim_rate
    bigint  prior_eav
    bigint  curr_new_prop
    bigint  cty_cook_eav
    bigint  cty_dupage_eav
    bigint  cty_lake_eav
    bigint  cty_will_eav
    bigint  cty_kane_eav
    bigint  cty_mchenry_eav
    bigint  cty_dekalb_eav
    bigint  cty_grundy_eav
    bigint  cty_kankakee_eav
    bigint  cty_kendall_eav
    bigint  cty_lasalle_eav
    bigint  cty_livingston_eav
    bigint  cty_total_eav
    double  pct_burden
    bigint  total_levy
    bigint  total_max_levy
    double  total_prelim_rate
    bigint  total_reduced_levy
    bigint  total_final_levy
    double  total_final_rate
    varchar reduction_type
    double  reduction_pct
    double  total_non_cap_ext
    double  total_ext
  }

  agency_info {
    varchar agency_num         PK
    varchar agency_name
    varchar agency_name_short
    varchar agency_name_original
    varchar major_type
    varchar minor_type
  }

  agency_fund {
    int     year               PK
    varchar agency_num         PK
    varchar fund_num           PK
    bigint  levy
    double  loss_pct
    bigint  levy_plus_loss
    double  rate_ceiling
    bigint  max_levy
    double  prelim_rate
    bigint  ptell_reduced_levy
    boolean ptell_reduced_ind
    bigint  final_levy
    double  final_rate
  }

  agency_fund_info {
    varchar fund_num           PK
    varchar fund_name
    boolean capped_ind
  }

  cpi {
    int     year
    double  cpi
    double  ptell_cook
    int     levy_year          PK
  }

  eq_factor {
    int     year               PK
    double  eq_factor_tentative
    double  eq_factor_final
  }

  metadata {
    varchar db_version
    varchar requires_pkg_version
    varchar created_with_pkg_version
    varchar created_at
    varchar created_by
    varchar author_name
    varchar author_email
    varchar source_url_database
    varchar source_url_package
    int     data_year_min
    int     data_year_max
  }

  pin {
    int     year               PK
    varchar pin                PK
    varchar class
    varchar tax_code_num
    double  tax_bill_total
    int     av_mailed
    int     av_certified
    int     av_board
    int     av_clerk
    int     exe_homeowner
    int     exe_senior
    int     exe_freeze
    int     exe_longtime_homeowner
    int     exe_disabled
    int     exe_vet_returning
    int     exe_vet_dis_lt50
    int     exe_vet_dis_50_69
    int     exe_vet_dis_ge70
    int     exe_abate
  }

  pin_geometry {
    int     year
    varchar pin10
    double  longitude
    double  latitude
    text    geometry
  }

  pin_geometry_raw {
    varchar pin10              PK
    int     start_year         PK
    int     end_year           PK
    double  longitude
    double  latitude
    text    geometry
  }

  tax_code {
    int     year               PK
    varchar agency_num         PK
    double  agency_rate
    varchar tax_code_num       PK
    double  tax_code_rate
  }

  tif {
    int     year               PK
    varchar agency_num         PK
    double  prev_year_revenue
    double  curr_year_revenue
    int     first_year
    boolean cancelled_this_year
  }

  tif_crosswalk {
    int     year
    varchar agency_num_dist
    varchar agency_num_final
  }

  tif_distribution {
    int     year               PK
    varchar agency_num         PK
    varchar tax_code_num       PK
    double  tax_code_rate
    bigint  tax_code_eav
    bigint  tax_code_frozen_eav
    bigint  tax_code_revenue
    double  tax_code_distribution_pct
  }

  eq_factor ||--|{ pin : "applies to"
  pin ||--|{ tax_code : "within"
  cpi ||--|{ agency : "applies to"
  tax_code }|--|| agency : "has"
  tax_code ||--o| tif_distribution : "may have"
  agency ||--|{ agency_fund : "contains"
  agency_info ||--|{ agency : "describes"
  agency_fund_info ||--|{ agency_fund : "describes"
  tif ||--|| tif_crosswalk : "in"
  tif_distribution }|--|| tif_crosswalk : "in"
  agency_info ||--o{ tif: "describes"
  tax_code }|--o| tif : "may have"
  pin_geometry ||--o| pin : "has"
  pin_geometry }|--|| pin_geometry_raw : "expands"
erDiagram

  agency {
    int     year              PK
    varchar agency_num        PK
    boolean home_rule_ind
    bigint  cty_cook_eav
    double  total_ext
  }

  agency_info {
    varchar agency_num         PK
    varchar agency_name
    varchar major_type
  }

  agency_fund {
    int     year               PK
    varchar agency_num         PK
    varchar fund_num           PK
    bigint  final_levy
    double  final_rate
  }

  agency_fund_info {
    varchar fund_num           PK
    varchar fund_name
    boolean capped_ind
  }

  cpi {
    int     year
    double  cpi
    double  ptell_cook
    int     levy_year          PK
  }

  eq_factor {
    int     year               PK
    double  eq_factor_tentative
    double  eq_factor_final
  }

  metadata {
    varchar db_version
    varchar requires_pkg_version
    int     data_year_min
    int     data_year_max
  }

  pin {
    int     year               PK
    varchar pin                PK
    varchar class
  }

  pin_geometry {
    int     year
    varchar pin10
    text    geometry
  }

  tax_code {
    int     year               PK
    varchar agency_num         PK
    double  agency_rate
    varchar tax_code_num       PK
    double  tax_code_rate
  }

  tif {
    int     year               PK
    varchar agency_num         PK
    double  prev_year_revenue
    double  curr_year_revenue
    int     first_year
    boolean cancelled_this_year
  }

  tif_crosswalk {
    int     year
    varchar agency_num_dist
    varchar agency_num_final
  }

  tif_distribution {
    int     year               PK
    varchar agency_num         PK
    varchar tax_code_num       PK
    double  tax_code_distribution_pct
  }

  eq_factor ||--|{ pin : "applies to"
  pin ||--|{ tax_code : "within"
  cpi ||--|{ agency : "applies to"
  tax_code }|--|| agency : "has"
  tax_code ||--o| tif_distribution : "may have"
  agency ||--|{ agency_fund : "contains"
  agency_info ||--|{ agency : "describes"
  agency_fund_info ||--|{ agency_fund : "describes"
  tif ||--|| tif_crosswalk : "in"
  tif_distribution }|--|| tif_crosswalk : "in"
  agency_info ||--o{ tif: "describes"
  tax_code }|--o| tif : "may have"
  pin_geometry ||--o| pin : "has"

Notes and caveats

  • Currently, the per-district tax calculations for properties in the Red-Purple Modernization (RPM) TIF are slightly flawed. However, the total tax bill per PIN is still accurate. See issue #4 for more information.
  • Special Service Area (SSA) rates must be calculated manually when creating counterfactual bills. See issue #3 for more information.
  • In rare instances, a TIF can have multiple agency_num identifiers (usually there’s only one per TIF). The tif_crosswalk table determines what the “main” agency_num is for each TIF and pulls the name and TIF information using that identifier. See issue GitLab #39 for more information.
  • PTAXSIM is relatively memory-efficient and can calculate every district line-item for every tax bill for the last 15 years (roughly 350 million rows). However, the memory required for this calculation is substantial (around 100 GB).
  • PTAXSIM’s accuracy is measured automatically with an integration test. The test takes a random sample of 1 million PINs, calculates the total bill for each PIN, and compares it to the real total bill.
  • This repository contains an edited version of PTAXSIM’s commit history. Historical Git LFS and other data files (.csv, .xlsx, etc.) were removed in the transition to GitHub. The most current version of these files is available starting in commit 1f06639. If you need the historical LFS files for any reason, please visit the GitLab archive of this repository.

Disclaimer

This package and the included database are for educational purposes only. The Assessor’s office releases the package and database without any representations or warranties of any kind, whether express or implied. Any data, figures, or amounts contained within the package/database, used by the package/database, or produced by the package are solely for illustrative purposes.

Any results produced by this package as distributed are not official, as they are hypothetical, and should not be relied upon for any business or commercial purpose. The Assessor’s office expressly disclaims any liability for any entity’s reliance on this package and/or database.

Release procedures

The PTAXSIM package consists of two components, a package and a database, each of which can be updated independently. Both components have built-in checks to ensure that minimum version expectations are met, i.e. package version 0.5.4 expects database version 2021.0.1 or higher, and database version 2021.0.1 expects package version 0.5.3 or higher.

Schema

The package uses the SemVer schema for versioning: <MAJOR VERSION>.<MINOR VERSION>.<PATCH>.

The database uses a custom schema for versioning: <TAX YEAR>.<MAJOR VERSION>.<MINOR VERSION>. Where TAX YEAR denotes the most recent year of data in the database.

Timing

The PTAXSIM database is updated whenever all the data necessary to calculate a new tax year becomes available. Typically this occurs about a year after initial assessments are mailed. Once all necessary data is available, it is manually incorporated into the database, and the database tax year version is updated to reflect the new data.

Checklists

The process of updating the package and/or database can be somewhat involved. As such, please use the following release checklists when creating a new version: