Skip to content

Extracting Findings and Recommendations From a Home Inspection Report

11 min read · updated August 11, 2026

The reason to extract a home inspection report is triage: out of ninety findings, which handful actually matter. That depends entirely on the severity rating attached to each one — and the severity vocabulary is not standardised. It is defined by the inspector’s software, on a legend page inside the same report, and it differs between reports.

The severity vocabulary belongs to the report

Professional bodies such as ASHI and InterNACHI publish standards of practice that govern what an inspector must examine and report. Those standards are about scope. They do not impose a severity scale, and inspectors do not share one. What you will actually meet, depending on the reporting platform and the inspector’s configuration, is rating sets along the lines of:

  • Safety hazard / major defect / repair or replace / monitor / maintenance / cosmetic
  • Deficient / marginal / satisfactory / not inspected
  • A numeric or coloured scale with a key
  • No rating at all, with severity expressed only in the prose (“recommend evaluation by a licensed electrician prior to closing”)

The consequence for extraction is direct and it is the point of this page: do not map to a fixed enum at extraction time. Extract the rating as the literal string the report used, and separately extract the report’s own legend — the block, usually in the first few pages, that defines each term. Store both. Normalisation to your internal scale is then a second, explicit step with the legend as its input, which means it is inspectable and correctable, rather than a judgement the model made and did not record.

Why this matters concretely: “monitor” means “not a defect now, watch it” on most templates, and a normaliser that maps it to a repair item inflates every report by a third. Meanwhile “major defect” on one template and “deficient” on another may be the same tier or two tiers apart, and only the legend tells you. A pipeline that hard-codes a mapping learned from one inspector’s reports will be quietly wrong on the next inspector’s.

Where there is no rating, do not synthesise one from the prose and present it as extracted. Record rating: null with a separate, clearly-labelled inferred_urgency field if you need one, so the distinction between what the inspector said and what your system concluded survives into the database. That separation is the same discipline described in extracting first and reasoning second.

Findings hang off a system hierarchy

A finding is not a free-floating sentence. It sits at a position in a hierarchy — Roof, then Flashings, then a specific observation — and the hierarchy is expressed by heading levels rather than repeated on each finding. “Rust visible at the base” is uninterpretable without the two headings above it, and a flat extraction of finding-sentences produces exactly that.

So the extraction carries system, component and, where the report gives it, location (“northeast corner”, “second floor bathroom”). Location is usually inside the finding text or in a photo caption rather than in the heading, and it is the field that decides whether two similar findings are one problem or two.

The other structural field is the recommendation, which is separate from the observation and often uses a distinct verb pattern: “recommend”, “further evaluation by”, “should be repaired by a qualified”. The trade named in the recommendation — electrician, roofer, structural engineer — is directly useful for triage and routing, so extract it as its own field rather than leaving it inside the sentence. A recommendation for evaluation by a structural engineer is a materially different item from a recommendation to caulk, regardless of what rating either carries.

What was not inspected is a finding

Every report contains a limitations section, and most contain limitation notes scattered through the body: the crawlspace was not entered due to standing water, the roof was not walked due to pitch and was observed from the ground, the electrical panel cover was not removed, areas were obstructed by stored items.

These are routinely dropped as boilerplate, and dropping them inverts the meaning of the report. A section with no findings because the inspector examined it and found nothing is not the same as a section with no findings because the inspector could not get to it — and the second is precisely where the expensive surprises live. Extract limitations as their own array, each tied to the system it constrains, and compute a coverage view: for every system in the report’s scope, was it inspected, partially inspected, or not inspected.

The same reasoning applies to systems that are simply absent from the report. Scope is set by the standard of practice the inspector works to, and by the agreement, so a report with no chimney section may mean there is no chimney or may mean chimneys are outside scope. Extract the declared scope where the report states it, and treat absence as unknown rather than as satisfactory.

The summary duplicates the body

Nearly every report has a summary section listing the significant findings, and every one of those findings also appears in the body of the report, usually with more detail and different wording. Extract both without deduplicating and your finding count is inflated by however many made the summary; extract only the summary and you have lost everything the inspector judged less significant, which is most of the report.

The correct treatment is to extract the body as the record and the summary as a flag on it. Match on system plus component plus location rather than on text, because the summary is a rewrite rather than a copy — embedding similarity within a component is a reasonable matcher where the strings differ, and it is bounded enough to be cheap because you only compare within one component. Record in_summary: true on the matched body findings, and treat a summary item that matches nothing in the body as an exception worth reviewing, since it usually means the body finding was extracted under the wrong heading.

Where it breaks

The photograph carries the finding. Some templates put a numbered photo and a one-line caption where the finding text would be, so the observation exists only as a caption. Captions sit outside the text flow and are easily lost. Extract them explicitly and treat a section whose findings are all captions as a normal case rather than an empty one.

Reports are generated, not typed, and the generator repeats itself. Platform-generated reports include per-component informational blocks — material type, approximate age, standard maintenance advice — that read exactly like findings and carry no rating. If your finding count is three times what a human would say, this is why. Filter on the presence of a rating or a recommendation verb, and validate the filter against a handful of reports from each platform you see.

Page count and cost scale badly. A sixty-page report with a hundred photographs does not fit a single request comfortably, so it is chunked — and chunking mid-section separates a finding from the heading that gives it meaning. Chunk on section boundaries detected from the heading structure, never on a fixed page count.

Ratings appear as colour alone. Some templates carry severity as a coloured bar or an icon with no text. Colour is not recoverable from a greyscale scan and is not reliably describable by a model, so on those templates the rating must come from the icon shape or from the legend’s position, and where neither is readable the honest output is null. A guessed severity in a triage system is worse than a missing one, because a missing one gets looked at.