Blocked-by: #15161 — discharged 2026-09-05: the write-path enforcement landed on origin/main (fa125f3bf), measured by content; see the discharge comment on this card.
A capability gap rather than a defect. Raised from building a recurring-obligation application (objectstack-ai/duly) on published @objectstack/* 17.2.0, where it turned a product decision into a platform-shaped one.
The gap
Neither sys_organization, sys_business_unit, nor sys_user carries a timezone, locale, region or country column. Measured on a live 17.2.0 boot — scanning each object's columns for anything matching time|zone|locale|lang|region|country|tz returns nothing on all three.
So an application that has to answer "when does this day end?" has nowhere to resolve it from, and must add a field of its own to whichever object it decides owns the answer.
Why that is a platform question and not an app one
A date boundary is not a display concern — it decides which record exists, not just how one is shown:
- a monthly obligation "due on the 5th" expires at midnight; in UTC+8 that is 08:00 local, so work finished at 09:00 on the 5th is recorded as late;
- a weekly period boundary shifts by the same offset, so Monday-morning work before the offset falls into the previous week's bucket — the record it should belong to does not exist yet;
- anything built on those two — completion rates, escalation timing, "my week" — inherits both errors, silently, with nothing to report.
Only a deployment sitting on UTC is correct today.
Every app with periods, deadlines, SLAs, rosters, or billing cycles hits this, and each one solves it privately: one puts a timezone field on its own tenant object, another on its own team object, a third on the user. Two apps in the same deployment then disagree about when Tuesday ended, and neither is wrong by its own metadata.
What would close it
The organization hierarchy is the natural home, because it is the axis the platform already models and the one that matches how the answer is actually determined — work happens at a place, and the deadline usually belongs to that place's regulator or shift calendar:
- a timezone on
sys_business_unit, nullable, inheriting down the parent_business_unit_id chain;
- a tenant-level default on
sys_organization as the root of that chain;
- ideally a resolver an app can call — "the effective zone for this record" — so apps do not each re-implement the walk up the hierarchy plus the fallbacks.
sys_user is the wrong home on its own: two people in different zones owning work in the same period would compute different period boundaries for what the business considers one period, so a shared deadline stops being shared. A per-user zone is a display preference on top of an org-resolved boundary, not a substitute for it.
Application impact
In the app that raised this, the product decision — which object owns a duty's timezone — has been deliberately parked rather than answered, because answering it means inventing a field the platform may well grow in a different place, and a migration off a privately-invented duly_* timezone field later is worse than waiting. Every deployment is UTC in the meantime, which is correct for exactly one set of customers.
Recorded app-side as objectstack-ai/duly#26.
Generated by Claude Code
Blocked-by: #15161— discharged 2026-09-05: the write-path enforcement landed onorigin/main(fa125f3bf), measured by content; see the discharge comment on this card.A capability gap rather than a defect. Raised from building a recurring-obligation application (
objectstack-ai/duly) on published@objectstack/*17.2.0, where it turned a product decision into a platform-shaped one.The gap
Neither
sys_organization,sys_business_unit, norsys_usercarries a timezone, locale, region or country column. Measured on a live 17.2.0 boot — scanning each object's columns for anything matchingtime|zone|locale|lang|region|country|tzreturns nothing on all three.So an application that has to answer "when does this day end?" has nowhere to resolve it from, and must add a field of its own to whichever object it decides owns the answer.
Why that is a platform question and not an app one
A date boundary is not a display concern — it decides which record exists, not just how one is shown:
Only a deployment sitting on UTC is correct today.
Every app with periods, deadlines, SLAs, rosters, or billing cycles hits this, and each one solves it privately: one puts a
timezonefield on its own tenant object, another on its own team object, a third on the user. Two apps in the same deployment then disagree about when Tuesday ended, and neither is wrong by its own metadata.What would close it
The organization hierarchy is the natural home, because it is the axis the platform already models and the one that matches how the answer is actually determined — work happens at a place, and the deadline usually belongs to that place's regulator or shift calendar:
sys_business_unit, nullable, inheriting down theparent_business_unit_idchain;sys_organizationas the root of that chain;sys_useris the wrong home on its own: two people in different zones owning work in the same period would compute different period boundaries for what the business considers one period, so a shared deadline stops being shared. A per-user zone is a display preference on top of an org-resolved boundary, not a substitute for it.Application impact
In the app that raised this, the product decision — which object owns a duty's timezone — has been deliberately parked rather than answered, because answering it means inventing a field the platform may well grow in a different place, and a migration off a privately-invented
duly_*timezone field later is worse than waiting. Every deployment is UTC in the meantime, which is correct for exactly one set of customers.Recorded app-side as objectstack-ai/duly#26.
Generated by Claude Code