A sponsor is requesting acquisition financing at 70% LTV for The Modern Apartments in San Diego. Please stress test the deal at 135M
ls -la /vercel/sandbox/agents/01a087be-a40c-70fb-88a9-40a61b0703c2/ 2>/dev/null; find / -iname "*RealAI_Credit_Underwriting*" 2>/dev/null
Setup for The Modern Apartments (San Diego, CA) — 369-unit garden/townhome community built 1959, renovated 2020, in-place NOI ~$9.0M on the datamart T12. Before I stress-test the acquisition financing, confirming a few terms:
cd /vercel/sandbox && pip install openpyxl -q 2>/dev/null; python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("agents/01a087be-a40c-70fb-88a9-40a61b0703c2/RealAI_Credit_Underwriting_Template_v3_clean.xlsx", data_only=False)
print(wb.sheetnames)
ws = wb["Assumptions"]
for row in range(1,60):
for col in ["B","C","E","F"]:
c = ws[f"{col}{row}"]
if c.value is not None:
print(f"{col}{row}: {repr(c.value)}")
EOFcd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("agents/01a087be-a40c-70fb-88a9-40a61b0703c2/RealAI_Credit_Underwriting_Template_v3_clean.xlsx", data_only=False)
ws = wb["Assumptions"]
for dv in ws.data_validations.dataValidation:
print(dv.sqref, dv.formula1)
EOFcd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("agents/01a087be-a40c-70fb-88a9-40a61b0703c2/RealAI_Credit_Underwriting_Template_v3_clean.xlsx", data_only=False)
ws = wb["Pro Forma"]
for row in range(1,55):
for col in ["B","C","D","E","F","G","H","I","J"]:
c = ws[f"{col}{row}"]
if c.value is not None:
print(f"{col}{row}: {repr(c.value)}")
EOFimport openpyxl
SRC = "agents/01a087be-a40c-70fb-88a9-40a61b0703c2/RealAI_Credit_Underwriting_Template_v3_clean.xlsx"
OUT = "The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx"
wb = openpyxl.load_workbook(SRC, data_only=False)
A = wb["Assumptions"]
PF = wb["Pro Forma"]
PP = wb["Prepayment"]
DF = wb["Defeasance"]
# ---- Assumptions: Collateral ----
A["C5"] = "The Modern Apartments"
A["C6"] = "3201 Annrae St"
A["C7"] = "San Diego, CA 92123"
A["C8"] = "Multifamily"
A["C9"] = 369
A["C10"] = 367155
A["C11"] = "Units"
A["C13"] = 1959
A["C14"] = 0.9675
A["C15"] = "T12 Actuals"
# ---- Loan request ----
A["F5"] = "Origination"
A["F6"] = "Acquisition-Term"
A["F7"] = "2026-10-15"
A["F8"] = 94500000 # 70% LTV x $135.0M purchase price
A["F9"] = 0.059 # Freddie Mac CME 10yr fixed, ~70% LTV bucket
A["F10"] = 10
A["F11"] = 2
A["F12"] = 30
A["F14"] = 0.01
A["F15"] = "Non-Recourse"
# ---- Credit box (default) ----
A["F18"] = 0.65
A["F19"] = 1.25
A["F20"] = 1.20
A["F21"] = 0.095
A["F22"] = 0.10
A["F23"] = "default"
A["F24"] = 50
A["F25"] = 50
# ---- Sponsor & guarantee ----
A["C19"] = "Partial / Springing"
A["C20"] = "No"
# ---- Growth & exit ----
A["C28"] = 0.02
A["C29"] = 10
A["C30"] = 0.02
A["C31"] = "Deep"
# ---- Takeout terms at maturity ----
A["C34"] = 0.060
A["C35"] = 1.25
A["C36"] = 0.65
A["C37"] = 0.095
A["C38"] = 30
A["C41"] = "Deep"
# ---- Market benchmarks ----
A["F29"] = 0.072 # San Diego MF market vacancy (supply_snapshot)
A["F30"] = 0.05 # MF asset-class norm
A["F32"] = 0.4045 # San Diego MF opex ratio benchmark
A["F33"] = 0.42 # MF asset-class norm
A["F35"] = "Yes"
A["F36"] = 0.0493 # San Diego MF cap rate, 2Q26 (lender cap)
A["F44"] = "Heavy" # deliveries 3,875 YTD + 7,549 UC vs 1,630 net absorption
# ---- Rollover (multifamily -> not applicable) ----
A["F47"] = "No"
# ---- Flag thresholds: keep template defaults ----
A["F55"] = 0.90
A["F56"] = 0.30
A["F57"] = 0.10
A["F58"] = 0.03
# ---- Pro Forma: T12 (column E) ----
PF["E5"] = 12485572.08 # Gross Potential Rent
PF["E6"] = 482471.36 # Vacancy
PF["E7"] = 0 # Concessions (not broken out)
PF["E8"] = 0 # Bad Debt (not broken out)
PF["E9"] = 1067470.15 # Other Income
PF["E13"] = 792020.57 # Payroll
PF["E14"] = 297758.65 # Repairs & Maintenance
PF["E15"] = 813046.50 # Utilities
PF["E16"] = 0 # Contract Services
PF["E17"] = 0 # Turnover & Make-Ready
PF["E18"] = 213359.88 # Marketing & Administrative (advertising 37,448.65 + G&A 175,911.23)
PF["E19"] = 326764.27 # Management Fee ($)
PF["E20"] = 1306170.80 # Real Estate Taxes
PF["E21"] = 320833.83 # Insurance
PF["E22"] = 0 # Replacement Reserves (capex tracked separately, not in T12 opex)
PF["C39"] = 0.025 # Management Fee rate, lender case
PF["C40"] = 400 # Replacement Reserves $/unit, lender case
# ---- Prepayment ----
PP["C4"] = 60 # exit month 5 (year 5 of 10yr term)
PP["C5"] = 0.01
PP["C6"] = 0.02
PP["C7"] = 50
PP["C8"] = 0 # agency loan - no hard lockout, YM from day 1
PP["C9"] = 3 # 90-day open window before maturity
PP["C10"] = "Yield Maintenance"
curve = {
"D27": 0.0389, # 6mo
"D28": 0.0410, # 1yr
"D29": 0.0438, # 2yr
"D30": 0.0445, # 3yr
"D31": 0.0457, # 5yr
"D32": 0.0466, # 7yr
"D33": 0.0477, # 10yr - platform anchor (national_metrics_daily, 2026-09-03)
"D34": 0.0521, # 20yr
"D35": 0.0519, # 30yr
}
for cell, val in curve.items():
PP[cell] = val
PP["C36"] = "2026-09-03"
# ---- Defeasance ----
DF["C11"] = 25000
DF["C12"] = 40000
DF["C13"] = 10000
DF["C14"] = 15000
DF["C15"] = 10000
DF["C16"] = "Open Window"
wb.save(OUT)
print("saved", OUT)
cd /vercel/sandbox && python3 populate_model.py
Now recalculate and check integrity.
cd /vercel/sandbox && python skills/xlsx/scripts/recalc.py The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx 2>&1 | tail -50
cd /vercel/sandbox && cp "agents/01a087be-a40c-70fb-88a9-40a61b0703c2/RealAI_Credit_Underwriting_Template_v3_clean.xlsx" orig_check.xlsx && python skills/xlsx/scripts/recalc.py orig_check.xlsx 2>&1 | tail -30
Pre-existing on the unmodified template — not something I introduced. Now check integrity checks and read back key outputs.
cd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx", data_only=True)
A = wb["Assumptions"]
print("--- Key metrics H5:I20 ---")
for r in range(5,21):
print(r, A[f"H{r}"].value, "|", A[f"I{r}"].value)
print("--- Integrity checks H23:I47 ---")
for r in range(23,48):
print(r, A[f"H{r}"].value, "|", A[f"I{r}"].value)
EOFcd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx", data_only=True)
LS = wb["Loan Sizing"]
print("--- Loan Sizing ---")
for r in range(1,45):
row=[]
for col in ["B","C","D","E","F","G"]:
v = LS[f"{col}{r}"].value
if v is not None:
row.append(f"{col}{r}={v}")
if row: print(row)
EOFcd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx", data_only=True)
RA = wb["Refi Analysis"]
print("--- Refi Analysis maturity block ---")
for r in range(18,42):
row=[]
for col in ["B","C"]:
v = RA[f"{col}{r}"].value
if v is not None:
row.append(f"{col}{r}={v}")
if row: print(row)
REC = wb["Recovery"]
print("--- Recovery ---")
for r in range(1,26):
row=[]
for col in ["B","C","D","E","F"]:
v = REC[f"{col}{r}"].value
if v is not None:
row.append(f"{col}{r}={v}")
if row: print(row)
SB = wb["Stress & Break-Even"]
print("--- Stress & Break-Even ---")
for r in range(1,35):
row=[]
for col in ["B","C","D","E","F","G"]:
v = SB[f"{col}{r}"].value
if v is not None:
row.append(f"{col}{r}={v}")
if row: print(row)
PP = wb["Prepayment"]
print("--- Prepayment ---")
for addr in ["C70","C71","C72","C73","C74","C77","C78"]:
print(addr, PP[addr].value)
DF = wb["Defeasance"]
print("--- Defeasance ---")
for addr in ["C33","C39","C47","C48","C50","C51"]:
print(addr, DF[addr].value)
EOFcd /vercel/sandbox && mv "The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx" "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx" && python skills/xlsx/scripts/workbook_integrity_scan.py "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx" 2>&1 | tail -60
cd /vercel/sandbox && python skills/xlsx/scripts/workbook_integrity_scan.py "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx" --json scan.json 2>&1 | tail -5
python3 -c "
import json
d=json.load(open('scan.json'))
highs=[f for f in d['findings'] if f['severity']=='high']
print(len(highs))
for f in highs:
print(f['sheet'], f['cell'], f['category'], f.get('references'))
"PF["E20"] = 1306170.80 # Real Estate Taxes
PF["E20"] = 1661580.00 # Real Estate Taxes - CA Prop 13 reassessment at $135.0M purchase price
# (seller's actual tax was $1,306,171 on a $106.1M assessed value, an effective
# rate of 1.2308%; applied to the new basis this reassesses to ~$1.66M)OUT = "The_Modern_Apartments_Credit_UW_2026-09-11_v1.xlsx"
OUT = "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx"
cd /vercel/sandbox && rm -f "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx" && python3 populate_model.py && python skills/xlsx/scripts/recalc.py "The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx" 2>&1 | tail -20
Good — same pre-existing template error only. Now read back final figures.
cd /vercel/sandbox && python3 << 'EOF'
import openpyxl
wb = openpyxl.load_workbook("The Modern Apartments_Credit_UW_2026-09-11_v1.xlsx", data_only=True)
A = wb["Assumptions"]
print("--- Key metrics ---")
for r in range(5,21):
print(r, A[f"H{r}"].value, "|", A[f"I{r}"].value)
print("--- Flags ---")
for r in range(34,48):
print(r, A[f"H{r}"].value, "|", A[f"I{r}"].value)
LS = wb["Loan Sizing"]
for addr in ["C14","C17","C18","C19","C29","C30","C35","C36","C39","C40","C41"]:
print("LS",addr, LS[addr].value)
RA = wb["Refi Analysis"]
for addr in ["C20","C21","C28","C29","C30","C33","C40"]:
print("RA",addr, RA[addr].value)
PF = wb["Pro Forma"]
for addr in ["E28","G28","G29","G30","C44"]:
print("PF",addr, PF[addr].value)
SB = wb["Stress & Break-Even"]
for addr in ["C18","C21","C23","C24"]:
print("SB",addr,SB[addr].value)
REC = wb["Recovery"]
for addr in ["E14","E16","C20"]:
print("REC",addr,REC[addr].value)
DF = wb["Defeasance"]
for addr in ["C47","C48","C51"]:
print("DF",addr,DF[addr].value)
PP=wb["Prepayment"]
for addr in ["C70","C71","C73"]:
print("PP",addr,PP[addr].value)
EOFDecline as requested; ~$76.6M clears — not $94.5M
The Modern Apartments doesn't support a $94.5M loan (70% of the $135.0M price). Debt yield is the binding constraint: at $94.5M, debt yield is 7.70% against a 9.5% floor — the loan needs to come down to $76,604,776 (56.7% of price, 51.9% of lender value) to clear . That's an $17.9M, 18.9% cut to the request .
Why the gap is this wide. The platform's operating data for the property shows a 68% NOI margin — richer than the San Diego multifamily benchmark of 59.6% — driven by vacancy running near 3% against a 7.2% market average and a 32% expense ratio against a 40.5% submarket / 42% asset-class norm . None of that survives the credit case: floored to market vacancy and the higher of the two OpEx benchmarks, other income haircut 10%, lender-case NOI comes in at $7,277,454 — a 19% haircut off the property's own $9.0M NOI, before even reassessing property tax . San Diego is Prop 13 territory: the seller's $1.31M tax bill sits on a $106.1M assessed value; reassessed at the $135.0M purchase price that's ~$1.66M, a further ~$355K annual drag the sponsor's basis likely hasn't priced in . At $7.28M lender NOI and the market's 4.93% cap rate, lender value is $147.6M — comfortably above the $135M price, so LTV (64.0%) and interest-only DSCR (1.31x) both clear on their own. Debt yield doesn't, and it's debt yield — not LTV or DSCR — that sets the ceiling here.
| Test | Floor/Limit | Result at $94.5M request | Max Loan Supported | Pass/Fail |
|---|---|---|---|---|
| Debt Service Coverage (Amortizing) | 1.25x | 1.08x | $81.8M | FAIL |
| Debt Service Coverage (Interest-Only) | 1.20x | 1.31x | $102.8M | PASS |
| Debt Yield | 9.50% | 7.70% | $76.6M | FAIL1 |
| Loan-to-Value (on lender value $147.6M) | 65% | 64.0% | $96.0M | PASS |
There's a second problem hiding behind the 2-year IO: once amortization starts, DSCR falls to 1.08x against the 1.25x amortizing floor — the request only clears today because IO is masking it. Stretching amortization to fix it would need ~54 years, which isn't a real lever ; the fix is smaller proceeds, not a longer schedule.
Getting out at maturity clears, comfortably. Grown at 2%/yr, NOI reaches $8.87M by year 10 against an $82.8M balance . Stress the takeout +50/+50 bps (6.5% rate / 6.43% cap) and the refi still produces $89.7M against that balance — a +$6.9M cushion, 8.3% of balance . Sale exit is stronger still: 1.63x coverage after 2% selling costs . The rate/NOI stress grid is the one place this loan is thin: push the rate to 7.9% with no NOI change and IO-DSCR drops to 0.97x; 18 of 30 grid cells fall below the 1.20x floor — a value that matters more at $94.5M than it would at the $76.6M counter-offer, where the added cushion buys real room.
Prepayment risk. Exiting at year 5, yield maintenance costs $3.44M (3.79% of balance) — cheaper than defeasance ($96.1M all-in vs. prepayment's $94.2M payoff, a $1.9M saving ) but above the 3.0% materiality threshold, so call protection is a real negotiating point, not boilerplate.
Recovery is fine; the 87.6% read is a technical artifact, not loss. Value would need to fall 42.8% before principal is impaired — at every stress level tested (0/−10/−20/−30%), loss severity is 0% . The 87.6% "recovery % of par" flag compares full recovery of the amortized $82.8M balance against the original $94.5M par; it isn't a credit loss, and it improves automatically once proceeds are cut to $76.6M.
Sponsor. No PFS was provided, which caps any verdict at Approve with Structure pending guarantor review regardless of the numbers above .
Bottom line: Approve with Structure at $76,604,776 (56.7% of price), non-recourse with springing carve-outs, DSCR 1.61x / debt yield 9.5% / LTV 51.9% at that sizing — plus a cash-sweep trigger tied to the post-IO DSCR step-down and a guarantor PFS as a closing condition. The single item most likely to move this number: an actual T12/rent roll from the sponsor. If it corroborates the platform's occupancy and expense levels rather than market averages, some of this haircut unwinds — but it would need to overturn a 7-8 point OpEx-ratio gap and a nearly 4-point vacancy gap simultaneously to get anywhere close to $94.5M.
(All figures from the attached model.)
This is a read-only snapshot of a RealAI analysis.