Repository navigation
Validate modelled habitat against fish observations (#283) - #289
Merged
NewGraphEnvironment merged 10 commits intoSep 26, 2026
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Scores a persisted run against fish observations: capture on accessible, spawning and rearing segments, cost in km, miss reasons from the bundle's own habitat predicates with gradient and width relaxed, and optional absences. All joins on the full (id_segment, watershed_group_code) key. schema is required: default's pipeline.schema names the schema bcfishpass builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
With the overlay on, 237 of 245 spawn-staged CH locations in the 51 shared WSGs sit in reaches default forces to spawning, so the headline capture is mostly decided by construction. The *_outside_uhc shares are the rest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
With buffer_m > 0 capture credits habitat upstream of the point, so a UHC reach just above an observation forced its capture while the point tested as outside UHC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
default vs bcfishpass on 51 shared WSGs at 0c19e0a. CH spawn-staged capture is mostly the user_habitat_classification overlay (237 of 245); BT's 0.1349 would score in-sample. research/habitat_validation.md carries the method, caveats and the #284 step-5 command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
The preflight drift guard requires every fresh:: symbol link calls to be declared. And the pinned minimum's frs_habitat_predicates() has no `model` argument, so passing model = "cw" would have failed on every host running fresh 0.33.0; cw is the default in 0.34. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
observations is now a table or a data frame. Only the location columns and species_code are required. The bcfishobs filters become arguments (match_types, source_exclude) that default on, and a filter whose column the source lacks is an error rather than a skip. A source's own is_spawn / is_rear win over bcfishobs wording. A data frame without observation_key is keyed by its own row numbers, and then refuses non-NULL exclusions. Codes are compared upper-cased and trimmed. With defaults, the bcfishobs path reproduces the committed baseline: 120 of 120 summary rows on 5 WSGs. Review round 6 (in the #283 archive) found the key, exclusion, normalisation and 0/1-flag issues fixed here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
NewGraphEnvironment
deleted the
283-validate-modelled-habitat-against-fish
branch
September 26, 2026 22:09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #283. Relates to NewGraphEnvironment/sred#24.
This is the scorer for #284 step 5. #284 stays open until
default_tunedis modelled and scored.What
lnk_habitat_validate()scores a persisted run against fish observations rather than against bcfishpass. For each WSG × species × stage (any/spawn/rear) it reports:accessible_km,spawning_kmandrearing_km, fromlnk_rollup_wsg().fresh::frs_habitat_predicates()are re-evaluated with gradient and width relaxed, sofails_gradientmeans the gradient maximum is binding.Any observation source.
observationstakes bcfishobs (the default), another table, or a data frame. Onlyspecies_code,watershed_group_code,blue_line_keyanddownstream_route_measureare required, so crew data, eDNA or a held-out subset can be scored. A source can give its ownis_spawn/is_rear. The bcfishobs filters (match_types,source_exclude) default on. When the source lacks the column a filter needs, the function errors instead of skipping it. With the defaults, the bcfishobs path reproduces the committed baseline exactly (120 of 120 summary rows).data-raw/habitat_validate.R --bundles=<config>:<schema>,...runs one or two bundles, at buffers 0 and 100 m. It writes aggregate CSVs, per-bundle and shared-WSG totals, and a diff.The method, the caveats and the step-5 command are in
research/habitat_validation.md.Findings that changed the design
(id_segment, watershed_group_code). Naver Creek gives 187 rows on the full key and 4,301 on bareid_segment. The issue body is corrected.schemais required.defaultdeclarespipeline.schema: fresh, which the bcfishpass bundle builds. The function stops when<schema>.logrecords a WSG under a different config.user_habitat_classificationspawning reaches, whichdefaultforces to habitat.share_*_outside_uhcreports the part the observations did not decide.observationsargument accepts a held-out table.Baseline (read-only;
default:fresh_defaultvsbcfishpass:fresh, 51 shared WSGs, buffer 0)Reconciliation: on its own 55 WSGs,
fresh_defaultretains 5,104 BT+DV and 1,745 CH locations, exactly #284's counts. Build vintage differs between the two schemas (4 of 55 and 39 of 59 WSGs are logged), so the diff is not a pure config effect.This PR models nothing (scope decided at the plan gate). Scoring
default_tunedneeds its own run decisions, stated at launch.Verification
test-lnk_habitat_validate.R, including a DB fixture: two WSGs shareid_segment, and there are cases for exclusions, releases, DV where BT is absent, a buffer, UHC indicators, absences, a log mismatch, and an unattached point.id_segmenthabitat join fails 6 tests.:63333bcfp tunnel being down (test-lnk_db_conn,test-lnk_wsg_resolve×2), files this branch does not touch.devtools::check(): its one ERROR is those same tests; the 3 WARNINGs and 2 NOTEs are in pre-existing files.frs_habitat_predicatesdeclared, and checking that showed the pinnedfresh@v0.33.0has nomodelargument, so the call as written would have failed on every host running 0.33.0. It is fixed, and a test that fails with the argument restored guards it./code-check: 6 rounds, plus a plan review, so 7 reviewer agents, past the usual ~5. Round 6 covered the source-agnostic change, and its five findings are fixed and pinned by tests (key handling, exclusions without a key, code normalisation, empty prefix, 0/1 flags). Round 2 found a defect inside a round-1 fix, so from then on only an enumeration could end the loop. Round 3 named three mechanisms and enumerated 59 rows, and round 4 re-walked them. Round 5 reviewed the late outside-UHC delta; its one finding is fixed and pinned by a test. Findings are inplanning/archive/2026-09-issue-283-habitat-validation/review-*.md.toupper(NULL)ischaracter(0), so an absent--wsgsselected zero WSGs.Not done
diff.csvis per WSG × species × stage.🤖 Generated with Claude Code
https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx