---
name: nmtc-eligibility
description: >-
  Check whether a U.S. address or census tract is New Markets Tax Credit (NMTC)
  eligible as a Low-Income Community, and screen a project's NMTC feasibility.
  Use when the user asks "is this address/tract NMTC eligible", about "distress
  criteria", "severe distress", "deep distress", "low-income community" / "LIC"
  status, or wants a first-pass NMTC deal feasibility score. Backed by the
  audited PyPI packages nmtc-mapper and nmtc-screener — never estimate
  eligibility from general knowledge.
---

# NMTC Eligibility

Grounds NMTC eligibility answers in two published, audited packages instead of
guessing. **nmtc-mapper** geocodes an address to a census tract and looks the
tract up in the CDFI Fund's NMTC Low-Income Community (LIC) eligibility table.
**nmtc-screener** runs a structured first-pass feasibility score on a project.

## When to use

- "Is 2400 Grand Concourse, Bronx NY NMTC eligible?"
- "Is census tract 36005023702 a low-income community?"
- "Does this tract qualify for severe distress / the 85% investment commitment?"
- "Screen this $8.5M grocery project for NMTC feasibility."

## When NOT to use

- Anything requiring the *official* CDFI Fund allocation decision — this is a
  screening/eligibility lookup, not an allocation award or legal determination.
- Historic Tax Credit, LIHTC, or Opportunity Zone *investment* structuring
  (OZ *flag* is reported by the mapper, but OZ deal mechanics are `oz-tracker`).
- NMTC transaction / credit / capital-stack modeling beyond the screener's
  first-pass estimate — that depth lives in `nmtc-calc`.

## Install

```
pip install "nmtc-mapper>=0.4.1" nmtc-screener
```

Verified this session (PyPI): **nmtc-mapper 0.4.1**, **nmtc-screener 0.1.0**
(`nmtc-calc 0.2.1` is pulled in as a dependency). The `>=0.4.1` floor is not
cosmetic — 0.4.0 is where `nmtc_eligible` became tri-state (see below), and
0.4.1 binds the geocoder vintage to the eligibility table's 2020 tract basis
(see Data dependencies & fragility). A reader on 0.3.x following this skill's
third-state guidance would never see `None`, because 0.3.x collapses "could not
determine" into `False`.

Import names (dist name ≠ import name):

| dist | import |
|---|---|
| nmtc-mapper | `nmtcmapper` |
| nmtc-screener | `nmtc_screener` |

## The answer space is TRI-STATE (0.4.0 — read this before anything else)

`nmtc_eligible` is **`Optional[bool]`** — `True`, `False`, or **`None`**. There
are three outcomes, not two:

| `nmtc_eligible` | `distress_level` | meaning |
|---|---|---|
| `True`  | `deep` / `severe` / `lic` | **verified eligible** — the table says YES |
| `False` | `ineligible`              | **verified ineligible** — the table says NO |
| `None`  | `unknown`                 | **INDETERMINATE** — no verdict was reached |

**`None` / `"unknown"` means "could not be determined." It is NOT "not
eligible."** Never render `None` as "no," "ineligible," "not eligible," or a
falsy `False`. A `None` reached two ways: the address did not geocode, or the
tract is absent from the ~85k-tract universe (a bad/mistyped GEOID, or a
vintage mismatch). Neither is a NO — both are "we don't know."

`EligibilityResult.eligibility_status` (property, 0.4.0) collapses this into one
explicit four-way string so you never have to infer intent from a `None`:

```
verified-eligible  |  verified-ineligible  |  not-found  |  geocode-failed
```

`not-found` and `geocode-failed` are the two indeterminate cases. `summary()`
prints indeterminate results as `❓ UNKNOWN — … (indeterminate, NOT ineligible)`
on the eligibility line itself — that inline qualifier is defined in
`nmtcmapper/eligibility/checker.py::EligibilityResult.summary`, not a footer.

## The hard failure rule (non-negotiable)

**If a tool errors, report the error verbatim and stop. NEVER estimate NMTC
eligibility from general knowledge, from the address alone, or from what a
neighborhood "seems like."** Eligibility is a specific tract-level lookup
against a specific CDFI Fund table; there is no valid way to infer it. A wrong
"eligible" answer can send a real deal down a dead end. A user asking for a
"best guess," "ballpark," or "rough" eligibility answer does not override this
rule; decline and report that the lookup failed.

