The Saturday Reminder
Investigation · PM-facing notifications & office hours · Camellia Apartments · Sat Aug 15, 2026 · Proposed — pending Fede's review · no changes made
In one paragraph. On Saturday Aug 15 at 1:00 PM Clara emailed the Camellia office "Still waiting on your signature — Juan Lucero (Unit 401)". Fede's rule is that PM notifications go out during office hours only, and Camellia's office is not open Saturdays — Saturday is tours-by-appointment. But the property's stored office hours say Saturday 1:00–4:30 PM open (that is the tour window), and the reminder gate reads exactly that field — so it correctly held the reminder from 10:10 AM and released it at 1:00 PM, the moment the stored hours said "open". The gate worked as built; the data it reads means "when can tours happen", not "when is a person in the office". Separately, the first notice of any PM action is deliberately not gated at all — a decision recorded on Jul 28 as Fede's — and that is where most off-hours emails come from.
What actually happened to Juan Lucero (unit 401)
| When (Denver) | What | Inside stored hours? | Inside real staffed hours? |
| Fri Aug 14, 10:09 AM | AppFolio emails the office: renewal ready to countersign (Juan signed) | AppFolio's own email |
| Fri Aug 14, 10:10 AM | Clara's first notice to the office (+ copy to hello@): "A renewal is ready for your signature" | ✅ Yes | ✅ Yes |
| Sat Aug 15, 1:00 PM | Clara's reminder #1: "Still waiting on your signature" | ✅ Yes — Sat 1:00–4:30 is stored as open | No — office closed Saturday |
Why 1:00 PM and not 10:10 AM (24h after the first notice)? Because the gate did its job: 10:10 AM Saturday is before the stored Saturday open of 1:00 PM, so it deferred to open. That is the confirmation the gate reads the stored hours literally.
Also confirmed: the lease is genuinely still un-countersigned (nothing from AppFolio since the Friday notice), so the reminder's premise was true — it was only the timing that was wrong. The Friday first-notice was opened 8 times at the office.
Root cause 1 — one field, two meanings
officeHours in the property knowledge base is a plain per-day open/close map. It was built for tour availability, and Camellia's Saturday 1:00–4:30 entry is correct for that purpose — tours really do happen then. But six other parts of the system read the same field as "a human is in the office":
- PM reminder scheduling (this incident).
- Voice after-hours check — decides whether a caller is offered the emergency line. Saturday afternoon reads as "in hours", so a Saturday caller with a real problem is not pointed to the emergency line.
- Key-pickup slots for move-ins — could offer a Saturday pickup at a closed office (the code's own comment names "sending a resident with a moving truck to a closed office" as the failure to avoid).
- Move-in calendar placement and vendor-visit default time — both place events at "office open".
There is no separate "staffed hours" or "PM notification hours" concept anywhere. The closest thing is a per-day tour rule (tourDayPolicy) whose own documentation describes exactly Camellia's situation — "an office staffed Mon–Fri by a team and Saturdays by one person on appointment-only coverage" — but that flag only controls same-day tour booking, nothing else.
Two smaller inconsistencies noted for completeness: the fallback window when a property has no stored hours is Mon–Fri 9–6 (not 9–5), and the reminder gate deliberately ignores holiday closures (accepted tradeoff in code comments).
Root cause 2 — the first notice is not gated, on purpose
Only follow-up reminders are held to office hours. The first notice of any PM action ("a lease is ready for your signature", "an application needs review", execution notices) sends the moment the triggering event lands — midnight included.
This is recorded as Fede's decision on Jul 28, 2026, in three places with the same wording: the code comment, PR #4769's description, and the design doc PM Notifications — State & Gaps: "O1 accepted — window = property office hours, reminders only; O2 dropped — Clara always sends her initial… midnight initials remain by design; the future lever, if it ever bothers the team, is widening the O1 gate to initials."
caveat None of the three is a direct quote of Fede's words, and no Slack/Trello source is linked (unlike ADR-0104, which links its sources). If Fede's actual instruction was "office hours for everything", the write-up narrowed it. Either way the record explicitly anticipated widening the gate later.
The audit says it matters: of 34 PM-facing emails Camellia received Aug 12–15, 27 were outside Mon–Fri 9–5. Roughly 20 were ungated first notices / execution notices between 11 PM and 4:40 AM (a batch of leases and applications processed overnight); 5 were Saturday sends passing through the "Saturday is open" gap; the rest were edge cases. (Four-day sample; a 30-day census is an open item.)
What is NOT broken
- Tenant-facing timing is a separate, working gate: texts/emails to residents are held to 8 AM–9 PM property-local, seven days (the legal texting window), deferring anything outside it. Juan's renewal texts at 5:50 PM Sunday and 6:00 PM Friday were inside that window. If the team wants residents texted only on weekdays, that's a policy choice, not a bug.
- Reminders on weekdays are landing inside 9–5 as designed; the 1 AM incident class from July is closed.
Timeline of the rule (for the record)
- Jul 21 — PM action reminders ship (ADR-0104). No time-of-day rule.
- Jul 24 — Fede flags a duplicate email; weekend nudges deferred to Monday 9 AM.
- Jul 27 — 12:15 AM first notice + 1:00 AM nightly reminders hit the Camellia inbox.
- Jul 28 — Design session; O1 (reminders held to stored office hours) accepted, O2 (suppress AppFolio duplicates) dropped, first notices left ungated. Shipped same day.
- Aug 15 (Sat) — this incident: reminder released at the stored Saturday "open" of 1:00 PM.
Gera's work in the area: extended this same reminder engine to chase forwarded questions (Jul 23), timezone-rendering hardening (Aug 6), and a fix so a relocated escalation resolves rather than cancels its cadence (Aug 7). Gera did not touch the office-hours gating.
Decisions
D1 · Stop treating tour-only hours as staffed hours this incident
A.Recommended: add a per-day "appointment-only / not staffed" flag next to the stored hours (Camellia: Saturday). The reminder gate, voice after-hours check, key-pickup, move-in placement and vendor placement treat such days as closed; tour availability keeps using the hours as-is. Six call sites, each an additive check; Saturday tours untouched.
B.Data-only: set Camellia's Saturday hours to closed. Zero code — but kills Saturday tour booking and any "we're open Saturday 1–4:30" answer. Not viable alone.
C.A separate "PM notification hours" setting, fully decoupled from tour hours. Cleanest long-term; largest change; doesn't fix the voice/key-pickup/vendor misreads by itself.
D2 · Should the FIRST notice respect office hours too? reverses a recorded decision
A.Recommended if the intent was always "office hours only": widen the existing gate to the initial send (deferral to next open, same fail-closed re-check before sending). Removes ~20 of the 27 off-hours emails in the sample. Tradeoff: the office learns about a midnight lease signature at 9 AM instead of 12:15 AM — which is when they'd read it anyway.
B.Keep first notices immediate (the Jul 28 record); accept overnight emails.
C.Split it: first notices immediate for time-sensitive kinds (application review), deferred for countersign/execution notices.
D3 · Tenant-facing outreach on weekends policy
A.Keep the current 8 AM–9 PM, 7-day legal window (status quo).
B.Narrow renewal outreach (texts/calls) to weekdays, or to the property's staffed hours, so a resident who replies reaches a person.
Open items
- 30-day census of off-hours PM emails (only Aug 12–15 pulled so far).
- Juan's saga shows a "tenant-signed PM-notified" marker while its state still reads "offer prepared" — a possible state-machine mismatch, separate from timing.
- Juan's saga has no PM-action timing row despite three PM emails — check that the timing tracker is recording renewal countersign cadences.
- Two Camellia PM emails bounced with a Microsoft "banned sender" block on the shared SendGrid IP — unrelated to timing, worth a look.
Verified against production data (SendGrid message events, DynamoDB rows, the property's stored hours), the code, PR bodies and the Jul 28 design doc. Inferred and labeled: that the Jul 28 write-up narrowed Fede's instruction (no primary source either way). Nothing was changed.