import_bag: seed CUBE predicted surface from Chart prior to reject false-deep detections (#89)#90
Merged
Merged
Conversation
added 3 commits
June 29, 2026 00:29
Add a seed_settled=true parameter to primeFromTile and loadIntoSheet. When false, seed ONLY the predicted surface (setPredictedDepthAt) and skip the settled CUBE hypothesis (setSettledDepthAt), so the cell carries a blunder-rejection prior that turns on Node::insert's predicted-surface gate without filling/settling the cell. Default true preserves the existing #21/#70 warm-start reload behavior. This is the mechanism behind seeding the CUBE predicted surface from a Chart (contour) prior: settling coarse contour depths would contaminate the survey layer (and its co-estimated backscatter) with non-measured fill, so the prior only gates, it does not fill. Tests: PredictedOnlyPrimeSeedsNoSettledHypothesis (predicted set, no settled hypothesis, sheet stays clean, contrasted against seed_settled=true) and SeededPredictedSurfaceRejectsDeepBlunder (a shallow predicted surface rejects a false-deep sounding that is accepted with no prior). Part of #89
…ior (#89) Add a --prior <store_dir> flag. Before the CUBE replay, load that store's Chart (contour) layer and prime the GeoMapSheet predicted surface with loadIntoSheet(..., seed_settled=false). The prime lazy-creates a node per chart cell carrying a predicted depth, turning on CUBE's predicted-surface blunder gate (Node::insert is a pass-through when predicted_depth_ is NaN), so false-deep detections below target - blunder_scalar*sqrt(predicted_var) are rejected before they reach the winning hypothesis -- protecting both the bathy and backscatter stores. The prior store is built at the survey's GGGS level; a code comment documents that a chart cell only gates when its level is compatible with the survey node (a future refinement could resample). Part of #89
…ld (#89) Review found the --prior path could silently no-op: load() returns 0 with no error on a missing dir / no chart layer / level-mismatched store, yet the code logged 'blunder rejection active' regardless — the operator could ship an unprotected store believing outliers were gated. - Hard-error when --prior yields 0 Chart tiles (bad path / no chart/ layer). - Hard-error when ALL Chart tiles are at a non-survey GGGS level (none would coincide with a survey node → gate inactive); warn on partial mismatch. - Wrap load() in try/catch for a friendly diagnostic instead of an abort. - Correct the ALIGNMENT comment: load() keys level off each tile's filename, so fromCellSize() does not pin the prime level. - Note the shallow-chart false-reject tradeoff in --prior help text.
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.
Summary
Seeds the CUBE predicted surface in
import_bagfrom a Chart (contour) priorso CUBE's predicted-surface blunder gate turns on and rejects false-deep
detections — the false detections (water-column / second-bottom returns) that
place soundings much too deep and corrupt both the bathy and (via the bogus large
range) the co-estimated backscatter.
Closes #89.
Mechanism
CUBE's blunder gate is predicted-surface-relative and is skipped when
predicted_depth_is NaN (node.cpp). With no prior there is nothing to rejectfalse-deep soundings against — which is why they survive today. Priming the
predicted surface from the existing
Chartlayer (e.g. the Massabesic contour)turns the gate on: a sounding below
target − blunder_scalar·√(predicted_var)is rejected.Changes
primeFromTile/loadIntoSheetgainseed_settled(default
true, preserving the Persist GeoMapSheet draft tiles between sessions #21/Bound memory + output for long-duration operation: evict cold tiles from RAM; retire monolithic publish for incremental tiles #70 warm-start callers). Withfalse, onlythe predicted surface is seeded — no settled hypothesis — so the survey/Processed
layer keeps honest holes rather than being filled with coarse contour depths
(which would contaminate the bathy and the co-estimated backscatter). Gap-filling
survey→chart stays a query-time overlay concern (ADR-0002).
import_bag --prior <store_dir>— loads that store'sChartlayer and primesthe predicted surface before the replay.
--priorrefuses to build a silentlyun-gated store: hard-errors on a bad path / missing
chart/layer (0 tiles) andon an all-wrong-GGGS-level chart (none would coincide with a survey node), warns
on partial level mismatch, and wraps
load()in try/catch for a friendlydiagnostic. The shallow-chart false-reject tradeoff is noted in the help text.
Tests
PredictedOnlyPrimeSeedsNoSettledHypothesis— predicted-only seeds predicted, notsettled (sheet stays clean).
SeededPredictedSurfaceRejectsDeepBlunder— a deep blunder accepted without aprior is rejected once the predicted surface is seeded.
Local review
Pre-push review (Standard tier) run before opening: 1 must-fix (silent
--priorno-op) + suggestions, all addressed in this branch. Build + tests green.
Authored-By:
Claude Code AgentModel:
Claude Opus 4.8 (1M context)