Explicit Schedule time-zone boundary
显式 Schedule 时区边界
Implicit local `at` input made a browser fact into shared product state. Capturing a default zone on Session creation required new Session headers, create/resume/fork conflict rules, JSONL metadata, a SQLite migration, client creation plumbing, Host comparisons, and Schedule logic coupled to time-context markers. Travel, concurrent tabs, missing provenance, and old Sessions then needed a confirmation protocol merely
English
Problem
Implicit local at input made a browser fact into shared product state. Capturing a default zone on Session creation required new Session headers, create/resume/fork conflict rules, JSONL metadata, a SQLite migration, client creation plumbing, Host comparisons, and Schedule logic coupled to time-context markers. Travel, concurrent tabs, missing provenance, and old Sessions then needed a confirmation protocol merely to decide whether an omitted field was safe.
Most of that complexity sat outside Schedule. The model already interprets natural language before it calls the tool, so a durable Session default duplicated an assumption instead of strengthening the absolute-time boundary.
Decision
Browser zone is request-local provenance. The Web client samples Intl.DateTimeFormat().resolvedOptions().timeZone for every prompt. The Host accepts an optional clientTimeZone, validates and canonicalizes UTC or an IANA Area/Location at the RPC boundary, and logs it on that exact user-rpc message. Invalid values reject prompt admission. Non-browser clients may omit it.
Time-context derives unique, mixed, or missing browser facts from original user-rpc messages in the open turn. A unique zone formats the clock and tells the model to interpret otherwise-unqualified dates and times in that zone. Mixed or missing provenance tells the model to ask the user. The configured or process zone is only a display fallback and is never presented as user authority.
Schedule accepts no implicit local zone. at is either a strict offset-bearing RFC 3339 string or exact { date, time, time_zone }. The structured form requires its zone even when time-context just showed the model a browser zone. Schedule does not import time-context, inspect user-message provenance, read a Session header, or produce a confirmation error. Its parser validates the explicit value, rejects daylight-saving gaps, chooses the first instant in overlaps, and stores only canonical UTC scheduledAt.
No Session time-zone field, create/resume/fork zone conflict, JSONL header field, SQLite column or migration, connection default, or Schedule-specific Host/client presentation remains. The browser assumption crosses into Schedule only through the model's explicit tool arguments.
Alternatives considered
Persist the first browser zone as an immutable Session default. This makes later local input deterministic but spreads ownership across core and persistence, while travel and concurrent tabs still require mismatch handling.
Use the most recent browser zone as mutable Session state. This reduces confirmation prompts but lets one tab silently change another tab's interpretation and makes replay depend on update ordering.
Let Schedule inspect the latest time-context message. A prose snapshot is model-visible evidence, not a typed package seam. Consuming it would couple Schedule to AgentLoop history and duplicate validation against original provenance.
Let the Host inject time_zone into tool calls. The Host cannot know which natural-language expression the model interpreted or whether the user named another zone. Rewriting model arguments hides meaning at the wrong boundary.
Require the model to ask on every unqualified time. This is safe but unnecessarily interrupts the common browser-local case. The request-local instruction provides the intended assumption while mixed or missing provenance still asks.
Verification
Host tests pin canonical aliases, omission, and rejection before Agent entry. Client tests pin one browser-zone sample on each prompt. Time-context tests pin unique, mixed, and missing current-turn derivation and exact model policy. Schedule tests pin required time_zone, strict offsets, calendar validation, canonical zones, gap rejection, overlap-first selection, and absence of an implicit context path. The assembled Web scenario fixes Playwright to Asia/Shanghai, sends through the real composer, observes the same zone in the model request, verifies an explicit local tool call, and snapshots the ordinary reminder response.
Source audits reject SessionHeader.timeZone, persistence time_zone columns, confirmation errors, Schedule imports of time-context, and independent receipt machinery.
Consequences
- Browser-local natural language works without a persisted Session-zone subsystem.
- Schedule has one explicit, independently testable absolute-time boundary.
- Travel and concurrent tabs affect only their own prompts; a turn with mixed provenance asks instead of mutating shared state.
- Non-browser clients remain valid but must provide enough natural-language context or explicit tool arguments.
- The model may still make an interpretation error; the tool guarantees only that the explicit calendar value is valid and deterministic.
中文
问题
隐式本地 at 输入把浏览器事实变成了共享产品状态。在 Session 创建时捕获默认时区,需要增加新的 Session header、create/resume/fork 冲突规则、JSONL metadata、SQLite migration、client 创建 plumbing、Host 比较,以及与 time-context 标记耦合的 Schedule 逻辑。随后,旅行、并发 tab、缺失 provenance 和旧 Session 都需要一套确认协议,仅仅为了判断省略字段是否安全。
大部分复杂度都位于 Schedule 之外。模型在调用工具前已经解释自然语言,因此持久 Session 默认值只是重复了一个假设,并没有强化绝对时间边界。
决策
浏览器时区是请求本地的 provenance。Web client 会为每条提示词采样 Intl.DateTimeFormat().resolvedOptions().timeZone。Host 接受可选的 clientTimeZone,在 RPC 边界校验并规范化 UTC 或 IANA Area/Location,再将其记录在确切的那条 user-rpc 消息上。无效值会使提示词准入被拒绝。非浏览器 client 可以省略它。
Time-context 从 open turn 中的原始 user-rpc 消息派生唯一、混合或缺失的浏览器事实。唯一时区会用于格式化时钟,并告诉模型把未明确限定时区的日期和时间解释为该时区。provenance 混合或缺失时,模型会被告知询问用户。配置或进程时区只作为显示 fallback,绝不会被呈现为用户权威。
Schedule 不接受隐式本地时区。at 要么是带显式偏移量且严格符合 RFC 3339 的字符串,要么是精确的 { date, time, time_zone }。即使 time-context 刚向模型展示了浏览器时区,结构化形式仍要求自己的时区。Schedule 不导入 time-context、不检查 user message provenance、不读取 Session header,也不产生确认错误。它的 parser 会校验显式值、拒绝夏令时缺口、在重叠时选择第一个时点,并且只存储规范化后的 UTC scheduledAt。
不再保留 Session 时区字段、create/resume/fork 时区冲突、JSONL header 字段、SQLite column 或 migration、连接默认值,也不再保留 Schedule 专属的 Host/client 呈现。浏览器假设只会通过模型的显式工具参数跨入 Schedule。
已考虑的替代方案
把第一个浏览器时区持久化为不可变的 Session 默认值。 这会使后续本地输入具有确定性,却把归属扩散到 core 和 persistence;旅行与并发 tab 仍然需要不匹配处理。
把最近的浏览器时区用作可变 Session 状态。 这会减少确认提示,却允许一个 tab 悄然改变另一个 tab 的解释,并使回放依赖更新顺序。
让 Schedule 检查最新的 time-context 消息。 prose snapshot(文本快照)是模型可见证据,而不是有类型的包 seam。消费它会使 Schedule 与 AgentLoop history 耦合,并针对原始 provenance 重复校验。
让 Host 向工具调用注入 time_zone。 Host 无法知道模型解释的是哪个自然语言表达式,也无法知道用户是否指定了另一个时区。重写模型参数会在错误的边界隐藏含义。
要求模型对每个未限定时区的时间都询问用户。 这样做是安全的,却会不必要地打断常见的浏览器本地场景。请求本地指令提供预期假设,而 provenance 混合或缺失时仍会询问用户。
验证
Host 测试固定别名的规范化、可省略行为和进入 Agent(智能体)前的拒绝。client 测试固定每条提示词进行一次浏览器时区采样。Time-context 测试固定当前 turn 中唯一、混合与缺失情况的派生,以及精确模型策略。Schedule 测试固定必需的 time_zone、严格偏移量、日历校验、规范时区、缺口拒绝、重叠时选择第一个时点,以及不存在隐式上下文路径。组装 Web 场景把 Playwright 固定到 Asia/Shanghai,通过真实 composer 发送提示词,在模型请求中观察同一时区,验证显式本地工具调用,并对普通提醒响应执行 snapshot。
源代码审计会拒绝 SessionHeader.timeZone、persistence time_zone column、确认错误、Schedule 对 time-context 的导入,以及独立回执机制。
后果
- 无需持久 Session 时区子系统,浏览器本地自然语言也能工作。
- Schedule 具有一个显式且可独立测试的绝对时间边界。
- 旅行与并发 tab 只影响各自的提示词;provenance 混合的 turn 会询问用户,而不是改变共享状态。
- 非浏览器 client 仍然有效,但必须提供足够的自然语言上下文或显式工具参数。
- 模型仍可能产生解释错误;工具只保证显式日历值有效且具有确定性。