PATH Cost-Effective (PathCE) NoDb Module
Select the most cost-effective set of post-fire hillslope treatments that meets user-defined sediment-yield and outlet-discharge thresholds, by binary integer programming over Omni scenario/contrast outputs. Vendored from Jackson Nakae's PATH-cost-effective (upstream commit
4e3b4a6), parquet-native, with an interactive Quarto HTML report.
See also:
../../AGENTS.mdfor NoDb conventions;docs/adrs/ADR-0023-path-ce-v2-parameterization.mdfor the parameterization contract;docs/work-packages/20260720_path_ce_v2/for provenance, reference goldens, review dispositions, and the security review.
Model
The primary model minimizes treatment cost subject to: at most one treatment per
hillslope (or contrast group); per-hillslope sediment-yield reduction
requirements derived from sdyd_threshold; and a watershed outlet
sediment-discharge constraint derived from sddc_threshold against Omni outlet
contrast deltas. When the primary model is infeasible, a secondary model
maximizes total discharge reduction under the same per-hillslope constraints
(reported as primary_status = 0). Hillslopes whose yield increases under every
treatment are force-excluded and reported as a distinct untreatable class.
Faithfulness: path_ce_solver.ce_select_sites_flexible, data_prep, and
threshold_sweep are faithful extractions of upstream — keep them diffable when
syncing; wepppy-specific behavior lives in the seams (prepare_solver_inputs,
run_path_cost_effective_solver, module docstrings enumerate the deltas). The
solver seam converts the hectare-valued area column to acres so costs are
area (ac) × unit_cost ($/ac) × quantity (tons/ac), and realigns treatment
vectors to the frame's reduction-column order (the core pairs positionally).
Module map
path_ce_solver.py— faithful core + wepppy seam wrapper (SolverResult).data_prep.py— faithful aggregation/preparation; consumes run artifacts in place; grouped (psv) and cumulative (contrast_topaz_id) schema modes.threshold_sweep.py— feasibility-range binary search + bounded threshold grid sweep (powers the report's sliders and cost surface); plot helpers.presets.py— treatment-vector contract and defaults; labels derive from scenario names (mulch_15_sbs_map→0.5 tons/acre) and mismatches are rejected — labels key the prepared-frame columns.preconditions.py— validates user-provisioned Omni artifacts (D3: PATH never provisions); actionable errors name what to run. psv contrast ids absent fromcontrasts.out.parquetare legitimate (landuse_unchangedskips); coverage means each configured treatment has completedsbs_map-control contrasts.path_cost_effective.py—PathCostEffectiveNoDb controller: config normalization, stage methods (validate → prepare_data → solve → run_sweep → render), results/status persistence, sweep cache (config + frame hash keyed).report_service.py— stages and renders the Quarto HTML report in-worker (pinned Quarto CLI in the image; payload delivered via env var), publishes to<wd>/path/report/with a near-atomic rename swap.report/— vendored QMD (anchor-splicing builder in the work package keeps upstream sections byte-identical; WEPPPY-SEAM markers) + static JS/CSS (deck.gl/papaparse vendored; plotly.js staged from the Python package).
Configuration (path_ce.nodb)
sdyd_threshold (tonnes/acre — matches the prepared-data unit),
sddc_threshold (tonne/yr — matches the Omni outlet artifact unit),
slope_range (degrees, either bound nullable), severity_filter
(High/Moderate/Low subset or null; group-mode caveat in ADR-0023 §5),
treatments (list of label/scenario/unit_cost $/acre/quantity/fixed_cost).
Normalization is strict: non-finite, negative, mismatched-label, duplicate, or
unknown-scenario payloads are rejected. The HTML report always renders (the
retired render_reports flag is dropped from stale payloads on normalization).
Preconditions (user-provisioned, D3)
Before running PATH-CE the run must carry: Omni scenario summaries covering
sbs_map, undisturbed, and every configured treatment scenario; Omni outlet
contrasts (treatment vs sbs_map control) for every configured treatment;
omni/contrast_id_definitions.psv for grouped runs; omni/scenarios.out.parquet;
watershed/hillslopes.parquet. WGS geojson exports are required only for the
report (missing → run completes, report skipped with a recorded reason).
Pipeline and artifacts
The RQ task (wepppy.rq.path_ce_rq, channel {runid}:path_ce) runs the
controller stages against one config snapshot. Artifacts under <wd>/path/:
prepared frame + aggregation tables (path_ce_*.parquet), selection.parquet
(per-site treatment + acre-based cost), hillslope_sdyd.parquet,
untreatable.parquet, untreatable_increase.parquet, sweep.parquet
(per-cell results incl. JSON-encoded selections and error column) +
sweep_manifest.json, and report/ (self-contained HTML tree + download CSVs).
Report serving
The browse microservice serves <wd>/path/report/ inline at
runs/{runid}/{config}/report/path_ce/ with a sandbox CSP (opaque origin — no
cookies or credentialed API reach), inline media-type allowlist, and strict
subtree/symlink containment. See the package security review for the full
surface analysis.
Testing
tests/nodb/mods/path_ce/ (solver/data-prep parity against upstream goldens,
seam contracts, controller stages, preconditions, report service, plus a real
Quarto render integration test gated on the CLI), tests/rq/test_path_ce_rq.py,
tests/weppcloud/routes/test_path_ce_bp.py,
tests/microservices/test_browse_report_routes.py. Fixtures and goldens live in
tests/data/path_ce/; regeneration scripts and provenance in the work package.
Known upstream flags (reported to Jackson)
Upstream multiplies $/acre rates against hectare areas (wepppy corrects at the seam); "tons" labels denote metric tonnes in the artifacts; the prepared-data yield unit is the mixed tonne/acre; upstream's report QMD had a vestigial ipywidgets import, an infeasible-fallback type bug, and dead per-treatment extraction in the 3D surface cell (all corrected in the vendored copy).