Skip to content

Workstream A: label-verified SIPP job-level monthly reader (EJB job records) + C1-preview spell collapse #200

Description

@daphnehanse11

Part of #192, Workstream A week-1 deliverable ("SIPP job-level reader in data/ — label-verified, family.py pattern"). Third reader after #193/#194 (ASEC NOEMP) and #198/#199 (January tenure supplement).

What

A label-verified reader for the SIPP 2014-redesign public-use files' job-level monthly records — the primary label panel that trains and scores job-spell transitions (plan architecture; SIPP holdouts referee gates E4/E5/E6/E8/E9) — plus a spell-collapse helper that emits a C1-preview frame (explicitly not the frozen C1: ADR 0003 is still Proposed on #195).

Verified facts (Census SIPP variable API + published input examples, read 2026-07-14)

  • The pu files are pipe-delimited CSVs, and Census's own 2023_sipp_python_input_example.py instructs reading with usecols (the full file does not fit in memory). One row per person-month (SSUID × PNUM × MONTHCODE), with up to seven job slots per row (EJB1_*EJB7_*).
  • Per-job variables, all verified via api.census.gov/data/{2022,2023}/sipp/variables/*.json with identical labels in both years:
    • EJB{n}_JOBID — "Unique identifier for a job which is consistent across waves" (−999 missing) — the within-panel employer-attachment key the whole phase-1 hazard story rests on;
    • EJB{n}_BMONTH / EJB{n}_EMONTH — beginning/ending month of the job spell with employer n;
    • EJB{n}_CLWRK — class of worker (1 federal / 2 active-duty military / 3 state / 4 local / 5 private for-profit / 6 private nonprofit / 7–8 self-employed inc/uninc; −9 missing);
    • EJB{n}_JBORSE — employer vs self-employed vs other work arrangement;
    • EJB{n}_EMPSIZEestablishment size at the worker's location (the C2 proxy-chain input, per the Employer–firm relationships: US-first plan, evaluation gates, and two-workstream split #192 finding and ADR 0003; codes 1–8, verified on Employer-firm Workstream B: canonical banding (C2), ADR 0003, target pipeline (#192) #195);
    • TJB{n}_IND / TJB{n}_OCC — industry/occupation codes (string-typed in the API schema);
    • TJB{n}_MSUM — monthly earnings from job n (−999 missing).
  • Person-month variables: SSUID (string — a scrambled PSU/sequence/frame composite; the PERIDNUM/HRHHID dtype lesson applies), PNUM, MONTHCODE (reference month 1–12), SWAVE, WPFINWGT (final person weight, is-weight: true), TAGE, ESEX.
  • The API base exists for 2022+ only; 2021-and-earlier files (and the 2014 panel's wave files) are documented extensions requiring their own dictionary verification, same posture as the other two readers.

Scope

  • data/sipp_jobs.py:
    • read_sipp_job_months(year, ...) for 2022 and 2023: staged pu{year}.csv[.gz] under ~/PolicyEngine/sipp-data (env POPULACE_DYNAMICS_SIPP_DIR), pipe-delimiter enforced, usecols restricted to the verified set, SSUID as string. Emits one row per person-month-job (job slots with non-missing JOBID): person id (SSUID-PNUM), reference year/month, wave, job slot, job id, class of worker (raw + label), work arrangement, establishment-size code, industry, monthly earnings, within-month earnings_share and top-earner flag, age, sex, weight.
    • Read-time verification: required columns per detected job slot, domains for every coded variable (MONTHCODE 1–12, CLWRK/JBORSE/EMPSIZE code sets, BMONTH/EMONTH in {−9} ∪ 1–12, JOBID positive or −999, MSUM ≥ 0 or −999, weight ≥ 0), loud refusal otherwise; path/year consistency for pu{yy} filenames; unsupported years refused.
    • job_spells(job_months): collapse maximal consecutive-month runs per (person, job id) into spells — start/end (year, month), months observed, total/mean earnings, majority-of-months primary flag, spell-constant attribute checks (class of worker / industry / size within a spell surfaced, not silently averaged). Output shape mirrors C1 (person_id, spell bounds, industry, size-code, earnings_share, primary_job) and is labeled C1-preview: it also gives Workstream B a real generator for C1-conforming fixture files.
  • Tests: fixture-based (small pipe-delimited files), every refusal path, spell-collapse geometry (gaps split spells; concurrent jobs share earnings correctly), and a skipif-gated real-data pass.

Non-goals

  • No transition hazards, no imputation, no seam-bias handling (phase-1 work with its own pre-registration), no cross-wave linkage yet (JOBID makes it possible later; single-file first), no 2014-panel/2021-and-earlier support, no frozen C1 emission, no committed microdata.

Acceptance

  • Fixture round-trips: person with two concurrent jobs → correct shares and primary flags; a mid-year gap in the same JOBID → two spells; attribute change within a JOBID run → surfaced.
  • Every domain/universe violation raises with the year and column named.
  • Module docstring records the API-verification provenance per supported year.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions