# External check of the place categories (second recheck, items M3 and S7)

Written 2026-10-29 at about 03:55 GMT-3, before any classification was run.
The script that carries out this plan is `11_external_check.py`.

## What had been seen when this plan was written

- The lab code: `common.py`, `03_build.py` (the text rules), `09_classifier_check.py`,
  the panel part of `06_diagnostics.py`, and `EXPERIMENT.md`.
- Items M3 and S7 of the second recheck.
- The headers, data dictionaries and row counts of the registers below, and the
  column names of the TSE polling-place files.

## What had not been seen, and stays unseen until step 6

- `handcheck/*`, every `results/m5_*` file, and every value of the lab's place flag
  columns (`is_indigenous`, `ind_*`, `is_quilombola`, `is_rural`, `is_river`,
  `place_category` and the `*_v1` columns).
- The script reads `is_indigenous` once, inside the sample draw. That function returns
  place keys only. The flag of a drawn place is known by construction (sample A is
  flagged, sample B is not) and nothing else about the lab's labels is read.
- The lab's labels for the 110 zero sections are read only in step 6. Before that step,
  the script writes this check's own labels and logs their SHA-256.

## Outside registers

Every file is stored under the registers folder (`ZV_REGISTERS_DIR`). The script
checks each SHA-256 before use.

| Register | Publisher | URL | Retrieved (UTC) | SHA-256 |
|---|---|---|---|---|
| Indigenous localities, 2022 Census (LI), points | IBGE | https://geoftp.ibge.gov.br/organizacao_do_territorio/estrutura_territorial/localidades/localidades_indigenas_2022/Arquivos_vetoriais/LI/csv/BR/BR_LIs_CD2022_20250919.csv | 2026-10-29 06:43 | e41ddeb9274b50743a0dd4807e3f1b5fc8b162486bfb9bf9dc1597960dbee411 |
| Places of concentration of indigenous people, 2022 Census (LCPI), points | IBGE | same folder, `LCPI/csv/BR/BR_LCPIs_CD2022_20250919.csv` | 2026-10-29 06:43 | dd16fb8d544acc866fa9de99d8c062c8844218bab98a89e3bde902b2e9fa53a4 |
| Quilombola localities, 2022 Census (LQ), points | IBGE | https://geoftp.ibge.gov.br/organizacao_do_territorio/estrutura_territorial/localidades/localidades_quilombolas_2022/Arquivos_vetoriais/csv/BR/BR_LQs_CD2022.csv | 2026-10-29 06:43 | daa2e0a20e6371f69575ecf8212a4bb722270e13b88de77e2f8a3cd3d8d2470a |
| Census sectors 2022, polygons, with urban or rural situation and sector type | IBGE | https://geoftp.ibge.gov.br/organizacao_do_territorio/malhas_territoriais/malhas_de_setores_censitarios__divisoes_intramunicipais/censo_2022/setores/gpkg/BR/BR_setores_CD2022.gpkg | 2026-10-29 06:45 | 7709750446c5fa2333afa460256c2b0dc0b73bcc3f5226b9650300d02f1db265 |
| Indigenous lands, polygons (`tis_poligonais`) | FUNAI | https://geoserver.funai.gov.br/geoserver/Funai/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=Funai%3Atis_poligonais&maxFeatures=10000&outputFormat=SHAPE-ZIP | 2026-10-29 06:44 | 7faa621d4922c54bd4888b584feb2a141619fa456c53c57c3f5eeebfbb904eb3 |
| Indigenous villages, points (`aldeias_pontos`), supplementary only | FUNAI | same service, `typeName=Funai%3Aaldeias_pontos&outputFormat=SHAPE-ZIP&maxFeatures=10000` | 2026-10-29 06:45 | db389ab9469b9d94812a5df79c77c2e02a32cc99d0a6f00735376388c5cbaab6 |
| Quilombola territories, polygons | INCRA | https://certificacao.incra.gov.br/csv_shp/zip/%C3%81reas%20de%20Quilombolas.zip | 2026-10-29 06:45 | 0f69385abbee16bd405ee5c3b7d515218ebbf84354a1acae6576cf0a8321432e |

Notes on the registers.

- The FUNAI links are the ones listed on
  https://www.gov.br/funai/pt-br/atuacao/terras-indigenas/geoprocessamento-e-mapas
  (page fetched 2026-10-29 06:45 UTC). The FUNAI server sends an incomplete TLS chain.
  The download was verified against the issuer certificate published by Sectigo
  (http://crt.sectigo.com/SectigoPublicServerAuthenticationCAOVR36.crt, SHA-256
  fingerprint 65:42:D1:76:...:85:30). The server refuses the default curl client
  (HTTP 403) and serves the same link to a browser client. The layer's own date field
  shows updates up to 2023 and later.
