Skip to content

fix(fmsr): match failure-mode records on asset_class only - #553

Merged
ShuxinLin merged 2 commits into
refactor/drop-fmsr-generate-toolfrom
fix/fmsr-asset-class-matching
Sep 25, 2026
Merged

ShuxinLin merged 2 commits into
refactor/drop-fmsr-generate-toolfrom
fix/fmsr-asset-class-matching

Conversation

@ShuxinLin

@ShuxinLin ShuxinLin commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Fixes two asset-class lookup bugs in the FMSR server.

Stacked on #552 (refactor/drop-fmsr-generate-tool). Merge that first; this PR's base will then switch to main.

1. Stored classes with capitals or punctuation could not be found. The CouchDB loader stores each record as _id = "fm:" + asset_class using the raw name (src/couchdb/loader.py:_make_id). The server lowercased the input and then matched exactly on fm:<key> and on asset_class == key. As a result, a record such as "asset_class": "Hydraulic Pump" was never found, and add_failure_modes created a duplicate record next to it. This stayed hidden because the only sample record is "pump".

2. Digits were stripped from class names. re.sub(r"\d+", "", ...) turned CO2 Compressor into co compressor, Type 2 Chiller into type chiller and 3-Phase Motor into phase motor.

Fix Details

  • Match on asset_class only, never on _id. The server reads the records' asset_class values (a small collection, capped at 10,000) and compares the normalised names in Python.
  • Simple normalisation, applied the same way to input and stored names: it ignores case, punctuation, _ and whitespace, and leaves digits alone. The caller is expected to pass a real class name. Instance ids like Pump-1 are not rewritten.
  • Not-found errors suggest close matches ("Did you mean: Hydraulic Pump?") alongside the available classes, so an agent can correct its input.
  • add_failure_modes keeps the stored asset_class name when it updates a record. New records are still created as fm:<normalised name>.
  • Ties: if several records normalise to the same name, the lowest _id wins, deterministically.
  • Agent guidance in the tool descriptions: each asset_class description now tells the agent to pass a generic equipment type rather than an asset id (for "Chiller 6", use "chiller"). get_failure_modes says to retry with a class suggested in the error. add_failure_modes says to reuse an existing class name where one fits, to avoid near-duplicate classes.

Impact on Benchmarking

  • No change to baselines
  • Baseline change (possible)
    • Class-name inputs such as pump, Pump and hydraulic_pump behave as before for the bundled pump sample.
    • Inputs that are really instance ids (Pump-1) no longer map to pump. They now return a not-found error that suggests pump.
    • No before/after benchmark run was done.

Related Issues

Verification Steps

  1. uv run pytest src/servers/fmsr -q passes (32 tests).
  2. uv run pytest src/ -k "not integration": 19 failures, the same set that fails on main (iot test_invalid_site, test_static_json_scorer, test_file_exporter). None are in fmsr.

New tests cover:

  • stored names with capitals or punctuation, and _ids not in the fm:<class> form
  • digits kept in class names
  • instance ids rejected, with a suggestion
  • _id never used for matching
  • duplicate normalised classes
  • add updating the matched record in place

Test gaps closed:

  • FakeDatabase.find returned the stored dicts themselves, so write tests passed even if save was never called. It now returns copies.
  • FakeDatabase now enforces _rev conflicts the way CouchDB does.
  • There are now tests for a failed save and for a concurrent update (conflict).

Checklist

  • I have added tests that prove my fix is effective.
  • My code follows the project's Ruff formatting rules. ruff check still reports the file's existing List/Optional typing-style warnings (UP006/UP045).
  • I have signed off my commits (DCO).

- Look up records by comparing normalised asset_class values in Python
  instead of by _id. The loader keys docs as fm:<raw asset_class>, so
  classes like 'Hydraulic Pump' were unreachable by the lowercased key.
- Normalise only case, punctuation and whitespace; stop stripping digits,
  which turned 'CO2 Compressor' into 'co compressor'.
- Keep the stored asset_class name when updating a record.
- Suggest close matches in the not-found error.

Tests: FakeDatabase now returns copies from find() and enforces _rev
conflicts like CouchDB; add coverage for write failures, concurrent
updates, duplicate normalised classes and non-fm: _ids.

Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
@ShuxinLin
ShuxinLin merged commit 8fb5a8c into refactor/drop-fmsr-generate-tool Sep 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant