0099 — Trending occupancy counts pending applications and subtracts notices
- Status: Accepted
- Date: 2026-07-16
- Deciders: Sean (specified), Fede (confirmed) — 2026-07-16 afternoon standup
Context
Since 2026-07-13 (ADR-0093 dedup + the shared trending-occupancy.ts module) the
Trending occupancy figure was (occupied + vacantLeased + approvedUnits) / totalUnits — vendor-convention-aligned: unsigned applications excluded (the vendor
bar for a forward figure is a signed/executed lease) and notices never subtracted
(no vendor formula blanket-subtracts them).
At the 2026-07-16 afternoon standup the team reviewed the occupancy card (83.3% now → 84.2% trending, the +1 being Unit 308's signed-not-countersigned lease) and decided on a more inclusive house methodology. Sean, verbatim from the transcript: "if they put an application, it should be [counted]. If the application is approved, it should be. If the lease is signed… even if they haven't moved in yet… those 3 categorizations should count towards the trending occupancy"; "let's just count it towards the trending, unless it gets denied, and then… it would get taken back"; and "if a unit's on notice, then it would also go against the trending occupancy" (Fede: "Yes."). Yale 25 Station's "approved and with deposits" bar was considered as a reference and explicitly not adopted.
Decision
One shared formula, every surface (computeTrendingOccupancy() — dashboard
OccupancyCard, LeasingSection projection, MetricInsight dock, owner-report email):
(occupied + vacantLeased + approvedUnits + pendingUnits − noticeUnits) / totalUnits
- pendingUnits — units newly covered by a submitted-but-undecided
application. Counts on submission; the AppFolio rental-application sync pulls
it back within one 5-minute poll when the PMS denies (and its ADR-0097 orphan
pass retires unlinkable strays). Unit-deduped via
countApprovedUnits()(ADR-0093), additionally excluding units the approved term already claimed, and staleness-bounded 30 days like the approved term. - noticeUnits — units whose resident gave notice, subtracted. They sit
inside
occupied, so the subtraction nets them out. No extra lookahead window: a notice only exists once filed and lease notice periods are 30–60 days, so the status is self-bounding; an arbitrary cutoff would add a cliff with no real-world event behind it. - Captions on the card name every non-zero component ("+1 moving in · +1 pending application · −4 on notice") so the number stays explainable, and a pending caption flips to "approved" when the application is approved.
Known limitations / consequences
- Notice-Rented conflation. PropFlow maps both AppFolio notice flavors
(
Notice-Rented,Notice-Unrented) to the singlenoticeunit status, so a re-leased notice also subtracts — diverging from RealPage's NTV-L routing (which counts it toward leased). When a rented/unrented split lands in the unit model, pass only unrented to the formula. - Vendor divergence is deliberate. Counting unsigned applications matches no verified vendor formula; the deny-pullback sync + staleness bound are the honesty guards. The prior vendor-aligned rationale is preserved in the module doc for the day this is revisited.
- Trending can now honestly read below current occupancy (notices outpacing inbound demand) — the card renders that as a real downward projection, which is the point.
- With 2026-07-16 verified data (Camellia): (100 + 1 + 0 + 1 − 4) / 120 = 81.7%, versus 84.2% under the old formula.