## The third-state rule (non-negotiable — the load-bearing addition)

The hard failure rule above governs a tool that *errors*. This rule governs a
lookup that *succeeds and returns UNKNOWN* (`nmtc_eligible is None`,
`distress_level == "unknown"`, `eligibility_status` in `{not-found,
geocode-failed}`). An unknown verdict is a **result, not an error** — and it
must be reported as its own answer:

- Report it as **"NMTC eligibility could not be determined for this tract"**,
  and **name the tract ID** (or state the address did not geocode). Say *why*:
  tract absent from the vintage's universe, or address failed to geocode.
- **Never** collapse it into "not eligible," "no," or "ineligible."
- **Never** soften it into "probably not eligible" or "likely ineligible."
- **Never** resolve it from a neighboring tract, the ZIP, the city, or the
  address's apparent neighborhood — the same anti-pressure posture as the
  best-guess rule above.

**Why, inline (a model reading this needs the reason, not just the rule):** a
`None` rendered as "not eligible" is a *fabricated negative*. It kills a deal
that may genuinely qualify — the tract simply was not checkable in this vintage,
and the correct next step is to re-check against the vintage in force at
application time, not to declare the deal dead. A false "ineligible" is exactly
as damaging as a false "eligible," in the opposite direction.

## The vintage-scope rule (non-negotiable)

**This package carries the 2016–2020 ACS vintage ONLY** (the 85,395-tract table
below). NMTC LIC eligibility is governed by the ACS vintage tied to the deal's
**QLICI close date**, and answering the wrong vintage confidently is the same
class of failure as rendering `None` as "not eligible" — a confident answer
against data that does not govern. The CDFI Fund's transition rules (primary:
CDFI Fund, *2016-2020 ACS Data FAQ*, updated **Feb 1, 2024** —
`NMTC_LIC_FAQs_2020_ACS_Sept1_2023_Update_Jan2024.pdf` at
`cdfifund.gov/system/files/2024-01/`, announced at `cdfifund.gov/news/567`;
secondary, quoted verbatim: NMTC Coalition,
`nmtccoalition.org/2023/09/06/new-nmtc-data`):

| QLICI close date | Governing data | May this package answer? |
|---|---|---|
| **before Sept 1, 2023** | **must use 2011–2015** ACS | **No** — 2011–2015 is not carried here |
| **Sept 1, 2023 – Aug 31, 2024** | **may use either** 2011–2015 or 2016–2020 | Yes, but the 2011–2015 vintage is equally permitted |
| **on/after Sept 1, 2024** | **must use 2016–2020** ACS on 2020 tracts | Yes — authoritative |

Apply it:

- **Close date before Sept 1, 2023** → the 2016–2020 table does **not** govern;
  2011–2015 ACS does, and this package does **not** carry it. Do **not** answer
  from the 2016–2020 table. Say so and route the user to the CDFI Fund's CIMS
  (CDFI Information Mapping System), which carries the governing vintage.
- **Close date in the Sept 1, 2023 – Aug 31, 2024 window** → the 2016–2020
  answer is valid and permitted, but state that 2011–2015 is **also** an
  acceptable basis in this window, so the deal may qualify under the other
  vintage even if 2016–2020 says NO.
- **Close date on/after Sept 1, 2024, or unknown** → state which vintage the
  answer is based on (2016–2020) and that it is valid for QLICIs closing
  on/after Sept 1, 2023 and mandatory on/after Sept 1, 2024. If the close date
  is unknown or earlier, confirm it before relying on the answer — for a
  pre-Sept-1-2023 closing the 2011–2015 vintage (not carried here) governs.

**Island Areas are a second scope hole of the same class.** This table's
~85,395 rows cover the **50 states + DC + Puerto Rico only** (PR verified
present this session). The **Island Areas — American Samoa, Guam, the CNMI, and
the US Virgin Islands — were NOT covered by the 2016–2020 ACS** and are absent
from this package's table entirely. The CDFI Fund publishes a **separate**
Island Areas NMTC LIC file — `NMTC_LIC_Territory_2020_December_2023.xlsx`, built
on the **2020 Island Areas Decennial Census** (not the 2016–2020 ACS), released
Dec 19, 2023 and available in CIMS as of Jan 25, 2024 — which **this package
does not carry**. Per the CDFI Fund's *2016-2020 ACS Data FAQ* (updated Feb 1,
2024, General Q3): *"For Island areas, CDEs should continue to use 2011-2015
NMTC Low-Income Community eligibility data and follow the same transition dates
outlined in question 3."* An Island Area address/tract that is absent here is
therefore **"not carried by this package," never "ineligible"** — route to CIMS
or to the separate territory file; do not answer it from this 2016–2020 ACS
table.

