bhcto.com

ANALYSIS_DEFICIT.md

Analysis-phase deficit — Northern Illinois Recovery onboarding

Recorded 2026-07-06. This documents a known, intentional shortcut so it can be repaid later.

What happened

The NIR "analysis phase" (the work that turns raw source data into the 15 content briefs) was produced manually / ad hoc: a one-off script (build_analysis.js) tuned by judgment to NIR's full-continuum Illinois positioning, plus hand-authored briefs. There is no reusable, parameterized system — provider onboardings before this one carried the same debt, and it is documented in the parent addiction.md repo. This run accommodated an urgent need; the intended long-term approach is a programmatic, replicable "semantic basis."

New in this onboarding (worth folding into the eventual system):

  • Net-new harvest lane: NIR's WordPress REST API is deliberately disabled, so a sitemap slow-lane harvester (sitemap_harvest.js, parent repo root) was built: Yoast sitemap → polite HTML fetch → chrome-strip → WP-REST-shaped wp_content/<domain>/<type>.json → the existing wp_to_markdown.js convert. Currently hardcoded to NIR's domain — the systematized version should take {domain} as a parameter and become the standard fallback whenever a site's REST API is unusable.
  • A third strategic-filter variant now exists across the provider analyses (outpatient-only, residential-only, and NIR's full-continuum "zero nothing"). Three data points make the declarative config shape obvious: {ownedThemes[], zeroedThemes[], exemptThemes[]}.

Which steps were manual / ad hoc

StepArtifact(s)How it was doneFragility
Cohort state-joinil_wp_*.txtbuild_analysis.js joins harvested domains → CARF/JC/SAMHSA/NAATP by registrable domain; full-state-name→2-letterJoin keyed on URL/domain match; no NPI/entity key
Blog inventoryil_local_blog_inventory.tsvAggregated from the parent repo's corpus, editorial-class itemsDepends on a heuristic class field
Taxonomy taggingtopic_matrix.json, topic_coverage_matrix.tsvKeyword/regex title classifier over 46 themesNo canonical taxonomy file; single-best-theme cascade over-assigns to the "Understanding/What Is" catch-all (local_items inflated there)
Benchmarkbench_all.jsonPercentiles vs IL + NAATP cohortsFine, but formula lives only in the script
Gap filternir_topic_gaps.*, nir_aligned_opportunities.tsv, nir_continuum_opportunities.tsvFull-continuum filter: nothing zeroed, six owned-core themes exempt from the coverage penaltyFilter is a judgment call encoded as constants in one script
BriefsNIR_tierA_backlog.*, NIR_tierA_content_briefs.mdBacklog from NAATP demand + extracted service map; the 15 briefs hand-authoredHuman authorship; not reproducible

Gap formulas (so they're not lost):

  • gap_ratio = (na_items / local_items) × (Σlocal_items / Σna_items), local_items floored at 1.
  • gap_score = round(gap_ratio × na_items / 8).
  • topic-gaps opportunity = round(na_items × max(0, 1 − 0.25 × own_posts)); owned-core themes exempt.

External data dependencies (not in this repo)

build_analysis.js reads from the parent addiction.md repo (it will not run from a bare NIRC checkout): the source directories (carf_all.json, jc_snapshots/, samhsa_facilities.json, naatp_deep/, provider_urls.json), the harvested corpus (corpus/*.jsonl), and the shared NAATP baseline artifacts (naatp_blog_inventory.tsv, the national topic_matrix.json). The generated outputs are committed here, so the site builds standalone.

Target: a programmatic, replicable "semantic basis"

The scalable version onboards provider N as a config, not a manual pass:

  1. Canonical taxonomy as data — a versioned taxonomy.json (46 themes + signals), ideally a semantic/embedding classifier rather than a keyword cascade.
  2. Parameterized cohort builder — buildCohort({state, providerDomain}) over a shared domain→state resolution layer.
  3. Parameterized gap engine — gapAnalysis({cohort, ownPosts, serviceFilter}) with a declarative serviceFilter rather than hand-edited constants.
  4. Service-map extractor — generalize the harvested-page → service-URL extraction.
  5. Brief scaffolding — generate brief skeletons from the backlog + service map; keep human review for voice/clinical nuance.
  6. Provider-parameterized pipeline — the content pipeline (lib/) is duplicated per provider with 3 hand-edited spots (SERP location, prompt identity, briefs path). Make it a single engine taking a provider profile.
  7. Harvest-lane selection — a single harvest({domain}) that probes REST first and falls back to the sitemap lane automatically.

Until that exists, each new provider repeats this manual pass.