Skip to content

dft_transition_attribute(): tag transition patches from an overlay layer (#42) - #43

Merged
NewGraphEnvironment merged 9 commits into
mainfrom
42-dft-transition-attribute-tag-transition
Jul 18, 2026
Merged

dft_transition_attribute(): tag transition patches from an overlay layer (#42)#43
NewGraphEnvironment merged 9 commits into
mainfrom
42-dft-transition-attribute-tag-transition

Conversation

@NewGraphEnvironment

Copy link
Copy Markdown
Owner

Summary

  • New exported dft_transition_attribute(): tags change patches from dft_transition_vectors() with columns from any overlay polygon layer (fire perimeters, cutblocks, roads), keeping drift free of domain knowledge (closes dft_transition_attribute(): tag transition patches from an overlay layer (optional temporal filter) #42)
  • Two assignment modes for a patch straddling multiple overlay features: match_mode = "all" (left join, one row per match) or "largest" (one row per patch by greatest overlap area); optional inclusive year_col + interval temporal filter so only overlay features within the transition interval attribute a change
  • Guards learned from adversarial review: custom predicate + match_mode = "largest" aborts because sf::st_join(largest = TRUE) silently ignores the join predicate; cols naming the overlay geometry column aborts instead of silently breaking the join contract
  • Release bookkeeping: v0.8.0 (NEWS.md, DESCRIPTION), tests-first workflow with 52 new assertions, full suite green

Related Issues

Test plan

  • devtools::test(): 402 pass / 0 fail (11 expected opt-in skips)
  • devtools::check(): 0 errors, 0 warnings, 1 unrelated timestamp NOTE
  • lintr clean on new files
  • Runnable @examples execute during check (no \dontrun)

Notes

spacehakr::spk_join() was evaluated as a dependency and rejected: its reusable part is a thin wrapper over sf::st_join (sf/dplyr already in Imports) and the load-bearing pieces — interval semantics and area-majority assignment — didn't exist there. Patches carry no interval columns, so the transition interval is an explicit argument by design.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr

NewGraphEnvironment and others added 9 commits July 17, 2026 07:51
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
Tests-first contract for the new overlay-attribution helper: fixture
chain integration, straddle assignment under both match modes,
inclusive temporal filter, silent CRS transform, custom predicate,
0-row short-circuit, and validation errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
Generic overlay attribution for change patches: left spatial join of
overlay cols via predicate, match_mode "all"/"largest", inclusive
year_col+interval temporal pre-filter, silent CRS transform +
st_make_valid, typed-NA short-circuit for empty inputs.

Code-check hardening: abort on custom predicate with match_mode =
"largest" (sf::st_join(largest = TRUE) ignores the join predicate) and
on cols naming the overlay geometry column.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
devtools::document() output plus cross-reference from
dft_transition_vectors(). devtools::check(): 0 errors, 0 warnings,
1 unrelated timestamp NOTE. lintr clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
dft_transition_attribute(): generic overlay attribution for change
patches (#42).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
Two gaps from a test-robustness audit: the invalid-geometry repair
(the reason st_make_valid exists — BC fire/cutblock perimeters fail
GEOS validity) had zero coverage, and the documented match_mode = "all"
default was never asserted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
Generalizes the filter's name to match its scale-agnostic mechanism (a
numeric comparison works for calendar years, decimal years, months, or
epoch offsets) while keeping the temporal intent. time_col mirrors the
zone_col precedent in dft_transition_vectors(); time_* groups the pair.

Docs now state exactly how the params must be presented: both numeric
and on the same scale, Date/POSIXct are a hard error, with a @details
coercion recipe (calendar-year and epoch-days) and a @section
Limitations noting numeric-only time and polygon-only overlays. No
behaviour change; still numeric, no coercion inside the function.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
…ribute (#42)

Maintainer-facing note at the geometry-column guard: only the active
sf_column is rejected from cols; a second sfc column named in cols would
leak into the result. Left unguarded as a documented low-risk edge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W1utBhUeke24nQo5M97LUr
@NewGraphEnvironment
NewGraphEnvironment merged commit 7009dc1 into main Jul 18, 2026
1 check passed
@NewGraphEnvironment
NewGraphEnvironment deleted the 42-dft-transition-attribute-tag-transition branch July 18, 2026 20:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dft_transition_attribute(): tag transition patches from an overlay layer (optional temporal filter)

1 participant