## Worked example — address eligibility (executed)

```python
import nmtcmapper as nm

m = nm.NMTCMapper()
result = m.check_address("2400 Grand Concourse, Bronx, NY 10458")
result.summary()          # prints a formatted block; returns None
print(result.eligibility_status)   # -> 'verified-eligible'
```

Actual output this session (nmtc-mapper 0.4.1, clean-venv PyPI install; byte-identical on 0.4.0):

```
NMTC Eligibility Result
==================================================
  Address:          2400 Grand Concourse, Bronx, NY 10458
  Census Tract:     36005023702
  NMTC Eligible:    ✅ YES
  Distress Level:   SEVERE
  Description:      Severe Distress — qualifies for 85% investment commitment

  Poverty Rate:     32.1%
  AMI Ratio:        53.2%
  Unemployment:     10.7%
  Non-Metro:        No
  Opportunity Zone: No
  High Migration:   No
```

`eligibility_status` is `verified-eligible`. Tract `36005023702` verified
**present** in the live 2016–2020 table this session.

**Do not repeat the `Opportunity Zone: No` line as fact.** Verified this session,
`36005023702` is genuinely absent from the loaded OZ list (`is_opportunity_zone
is False`) — which, under the OZ rule below, is exactly the ambiguous negative.
Narrate it as **"not confirmed as an Opportunity Zone,"** never "not an
Opportunity Zone." The `summary()` block prints a bare `No`; the skill's job is
to re-narrate that `No`, not echo it — a `False` here cannot distinguish
not-designated from a 2010/2020 tract-vintage miss.

