Skip to contents

Updated 2026-08-04. This file is the active project task list and should reflect shipped repository state. Completed implementation plans belong in project history, not in the pending queue.

Current status

ONgeoR 0.4.0 is feature-complete for the retrieve → link → crosswalk → map workflow, with the Shiny app split out to its own package (ONgeoRapp) so that ONgeoR can go to CRAN. Pre-submission checks are verified (R CMD check –as-cran clean); submission itself is pending.

Shipped

  • Retrieval — 29 registered sources, including the bundled HIVE grid, a bundled 2,407-station monitoring subset, and a synthetic raster, with provenance, bounded pagination with truncation detection, retry/backoff, actionable errors, progress messages, cache max_age, and source-specific simplification defaults. Live monitoring-station retrieval paginates automatically across pages of 2,000 features.
  • Caching — on-disk cache at ~/.cache/R/ONgeoR; refresh = TRUE and CLI --refresh bypass cached data.
  • Core APIlink(), nearest(), resolve(), and build_crosswalk(); weighted crosswalks and registry-driven column selection are shipped.
  • Mappingmap_layers(), map_crosswalk(), and map_nearest().
  • CLI — creates crosswalk.csv, self-contained map.html, and a standalone reproduce.R script.
  • Documentation — getting-started, crosswalk, and data-source contribution vignettes.
  • Postal resolutionresolve_postal() maps Ontario postal codes to dissemination areas from the OPCC M5 correspondence (checksum-verified, cached after first download); normalize_postal_code() and render_postal_reproducer_script(all_links = ) included.
  • Shiny app — split to its own package ONgeoRapp: source linking, nearest-facility search, postal-to-DA joining, interactive maps, data tables, map styling, basemap selection, and downloads.
  • Repository hygiene — obsolete phase-one scripts and rendered inventory output removed.

Current milestone — v0.3 consolidation

Status 2026-08-04: complete and superseded — v0.4.0 has shipped (app split, postal resolution, monitoring stations, HIVE validity repair). The remaining open item is the CRAN submission itself; see cran-comments.md.

Goal: make the shipped MVP internally consistent, package-driven rather than app-driven, repeatably tested, and protected by CI before adding more data sources or raster support.

Status 2026-07-18: issue #1 is complete (commits 9dda143, bed1602); evidence is recorded per item below. Residual validation gaps are listed as new unchecked items — close them opportunistically, they do not block v0.4.

v0.3.1 registry-drift fix pass (2026-07-19)

An audit found that the v0.3 “same product state” gate had regressed when the conservation authority and ORWN station sources were added: the registry, the retrieve_source() dispatch, the reproducer’s call table, and the app/vignette prose had drifted apart. Fixed in this pass:

  • Evidence: suite 568 pass / 0 fail / 0 skip after changes (2026-07-19); baseline before changes 471 pass / 0 fail. Implementation: venQ-supervised worker packets for the mechanical fixes plus direct edits for multi-file changes; full trial log in the agent memory repo.

Residual (non-blocking, fold into existing residual item): raster runs still have no reproducer story; nearest() does not validate k; clear_cache(source_id) fails on a corrupt sidecar; registry YAML re-read on every call (memoization); app “Use my own file” controls are inert placeholders — hide or implement.

P0 — Reconcile project state

  • Evidence: done in v0.3 bugfix pass, 2026-07-18.
  • Evidence: done in v0.3 bugfix pass, 2026-07-18.
  • Evidence: done in v0.3 bugfix pass, 2026-07-18.
  • Evidence: the acceptance gates below served as the criteria; validation recorded 2026-07-18 — suite 501 pass / 0 fail, offline-deterministic (passes with network blocked); R CMD check --as-cran 0/0/0 Status OK; browser smoke 7/7 in headless Chrome (installed-mode).

Acceptance gate: repository documentation, package metadata, and the actual implementation describe the same product state.

P0 — Make the Shiny app a thin package interface

The app should coordinate inputs and outputs. Spatial, retrieval, validation, and map-construction logic should live in testable package functions.

  • Evidence: zero ::: in app.R; guess_name_col(), extract_polygon_collection(), render_reproducer_script() exported (9dda143).
  • Evidence: retrieve_source() exported (d9d0d0c); used by CLI, app, and tools/live-smoke.R.
  • Evidence: build_nearest_layers() exported; map_nearest() delegates to it; app’s 48-line duplicate removed (9dda143).
  • Evidence: resolved by design decision, not literal move — the algorithmic duplication (nearest/connector construction) moved into the package; styled rendering stays app-level as pure presentation (deliberate 2026-07-15 decision to bypass map_layers() baked-in colors). The acceptance gate below is satisfied: no package algorithm is reimplemented in app.R.
  • Evidence: link() degenerate-within warning + build_crosswalk() auto-correct with inform (d9d0d0c); app applies the universal overlay-as-from rule (a4d1778); direction asserted in the testServer suite (9dda143).
  • Evidence: per-layer folded style accordions shipped in the awareness-first redesign (a4d1778).
  • Evidence: double-control bug found and fixed in 9dda143 (exactly one control on every nearest path, empty matches included). None basemap was browser-verified 2026-07-15 (Playwright); not re-covered by the current smoke test — see residual item below.