- The INCRA file is regenerated by the server. The copy used has HTTP Last-Modified
  2026-10-29 02:36 GMT.
- Licence. None of the download pages states a licence. Federal open data in Brazil
  falls under the open data policy (Decreto 8.777/2016), and IBGE asks that it be
  cited as the source. This is an inference, not a statement found on the pages. The
  lab cites the files and does not redistribute them.
- Sector type codes, read from the IBGE dictionary
  (`Dicionario_de_dados_malha_agregados.xlsx`, SHA-256
  0dffb669ee90e1ffb86a7c8666cc066d5121d44b494013cc1149e50cc75073b1): 5 is "indigenous
  grouping", 6 is "prison unit", 9 is "quilombola grouping". Situation codes 1 to 3 are
  urban, 5 to 8 are rural, 9 is water.
- All layers are in SIRGAS 2000 geographic coordinates. TSE coordinates are taken as
  WGS 84. The two differ by less than one metre in Brazil, which is ignored.

## Polling places and coordinates

- Unit: one polling place = (state, municipality, zone, place number), as in `common.PLACE`.
- Source: the TSE polling-place file of the year (`eleitorado_local_votacao_<year>.zip`),
  read straight from the raw folder. Round 2 rows, main sections. Coordinates
  `NR_LATITUDE`, `NR_LONGITUDE`, with a comma or a dot as decimal separator.