The `EligibilityResult` fields (read these, don't re-derive): `address`,
`tract_id`, `nmtc_eligible` (**`Optional[bool]` — True / False / None**),
`distress_level` (str: `'deep'`, `'severe'`, `'lic'`, `'ineligible'`,
`'unknown'`), `poverty_rate`, `ami_ratio`, `unemployment_rate`, `is_non_metro`,
`is_high_migration_rural`, `is_nmtc_native_area` (**always `False` — see note**),
`severe_distress`, `deep_distress`, `geocode_success`, `is_opportunity_zone`,
**`tract_found`** (bool, 0.4.0 — `False` when the tract is absent from the
table). Properties: `distress_description` (plain-English line, e.g. *"Severe
Distress — qualifies for 85% investment commitment"*) and
**`eligibility_status`** (the four-way string above).

**`is_nmtc_native_area` is always `False` in this package** — no column in the
live `.xlsb` populates it (verified this session: `False` for all 85,395 tracts,
`True` count 0; nmtc-mapper 0.4.1 Known Issues). It is hardcoded/defaulted, so a
`False` here means **"not determined," not "not a Native Area."** Do not report
it as a fact about a tract.

Note `.summary` is a **method** — call `result.summary()`. `result.summary`
alone returns the bound method object, not the text.

## Worked example — verified-ineligible tract + the NaN honesty rule (executed)

A tract that is **present in the table with an explicit NO flag** — distinct
from an absent tract (next example). Verified this session: `11001980000` **is**
one of the 85,395 rows, flagged not-eligible, with null (NaN) poverty and
income. The CDFI Fund documents several reasons a tract carries null
demographics: per its *2016-2020 ACS Data FAQ* (updated Feb 1, 2024;
`NMTC_LIC_FAQs_2020_ACS_Sept1_2023_Update_Jan2024.pdf`, General Q2), the Census
Bureau could not estimate income or poverty for such tracts —
a significant majority have no or very low population, and the remainder's
population is largely in **group quarters** (e.g. prisons, college dormitories),
which the ACS excludes from income and poverty calculations. Which of those
applies to `11001980000` is not something this lookup reports, so do not assert
it.

```python
import nmtcmapper as nm
m = nm.NMTCMapper()
r = m.check_tract("11001980000")   # present, explicit NO, null demographics
print(r.nmtc_eligible, r.distress_level, r.poverty_rate, r.ami_ratio)
print(r.eligibility_status, "| tract_found:", r.tract_found)
```

Actual output this session:

```
False ineligible nan nan
verified-ineligible | tract_found: True
```

`poverty_rate` and `ami_ratio` came back **NaN** — the Fund does not publish an
income or poverty estimate for this tract (see the FAQ Q2 reasons above) —
render them "not available," never invent a number.
`nmtc_eligible=False` / `eligibility_status='verified-ineligible'` /
`tract_found=True` is a **real NO from the table** — the answer *is*
ineligible. This is NOT the third state; contrast the next example, where the
tract is absent and the honest answer is "unknown."

## Worked example — the third state: an ABSENT tract (executed)

The teaching case for `None`/`"unknown"`. A syntactically valid GEOID that is
**not in the 2016–2020 universe** (a mistyped tract, or one from a different
vintage). Verified absent this session: `36061980000` is **not** among the
85,395 rows.

```python
import nmtcmapper as nm
m = nm.NMTCMapper()
r = m.check_tract("36061980000")   # a tract ABSENT from the 2016-2020 universe
print(r.nmtc_eligible, r.distress_level, r.eligibility_status, r.tract_found)
r.summary()
```

Actual output this session:

```
None unknown not-found False
```

```
NMTC Eligibility Result
==================================================
  Address:          Census Tract 36061980000
  Census Tract:     36061980000
  NMTC Eligible:    ❓ UNKNOWN — tract not in eligibility table (indeterminate, NOT ineligible)
  Distress Level:   UNKNOWN
  Description:      Indeterminate — eligibility not verified (no match / tract absent)
  Non-Metro:        No
  Opportunity Zone: No
  High Migration:   No
```

Report this as: *"NMTC eligibility could not be determined for tract
36061980000 — it is absent from the 2016–2020 eligibility universe."* Do **not**
report it as "not eligible." The `Description` line —
*"Indeterminate — eligibility not verified (no match / tract absent)"* — is the
verbatim value of `DISTRESS_LEVELS["unknown"]` in
`nmtcmapper/data/schema.py`.

**The program administrator documents this exact case — it is not just a
first-principles argument.** The CDFI Fund's *2016-2020 ACS Data FAQ* (updated
Feb 1, 2024; `NMTC_LIC_FAQs_2020_ACS_Sept1_2023_Update_Jan2024.pdf`, **Q10**,
*"I can't find a 2010 census tract in the 2016-2020 ACS Low-Income Community
data. Where is it?"*) explains
that the 2011–2015 data is built on **2010** census tracts and the 2016–2020
data on **2020** tracts, and that as part of the 2020 census the Bureau
**eliminated certain 2010 tracts and folded their land into new tracts** — so a
tract absent from this table is a **vintage artifact, not an ineligibility
finding**. The FAQ routes the reader to the Census Bureau tract-relationship
files and to CIMS for geocoding; do the same rather than reporting "not
eligible."

The same third state reaches you from `check_address` when an address does not
geocode: `nmtc_eligible=None`, `distress_level="unknown"`,
`eligibility_status="geocode-failed"`, and `summary()` prints *"❓ UNKNOWN —
address could not be geocoded (indeterminate, NOT ineligible)."* (executed this
session against a deliberately unresolvable address).

## Worked example — project feasibility screen (executed)

```python
import nmtc_screener as ns

r = ns.run_screening(
    project_name="Maple Street Grocery",
    location="Bronx, NY (Tract 36005023702)",
    total_project_cost=8_500_000,
    project_type="commercial",
    annual_revenue=3_200_000,
    lic_status="yes",          # accepted: "yes" | "unknown" | (anything else = treated as not-LIC)
)
print(r.qualification_likelihood, r.qualification_score)
```

Actual output this session (nmtc-screener 0.1.0):

```
HIGH 95
```

`qualification_reasons` (actual):

```
Project is in a confirmed Low Income Community census tract (+35 pts)
Project type 'Other': Eligibility depends on specific business activities and community benefit. (+10 pts)
Project cost ≥$5MM — meets minimum viable deal size (+5 pts)
Revenue ($3,200,000/yr) covers estimated debt service at 1.25x DSCR (+5 pts)
```

Note: the screener does not currently map project_type='commercial' to a
specific category — it scores it as 'Other' (+10 pts), so this component of the
score is type-agnostic; treat the result as a first-pass heuristic, not
underwriting.

`run_screening` signature (positional or keyword): `run_screening(project_name,
location, total_project_cost, project_type, annual_revenue, lic_status)`. The
`ScreeningResult` also carries `estimated_allocation`, `transaction_result`,
`credit_result`, `subsidy_result`, and a `plain_english_summary`.

**`lic_status` is the user's assertion, not a lookup.** If the user has not
confirmed LIC status, either run `nmtcmapper` first and pass the real answer, or
pass `"unknown"` — do not pass `"yes"` on assumption. And if the mapper returned
the **third state** (`None`/`"unknown"`), pass `"unknown"` to the screener —
never `"yes"`, and never `"no"`, because you do not know. The screener's score
is only as honest as this input.

## Output-presentation rules

- Always report the **census tract ID** alongside any eligibility verdict — it
  is the unit the answer is actually about — and, for an indeterminate result,
  name the tract (or state the address did not geocode) as part of the "could
  not be determined" answer.
- State the **eligibility table vintage** (below) so the user knows what the
  answer is current as of.
- Render NaN/None demographic fields as "not available," never as a number.
- Report a `None`/`"unknown"` eligibility verdict as "could not be determined,"
  never as "not eligible." (See the third-state rule.)
- Distinguish the mapper's *tract-eligibility lookup* (authoritative table
  lookup) from the screener's *feasibility score* (a heuristic first pass).
