Skip to content

feat(ein): emit additive ein_prefixed + EIN2 columns (ADR 0036)#11

Open
Thiyaghessan wants to merge 1 commit into
mainfrom
feat/adr-0036-ein-additive-columns
Open

feat(ein): emit additive ein_prefixed + EIN2 columns (ADR 0036)#11
Thiyaghessan wants to merge 1 commit into
mainfrom
feat/adr-0036-ein-additive-columns

Conversation

@Thiyaghessan

Copy link
Copy Markdown
Collaborator

Sitrep — ADR 0036

  • Implements: ADR 0036 (E1, CORE scope) — additive, coercion-safe EIN renderings on the CORE tiers.
  • Diverged from ADR: none.
  • Needs ADR review: none. (One parity observation flagged below for the N1 backlog — not a contract-shape decision, not blocking.)
  • Contract surfaces touched (for the contracts reconcile):
    • conventions/ein-format.md — the ein_prefixed rendering (ein-XX-XXXXXXX), shared with the BMF order; whichever lands first carries it.
    • The CORE tier contract YAML(s) in nccs-contracts/contracts/ (core-990, core-legacy, core-panel) — gain ein_prefixed + EIN2 columns.
    • Not edited here — these are the reconcile work-list for a nccs-contracts session.

What this does

Emits two purely additive columns on every CORE tier output (processed/core, processed_legacy/core, processed_merged/core), alongside the unchanged canonical dashed ein:

column value role
ein_prefixed ein-XX-XXXXXXX new lowercase, coercion-safe house key (leading alpha forces text typing)
EIN2 EIN-XX-XXXXXXX legacy-compatibility alias (exact legacy name + format)

Both are bijective with ein and NA-preserving. The canonical ein is externally load-bearing (five external surfaces per ADR 0036) and is left untouched — this is additive, not a reformat.

Implementation

  • R/transforms/ein.Rein_to_prefixed() / ein_to_ein2() (twins of nccs-data-bmf/R/ein.R, byte-identical casing + prefixing) + add_ein_renderings().
  • R/03_harmonize.R / R/03_legacy_harmonize.R — add the columns last in apply_transforms, after the blanket financial coercion, so the character columns are never coerced numeric. Covers 990, 990ez, 990pf (SOI) and 990combined, 990pf (legacy).
  • R/04_derive_combined.R — added to COMBINED_UNIVERSAL_COLS so they survive project_to_shared into the SOI 990combined.
  • Merged tier (R/04_legacy_merge.R) — propagate automatically as shared columns; both sides derive them from the merge key ein, so they are always identical → no false disagreement-audit rows. (No code change needed.)
  • R/06_dictionary.R — disambiguating UNIVERSAL_DICTIONARY_ROWS entries stating which EIN to join on (forward → ein/ein_prefixed; legacy merge → EIN2).
  • R/quality/post_checks.R — whitelist both from check_schema extras so they aren't flagged as unexpected columns.
  • Tests — unit coverage for the renderings (incl. NA preservation, casing) and project_to_shared propagation.

N1 parity note (backlog, not for this PR)

The two renderings are kept in exact parity with the BMF order. The upstream canonical ein formatter (transform_ein) has already drifted between the repos and I did not reconcile it (per the brief — consolidation is the N1 backlog item, not a unilateral call):

  • empty string → NA here vs "00-0000000" in BMF;
  • CORE rejects >9-digit input (→ NA); BMF keeps it (warns).

This affects only edge-case handling of malformed/empty EINs in the base ein, not the format/casing of the new columns.

Tests

Rscript tests/run_all.R257 passed, 2 failed. The 2 failures (expected_col_count for 990pf 2022 / 990 2024) are pre-existing — they fail identically on a clean checkout of main (IRS var-matrix counts, unrelated to this change).

🤖 Generated with Claude Code

ADR 0036 (E1, CORE scope) — coercion-safe EIN renderings, purely additive.

Emit two new columns on all CORE tiers (processed/core, processed_legacy/core,
processed_merged/core) alongside the unchanged canonical dashed `ein`:
  ein_prefixed = ein-XX-XXXXXXX  (lowercase house key, provably text)
  EIN2         = EIN-XX-XXXXXXX  (legacy-compat alias)

The canonical `ein` is externally load-bearing and is left untouched; these
are extra columns, not a reformat. Both are bijective with `ein` and NA-
preserving.

N1 (BMF parity): ein_to_prefixed / ein_to_ein2 in R/transforms/ein.R are
twins of nccs-data-bmf/R/ein.R — byte-identical casing and prefixing. The
upstream canonical `ein` formatter (transform_ein) has drifted from BMF's
(empty -> NA here vs "00-0000000" in BMF; CORE rejects >9-digit input);
flagged for the N1 consolidation backlog, not changed here.

Wiring:
- 03_harmonize / 03_legacy_harmonize: add columns last in apply_transforms,
  after financial coercion, so the char columns are never coerced numeric.
- 04_derive_combined: add to COMBINED_UNIVERSAL_COLS so they survive
  project_to_shared into 990combined.
- merged tier: propagate automatically as shared cols (identical both sides;
  derived from the merge key, so no false disagreements).
- 06_dictionary: disambiguating UNIVERSAL_DICTIONARY_ROWS entries (which EIN
  to join on), per ADR 0036.
- quality/post_checks: whitelist the two from check_schema extras.
- tests: unit coverage for renderings + project_to_shared propagation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant