Tree Inventory Contract

FHOPS consumes a producer-neutral individual-tree inventory. It does not perform individual-tree detection, crown segmentation, species classification, or raw point-cloud processing. The producer (FEMIC, an ITD/ITC pipeline, or a reviewed tree list) supplies the records; FHOPS validates and references them.

The phase plan is notes/tree_scale_simulation_plan.md.

Inventory Format

The inventory is a UTF-8 CSV with a sidecar JSON metadata file:

tree_id,block_id,x_m,y_m,elevation_m,species_code,dbh_cm,height_m,\
crown_radius_m,status,confidence,source_id,source_tile_id,\
merchantable_height_m,defect,grade_hint
ST001,SYNTH_B01,881712.0,627512.0,412.0,Fd,28.0,22.0,2.4,live,0.94,\
synthetic,T01,,,

Required columns are tree_id, block_id, x_m, y_m, species_code, dbh_cm, height_m, status, and confidence. Optional columns cover elevation, crown radius, source identifiers, merchantable height, defect, and grade hints. Species codes are preserved as supplied; FHOPS does not silently normalize or remap them.

Metadata declares the schema version, inventory identity, generation time, source, producer, method, CRS, units, review state, reviewer, block IDs, caveats, row count, and optional CSV SHA-256:

{
  "schema_version": "fhops.tree.inventory.v1",
  "inventory_id": "synthetic-block-001",
  "generated_utc": "2026-10-27T00:00:00+00:00",
  "source_id": "synthetic-tree-fixture",
  "producer": "FHOPS synthetic fixture",
  "method": "Deterministic synthetic point list; not an ITD/ITC run.",
  "crs": "EPSG:3005",
  "units": {
    "x_y": "m",
    "elevation": "m",
    "dbh": "cm",
    "height": "m",
    "crown_radius": "m"
  },
  "review_status": "reviewed",
  "reviewed_by": "fixture-reviewer",
  "block_ids": ["SYNTH_B01"],
  "caveats": ["Synthetic contract fixture; not a real tree map."],
  "tree_count": 12,
  "inventory_sha256": "..."
}

If inventory_sha256 is present it must match the CSV. If review_status is reviewed, reviewed_by is required. Missing metadata, duplicate tree IDs, unknown blocks, non-finite dimensions, negative DBH/height/crown values, confidence outside 0–1, or a tree outside the declared block set fail.

Scenario Pin and Block Map

Register a validated inventory in a scenario without copying it:

fhops tree register scenarios/example/scenario.yaml \
  tests/fixtures/tree_inventory/synthetic_block/inventory.csv \
  --metadata tests/fixtures/tree_inventory/synthetic_block/inventory.meta.json

The scenario gains an optional tree_inventory section:

tree_inventory:
  inventory_id: synthetic-block-001
  inventory_sha256: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  metadata_sha256: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
  inventory_path: ../../trees/inventory.csv
  metadata_path: ../../trees/inventory.meta.json
  crs: EPSG:3005
  review_status: reviewed
  reviewed_by: reviewer
  source_id: synthetic-tree-fixture
  producer: FHOPS synthetic fixture
  method: Deterministic synthetic point list; not an ITD/ITC run.
  tree_count: 12
  block_ids: [SYNTH_B01]
  caveats:
    - Synthetic contract fixture; not a real tree map.

The pin records both checksums, review state, producer provenance, tree count, and block memberships. Re-registering the same inventory is idempotent; changing the inventory or metadata under the same identity is rejected. The inventory is referenced, not copied.

Map the pinned inventory to blocks and reconcile block evidence:

fhops tree map scenarios/example/scenario.yaml --out build/tree_map

The command requires a scenario pin. It resolves every tree to a scenario block, reports blocks without trees, and compares tree count and a crude gross-volume proxy with stem_density_per_ha and work_required. The proxy is not merchantable volume; stem-level volume is P17.3. Use --strict to refuse when reconciliation warns. Outputs are tree_inventory_map.csv and tree_inventory_map.json.

CLI

Validate an inventory, optionally against a known block set:

fhops tree inventory validate tests/fixtures/tree_inventory/synthetic_block/inventory.csv \
  --block SYNTH_B01

The command emits a deterministic JSON validation report and exits non-zero on an invalid inventory.

Fixture

tests/fixtures/tree_inventory/synthetic_block contains a deterministic 12-tree, 1 ha synthetic block in EPSG:3005. It exists to test the contract. Its species, dimensions, positions, and provenance are fabricated; it is not a real LiDAR-derived tree inventory or a tree map.

Limits

P17.1 defines and validates only the inventory contract. It does not map trees to a scenario, derive stem volume or bucking, simulate machines, or export 3D scenes. See Stem Volume and Bucking for the P17.3 stem layer. The current FEMIC/LidarBC bundle contract has no individual-tree product; a real tree list must be supplied by a producer and reviewed before any operational tree map is claimed.