- **OZ status is asymmetric — treat a `No` like the third state.** NMTC
  eligibility and OZ status are independent, so report OZ separately either way.
  An OZ **"Yes" (`is_opportunity_zone is True`) may be reported as fact.** An OZ
  **"No" must NOT be reported as "not an Opportunity Zone"** — report it as
  **"not confirmed as an Opportunity Zone (this package cannot distinguish
  not-designated from a 2010/2020 tract-vintage miss; ~16% of designations are
  unreachable)."** `is_opportunity_zone` is a plain `bool`, so a `False` means
  EITHER not-designated OR a vintage miss: OZs were designated in 2018 on 2010
  tracts, the geocoder now returns 2020 tracts, and the ~16% that
  split/merged/renumbered can never match — a confident `False` for 1,408 of the
  8,764 designated OZs (16.1%). Same posture as the third-state rule — an
  unknowable negative is not a negative. (nmtc-mapper 0.4.1 Known Issues; the fix
  to `Optional[bool]` is slated for 0.5.0. The 8,764-tract OZ load verified this
  session; the 1,408 vintage-miss count is from the 0.4.1 Known Issues.)

## Data dependencies & fragility (must document)

- **Census geocoder** — `geocode_address()` / `check_address()` call
  `geocoding.geo.census.gov`. This host has **no cloud WAF**, so it works from
  cloud/datacenter IPs (unlike the CRA/Cloudflare-blocked hosts elsewhere in the
  portfolio). Verified working this session (geocoded 2400 Grand Concourse to
  tract `36005023702`).
- **CDFI Fund eligibility table** — `load_eligibility_table()` downloads the
  NMTC LIC eligibility workbook from cdfifund.gov and caches it under
  `~/.nmtcmapper/cache/`. **CDFI Fund URLs move**: the Fund relocates these files
  periodically, so a download can fail even though the package is fine. On
  failure the loader now **raises** `EligibilityDownloadError` /
  `EligibilityParseError` (0.3.4+) rather than silently substituting demo data —
  **say the lookup failed and why; never guess eligibility.** (For offline
  demos only, `NMTCMapper.from_sample()` exists and stamps `data_source ==
  "sample"`; its 12 synthetic tracts are NEVER valid for a real answer.)
