Skip to content

Latest commit

 

History

History
338 lines (225 loc) · 32.3 KB

File metadata and controls

338 lines (225 loc) · 32.3 KB

fresh 0.19.0

Decompose frs_habitat_classify() into composable pieces; rename frs_habitat_known()frs_habitat_overlay(). Pre-1.0, breaking changes accepted to set the right shape before external use.

  • New exported frs_habitat_predicates(sp_params) — pure-R helper that takes a single species' params and returns a named list of SQL boolean predicates (spawn, rear, lake_rear, wetland_rear) ready to embed in CASE WHEN <pred> THEN TRUE ELSE FALSE END. Extracted from frs_habitat_classify()'s per-species loop. Testable without a DB; 33 unit tests cover both rules-YAML and CSV-ranges paths, edge_type filters, and the lake/wetland W-rule gating.
  • frs_habitat_classify() shrinks from 551 → ~447 lines and gains a known = NULL parameter — when supplied, calls frs_habitat_overlay() automatically as a post-step. Rule-based classification + observation overlay can now be a single call.
  • Breaking: frs_habitat_known() renamed to frs_habitat_overlay(). The mechanism is overlay (additive OR-in); "known" presupposed provenance the function doesn't enforce. No deprecation alias — pre-1.0, no external users.

fresh 0.18.0

  • New frs_habitat_overlay() — stitches known-habitat boolean flags from a wide-format lookup table INTO an existing streams_habitat classified by frs_habitat_classify(). Mirrors the bcfishpass blend of model output (habitat_linear_<sp>) with manual / observation-based knowns (streams_habitat_known) into the published streams_habitat_linear integer encoding. Purely additive (FALSE → TRUE only). Per-species columns {habitat}_{species_lower} matched against the species code in streams_habitat; missing per-species columns skip with a verbose message rather than erroring. Compound join key parameterisable via by (default c("blue_line_key", "downstream_route_measure")). Surfaced as a need in link#55 — link's pipeline loaded user_habitat_classification.csv for break-points + barrier overrides but never propagated its flags into fresh.streams_habitat. After this lands, link's lnk_pipeline_classify can call frs_habitat_overlay() as a post-step.

fresh 0.17.1

  • Params validator accepts wetland_ha_min predicate on rear rules with waterbody_type: W — mirrors the existing lake_ha_min / waterbody_type: L rule. The classifier in 0.17.0 already read wetland_ha_min from rear rules to filter the fwa_wetlands_poly join; the validator predicate allowlist hadn't been extended so rules YAML with the key was rejected. Surfaced in link#51 when lnk_rules_build() started emitting waterbody_type: W rules with the threshold.

fresh 0.17.0

  • frs_habitat_classify() now honours the waterbody_type: L / waterbody_type: W entries under a species' rear: rules in the rules YAML. Previously the lake_rearing / wetland_rearing booleans were set whenever a segment fell in the species' rear channel-width window and matched a lake/wetland waterbody_key — regardless of whether the species had a lake/wetland rear rule declared. Now the flag is FALSE unless the species has the matching rule, and the rule's optional lake_ha_min / wetland_ha_min threshold filters the polygon join to exclude waterbodies below that area (#165). Surfaced in link#51 when every species in link's bcfishpass and default bundles produced bit-identical lake_rearing_ha totals despite the bundles declaring different rear rules.