Acceptance gate: app.R contains reactive orchestration and presentation, not a second implementation of package algorithms.

P0 — Build a repeatable validation suite

  • Evidence: tests/testthat/test-shiny-server.R + helper-shiny.R (30 assertions, retrieval mocked at the package boundary; 9dda143).
  • Evidence: covered in the testServer suite (selection/type display, direction, preview invalidation on selection change; 9dda143).
  • Evidence: malformed CSV (missing lat -> error state, no table) and zero-row results covered (9dda143). Invalid distance settings and mocked retrieval-failure paths are NOT yet covered — residual item below.
  • Evidence: readiness covered incl. the zero-row fix (9dda143); generation of the three outputs is exercised at the unit level (render_reproducer_script() exported and tested) but download handlers are not driven end-to-end — folded into the residual item below.
  • Evidence: helper-fixtures.R (b13a1a5); whole suite passes with networking blocked (dead-proxy run, 2026-07-18).
  • Evidence: test-app-smoke.R, shinytest2 + chromote in Suggests (bed1602, d972f7e); 7/7 in headless Chrome installed-mode; skips under dev-loading and when Chrome is absent.
  • Evidence: R CMD check --as-cran 0/0/0 Status OK, 2026-07-18, after all consolidation changes.
  • Evidence: added to test-shiny-server.R (2026-07-20); suite 609 pass / 0 fail, R CMD check --as-cran 0 errors / 0 warnings.
  • Evidence: test-app-smoke.R drives all five basemap options in headless Chrome (None asserted tile-less). Runs offline and ungated as of 2026-07-20: 22 assertions, 0 failures, 0 skips. R CMD check --as-cran: 0 errors, 0 warnings, 1 NOTE.
  • The “detritus in the temp directory - com.google.Chrome.*” NOTE was first dismissed as cosmetic, and that was a mistake: it was reporting the exact leak that caused the startup timeouts below. Resolved by the teardown in test-app-smoke.R, which removes the NOTE and the flakiness together. A check NOTE about leftover state is evidence about the environment, not a formatting complaint.
  • Five mechanisms proposed and each falsified by measurement: map-layer payload size (2.19 vs 1.46 MB), feature count (34 -> 1629 features moves serialisation only 1.0 s -> 2.0 s), vertex count, SVG-vs-canvas rendering (0.3 s either way), and accumulated TMPDIR/com.google.Chrome.* dirs (a run failed with a completely clean TMPDIR). Whole render path costs ~5 s against a 90 s budget, so the time is not going into the map.
  • RETRACTION. Commits 4b0b8ef / 59cc4f0 claim hive’s 2.19 MB widget caused this. That claim is WRONG. It rested on single runs per condition through an instrument later shown to be ~50% flaky. Dropping hive from startup is still correct — users should not pay for a layer they did not request — but the stated reason was not established.
  • The test also SKIPS in CI, so removing the ONGEOR_BASEMAP_SMOKE gate bought nothing there: all three platforms report “AppDriver can not be initialized as {chromote} can not be started” and the matrix stays green. Making it genuinely run in CI needs chromote::set_chrome_args("--no-sandbox") or equivalent — but it should NOT be enabled until the flakiness above is understood, or CI goes red half the time.
  • Chrome does leak ~2 temp dirs per launch (this is what the R CMD check “detritus in the temp directory” NOTE reports); test-app-smoke.R now cleans up after itself. Worth doing on its own merits, but it does NOT fix the flakiness - that was tested and disproved.
  • Still true and worth keeping: this failure was invisible to devtools::test(), which stayed green at 634+ passes throughout. The browser test is the only thing that starts a real Shiny process.
  • Fixes applied: hive simplified in place at 250 m (data-raw/hive_simplify.R, 575 KB -> 354 KB on disk, all 1629 cells and the all-MULTIPOLYGON contract preserved), and hive is no longer drawn at load at all. leaflet::hideGroup() only hides client-side, so an “unchecked” furniture layer still ships its full geometry to every browser; hive is now reached through the source pickers, where its cost is paid on request. Guarded by a test asserting no addPolygons call for hive exists in the load-time widget.
  • NOT established: why 2.19 MB exceeded a 90 s startup budget when the geometry serialises in ~2.8 s. The differential is unambiguous and reproducible; the mechanism is not explained, and AppDriver’s readiness detection is the untested part. Do not cite a specific mechanism here without measuring it.
  • Fix: pack_spatial() / unpack_spatial() in inst/shiny/app.R wrap the raster with terra::wrap() before it leaves the worker and restore it with terra::unwrap() on arrival, applied at every future boundary (preview_task and both build_task return paths).
  • Evidence: live browser, hive + synthetic_air_quality after the fix - map 440,145 chars (was 0), layers control present (was absent), 18 raster canvas tiles (was 0), map.html download 2,806,750 bytes (was ~32 KB), matching the offline 2,741 KB baseline. Visually confirmed: HIVE hex grid and the PM2.5 surface render together correctly.
  • Regression test: test-shiny-server.R “rasters are packed across the future boundary and survive” asserts the wrap/unwrap contract including a real serialize/unserialize round trip; verified to FAIL when the helpers are reduced to pass-through.
  • Why every existing test missed it: the offline suite runs use_sequential_futures(), so nothing ever crossed a process boundary, and render_styled_map() in-process was always fine. Only a live browser run with a real multisession worker reproduced it.
  • Note for future browser tests: leaflet 2.2.3 draws a SpatRaster as a CANVAS grid layer (options = gridOptions()), not an img.leaflet-image-layer overlay - asserting on that img selector gives a false negative.