- A coordinate is **unusable** if any of these holds:
  1. missing, not a number, or equal to 0 or -1,
  2. outside the box latitude -34 to 5.5, longitude -74.5 to -28.5,
  3. more than 5 km outside its own municipality polygon (IBGE simplified mesh, already
     in the lab's raw folder, TSE to IBGE codes from `municipio_tse_ibge.zip`),
  4. a **shared default**: the same coordinate (rounded to 5 decimals) is used by 3 or
     more places with different names in the same municipality.
- Each reason is counted separately and reported. A sensitivity run keeps the shared
  defaults (rule 4) as usable.
- Places with an unusable coordinate get no register category. They are "unresolved".

## Register signals per place

All distances are great-circle distances.

- **IND** (indigenous register signal, primary): the place is inside a FUNAI indigenous
  land polygon (any stage), or inside a 2022 census sector of type 5 (indigenous
  grouping), or within 1 km of an IBGE indigenous locality (LI).
- **IND5**: the same with 5 km instead of 1 km.
- Components are kept: inside TI, in sector type 5, nearest LI distance, nearest FUNAI
  village distance, nearest LCPI distance. FUNAI villages and LCPI are reported, not used
  in IND.
- **QUI** (quilombola register signal): inside an INCRA quilombola territory, or inside
  a sector of type 9, or within 1 km of an IBGE quilombola locality (LQ). QUI5 with 5 km.
- **PRI** (prison register signal): the TSE official place type names custody (the type
  "Preso provisório" or any type naming adolescents in custody), or the place is inside a
  sector of type 6.
- **Situation**: the census sector that contains the point. Urban (codes 1 to 3) or rural
  (codes 5 to 8, and 9, water). A point in no sector is unresolved.

## Categories, defined before classification

Exclusive, applied in this order.

1. **prison or detention**: PRI.
2. **indigenous village or community**: IND, and the sector is rural or is of type 5.
3. **urban indigenous school (in a town)**: the sector is urban and not of type 5, and
   either IND holds or the place name has an indigenous word (INDIGEN..., ALDEIA followed
   by a name) together with a school word. The basis records which. This is the only
   category where text enters the register rule, and text never moves a place out of
   "urban".
4. **quilombola community**: QUI, and the sector is rural or is of type 9.
5. **other rural or riverside**: the sector is rural.
6. **urban**: the sector is urban.
7. **unresolved**: no usable coordinate, or the point is in no sector.

For the 110 zero sections only, an unresolved place gets a text fallback label, marked
"text only, no usable coordinate", with lower confidence. A label whose basis is text is
never counted as register agreement.

## Steps

1. Load and hash-check the registers. Build per-place signals for 2026 and 2022.
2. Report coordinate coverage: places, sections and voters with a usable coordinate, and
   counts per unusable reason, for all places and for the zero-section places.
3. **The 110 zero sections.** Zero for a side = that side has 0 votes in a round-2 2026
   section with n >= 1 (the lab's definition). Computed here from votes, not read from the
   lab's lists. Each section gets the category of its place and a basis: which signals
   fired, distances, sector situation and type, and any text used. Labels are written to
   the private folder and their SHA-256 is printed before step 6.
4. **Samples, place level, seed 20261029 (numpy `default_rng`).**
   - Universe: 2026 polling places with at least one round-2 section with n >= 1.
   - Text flag of a place (T): any of its sections has the lab's `is_indigenous`.
   - Frame municipalities: those whose IBGE polygon intersects a FUNAI land, or that hold
     an IBGE indigenous locality.
   - Sample A: 200 places drawn from places with T.
   - Sample B: 200 places drawn from places without T in frame municipalities.
   - Each sampled place is classified by the register rule only (IND, and the category).
5. **Agreement of the text rule with the registers.**
   - Precision = share of sample A with IND. Wilson 95% interval on 200 places.
     Also the share of sample A that is "indigenous village or community", and the share
     that is urban.
   - Miss rate = share of sample B with IND. Wilson on places.
   - Recall in the frame = N_A p_A / (N_A p_A + N_B p_B), with N_A the flagged places in
     the frame and N_B the unflagged places in the frame. Interval by 20,000 draws from the
     Jeffreys Beta posteriors of p_A and p_B.
   - Cohen's kappa from the 2x2 table estimated for the frame (strata weighted by N_A and
     N_B), with the same draws for its interval.
   - Sensitivity: a municipality cluster bootstrap (2,000 resamples) of the sample shares.
   - Census check: because the register rule is automatic, the same quantities are also
     computed on every place, with no sampling error, at 1 km and 5 km. Places with an
     unusable coordinate are left out and counted. Neither the text rule nor the register
     rule is ground truth. Agreement is between two instruments.
6. **Comparison with the lab's labels**, only after step 3 is written. The lab's
   categories for the 110 sections are mapped to the categories above. Report the
   agreement table, and list every disagreement with both bases (private file, because it
   names places).
7. **Panel with the register definition.** The lab's panel matches places across 2022 and
   2026 by state, municipality and normalised place name (the lab's `norm`), and keeps
   places flagged in both years. Here the flag is replaced by "indigenous village or
   community" by the register rule, using each year's own TSE coordinates. Zero rates per
   section (n >= 1) for each side and year. IND alone is a sensitivity row.

## Privacy

- Published files in `results/m5b_*` hold counts, shares and intervals only. No section
  key, place name, address or coordinate.
- Row-level files (the 110 labels, the samples, the disagreement list) go to
  `<data>/private/external_check/`. That subfolder is not removed by `run_all.sh`, which
  deletes only `private/*.csv`.
- Any published cell with fewer than 10 sections that could single out a community is
  shown as a count only in aggregate tables, never with a name.

## What this check cannot do

- The registers are of 2022 (census) and 2023 to 2026 (FUNAI, INCRA). A polling place
  can be in a village that the census missed, or a register point can be off by more
  than 1 km. That is why 5 km is reported too.
- TSE coordinates are entered by the electoral offices. A wrong coordinate cannot be
  detected unless it hits one of the four rules above.

## Deviations, recorded after the first run (2026-10-29, 03:55 to 04:05 GMT-3)

Everything above this heading is the plan as written before classification. Its SHA-256
was `802a8b4e053db0ced1b6acada68a25971866adc51caefa9a29eafeab5e90ba32`.

1. **The lab's label file was renamed while this check ran.** The packaging of the lab
   moved it to `<data>/private/labels/zero_sections_2026_labels.csv` and renamed its
   columns from `manual_*` to `label_*`. Step 6 now accepts both. The first run stopped at
   step 6 for this reason, after this check's labels had been written.
2. **A mapping bug in step 6 was fixed before any reading of the result.** The lab
   category "rural or river, no indigenous marker" contains the letters "indig", so the
   first comparison counted it as indigenous. The map now checks "no indigenous" first. A
   yes or no agreement on "indigenous" with Cohen's kappa was added to the summary.
3. **A place-cluster bootstrap was added to the panel** (2,000 Poisson weights per place,
   as the lab does). It was not in the plan. It adds intervals and changes no estimate.
4. **The shared-default sensitivity run was not done.** No zero-section place, and no
   sampled place, had that reason. The run therefore cannot change step 3 or the samples.
   It would move the census numbers of step 5 slightly. That run is still open.
5. The labels of the 110 zero sections had the same SHA-256 in all three runs
   (`e9ce840f52b6a277db31fd2dda4d4fa6ef495f68997716fbb8b7c25ed566fcda`). None of the
   fixes above changed them.
6. Before publication on 2026-10-29, the title line and one line of "What had been seen" were reworded to name the source of the items as the second recheck. No method, threshold or result changed.
