FEMIC Hydrology Response Bundles
For a pinned synthetic FEMIC → WS4 → FHOPS walkthrough, see Hydrology Quickstart — FEMIC to WS4 to FHOPS. For the cross-repo contract index and failure matrix, see Hydrology Contract and Schema Index.
FHOPS consumes versioned FEMIC hydrology response bundles. It does not run FEMIC discovery, frequency fitting, surrogate training, or flood-risk calculation, and it does not import WS4 at runtime.
Bundle Contract
A FEMIC hydrology bundle contains manifest.json and
artifacts/<role>/<role>.json. FHOPS validates and pins:
bundle_idandbundle_version;the manifest SHA-256;
every artifact role, schema, media type, size, and SHA-256;
path containment inside the bundle;
the response-surface, flood-risk, domain, and disturbance-ledger identities;
the producer caveats and consumer contract; and
optional validation-report and model-card evidence.
Required roles are response_surface, flood_risk, domain, and
disturbance_ledger. Optional roles include the validation report, model
card, pilot run, frequency fits, and surrogate artifacts.
Python Usage
from pathlib import Path
from fhops.scenario.hydrology import (
assess_femic_hydrology_readiness,
bundle_pin,
load_femic_hydrology_bundle,
)
bundle = load_femic_hydrology_bundle(
Path("data/femic/hydrology-response-2026.10.0"),
expected_bundle_id="hydro-response-example",
expected_bundle_version="2026.10.0",
)
pin = bundle_pin(bundle)
readiness = assess_femic_hydrology_readiness(bundle)
print(pin["manifest_sha256"])
print(readiness.status)
Readiness
assess_femic_hydrology_readiness reports:
not_available: no validation report or model card is packaged;provisional: evidence exists but the model card is not reviewed;conditionally_ready: reviewed with conditions;ready: reviewed, with a recorded hydrologist review and no tail-check failures;blocked: a tail-check failure is recorded.
Missing evidence is reported as missing, never approved. A checksum pass is not a hydrologic validation. Phase 15 uses these states for screening policy; the validator itself does not grant operational use.
Scenario Pin
Register a validated bundle in a scenario without copying it:
fhops scenario hydrology register scenarios/example/scenario.yaml \
data/femic/hydrology-response-2026.10.0
The scenario gains an optional hydrology_products section:
hydrology_products:
- bundle_id: hydro-response-example
bundle_version: 2026.10.0
manifest_sha256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
domain_id: example-domain
ledger_id: example-ledger
response_surface_id: example-surface
manifest_path: ../../data/femic/hydrology-response-2026.10.0/manifest.json
readiness_status: ready
readiness_evidence_sha256: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
artifacts:
- role: response_surface
relative_path: artifacts/response_surface/response_surface.json
schema_version: femic.hydrology.flood_response.v1
media_type: application/json
size_bytes: 1234
sha256: cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
caveats:
- Screening only; not a regulatory flood map.
The pin records the bundle identity, manifest and artifact checksums, domain, ledger, response surface, readiness state, and caveats. It is a reference; the bundle is not copied into the scenario or repository. Re-registering the same pin is idempotent; reusing the same bundle id/version with a different manifest checksum is rejected. Existing scenarios without the section remain valid.
Use --dry-run to validate and print the pin without writing the scenario.
Support Mapping
Hydrology mapping is an explicit crosswalk. A CSV row names exactly one FHOPS support key and one FEMIC unit/watershed/receptor:
block_id,landing_id,road_id,unit_id,watershed_id,receptor_id,notes
B01,,,unit-1,watershed-1,receptor-1,block review
,L01,,unit-1,watershed-1,receptor-1,landing review
,,R01,unit-1,watershed-1,receptor-1,road review
Review metadata is a separate JSON document:
{
"schema_version": "fhops.hydrology.crosswalk.v1",
"crosswalk_id": "crosswalk-example",
"created_utc": "2026-10-27T00:00:00+00:00",
"review_status": "reviewed",
"reviewed_by": "reviewer-id",
"method": "Manual block/landing/road review",
"source": "Reviewed FEMIC domain bundle",
"caveats": ["Screening crosswalk only."]
}
The optional crosswalk_sha256 field pins the CSV. Missing metadata is
recorded as not_reviewed and the mapping is provisional.
Map the scenario:
fhops scenario hydrology map scenarios/example/scenario.yaml \
data/femic/hydrology-response-2026.10.0 \
reviewed-crosswalk.csv \
--metadata reviewed-crosswalk.meta.json \
--out build/hydrology_mapping
The command requires the bundle to be pinned in the scenario. It checks every
FHOPS block, landing, and road-construction id, every FEMIC unit/watershed/
receptor id, and the unit-to-watershed assignment. Complete coverage is required
unless --allow-partial records the gaps. The output is
hydrology_mapping.csv plus hydrology_mapping.json with the bundle pin,
crosswalk checksum, review state, rows, coverage, warnings, and caveats.
No centroid, buffer, nearest-watershed, or nearest-road operation is performed.
Schedule-Bound Exposure
Road and culvert exposure is an explicit table shared with WS4. FHOPS validates the ws4.hydrology.exposure.v1 contract independently and binds it to one assignments CSV.
{
"schema_version": "ws4.hydrology.exposure.v1",
"exposure_id": "exposure-2026-001",
"generated_utc": "2026-10-27T00:00:00+00:00",
"source_id": "reviewed-road-and-culvert-inventory",
"review_status": "reviewed",
"reviewer_id": "reviewer-id",
"schedule_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"watershed_ids": ["watershed-1"],
"periods": [0, 1],
"rows": [
{
"watershed_id": "watershed-1",
"period": 0,
"road_built_km": 0.0,
"road_used_km": 1.25,
"road_decommissioned_km": 0.0,
"culvert_count": 4,
"culvert_exposed_count": 1
},
{
"watershed_id": "watershed-1",
"period": 1,
"road_built_km": 0.5,
"road_used_km": 1.75,
"road_decommissioned_km": 0.0,
"culvert_count": 4,
"culvert_exposed_count": 2
}
],
"caveats": ["Screening input only."]
}
The declared watershed/period grid must be complete. Missing, duplicate, undeclared, negative, or non-finite rows fail. Reviewed metadata requires a reviewer. The schedule_sha256 must match the assignments CSV.
Use fhops.scenario.hydrology_exposure.load_hydrology_exposure with the
assignments CSV. The loader preserves the file digest, source, review state,
schedule binding, and raw features. features_for adds the calculated
densities when a positive FEMIC watershed area is supplied:
road_built_density_km_per_km2;road_used_density_km_per_km2;road_decommissioned_density_km_per_km2;culvert_exposure_per_km2.
FHOPS does not derive road state or culvert locations from geometry. A table bound to one schedule is not reused for another schedule.
Screening
Screen one assignments schedule against the pinned bundle, explicit mapping, and schedule-bound exposure:
fhops scenario hydrology screen scenarios/example/scenario.yaml \
data/femic/hydrology-response-2026.10.0 \
build/hydrology_mapping \
assignments.csv \
schedule-exposure.json \
--policy require_reviewed \
--out build/hydrology_screen
The screen computes cumulative block area by FEMIC watershed for each schedule
day, converts the day to the zero-based exposure period (day - 1), selects
the applicable response scenario, and applies the pinned flood-risk baseline and
response ratio. Block areas come from the scenario block GeoJSON area_ha
field, falling back to LiDAR block support area when necessary.
Readiness policies are allow_provisional, require_reviewed, and
require_ready. A tail-check block always refuses. Under a reviewed policy,
the crosswalk and exposure table must also be reviewed. Missing mapping,
exposure periods, block areas, scenarios, or flood-risk rows produce explicit
refusals; without --allow-refused the command exits non-zero.
Outputs are hydrology_screen.csv and hydrology_screen.json. Every row
carries the harvest fraction, exposure features, selected scenario, response
ratio, baseline flow, screening peak flow, and any producer receptor values.
The manifest carries bundle/mapping/exposure identities, exposure and schedule
digests, readiness, coverage, refusals, warnings, and the producer plus
screening-only caveats.
This is a one-schedule CLI screen. The optimizer does not consume a fixed exposure table; schedule-derived exposure for each candidate remains deferred.
CLI
Validate a delivered bundle without modifying a scenario:
fhops scenario hydrology validate data/femic/hydrology-response-2026.10.0
fhops scenario hydrology validate data/femic/hydrology-response-2026.10.0 \
--expected-bundle-id hydro-response-example \
--expected-bundle-version 2026.10.0
The command emits a deterministic JSON report and exits non-zero on an invalid
bundle. Use --no-verify-checksums only for a diagnostic inspection; the
default verifies every size and SHA-256.
Validate a schedule-bound exposure table and, optionally, its assignments CSV:
fhops scenario hydrology exposure build/exposure.json
fhops scenario hydrology exposure build/exposure.json \
--schedule build/assignments.csv
The command emits the validation report and exits non-zero when the table is invalid or its declared schedule hash does not match.
Limits
P15.4 validates the response bundle, maps an explicit crosswalk, and loads a schedule-bound exposure table. It does not screen a schedule, produce per-watershed risk rows, integrate flood exposure into the optimizer, or create a flood map or regulatory result. The committed synthetic bundle and exposure fixtures are not real watershed, road, culvert, or gauge records.
Later Phase 15 tasks add scenario registration, an explicit crosswalk, schedule-bound road/culvert exposure, and one-schedule screening.
Operational Hazard Windows
Phase 16 adds a separate operational hazard contract. It is not a FEMIC response bundle and does not run a hydrology model.
{
"schema_version": "fhops.hydrology.hazard.v1",
"hazard_id": "hazard-2026-001",
"generated_utc": "2026-10-27T00:00:00+00:00",
"source_id": "reviewed-operational-forecast",
"review_status": "reviewed",
"reviewer_id": "reviewer-id",
"windows": [
{
"watershed_id": "watershed-1",
"start_day": 1,
"end_day": 2,
"severity": "watch",
"return_period_years": 2.0,
"source_id": "reviewed-operational-forecast",
"notes": "Watch window."
},
{
"watershed_id": "watershed-1",
"start_day": 3,
"end_day": 4,
"severity": "warning",
"return_period_years": 10.0,
"source_id": "reviewed-operational-forecast",
"notes": "Warning window."
},
{
"watershed_id": "watershed-1",
"start_day": 5,
"end_day": 5,
"severity": "closure",
"return_period_years": 50.0,
"source_id": "reviewed-operational-forecast",
"notes": "Closure window."
}
],
"caveats": ["Operational screening only."]
}
Severity ranks are closure > warning > watch. A lookup returns the
highest severity covering a watershed/day, or nothing outside the declared
windows. Overlapping windows of the same severity are rejected; overlapping
windows of different severity are allowed with a warning that the highest
severity applies.
Validate the table with:
fhops scenario hydrology hazard validate hazard.json
The command emits JSON and exits non-zero on an invalid table. FHOPS does not derive hazard windows from weather or hydrology at runtime.
Road and Culvert Assets
Phase 16 asset evidence is explicit; FHOPS does not infer assets from geometry.
{
"schema_version": "fhops.hydrology.assets.v1",
"inventory_id": "assets-2026-001",
"generated_utc": "2026-10-27T00:00:00+00:00",
"source_id": "reviewed-road-culvert-inventory",
"review_status": "reviewed",
"reviewer_id": "reviewer-id",
"assets": [
{
"asset_id": "R1",
"asset_type": "road",
"watershed_id": "watershed-1",
"road_job_id": "R1",
"vulnerability_class": "high",
"notes": "Road asset."
},
{
"asset_id": "C1",
"asset_type": "culvert",
"watershed_id": "watershed-1",
"road_job_id": null,
"vulnerability_class": "moderate",
"notes": "Culvert asset."
}
],
"caveats": ["Operational screening only."]
}
Road assets require a scenario road_job_id; culverts do not. Every asset
watershed must appear in the hydrology mapping. Validate and map with:
fhops scenario hydrology assets validate assets.json
fhops scenario hydrology assets validate assets.json \
--scenario scenarios/example/scenario.yaml \
--mapping build/hydrology_mapping
The command reports asset count, mapped road jobs, watersheds, warnings, and caveats. No asset is converted into a damage curve or a flood-risk finding.
Operational Constraint Check
Check one assignments schedule against fixed hazard windows:
fhops scenario hydrology constraint-check scenarios/example/scenario.yaml \
build/hydrology_mapping \
assignments.csv \
hazard.json \
--assets assets.json \
--out build/hydrology_constraint_check
The check maps each scheduled block to a FEMIC watershed, looks up watch/ warning/closure severity for the day, and emits one event per activity. Assets in the same watershed are attached as context. Closure activity fails by default; –no-fail-on-closure reports it without failing. Warning activity is informational unless –fail-on-warning is set.
Outputs are hydrology_constraint_events.csv and hydrology_constraint_check.json. Missing block mapping, hazard evidence, or asset mapping refuses. This is an operational exposure check against a fixed hazard, not a watershed flood model.
End-to-End Path
The P15.6 integration test runs the complete synthetic path through the CLI:
fhops scenario hydrology validate BUNDLE
fhops scenario hydrology register SCENARIO BUNDLE
fhops scenario hydrology map SCENARIO BUNDLE CROSSWALK --out MAPPING
fhops scenario hydrology exposure EXPOSURE --schedule ASSIGNMENTS
fhops scenario hydrology screen SCENARIO BUNDLE MAPPING ASSIGNMENTS EXPOSURE --out SCREEN
The test also covers a tampered bundle, a schedule-hash mismatch, and the reviewed-policy failures. It is synthetic and makes no real watershed or regulatory claim.
Solver Boundary
FHOPS solvers do not consume hazard windows. The supported enforcement point is
fhops scenario hydrology constraint-check, which fails closure activity and
reports warning/watch exposure. A solver-side closure constraint is deferred
until a single shared block/day availability hook is honoured by the MILP,
heuristics, playback, and rolling-horizon paths.
Operational End-to-End Path
The P16 integration test runs the operational path through the CLI:
fhops scenario hydrology hazard validate HAZARD
fhops scenario hydrology assets validate ASSETS --scenario SCENARIO --mapping MAPPING
fhops scenario hydrology constraint-check SCENARIO MAPPING ASSIGNMENTS HAZARD \
--assets ASSETS --out CHECK
It covers watch/warning/closure reporting, default closure failure, an explicit no-fail policy, a tampered hazard, and an unknown road asset. It is synthetic and makes no watershed or regulatory claim.