Acceptance gate: both workflows can be exercised automatically from input to downloadable output, including expected failure paths.

P1 — Add repository automation

  • Evidence: .github/workflows/R-CMD-check.yaml (9dda143); first run green on all three OSes (run 29668240825).
  • Evidence: vignettes build inside the check job (no --no-build-vignettes); install exercised by check on 3 OSes.
  • Evidence: the smoke test runs inside the check matrix (r-lib check-r-package sets NOT_CRAN=true and installs the package); green on all three OSes at d972f7e (run 29668874746). That run also caught an undeclared chromote Suggests dependency first (bed1602 run failed) — CI doing its job on day one.
  • Evidence: live-geohub.yaml (workflow_dispatch + weekly cron); first manual run green (run 29668390742), 34 PHUs / 403 airports live.
  • Evidence: README.md R-CMD-check badge added (2026-07-20), linking to .github/workflows/R-CMD-check.yaml; workflow proven green on all 3 OSes across multiple runs before the badge was added.

Acceptance gate: changes to main receive repeatable package, test, and UI validation without depending on Ontario GeoHub availability.

P1 — Improve Shiny responsiveness

  • Evidence: ExtendedTask + promises/future (multisession) with plan-restore on stop, merged in PR #4 (1eab55e).
  • Evidence: generation counters (preview_generation/link_generation, bumped on every relevant input change) are carried through each ExtendedTask and checked before results are stored, so a completion whose inputs have moved on is discarded. Test: “Link discards a completion invalidated by changed inputs” (test-shiny-server.R).
  • Evidence: task_status_ui() renders idle/running/failed/cancelled/completed with a data-state attribute; wired into both tabs via link_task_status and nearest_task_status. Tests assert Running, Cancelled, Failed (with the error text) and Completed.
  • Evidence: test “repeat Link runs use cached retrieval without re-fetching” asserts the second identical run is faster than the first and that no extra retrieval work is started.

Acceptance gate: a slow or temporarily unavailable external source does not freeze the user interface or leave misleading prior results visible.

P1 — Public release readiness

  • [~] Add pkgdown configuration and publish documentation. Config done, publishing NOT done. _pkgdown.yml added and pkgdown::build_site() completes; the site has not been deployed anywhere, and _pkgdown.yml is .Rbuildignored so it does not trip the top-level-files check. Remaining work is choosing a host (GitHub Pages) and wiring a workflow.
  • Evidence: three templates incl. data-source-request, PR #5 (1eab55e).
  • Evidence: Title already compliant (title case, no trailing period, does not open with the package name or an article). Description reworded to expand LIO and REST on first use.
  • Evidence: every network-touching example is already wrapped in if (interactive()) { ... }, which R CMD check skips - equivalent to \donttest{} here. Audited all @examples blocks in R/*.R; no changes needed, and devtools::document() produces no man/ or NAMESPACE drift.
  • Evidence: installed into an empty library via .libPaths(c("/tmp/ongeor-clean-lib", .libPaths())); devtools::install(); install succeeded and library(ONgeoR) loaded 0.3.0.9000 cleanly.

Acceptance gate: a new user can install the package, understand its scope, run a documented workflow, and report a source or software problem.

v0.4 — Expansion after v0.3 passes

Expansion is demand-driven. Do not begin these items until the v0.3 acceptance gates above are satisfied.

Blocked decisions

These are data-governance or scope questions, not implementation tasks.

  • Postal-code resolution — design decided 2026-07-16 (no PCCF required): resolve_postal() on free centroids with an optional BYO-PCCF seam, output feeding the normal linking verbs. Centroid source pending one decision: GeoNames (0.27 km median deviation) vs the OPCC project’s NAR-derived open centroids (100% SLI coverage, ~0 km median; OPCC M2 correspondence table closed 2026-07-18). Awaiting Lennon’s go. Deliberately parked (2026-07-20, Lennon) — excluded from the v0.3 P1 cleanup pass; revisit when Lennon picks a centroid source.

Task discipline

  • Keep only current and future work unchecked in this file.
  • When a task is completed, update its checkbox and milestone status in the same change that closes the implementation handoff.
  • Every milestone must state its acceptance gate and record evidence that the gate passed before the next milestone begins.
  • Do not create source-specific linking functions when existing geometry-driven verbs already cover the operation.
  • Do not add a source without provenance, licensing notes, deterministic tests, and live retrieval validation.