DEV Community

Cover image for How to Use AI to Compare Two Versions of the Same Real Estate Feasibility Model Published
Real Estate Hub
Real Estate Hub

Posted on

How to Use AI to Compare Two Versions of the Same Real Estate Feasibility Model Published

Comparing two versions of a real estate feasibility model sounds like a different problem. It's mostly an interpretation problem. Excel can tell you that 214 cells changed. It can't tell you that three of those changes explain a four-point swing in IRR and the other 211 are formatting side effects. Pairing a deterministic cell diff with an AI explanation layer gets you closer to what a reviewer needs. This post walks through a workable approach, what each piece is for, and where it breaks.

Why Comparing Feasibility Model Versions Is Harder Than a Cell Diff

Files like Model_v7.xlsx and Model_v8_final2.xlsx tend to differ in three ways. Inputs change on purpose, as when sales prices, land cost, or absorption get updated. Formulas change on purpose, for example, when someone adds a new cost line. And things change by accident: a pasted value over a formula, an inserted row that shifted references, a scenario selector left on the wrong case.

A raw diff treats all of these the same. A reviewer cares about which changes touched assumptions, which changed logic, and which moved the outputs. That's the layer AI is good at, provided it works from facts you extracted rather than from the raw file.

Step One: Extract Both Versions Deterministically

Don't ask a language model to read two workbooks and find the differences. Extract cells with code, so the diff is reproducible and checkable. With openpyxl, you can load each file twice, once for formulas and once for cached values.

from openpyxl import load_workbook

def read_cells(path):
wb_f = load_workbook(path, data_only=False)
wb_v = load_workbook(path, data_only=True)
cells = {}
for ws in wb_f.worksheets:
ws_v = wb_v[ws.title]
for row in ws.iter_rows():
for c in row:
if c.value is None:
continue
is_formula = isinstance(c.value, str) and c.value.startswith("=")
cells[(ws.title, c.coordinate)] = {
"formula": c.value if is_formula else None,
"input": None if is_formula else c.value,
"value": ws_v[c.coordinate].value,
}
return cells

One caveat: cached values only exist if the file was last saved by Excel. If a script wrote the workbook, values may be empty until it's recalculated, so check for that before trusting the output.

Step Two: Classify Changes Into Inputs, Formulas, and Hardcodes

def diff(old, new):
changes = []
for key in old.keys() | new.keys():
a, b = old.get(key), new.get(key)
if a == b:
continue
if a is None or b is None:
kind = "added_or_removed"
elif a["formula"] and not b["formula"]:
kind = "formula_to_hardcode"
elif a["formula"] != b["formula"]:
kind = "formula_changed"
elif a["input"] != b["input"]:
kind = "input_changed"
else:
kind = "value_changed" # downstream effect only
changes.append({"cell": key, "kind": kind, "old": a, "new": b})
return changes

This gives you a typed change list. The formula_to_hardcode category is worth reading first, because typed values replacing formulas are among the most consequential accidental changes.

Step Three: Separate Root Causes From Downstream Effects

In a feasibility model, one changed input can alter hundreds of dependent cells. If you hand the AI all of them, the explanation gets noisy. Keep the root changes (input_changed, formula_changed, formula_to_hardcode, added_or_removed) and treat value_changed as downstream effects to summarize rather than explain one by one.

Then pull the output metrics you care about for both versions: IRR, equity multiple, development margin, residual land value, peak debt. Keep the sheet and cell addresses attached so everything stays traceable.

Step Four: Ask the Model to Explain the Change, Not Discover It

Now the AI layer is useful. Send a structured payload: the root changes, the before and after values of the headline outputs, and the labels from neighboring cells so the model knows that C14 is "Sales price per sqm" rather than just C14. You can pull labels by reading the cell to the left or the row header.

A prompt along these lines works

You are reviewing two versions of a real estate feasibility model. Using only the changes listed below, explain which changes most plausibly drove the movement in IRR and residual land value. Cite the sheet and cell for every claim. If the listed changes can't explain the movement, say so. Flag any formula replaced by a hardcoded value.

The "say so" instruction matters. Without it, models tend to produce a tidy story even when the evidence doesn't support one.

What to Do With the AI Output

Treat the explanation as a reviewer's first draft. Before anyone reads it, run two cheap sanity checks in code. First, confirm that every cell reference the model cited actually exists in your change list, since a made-up address is the clearest sign the explanation drifted from the evidence. Second, confirm that the direction of each claimed effect matches the data: if the explanation says a higher land cost lowered residual land value, check the before and after values rather than assuming. A good output looks like a short list of root changes, each tied to cell references, with a plain-language statement of what it likely did to returns. The reviewer opens those cells and confirms. Anything the AI describes without a cell reference should be treated as unverified.

You can also run an attribution check yourself. Reapply changes one at a time to a copy of the old version and recalculate, which tells you how much each change moved IRR. It's slower, but it's the only way to be sure about contribution, because feasibility models are non-linear and changes interact.

Limitations Worth Planning For

A few things will trip up this pipeline. Named ranges, array formulas, and data tables don't always parse cleanly. External links to other workbooks are invisible to openpyxl. Inserted rows shift addresses, so a cell-address diff reports huge numbers of changes when only one row was added, and matching rows by label instead of address helps. Macros that write values at open aren't captured. And a language model can still misread a convention, so its commentary needs checking against the cells.

Scale is another consideration. A large workbook can produce thousands of root changes after a restructure, which won't fit in one prompt and shouldn't be summarized blindly. Group changes by sheet, explain each group separately, and only then ask for a combined view.

Keep confidentiality in mind too. Sending a development model's assumptions to an external API is a data-handling decision, so check your organization's policy and the provider's data terms before wiring this up.

Where Packaged Tools Fit

If you'd rather not build this yourself, teams evaluating existing options for model comparison, auditing, and feasibility workflows may look at EstateMaster, Deepblocks, Northspyre, Aprao, and Feasibilitypro.AI, and the comparison comes down to how each handles Excel workbooks, cell-level citations, version history, scenario analysis, and data security. Capabilities change, so verify current details directly with each vendor.

A Reliable Workflow for AI-Assisted Model Comparison

The dependable version of AI-assisted model comparison is deterministic extraction, typed change classification, root-cause filtering, and an AI explanation with cell citations. Each step makes the next one checkable, and the person reviewing still owns the conclusion, including the call on whether a flagged change was intentional.

What does your team do today when a model goes from v7 to v8, and the IRR moves? Share your approach in the comments.

Top comments (0)