- **Tract vintage in force (verified this session):** the cached table is
  `NMTC_LIC_Eligibility_2016_2020.xlsb`, **85,395 census tracts**, sourced from
  the CDFI Fund's Aug-2025b Severe/Deep Distress release. Normalized columns
  include `nmtc_eligible`, `distress_level`, `poverty_rate`, `ami_ratio`,
  `unemployment_rate`, `is_non_metro`, `is_high_migration_rural`,
  `is_nmtc_native_area`, `severe_distress`, `deep_distress`. This is a
  2016–2020 ACS-based vintage. Per the CDFI Fund's transition rules this vintage
  became **usable as of Sept 1, 2023** and is **mandatory for QLICIs closing
  on/after Sept 1, 2024** (primary: CDFI Fund, *2016-2020 ACS Data FAQ*, updated
  Feb 1, 2024 — `NMTC_LIC_FAQs_2020_ACS_Sept1_2023_Update_Jan2024.pdf` at
  `cdfifund.gov/system/files/2024-01/`, announced at `cdfifund.gov/news/567`;
  secondary, stating the mandatory date plainly: NMTC Coalition,
  `nmtccoalition.org/2023/09/06/new-nmtc-data`). This package carries **only**
  this vintage — see the vintage-scope rule above before answering for any deal
  whose QLICI closed before Sept 1, 2024. Report the vintage with the answer;
  the CDFI Fund periodically re-bases eligibility, and a deal must be checked
  against the vintage in force at its QLICI close date. 0.4.0 validates this
  structure at load
  (`EligibilitySchemaError` / `EligibilityValueError`) before trusting any row,
  because the loader binds columns positionally.
- **Geocoder vintage is bound to the table (0.4.1).** 0.4.1 pins the Census
  geocoder to the eligibility table's 2020 tract basis (`schema.TRACT_VINTAGE`).
  0.4.0 and earlier geocoded at `Current_Current`, which since the 2022 ACS
  returns COG-based county FIPS for Connecticut while the CDFI Fund table keeps
  legacy county FIPS — so every CT address missed the lookup (883 tracts, 316
  eligible). Fixed in 0.4.1; noted here only as data-source fragility context.

## Failure modes

**Geocoder (0.4.0 splits the old single `None` return into four distinct
outcomes).** `geocode_address` / `check_address` now behave as follows. All
four executed this session against the installed 0.4.0 wheel: the no-match,
disagree, and agree branches ran against the live Census endpoint; the
transport failure was **induced** by pointing the geocoder URL at a closed
local port, which raised `GeocoderTransportError` (`connection/DNS`,
`isinstance NMTCMapperError == True`), message naming the failure kind and the
address.

- **Transport / HTTP-status / decode failure** (403, 5xx, timeout,
  connection/DNS, non-JSON body), after retries are exhausted → **raises
  `GeocoderTransportError`**. The message names the failure kind and the address.
  Report it verbatim and stop.
- **Address matches multiple tracts that disagree** → **raises
  `AmbiguousAddressError`**, naming the candidate tracts; it refuses to silently
  take the first match. Report it and stop — do not pick one.
- **Genuine no-match** (HTTP 200, zero address matches) → **returns `None`**.
  This is the *only* thing `None` means now. It is the third state, not a NO:
  report "address could not be geocoded" / `eligibility_status='geocode-failed'`
  — do not fall back to a ZIP-code or city-level guess.
- **Matches that all agree on the same tract** → proceeds normally, returning
  that tract.

  Both `GeocoderTransportError` and `AmbiguousAddressError` subclass
  `GeocoderError`, which subclasses `NMTCMapperError` (verified by reflection
  this session) — so `except NMTCMapperError` catches every error the package
  raises. Source: `nmtcmapper/exceptions.py`, `nmtcmapper/geocoder/census.py`.

**Tract absent from the table** (`check_tract` on a GEOID not in the ~85k
universe): **not a failure** — it is the third state. Returns
`nmtc_eligible=None`, `distress_level="unknown"`, `tract_found=False`,
`eligibility_status="not-found"`. Report "could not be determined," never
"ineligible." (See the third-state rule and its worked example.)

**CDFI Fund file download fails / 404** (URL moved): raises
`EligibilityDownloadError` / `EligibilityParseError`. Report the error and that
eligibility could not be determined. Do not answer from memory.

**NaN demographic fields** (a real tract with no measurable population, e.g.
`11001980000`): report "not available," never fabricate. This is orthogonal to
the tri-state verdict — the tract is genuinely `False`/verified-ineligible; only
its demographics are null.

**Screener `lic_status` misuse**: passing `"yes"` without confirming LIC status
produces a falsely high score. Confirm first; pass `"unknown"` when the mapper
returned the third state.

## Caveats

- This is an **eligibility and feasibility screening layer**, not an allocation
  award, legal opinion, or the CDFI Fund's determination.
- Eligibility is **tract-specific and vintage-specific**. An "eligible" answer is
  only valid for the table vintage named above.
- An **"unknown" answer is a real answer** — "could not be determined for this
  tract/address," never "not eligible."
- The screener's score and estimated allocation are **first-pass heuristics** to
  triage deals, not underwriting or a commitment.
