Skip to content

MIP-0031 tasks

Written by hand, following .claude/skills/mip-tasks/SKILL.md's Step 1 process. That skill has disable-model-invocation: true, so this file was produced without invoking it as a slash command; the process it documents was followed manually instead.

Both research gaps that blocked design (§11: INEA's real bulletin layout, whether INEMA's search form offers an HTML shortcut) were resolved 2026-09-07; see the MIP's own §11 for what was verified live and how. This file is the resulting build plan.

Progress (verified against origin/main 2026-09-07): tasks 1/3 merged as PR #203 (InemaPdfParser, sampling_points_ba.json); tasks 2/4 merged as PR #200 (IneaPdfParser, sampling_points_rj.json). Tasks 5/6 (the actual WaterQualityClient wiring into AppConfig) have not landed: InemaBaWaterQualityClient/IneaRjWaterQualityClient do not exist on main yet, so beaches in Rio/Bahia still get "no data" for water quality despite the parsers/coordinate tables existing.

# slug delivers tests (must exist before the PR) depends on
1 pdf-parser-inema ✅ merged (PR #203): local/src/main/scala/marola/water/InemaPdfParser.scala (Apache PDFBox text extraction + fixed-column split) parsing a real INEMA bulletin (§4.3's captured Salvador bulletin, checked into local/src/test/resources/) into rows: point code, description, category. Multi-line description wrapping (confirmed real in §4.3's captured output) handled InemaPdfParserSpec against the real fixture PDF, point code, category and the multi-line-description case all asserted —
2 pdf-parser-inea ✅ merged (PR #200): a sibling IneaPdfParser for INEA's real bulletin layout (§11's verified fetch: PRAIAS/LOCALIZAÇÃO/Ponto Coleta/CONAMA 274/2000), checked into a fixture the same way IneaPdfParserSpec against a real captured INEA fixture 1
3 coordinate-table-bahia ✅ merged (PR #203): local/src/main/resources/sampling_points_ba.json, hand-curated: real coordinates for INEMA point codes near site/areas.json's salvador radius, each entry sourced (geocoded from the bulletin's own "Local da Coleta" description, per-entry note on how). The real data-entry task §11 flagged as the largest unknown, now scoped to just the points marola's configured area actually needs SamplingPointCoordinatesSpec: a point code present in the table resolves to its coordinate; one absent from it is dropped, not defaulted (same tolerant-parsing rule ImaScWaterQualityClient already follows) —
4 coordinate-table-rio ✅ merged (PR #200): the same for INEA point codes near site/areas.json's rio radius, real data entry, same sourcing discipline Extends task 3's spec with INEA-shaped codes —
5 inema-client not started: InemaBaWaterQualityClient (fetches INEMA's live geraBoletim?idcampanha=N PDF, task 1's parser, task 3's coordinate table, drops unmatched points) wired into AppConfig.waterQualityClient's Auto case and WaterProvider enum (InemaBa case, MAROLA_WATER_QUALITY_PROVIDER override) InemaBaWaterQualityClientSpec, end-to-end from a fixture PDF to List[SamplingPoint], mirroring ImaScWaterQualityClientSpec's existing shape; a live check before merge: just run -- --brief --lat -12.9777 --lon -38.5016 shows a real water-quality line for at least one Salvador beach 1, 3
6 inea-client not started: IneaRjWaterQualityClient, the extra step §11/§5 found INEMA doesn't need: fetch INEA's bulletin-listing page, find the newest PDF matching the rio area's zone(s), then task 2's parser + task 4's coordinates. Same AppConfig/WaterProvider wiring as task 5 IneaRjWaterQualityClientSpec including the listing-page discovery step (fixture the listing HTML, not just the PDF); live check: just run -- --brief --lat -22.9878 --lon -43.1913 shows a real water-quality line for at least one Rio beach 2, 4

Sequencing notes

  • Tasks 1/3 (Bahia) and 2/4 (Rio) are independent of each other: different institutes, different files, no shared code beyond whatever parser-sharing decision task 2 makes (flagged there as an implementation-time call, not pre-decided). They can be worked in parallel.
  • Tasks 5 and 6 are the integration points and each depends on both halves (parser + coordinates) for their own institute, not parallel with their own dependencies, but 5 and 6 are parallel with each other once their prerequisites land.
  • The Risk row this MIP's own header names, the coordinate table drifting as institutes add or retire points, with no self-updating feed to catch it, applies to tasks 3 and 4 specifically. Neither task's own tests can catch future drift (that's the nature of a hand-curated table); the mitigation is procedural (re-check when just benchmark runs against a rio/salvador origin starts returning more "no data" than expected), not something to over-engineer into task 3/4's scope now.