fresh 0.16.0

  • frs_habitat_classify() output schema gains a wetland_rearing boolean column, mirroring lake_rearing but joined to whse_basemapping.fwa_wetlands_poly on waterbody_key (#164). Additive schema change — existing callers are unaffected; lake_rearing semantics unchanged. Prerequisite for link's compound rearing rollup (link#51).

fresh 0.15.0

  • Remove unused frs_fish_habitat() and frs_fish_obs(). Both were BC-specific fetchers hard-coded to bcfishpass/bcfishobs table names and had no callers in fresh or link. If BC-specific fetchers become useful later they belong in link where the domain context lives (#162)
  • Exported function count: 41 → 39.
  • Add missing @param barrier_overrides docstring on frs_habitat_classify() — the parameter was already in the signature but absent from roxygen so the rendered help didn't describe link's main integration point.
  • Docs role-clarity refresh: README + CLAUDE.md ecosystem tables updated to describe link's full scope; pipeline wording split into fish-habitat (link → fresh) and land-cover-change (fresh → flooded → drift); CLAUDE.md version + architecture file list brought current.

fresh 0.14.0

  • Add frs_barriers_minimal() — reduce barrier points to the downstream-most per flow path via fwa_upstream() self-join. Extracts the bcfishpass "non-minimal removal" pattern from link's compare pipeline into a reusable fresh function. Typical reduction ~27,000 raw gradient barriers → ~700 minimal on a full watershed group (#160)

fresh 0.13.8

Three-phase cluster connectivity for rearing.

  • Phase 1: on-spawning segments (both rearing AND spawning) excluded from clustering — always valid. Prevents over-removal of rearing on spawning streams (#153)
  • Phase 3: FWA_Downstream() on the broken streams table (mainstem only) replaces fwa_downstreamtrace() on raw FWA. Finds spawning downstream of rearing clusters with path gradient + distance constraints (#153)
  • BULK CH rearing +6.0% → +2.6%, BT rearing +1.3% → -2.2%. All species within 5% across 4 WSGs

fresh 0.13.7

Apply bridge gradient along downstream path in frs_cluster.

  • frs_cluster() downstream check now applies bridge_gradient and bridge_distance segment-by-segment along the fwa_downstreamtrace path. Upstream check remains boolean — FWA_Upstream returns tributaries that interleave with mainstem in row_number() ordering, making path gradient unreliable on branching networks (#153)

fresh 0.13.6

Support spawn_connected rules for waterbody-adjacent spawning.

  • Parse spawn_connected block in rules YAML — permissive spawn thresholds for segments in the downstream trace from waterbody outlets. Own validation separate from spawn/rear rules (#154)
  • Additive step in .frs_connected_waterbody(): accessible segments in the trace meeting spawn_connected thresholds get spawning = TRUE even if they failed standard classification. BULK SK spawning -9.6% to -0.7% vs bcfishpass (#154)

fresh 0.13.5

Fix lake outlet ordering and extract reusable downstream trace.

  • Fix multi-BLK lake outlet selection: use wscode_ltree network topology instead of downstream_route_measure (meaningless across BLKs). BULK SK spawning -22.6% to +0.1% vs bcfishpass (#147)
  • Fix cumulative distance partitioning: partition by waterbody_key instead of blue_line_key so distance accumulates per lake, not per BLK (#147)
  • Extract .frs_trace_downstream() — reusable downstream trace with distance cap and gradient stop (#147)
  • Rename .frs_connected_spawning() to .frs_connected_waterbody() — parameterized for any waterbody type (#147)
  • waterbody_type: L now includes reservoirs (fwa_manmade_waterbodies_poly) via shared .frs_waterbody_tables() helper — the FWA table split is digitization origin, not ecology (#147)

fresh 0.13.4

Index input tables for standalone frs_habitat_classify performance.

  • frs_habitat_classify() now indexes input tables before the access gating loop — 35x speedup when called directly (bypassing frs_habitat) (#150)
  • .frs_index_working() is now idempotent with IF NOT EXISTS — safe to call multiple times on the same table (#150)

fresh 0.13.3

Two-phase connected spawning and multi-label breaks.

  • Two-phase connected spawning for lake-rearing species (SK, KO) matching bcfishpass v0.5.0: downstream trace from lake outlets (3km cap, gradient stop) + upstream cluster with lake polygon proximity (ST_DWithin). Auto-dispatched when rearing rules include waterbody_type: L (#147)
  • Multiple labels per break position preserved — a gradient_15 and a falls at the same measure both survive in streams_breaks (#145)

fresh 0.13.2

Preserve multiple labels per break position.

  • Multiple labels at the same (blue_line_key, downstream_route_measure) now survive in streams_breaks — a gradient_15 and a falls at the same measure are both preserved. Enables per-barrier overrides, access reporting, and habitat reporting by barrier type (#145)

fresh 0.13.1

Persist gradient barriers and downstream-only distance fix.

  • to_barriers parameter on frs_habitat() — persist gradient barriers table with ltree enrichment for link's lnk_barrier_overrides() (#143)
  • connected_distance_max distance filter now downstream-only with correct fwa_upstream direction (#133)
  • Fix aoi + wsg interaction — character aoi ANDed with WSG filter instead of replacing it (#141)

fresh 0.13.0

Distance filter, aoi fix, and measure rounding.

  • connected_distance_max distance filter now downstream-only — upstream spawning has no distance cap, matching bcfishpass v0.5.0 SK spawning logic. Uses DRM difference (same-BLK) and ST_Distance Euclidean (cross-BLK) (#133)
  • Fix aoi replacing wsg filter instead of being additive — frs_habitat(wsg = "ADMS", aoi = "edge_type != 6010") now correctly scopes to ADMS, not province-wide (#141)
  • measure_precision parameter on frs_network_segment() and frs_habitat() — controls break measure rounding. Default 0 (integer, matching bcfishpass). Breaks table rounded and deduped before splitting (#135)
  • Auto-skip gradient/channel_width inheritance on waterbody_type: L/W rules (#131)

fresh 0.12.9

Post-cluster distance filter, measure rounding, and lake threshold auto-skip.

  • connected_distance_max now caps habitat EXTENT from connected segments (not just search distance). Post-cluster filter removes individual segments beyond the cap. SK spawning 112 km → ~74 km (#133)
  • measure_precision parameter on frs_network_segment() and frs_habitat() — controls decimal places for break measure rounding. Default 0 (integer, matching bcfishpass). Breaks table rounded and deduped before splitting (#135)
  • Auto-skip gradient/channel_width inheritance on waterbody_type: L/W rules — lake/wetland flow lines are routing lines (#131)

fresh 0.12.8

Lake/wetland threshold auto-skip and connected distance cap.

  • Auto-skip gradient/channel_width CSV inheritance on waterbody_type: L and waterbody_type: W rules — lake/wetland flow lines are routing lines, channel dimensions are meaningless (#131)
  • connected_distance_max predicate in rules YAML — caps network distance from connected habitat when requires_connected is present. SK/KO spawning capped at 3km from rearing lake (#133)

fresh 0.12.7

Replace observations with barrier_overrides.

  • barrier_overrides parameter replaces observations on frs_habitat() and frs_habitat_classify() — accepts a pre-computed table of (blue_line_key, downstream_route_measure, species_code) from link. Fresh skips matched barriers without counting, thresholds, or date filters (#129)
  • Remove observation counting SQL and observation_* columns from parameters_fresh.csv — fish passage interpretation belongs in link, not the network engine

fresh 0.12.6

Multi-class gradient barrier detection.

  • frs_break_find(classes =) — single-pass multi-class gradient detection matching bcfishpass v0.5.0. Tags every vertex with its gradient class, groups consecutive same-class vertices into islands, places one barrier at each class transition. Catches transitions WITHIN steep sections that boolean above/below missed (#127)
  • frs_break_find(blk_filter =) — restrict to main flow lines (blue_line_key = watershed_key). Default TRUE (matches bcfishpass)
  • frs_habitat() now calls frs_break_find() once with all gradient classes instead of looping per threshold. Simpler, faster, more barriers detected.

fresh 0.12.5

Observation-based access override.

  • observations parameter on frs_habitat() and frs_habitat_classify() — fish observations upstream of gradient/falls barriers override access gating per species. Thresholds from parameters_fresh.csv: observation_threshold, observation_date_min, observation_buffer_m, observation_species (#69)
  • Defaults match bcfishpass v0.5.0: BT >= 1 obs (all salmonids count), CH/CO/SK/PK/CM/ST >= 5 obs (species-specific), since 1990, 20m buffer
  • ADMS: BT accessible +103%, CH/CO +10% with bcfishobs.observations

fresh 0.12.4

Post-segmentation gradient control.

  • gradient_recompute parameter on frs_network_segment() and frs_habitat()TRUE (default) recomputes gradient from DEM vertices after splitting; FALSE inherits parent segment gradient, matching bcfishpass v0.5.0 behavior (#124)
  • frs_col_generate(exclude =) — skip named columns from regeneration (generic, reusable)

fresh 0.12.3

SK/KO spawning requires connected rearing lake.

  • requires_connected predicate in rules YAML — spawning segments must be spatially connected to rearing via frs_cluster(). No rearing lake = no spawning (#120)
  • New .frs_run_connectivity() orchestrates both rearing cluster checks (cluster_rearing) and spawning connectivity checks (requires_connected + cluster_spawning) after classification
  • SK/KO: cluster_spawning = TRUE with 3km bridge distance. KO added to parameters_fresh.csv
  • ADMS sub-basin: SK spawning 15 → 0 (correct — no lakes >= 200 ha)

fresh 0.12.2

Fix short barrier detection.

  • frs_break_find() gains min_length parameter (default 0) — keeps all gradient islands regardless of length. A 30m waterfall at 20% gradient is a real barrier but was silently dropped by the old 100m minimum. Pass min_length = 100 to restore pre-0.12.2 behavior (#118)
  • ADMS sub-basin at 15%: 137 barriers (was 98, +39 recovered)

fresh 0.12.1

Per-rule threshold overrides in habitat rules YAML.

  • Rules can now specify gradient: [min, max] and channel_width: [min, max] that override CSV inheritance per rule. Missing fields still inherit from CSV when thresholds: true (#116)
  • Bundled YAML updated: all waterbody_type: R rules now have channel_width: [0, 9999] — skips channel_width_min on river polygons (matching bcfishpass v0.5.0 pattern where river polygon widths are unreliable)

fresh 0.12.0

Habitat eligibility rules format (Phase 1).

  • YAML-based habitat rules for multi-rule species — each species gets a list of rules per habitat type joined by OR, each rule is AND of predicates. Replaces the single-rule-per-CSV-row limitation (#113)
  • Bundled inst/extdata/parameters_habitat_rules.yaml with NGE defaults for 11 species (synced from link/inst/extdata/parameters_habitat_dimensions.csv)
  • frs_params(rules_yaml =) loads rules YAML (default = bundled, NULL = skip rules for backward compat)
  • frs_habitat(rules =) pass-through (NULL = bundled, FALSE = disable, string path = custom file)
  • thresholds: false per rule — wetland-flow carve-out pattern where a rule bypasses CSV gradient/channel_width inheritance
  • Default behavior change: SK rearing now lake-only (area >= 200 ha); PK/CM rearing = 0 (explicit rear: []); CO/BT/CH/ST/WCT/RB rearing expanded to include river polygons + wetland-flow segments. Pass rules = FALSE to restore pre-0.12.0 behavior.
  • Phase 2 MAD support deferred to #114

fresh 0.11.1

Gradient barrier label format precision fix.

  • New gradient_NNNN label format — 4-digit zero-padded basis points (threshold × 10000) preserves precision for fractional thresholds. 0.05gradient_0500, 0.0549gradient_0549, 0.15gradient_1500. Resolution: 1 basis point (#110)
  • Fixes silent precision loss in 0.11.0 where as.integer(thr * 100) collapsed 0.05 and 0.0549 both to gradient_5, causing distinct biological thresholds to share a single break
  • New .frs_validate_gradient_thresholds() errors on out-of-range, excess precision, NA, or label-collision inputs (catches the bug class going forward)
  • Parser .frs_access_label_filter() accepts BOTH new format and legacy gradient_N for backward compat with user-supplied labels via frs_break_find(label = "gradient_15")

fresh 0.11.0

Sub-segment gradient resolution via auto-derived breaks.

  • breaks_gradient parameter on frs_habitat() — generates gradient breaks at biologically meaningful thresholds derived from spawn_gradient_max + rear_gradient_max in parameters_habitat_thresholds.csv. Three modes: NULL (default auto-derive), numeric vector (explicit override), numeric(0) (disable, 0.10.0 behavior) (#101)
  • Default behavior change: frs_habitat() now produces ~30% more segments on typical sub-basins (ADMS test: 312 → 409). The added breaks are at biologically meaningful gradient thresholds and give frs_cluster() the resolution it needs to detect within-segment steep sections that would otherwise be hidden by averaging
  • Pass breaks_gradient = numeric(0) to restore 0.10.0 behavior (only species access thresholds)

fresh 0.10.0

Network cluster connectivity analysis.

  • frs_cluster() — generic cluster connectivity validation. Groups adjacent segments sharing one label, checks if another label exists upstream, downstream, or both on the network. Disconnected clusters set to FALSE. Uses ST_ClusterDBSCAN for spatial clustering and fwa_downstreamtrace() for downstream trace with gradient bridge and distance cap (#107)
  • Per-species cluster config in parameters_fresh.csvcluster_rearing, cluster_direction, cluster_bridge_gradient, cluster_bridge_distance, cluster_confluence_m. Anadromous species opt in; resident species do not
  • direction = "both" evaluates upstream and downstream independently, keeps clusters valid in either direction

fresh 0.9.0

Flexible AOI, configurable access gating, and feature indexing.

  • frs_habitat() accepts any AOI — sf polygons, WHERE clauses, ltree filters — not just WSG codes. Add species and label params for custom runs (#96)
  • gate parameter on frs_habitat_classify() — set FALSE to classify raw habitat potential without access restrictions (#98)
  • blocking_labels parameter — configurable which labels restrict access. Default "blocked". Set c("blocked", "potential") for conservative analysis. Only "blocked" and gradient_N block by default; everything else passes through
  • frs_feature_find() — locate any point features on the network (crossings, observations, stations) with col_id for feature identity (#92)
  • frs_feature_index() — index upstream/downstream relationships between segments and features as ID arrays (#93)
  • frs_break_find() slimmed to gradient-only. Point/table modes moved to frs_feature_find()
  • Province-wide run completed: 229 WSGs, 5.98M segments
  • Classify growth penalty fixed: constant-time DELETE by watershed_group_code (#91)

fresh 0.8.0

Unified pipeline, domain-agnostic network segmentation, and major performance improvements.

New functions

  • frs_network_segment() — domain-agnostic network segmentation. Extracts, enriches, breaks at any point sources, assigns id_segment. One table, one copy of geometry.
  • frs_habitat_classify() — long-format habitat classification. One row per segment x species with accessible, spawning, rearing, lake_rearing. Species-specific accessibility via break label filtering.
  • frs_feature_find() — locate any point features on the network (crossings, observations, stations). Replaces frs_break_find() points/table modes.
  • frs_feature_index() — index upstream/downstream relationships between segments and features. Stores feature ID arrays per segment.

Pipeline changes

  • frs_habitat() rewritten to wrap frs_network_segment() + frs_habitat_classify(). Auto-generates gradient barriers per WSG from species parameters.
  • to_streams + to_habitat params replace to_prefix for persistent output tables.
  • mirai replaces furrr for parallel execution — lighter daemons, foundation for crew.aws.batch.
  • frs_break_find() slimmed to gradient-only (island detection). Point/table modes moved to frs_feature_find().

Performance

  • Island-based gradient barriers: 85% fewer barriers than interval method (#86)
  • Accessibility recycled by threshold group: 5 queries → 2 for species sharing thresholds (#89)
  • Classify growth penalty fixed: constant time DELETE by watershed_group_code (#91)
  • Breaks table indexed with ltree GIST for cross-BLK queries: 15x speedup
  • Province-wide: 229 WSGs, 5.98M segments completed

Other

  • id_segment for unique sub-segment identity after breaking (#82)
  • col_blk + col_measure on break sources for configurable column names (#80)
  • .frs_sql_num() for locale-safe numeric SQL literals
  • Docker-based local fwapg tuned for M4 Max Pro (128GB/16 cores)

fresh 0.7.0

Local Docker fwapg instance and generic network-referenced classification via break_sources.

  • Replace falls parameter with break_sources list across pipeline (frs_habitat(), frs_habitat_partition(), frs_habitat_access()) — accepts any number of point tables with label, label_col, and label_map for flexible classification (#70)
  • Add label and source columns to breaks table for provenance tracking
  • Ship inst/extdata/falls.csv (3,294 barrier falls) and inst/extdata/crossings.csv (533k crossings) with data-raw/ refresh scripts
  • Add Docker-based local fwapg: containerized PostGIS + loader with GDAL/psql/bcdata (#63)
  • Fix Phase 2 sequential mode to reuse conn instead of calling frs_db_conn()

fresh 0.6.0

Parallelized multi-WSG habitat pipeline — 2.5x speedup over sequential on BULK.

  • Add frs_habitat() — orchestrator: run the full habitat pipeline across watershed groups with furrr parallelism (#61)
  • Add frs_habitat_partition() — generic partition prep (extract, enrich, pre-compute breaks). Accepts any AOI, not just WSG codes
  • Add frs_habitat_access() — gradient + falls barrier computation at a threshold, deduplicated across species sharing the same access_gradient_max
  • Add frs_habitat_species() — classify one species with pre-computed access and habitat breaks
  • Both Phase 1 (partition prep across WSGs) and Phase 2 (species classification) parallelize via furrr::future_map() when workers > 1
  • Benchmark scripts and logs in scripts/habitat/

fresh 0.5.0

Watershed-group habitat pipeline — run the full pipeline across all species in a WSG.

  • Add where parameter to frs_extract() for SQL predicate filtering, ANDed with aoi when both provided (#60)
  • Add frs_wsg_species() to look up species presence and bcfishpass view names per watershed group from bundled wsg_species_presence.csv
  • Add data-raw/pipeline_wsg.R — runs full habitat pipeline per species per WSG with timing (baseline: 20 min for BULK, 7 species, 32K segments)

fresh 0.4.1

  • Add frs_categorize() for priority-ordered boolean-to-category collapse — mapping codes for QGIS, reporting, gq style registry (#57)
  • Refine habitat pipeline vignette: code below each narrative section with function links, 2x2 scenario grid, access barriers on habitat map

fresh 0.4.0

Coho habitat pipeline — classify habitat on the database at any scale. New vignette proves the workflow on the Byman-Ailport subbasin of the Neexdzii Kwa.

  • Add frs_col_join() for generic lookup table enrichment — channel width, MAD, upstream area, any key (#51)
  • Add frs_edge_types() lookup helper with bundled FWA edge type CSV (41 codes from GeoBC User Guide)
  • Add to param to frs_network() — write results to DB working tables instead of pulling to R, scales to any number of watershed groups (#53)
  • Add where param to frs_classify() — scope classification by SQL predicate for edge-type-aware and accessibility-filtered habitat modelling
  • Add where and append params to frs_break_find() table mode — filter points table and combine multiple break sources (gradient + falls) in one breaks table (#38)
  • Add exclude_edge_types param to frs_point_snap() — only exclude subsurface flow (1425) by default, not wetland connectors (1410) (#52)
  • Bundle bcfishpass habitat parameter CSVs and fresh-specific access gradient thresholds (#54)
  • Add coho habitat pipeline vignette: extract → enrich → break (gradient + falls) → classify (accessible, spawning, rearing, lake rearing) → aggregate → scenario comparison

fresh 0.3.1

  • Add from and extra_where params to waterbody specs in frs_network() for filtering waterbodies to those connected to habitat streams (#49)
  • Network traversal table configurable via .frs_opt("tbl_network") (#44)

fresh 0.3.0

Server-side habitat model pipeline — replaces ~34 bcfishpass SQL scripts with 4 composable functions. See the function reference for details.

  • Add frs_extract() for staging read-only data to writable working schema (#36)
  • Add frs_break() family (find, validate, apply, wrapper) for network geometry splitting via ST_LocateBetween and fwa_slopealonginterval gradient sampling (#38)
  • Add frs_classify() for labeling features by attribute ranges, break accessibility (via fwa_upstream), and manual overrides — pipeable for multi-label classification (#39)
  • Add frs_aggregate() for network-directed feature summarization from points (#40)
  • Add frs_col_generate() to convert gradient/measures/length to PostgreSQL generated columns — auto-recompute after geometry changes (#45)
  • Add .frs_opt() for configurable column names via options() — foundation for spyda compatibility (#44)
  • All write functions return conn invisibly for consistent |> chaining

fresh 0.2.0

  • Breaking: All DB-using functions now take conn as the first required parameter instead of ... connection args. Create a connection once with conn <- frs_db_conn() and pass it to all calls. Enables piping: conn |> frs_break() |> frs_classify() (#35)

fresh 0.1.0

  • Multi-blue-line-key support for frs_watershed_at_measure() and frs_network() via upstream_blk param (#20)
  • Add frs_watershed_at_measure() for watershed polygon delineation with subbasin subtraction
  • Add frs_network() unified multi-table traversal function replacing per-type fetch functions
  • Add frs_default_cols() with sensible column defaults for streams, lakes, crossings, fish obs, and falls
  • Add upstream_measure param for network subtraction between two points on the same stream
  • Add frs_waterbody_network() for upstream/downstream lake and wetland queries via waterbody key bridge
  • Add wscode_col, localcode_col, and extra_where params for custom table schemas
  • Add frs_check_upstream() validation for cross-BLK network connectivity
  • Add blue_line_key and stream_order_min params to frs_point_snap() for targeted snapping via KNN (#16, #17, #7, #18)
  • Add stream filtering guards: exclude placeholder streams (999 wscode) and unmapped tributaries (NULL localcode) from network queries; include_all to bypass. Subsurface flow (edge_type 1410/1425) kept in network results (real connectivity) but excluded from KNN snap candidates (#15)
  • Add frs_clip() for clipping sf results to an AOI polygon, with clip param on frs_network() for inline use (#12)
  • Add frs_watershed_split() for programmatic sub-basin delineation from break points — snap, delineate, subtract with stable blk/drm identifiers (#31)
  • Security hardening: quote string values in SQL, validate table/column identifiers, clear error on missing PG env vars, gitignore credential files (#19)
  • Input type validation on all numeric params
  • Add subbasin query vignette with tmap v4 composition
  • Fix ref CTE to always query stream network, not target table

Initial release. Stream network-aware spatial operations via direct SQL against fwapg and bcfishpass. See the function reference for details.