Repository navigation
Description
Stage 4 of the temporal-roles work. Split from the schema change so the two can land separately.
What
One-time rewrite of every published person file from office: {name, division_ocdid} to roles[], across ~3,430 files in 13 states (tx 964, mi 878, nj 496, wa 196, nh 187, ma 172, co 120, tn 113, id 95, sc 92, ca 73, nd 37, nc 7).
Follows the existing pattern in open-data/scripts/one_off/ — see reformat_people_yaml.py and backfill_person_ids.py for prior art on repo-wide YAML rewrites.
Why it is separate from the schema issue
The schema can merge behind a pinned shared (see the dependency-pinning issue) while the data has not moved yet. Bundling them means a single unrevertable step that breaks open-data CI for every file at once.
The hard part is not mechanical
Splitting office.name back into roles uses the same lossy parse we are removing — office_name_to_roles (pipelines/src/utils/people_utils.py:99) keeps only parts present in the alias map and drops the rest. Running the backfill through it would bake today's data loss permanently into history.
So the backfill needs a stricter rule:
- Every part of every
office.namemust map to a role term, or the file is flagged for human review — never silently dropped. - Records with
"Unknown Office"(theperson_to_officialfallback,people_utils.py:148) need an explicit decision. .title()-cased values must be mapped back to canonical display names, not preserved as-is.
The audit issue produces the numbers needed to size this — how many files parse cleanly, how many need judgment.
History for backfilled roles
Backfilled roles have no observation history. Decide what first_seen_at means for them:
- the record's existing
updated_at, or - the jurisdiction's
scraped_at(civicpatch.org/src/database/jurisdictions.py:638-651), or - null, with a marker that history begins at the backfill
Whatever we choose, it should be distinguishable from a genuinely observed first_seen_at.
Verification
Run against test-open-data first — the dev stack already points there (civicpatch.org/docker-compose.yml:16). Confirm validate_jurisdiction.py passes on every file, then a real E2E scrape → PR → merge → od_sync before touching the production repo.
Depends on
Schema change merged, shared pinned, audit complete.
Part of the temporal-roles work — see the tracking issue for ordering.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity