Working paper · Colorado housing data infrastructure · Living document
Instrumenting Housing Need
How a seven-month public data system learned to say “we don’t know,” and why that turns out to be the precondition for building the right housing in the right place.
00 Executive summary
- What this is
- A continuously rebuilt public dataset covering 546 Colorado geographies — 64 counties, 272 incorporated places and 210 census-designated places — free at cohoanalytics.com. Built in seven months across 6,654 commits.
- The central claim
- The system’s contribution is not data volume but epistemology: an enforced discipline separating a measured zero from an unknown. 39 of its 288 test files carry named assertions — 120 of them — whose declared subject is absence.
- Why that matters for money
- A coerced zero does not merely misinform — it misallocates. Every program dollar committed on a false zero is committed to the wrong income band, the wrong tenure, and the wrong timeline.
- What it enables
- Place-level targeting that county data cannot produce. Two towns with near-identical burden rates can need opposite programs; only municipal-scale tenure data reveals which.
- Worked result — Palisade, Mesa County
- 419 households below 80% AMI are cost burdened. Severe burden is an owner problem by 5.1 to one — 113 owners against 22 renters — which a renter-led assessment would miss entirely.
- Shortage versus mismatch
- Cost burden and unit deficit are different measurements licensing different actions. At 31–50% AMI, 96 of 97 renter households are burdened while the unit gap at that band is zero. A construction problem and an allocation problem are different problems.
- The sequencing result
- Ordering by intervention type rather than defaulting to construction reaches 113 households within a year and reserves the slow, expensive instrument for the one band that requires it.
- Where investment would land
- The binding constraint is not analysis but development cost data. The system can size need precisely and cannot cost it at all. See §07.
- What a commissioned build would cost
- 6.1–11.1 person-years, or 12–21 months for a team of 7, over 338,104 hand-written lines and 63 data sources. An analyst estimate, declared as one in §07.
- What it cost in energy
- Built with heavy AI assistance. Measured: 71,384 model turns and 40,000 CI jobs over a partial window. Published per-query energy spans 140×, giving 17–2,399 kWh. No midpoint is offered, and no net benefit is claimed. §09.
01 Emergence
The first commit is dated 2026-02-20. By 2026-09-15 the repository held 6,654 commits — sustained across seven months. The shape of that growth is not the smooth ramp of a planned build.
origin/main. The final month
(2026-09) is partial. The peaks correspond
to build-out of the place-level pipeline and the ownership model; the troughs are
consolidation, not pause.
What the curve conceals is a change in kind. Early months added surface — pages, charts, fetchers. Later months increasingly added constraint: tests, guards, and documented rules about what the system may claim.
| Component | Count | Note |
|---|---|---|
| Geographies | 546 | 64 counties · 272 places · 210 CDPs |
| Places with apportioned CHAS detail | 482 | Tenure × AMI band × cost burden |
| Data files | 1,653 | Tracked JSON, CSV, GeoJSON and Parquet |
| HTML pages | 556 | 62 top-level; 484 generated per place |
| Build & fetch scripts | 258 | Python and Node, run on schedule |
| Workflows | 71 | 59 carry a live cron — also the system’s main liability, §08 |
| Test files | 288 | 39 carry assertions named for absence |
| LIHTC features | 926 | CHFA portfolio, refreshed weekly |
An earlier draft reported 498 test files. That figure was wrong: the
shell glob used to count them matched every *.test.js twice, once under each
pattern. The generator described in §10 now counts a resolved set of paths, which
cannot double-count.
The same draft reported 52 absence-handling test files, from a scan that
looked for the word null anywhere in a file alongside any absence-related
word. That matched files which merely mention a missing key in passing. The count now
requires an assertion’s own name to declare absence as its subject, which
is a claim about intent rather than vocabulary. Both errors were caught by applying this
paper’s argument to the paper itself.
1.2 · What grows without anyone touching it
“Continuously rebuilt” is a claim worth making specific. 59 of the repository’s 71 workflows carry a live cron, on cadences from every thirty minutes to annually. They divide into three kinds, and the distinction matters: one kind brings in new facts, one computes over them, and one watches the other two.
Everything derived is generated, never hand-edited — the jurisdiction digests, the 484 place pages, the ranking index and its scenarios, the homepage snapshot, and the file manifests. A change to any of them is made by changing its generator and re-running it; CI fails a pull request whose generated files drift from what their sources would produce. That is the mechanism by which a one-person project stays internally consistent across 1,653 data files.
The third category — the watchers — exists because the first two run unattended. It is also, as §08 records, the least finished part of the system.
02 What it does well
2.1 · Place-level resolution, not county proxy
Housing policy is made at municipal scale — inclusionary ordinances, zoning, fee waivers, land contribution — while most published housing data is county-level. A county figure is almost never the figure a practitioner needs. Boulder County’s severe renter burden is one number; Louisville and Boulder city sit far apart inside it, and the spread is the product.
The system resolves 482 Colorado
places by apportioning tract-level CHAS data through tract-to-place membership, then
capping the result against the ACS occupied-household count. Every metric carries a
geography_level, so a figure that is really the county’s own says so
rather than masquerading as local.
2.2 · An explicit epistemology of absence
An unmeasurable quantity is
null, never0.A zero and an unknown are indistinguishable once rendered, so nothing downstream can catch the difference.
AGENTS.md, repository root
The rule exists because the same defect recurred five times: a zero-household AMI band; $0 and −$320,000 equity figures; an absent Proposition 123 commitment rendered as non-participation; a flat chart line standing in for a dead data series; and $0 resale price and owner equity shown for 53 of 482 places.
Every other quality depends on it. Place-level resolution is worthless if a place with no data renders as a place with no need. A recommendation built on a coerced zero recommends the wrong program. Marking absence is what makes the output actionable rather than merely available.
2.3 · Verification treated as a first-class artifact
The repository distinguishes green from verified: a passing check list
answers “did the jobs report success,” not “did the work happen.”
The documented tests for a real pass are whether the check actually ran, whether the
passing test asserted anything, whether a cancelled outcome is being misread
as neutral, and whether main is green at that moment.
03 The method in use: Palisade
Palisade, Mesa County (GEOID
0856970):
1,297
households, 433 renter and
864 owner. The town filed its
Proposition 123 commitment on 2024-08-29, so it is eligible for that
funding stream.
| AMI band | Renters | Burdened >30% | Severe >50% |
Owners | Burdened >30% | Severe >50% |
|---|---|---|---|---|---|---|
| ≤30% AMI | 51 | 29 | 17 | 113 | 87 | 56 |
| 31–50% | 97 | 96 | 5 | 132 | 70 | 51 |
| 51–80% | 142 | 103 | 0 | 90 | 34 | 6 |
| 81–100% | 40 | 0 | 0 | 65 | 0 | 0 |
| >100% | 103 | 0 | 0 | 464 | 23 | 8 |
| ≤80% AMI subtotal | 290 | 228 | 22 | 335 | 191 | 113 |
113 owner households below 80% AMI pay more than half their income for housing, against 22 renter households — 5.1 to one. A conventional assessment leading with renter cost burden and rental production would direct the entire program at the smaller population.
At 31–50% AMI, 96 of 97 renter households are cost burdened while the measured unit gap at that band is zero — the units exist and are occupied by households who cannot afford them. At the deepest band the gap is real. Both are true and they describe different problems: a shortage at the bottom, a mismatch above it.
The gap series is computed against household-size-adjusted income limits while the affordability comparison uses area medians. A one-person household at 50% AMI in Mesa County has an income limit of $35,200 (affordable rent ≈ $880), against a median gross rent well above it. “Zero gap at 50%” means zero deficit of units priced at the four-person 50% AMI level, not “no affordability problem at 50% AMI.” The burden column is the better guide to household experience; the gap column to production targets. Either alone produces a wrong program.
3.1 · The resulting program path
Preserve owners already in place
113severely burdened owners ≤80% AMI
Owner-occupied rehabilitation, weatherization, tax relief. No land, no entitlement, no construction financing. The households are already housed; the intervention keeps them housed.
Horizon: months
Income-target existing stock
96burdened renters, 31–50% AMI
The gap at this band is zero, so the units exist. Acquisition with deed restriction, or project-based subsidy on existing buildings, reaches these households without new construction.
Horizon: 6–18 months
Build the deep-tier units
116burdened households ≤30% AMI
The band where units do not exist at any occupancy. Requires the deepest subsidy and longest timeline — competitive credit, Proposition 123, and project-based rental assistance layered.
Horizon: 3–5 years
A strategy beginning with new construction reaches its first household in three to five years. A strategy sequenced by the data reaches 113 households within a year, 96 more within eighteen months, and reserves the slow instrument for the one band that requires it. Same total need, different order, materially different time-to-relief.
04 Generalizing: which jurisdictions are tractable
Of 482 places, 231 have at least 400 households and confident data. Within those, 63 meet a tractability test — acute burden concentration combined with an absolute target a single program could plausibly close. These are the jurisdictions where “eliminate the need” is a coherent sentence rather than a slogan.
| Place | Households | Burdened ≤80% AMI | Share | Renter / owner | Program implication |
|---|---|---|---|---|---|
| Air Force Academy | 657 | 266 | 40.5% | 266 / 0 | renter only |
| Rocky Ford | 1,369 | 532 | 38.8% | 249 / 283 | even split |
| Dolores | 511 | 185 | 36.2% | 159 / 26 | renter-dominant |
| Cripple Creek | 591 | 206 | 34.9% | 123 / 83 | both tenures |
| Snowmass Village | 1,758 | 595 | 33.9% | 344 / 251 | both tenures |
| Georgetown | 596 | 199 | 33.3% | 99 / 100 | even split |
| Mountain Village | 1,562 | 520 | 33.3% | 455 / 66 | renter-dominant |
| Pagosa Springs | 775 | 250 | 32.3% | 171 / 79 | renter-dominant |
| Winter Park | 477 | 154 | 32.2% | 81 / 73 | even split |
The renter/owner column is the operationally important one, and it is the column county-level analysis cannot produce. Two towns can share a burden share to within a tenth of a point and have opposite tenure profiles. They need different programs. A regional analysis would assign them the same one.
05 Policy decisions, and why
These are choices about what the system is for. They are not derived from the data; they shape what the data is permitted to say.
5.1 · Free, public, no account
The audience — municipal staff in towns of 500 to 5,000 households — is precisely the audience that cannot commission a consultant study or buy a data subscription. The marginal town in Table 3 does not have a housing department. A paywall would exclude exactly the jurisdictions where the tractability screen says the need is most closeable.
5.2 · The place, not the county, is the unit of analysis
This is a policy choice before it is a technical one. Regional analysis is cheaper, more statistically stable, and matches how most housing data is published. It is also unusable for the instruments that actually get built: an inclusionary ordinance, a fee waiver, a land donation, and a deed restriction are all municipal acts. Choosing the place as the unit accepts wider error bars in exchange for matching the scale at which decisions happen.
5.3 · Publishing absence rather than suppressing it
A system may handle a missing value three ways: omit the row, substitute a default, or publish the absence. Omission makes a place look uncovered; substitution is the coerced-zero failure; publishing absence is noisier and less impressive and is the only one that leaves the reader correctly informed. Four sources are currently displayed as stale on the dashboard rather than having their age limits quietly raised to silence them.
5.4 · Burden and gap kept as separate policy instruments
Most assessments report a single “units needed” figure. This system reports cost burden and unit gap separately because they license different actions — burden licenses preservation and subsidy, gap licenses production. The Finding 2 result is only derivable because the two were not merged.
5.5 · Preservation ordered before production
Where the data supports both, the sequencing in §03.1 places preservation first. The justification is time-to-relief rather than cost: a household severely burdened today is at risk this year, and the fastest unit to secure is one that already exists and is already occupied by the household that needs it. This ordering is a judgment, and a jurisdiction prioritising long-run stock growth over near-term stability could defensibly reverse it.
5.6 · Declining a paid data subscription
Commercial parcel data was evaluated and deferred: the cost could not be justified at current use. The consequence is recorded rather than hidden — parcel coverage is marked inactive, and the integration is left wired so it resumes if the decision changes. §07 revisits this as the clearest case where modest money would buy a capability the system cannot otherwise have.
06 Mathematical decisions, and why
Every decision below had a simpler alternative, rejected for a stated reason.
6.1 · Area-weighted apportionment over county inheritance
HUD CHAS — the only public source crossing cost burden with AMI band and tenure — publishes at tract level, and municipal boundaries do not follow tracts. The rejected alternative assigns each place its primary county’s rates; the repository documents why it fails: a parcel in Erie would see Weld County rates though half of Erie’s tracts sit in Boulder County. The error is systematic and largest exactly where towns straddle county lines.
The method: for each tract T overlapping place P the weight is
max(area_share, population_share), and each CHAS count
is multiplied by that weight and summed. (Area share alone collapsed small towns embedded
in large rural tracts; the file header still documents the superseded rule.)
The assumption is uniform household distribution within a tract — poor for slivers
under roughly 10% of tract area, which are flagged rather than silently included.
6.2 · The ACS occupied-household cap
Area weighting is geometrically sound and demographically optimistic: summed across overlapping tracts it overcounts households in roughly 31% of Colorado places, because population clusters in the built-up portion rather than spreading across tract area. The correction anchors each place’s total to the ACS occupied-unit count and scales the tiers to fit.
The property that matters: rates are preserved, only levels change. A cost-burden percentage — the number a policy is written against — survives the correction, while the household count becomes defensible against an independent source. The ordering is load-bearing: summary caches must regenerate before the CHAS build, or the cap silently no-ops.
6.3 · A PITI model rather than the 3× income rule
The conventional price = income × 3 heuristic is rejected because it ignores interest rates — where rate movement alone shifts affordability 20–40% — ignores property taxes and insurance, worth roughly $500–$1,500 per month in Colorado, ignores mortgage insurance, and substitutes a single multiple for the debt-to-income threshold lenders underwrite to.
The model is not one model. The registry defines
7 of them —
conservative screening, first-time buyer, conventional lender DTI, FHA, USDA, a
Proposition 123 eligibility gate, and a fully custom one — differing in ratio
convention, down payment, mortgage insurance and its loan-to-value gate. The default is
conservative_screening, which screens
at a 30% front-end ratio. A 43% back-end DTI is one of the others, and it answers a
different question: what a lender will approve, rather than what a household can carry
without being cost burdened. On the documented Denver illustration the heuristic and a
PITI model agree on the affordable price and disagree entirely on the gap — roughly
117% over affordable against roughly 206% — so a town using the heuristic would size
its subsidy at about half what a buyer needs. Which PITI model it uses changes the answer
again. The full specification, with every parameter read out of the registry, is in the
computational methods companion.
An earlier version of this section described a single model at “20% down, 6.5%,
0.65% tax, 0.85% insurance, 43% back-end DTI.” That is a recognisable description of
conventional_dti — one of the seven, and not the default. Writing out
the methods companion is what found it.
43% back-end DTI is the lender’s maximum, not the affordability standard. HUD calls a household cost burdened above 30% of income. A model solving at 43% answers “what will a bank approve,” which is a larger number than “what can this household carry without being cost burdened.” Both are legitimate questions and they are not the same question; a subsidy sized to the first leaves the buyer burdened on the day they move in.
6.4 · Absence handled before coercion, not after
The numeric core of the epistemology is one line of language semantics:
Number(null) === 0, and 0 is finite. A coercion two layers
upstream therefore produces a value passing every downstream
Number.isFinite() check. Three consequences are enforced: do not coerce a
possibly-null value that feeds arithmetic or a renderer; guard <= 0 rather
than < 0 wherever zero is not meaningful, since a price or rent of exactly
zero means unknown rather than free; and carry the reason with the data. Fixing
the renderer is insufficient — a renderer that formats null correctly
never sees the null if the coercion happened upstream.
6.5 · Published shares derived from published counts
Rates were originally computed from unrounded accumulators while counts were rounded
separately for display. Several shares land on exact .00005 ties, where a
one-ulp difference in the denominator flips the fourth decimal — producing files
that differed between machines and a freshness checker reporting five places as stale
whose inputs had not changed in months. Deriving each share from the published
counts makes the computation reproducible and, as a side effect, internally consistent: a
reader dividing the published count by the published total now obtains the published
share, which was previously not true.
6.6 · The tractability screen is analyst-constructed
The screen in §04 — burden share ≥ 20%, target ≤ 600 households, on places of ≥ 400 households with confident data — was constructed for this paper. It is not a published standard and carries no validation beyond face plausibility. The thresholds encode a judgment that one municipal program can address several hundred households but not several thousand. They live in the generator as named constants so a reader can change them and re-run rather than having to trust them. These cut points are the weakest part of this paper and are stated so a reader can reject them without rejecting the approach.
07 What a little real investment would buy
The system is labour-rich and capital-poor. Its limits are not analytical — they are four specific missing inputs, each of which costs less than a single consultant housing needs assessment.
The system can size need to the household and cannot cost it at all. That is why §03.1 sequences three tracks and attaches no budget: the repository holds no validated Colorado cost-per-unit figures for new construction, acquisition-rehabilitation, or owner-occupied repair, and inventing them would violate the discipline the whole system is built on.
This is the single highest-return investment available. The data largely exists — in CHFA’s credit allocations, in DOLA’s Proposition 123 awards, in completed project cost certifications. It needs assembling into a published series by intervention type and region, not inventing. With it, every jurisdiction in Table 3 gets a costed strategy instead of an ordered one.
Priority 2 · A preservation pipeline that refreshes
The National Housing Preservation Database extract has had no refresher since it was loaded — it is stale and displayed as such. This matters more than its size suggests: preservation is the fastest track in every sequencing above, and expiring affordability restrictions are time-bound in a way that need estimates are not. A unit lost to expiry costs far more to replace than to preserve. This is engineering time, not subscription cost.
Priority 3 · Parcel and zoning coverage
Commercial parcel data was deferred on cost. The capability it would unlock is specific: moving from “this town needs deep-tier units” to “here are the parcels where they could go, with their zoning, ownership and size.” Need analysis identifies the target; parcel data is what converts a target into a site. This is a genuine annual subscription cost and the clearest case where modest money buys a capability that cannot be substituted with effort.
Priority 4 · Roughly two weeks of engineering
59 scheduled workflows now run with no map of themselves, alerting that covers failures but not silence, and at least one quality gate that runs only after merge. On 2026-09-14 the public site stopped deploying for thirty-two hours and three separate monitoring mechanisms each failed to report it. None of this is hard; it is unglamorous consolidation work that no volunteer evening prioritises over a new feature, and it is currently the largest tax on the maintainer’s attention.
What replacing this would cost
A funder deciding whether to support an existing system is really asking what it would cost to commission one. The scope is measurable: 338,104 hand-written lines — excluding 226,824 generated lines of place pages — 62 pages of which 25 are substantial interactive tools, and 63 declared data sources feeding 59 scheduled pipelines.
Decomposed by workstream and summed, that comes to 6.1–11.1 person-years, or 12–21 months of calendar time for a team of 7 after allowing 12% for coordination and 25% for the fact that a team of seven is not seven times one person.
The scope above is measured; the person-weeks are a judgment, with no validation beyond face plausibility, and they live in the generator as named constants so a reader can change them and re-run rather than having to trust them.
More important is what the figure does not say. It is what a commissioned team would plausibly bill to build this from a specification. It is not a claim that 6.1–11.1 person-years of human effort were expended here. A commissioned build carries requirements negotiation, review cycles, sign-off and status reporting that a single maintainer does not, and the domain expertise that a team would spend two to four months acquiring was already resident. Treating the two as equivalent would be precisely the unsupported claim this paper spends nine sections arguing against.
One cross-check is worth recording because it initially looked like a contradiction. A line-count sanity test against defence-software productivity benchmarks implies roughly twenty-six person-years — two to four times the workstream estimate. The discrepancy is an artefact of the benchmark, not of the estimate: only 39% of the page markup is distinct rather than shared boilerplate, and modern web and data work sustains line rates several times those benchmarks assume. Adjusted for both, the two methods agree.
After front-end and data engineering, the largest workstream is quality assurance — and it produces nothing a demonstration would show. 39 of the 288 test files exist only to stop the system asserting things it cannot know. That is exactly the line a fixed-price bid removes, and exactly the line this system's argument rests on. A commissioned build of this site would very likely ship sooner, look more consistent, and be better documented — and publish coerced zeros, because nothing in a statement of work asks for the discipline that prevents them.
Priorities 1–4 are stated as capabilities and rough magnitude classes rather than budgets. Quoting costs for a cost-data-assembly project, a commercial subscription, or contract engineering without sourcing them would reproduce precisely the error this paper documents. A funder should expect to size these with the vendors and agencies involved; the argument here is about ordering and return, not price.
08 Limits, honestly stated
A paper describing a system built around admitting what it does not know owes the same treatment to itself.
The automation has outgrown its operator
59 scheduled workflows run against this repository, and the system offers no map of itself. Failures are discovered by inspection rather than notification. This is the limit most likely to end the project — not through technical failure but through maintainer exhaustion.
Gates that do not run where decisions are made
The deploy artifact guard runs on push, never on pull_request;
the inventory check sits outside the main suite. A pull request can be genuinely green and
still break production. The gates are correct; their placement is not.
Alerting covers failure, not silence
Failure and recovery notifications work. A job killed by its own timeout (recorded as
cancelled, rendered grey rather than red) and a scheduled job that quietly
stops firing remain uncovered. One instance went fifteen days undetected and was found by
hand. As of 2026-09-15 the staleness sweep is explicitly disabled rather than running as a
green placeholder that checks nothing.
Uneven data vintage across sources
ACS figures are 2020–2024 five-year estimates; home values are Zillow ZHVI; income
limits are HUD FY2026. Each metric carries its own as_of, which is the right
design, but a reader comparing two metrics is comparing two vintages and the interface
does not always make that prominent.
Single-state, and single-maintainer
Everything here is Colorado. The methods generalise; the data wiring does not, and no second state has been attempted. The bus factor is one.
09 What this cost to build
This repository was built with substantial AI assistance over roughly nine months. That is a material fact about how the work was produced, it carries an energy cost, and a paper arguing that systems should publish what they would rather omit cannot omit it.
Two things are measurable. Continuous integration has run 40,000 workflow jobs, about 1,509 runner-hours of hosted compute. Model inference across the surviving session transcripts comes to 71,384 turns generating 68,149,998 output tokens.
Session transcripts rotate. The surviving window runs 2026-06-05 to 2026-09-15 — roughly a third of the project. Everything below counts only that window, and the earlier and heavier build-out months are simply gone. The honest reading is “at least this much,” and the true figure is materially larger.
Turning turns into kilowatt-hours is where the accounting stops being measurement. The published per-query energy figures span 140×, from 0.24 Wh for a short prompt on optimised serving to 33.6 Wh for a reasoning model on a long one. Agentic coding turns carry longer context than the high-end benchmark, so neither end is a bound so much as a signpost.
| Assumption | Per query | Energy | CO2e |
|---|---|---|---|
| Short prompt, optimised serving | 0.24 Wh | 17 kWh | 7 kg |
| Reasoning model, long prompt | 33.6 Wh | 2,399 kWh | 936 kg |
The obvious move is to split the difference and publish one number. That number would be the most-cited figure in this paper and the least defensible thing in it — a precision manufactured by averaging away a disagreement in the literature. It is the same move as filling an unmeasured cell with a zero, and this system exists because that move is wrong. The range is the finding. At the high end the surviving window alone approaches a tonne of CO2e; at the low end it is a rounding error. Both readings are currently supportable, which is itself worth knowing.
What is not claimed here is a net benefit. It would be easy and self-serving to set this against the travel and staff time of the consultant studies the system substitutes for, and declare the trade favourable. That comparison has not been measured, the counterfactual is unknown, and asserting it would be exactly the unsupported claim this paper spends nine sections arguing against. The cost is stated because it was incurred, not because it has been justified.
The narrower point stands on its own: scripts/paper/measure-compute-footprint.mjs
computes these figures the same way every other figure here is computed, and they update
with the rest. A project that discloses its compute cost once, in a launch post, has
disclosed a historical curiosity. One that recomputes it has disclosed a number.
10 How to use it
- Read the tenure split before anything else. It determines which half of the toolkit applies, and it is the finding most often lost in county-level work.
- Separate the shortage from the mismatch. Compare unit gap by band against burden counts by band. Where the gap is zero and burden is high, the units exist — acquisition and income targeting beat construction on both cost and time.
- Find the severe-burden concentration. Households above 50% of income are at risk this year, and preserving an occupied unit is consistently faster than producing a new one.
- Check the funding gate before designing the program. Proposition 123 eligibility turns on a filed commitment; 217 jurisdictions’ filings are tracked, so this is a lookup rather than a phone call.
- Treat any “0” with suspicion and look for a stated reason. Where the system says “not published,” that is information about the source, not about the place.
A housing data system earns its keep not by how much it publishes but by how reliably it refuses to publish what it cannot support — because every program dollar committed on a coerced zero is committed to the wrong band, in the wrong tenure, on the wrong timeline.
11 Provenance, and how this paper stays current
Every figure in this paper is written by
scripts/paper/build-paper-figures.mjs and injected by
scripts/paper/inject-paper-figures.mjs. None is typed. Re-running them
refreshes the paper against whatever the repository then says, and
test/paper-figures-fresh.test.js fails continuous integration if this page
and the data ever disagree — so the paper cannot silently go stale while the site
beneath it moves.
A figure the generator cannot read is emitted as null with a stated reason
and rendered here as that reason, never as 0 — the same rule the system
applies to itself. That generator is what caught both corrections recorded in §01.
Authorship and standing. COHO Analytics is the sole product of pggLLC, built and maintained by one person. It has no institutional funding, no research grant, and no staff. That is relevant to reading this paper in two directions: it explains the limits catalogued in §08, and it is the reason the investment argument in §07 is framed around four specific inputs rather than a programme — the labour is already being supplied.
- Household and cost-burden detail —
data/hna/place-chas.json, from HUD CHAS tract data apportioned to places and capped at the ACS occupied-household count. - Geography coverage —
data/hna/geography-registry.json. - Income, rent, vacancy, AMI gap — ACS 2020–2024 five-year estimates.
- Median home value — Zillow ZHVI city index.
- Income limits and Fair Market Rents — HUD FY2026. Mesa County four-person AMI $100,600; 30% $30,200; 50% $50,300; 60% $60,350; 80% $80,500.
- Proposition 123 commitments — 217 jurisdictions from CDOLA commitment filings. Town of Palisade filed 2024-08-29; Mesa County 2023-08-07.
- LIHTC portfolio —
data/chfa-lihtc.json, CHFA, refreshed weekly. - Compute footprint —
data/paper/compute-footprint.json, written byscripts/paper/measure-compute-footprint.mjs; CI counts from the GitHub Actions API, inference counts from local session transcripts (partial window, stated in §09). Per-query energy from Jegham et al., How Hungry is AI? (arXiv:2505.09598) and Google's reported Gemini median; grid intensity from EPA eGRID; household comparison from US EIA. - Repository statistics — git history of
origin/main, counted at build time.
Figures reflect the repository at commit
0e3579672. The underlying data refreshes
continuously; a reader reproducing these tables later should expect vintage drift and is
encouraged to check each metric’s own as_of field rather than this
page’s date.