Skip to content

feat(spec,drivers): the temporal matrix gains its Field.time axis, and time gets a storage form off SQL (ADR-0053 D-A3.2) - #4147

Merged
os-zhuang merged 4 commits into
mainfrom
claude/adr-0053-temperature-consistency-akyja5
Jul 30, 2026
Merged

feat(spec,drivers): the temporal matrix gains its Field.time axis, and time gets a storage form off SQL (ADR-0053 D-A3.2)#4147
os-zhuang merged 4 commits into
mainfrom
claude/adr-0053-temperature-consistency-akyja5

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

把 D-A3 矩阵扩到第三个时间字段类型 Field.time,以及这条轴首跑当场量出来的缺口#4109 的后续。

一、为什么 time 要自己一张表

TEMPORAL_TIME_ROWS / TEMPORAL_TIME_CASES 与现有表并列,而不是在原表上加第三个 kind——因为墙上时钟与另外两者没有共享的比较值词汇:没有任何相对 token 会解析成一个时刻({today} 是日历日),而且裸日整日规则(#3777)绝不能波及它

最后这点现在是断言而非假设:nextUtcCalendarDay 只加宽 YYYY-MM-DD 字符串,而「规则渗漏到错误的字段类型」恰恰是一致性矩阵存在的意义。所以表里专门有一格钉死「time 的闭区间上界是精确的、不被加宽」。

夹具是一个营业日,边界取的正是 #3994 量过的那些:两个窗口端点、跨毫秒后缀宽度变化的一对(14:30:0014:30:00.500)、午夜、23:59:59.999

取舍与父表同一把尺子:只分钟的比较值('14:30')会被有类型的后端规范化、被无类型后端按原文比较,因此那一格是 schema-aware-only,留在各驱动自己的套件里——与上面 $gt-on-datetime 那个极限完全同构。

二、这条轴找到了什么:D-C 从未抵达非 SQL 驱动

ADR-0053 D-C 给了 Field.time每个 SQL 方言上的规范形态,但 driver-memorydriver-mongodb 从未被扩展:两者的 TemporalFieldKind 都只有 'datetime' | 'date',于是 indexTemporalFields 从不识别 time 列、coerceTemporalValue 从不碰它。列里就留着各个写入方各自的形态——而 mingo 与 BSON 都按类型桶比较,文本边界匹配不到任何 Date 写入的行,双向皆然,且对每个算子成立。

在 driver-memory 上实测:9 个共享用例红了 8 个。 营业时段窗口返回 [d_mid, f_close] 而不是 [c_open, d_mid, e_mid_ms, f_close]。这就是 #4047 的故障换了个字段类型——它能在 #4047 之后存活,正是因为那次工作扩展了 datetimedate 却没有回头看 time

mongo 侧还是一次文档失败mongodb-temporal.ts 自己的 canon 表从 #3994 起就写着 time 存为 HH:MM:SS[.fff] 文本——文档是对的,代码从未实现。典型的「声明了却没强制」(Prime Directive #10),在有东西真正执行它之前完全隐形。

三、修法

两个驱动各加 storageTimeValue,对齐 SQL 侧的 canonicalTimeOfDayHH:MM:SS,毫秒非零时才带 .fffDate / epoch / 完整时间戳折叠为其 UTC 时刻(绝不用宿主时区);保持全域性——'25:00' 这类越界墙钟原样透传而非被悄悄改写。

两边都用文本,mongo 也是:墙上时钟不是瞬间,存成 BSON Date 会凭空发明一个日历日和一个时区——与 date 在那里保持文本是同一条理由。

可变宽度是文本存储正确(而不只是方便)的关键:. 排在所有数字之前,所以字典序——正是 mingo 执行的比较、也正是 mongo 文本范围使用的顺序——在两种宽度间仍然等于时间顺序。

四、验证

结果
spec 7087
driver-sql 574(+38 skipped)
driver-memory 230
driver-sqlite-wasm 166
service-analytics 422
formula 298
  • 不带本修复时,memory 的 9 个 time 用例红 8 个(已实测,非推断)。
  • mongo 的端到端扫描需要真实服务器,本沙箱无二进制而 skip、CI 会真实执行;因此转换本身另由纯函数套件 mongodb-time-storage.test.ts 钉死(11 例,含 BSON Date 分支),它在任何环境都会运行。
  • spec 八个生成物 gate 全 PASS,api-surface.json 已随新导出重新生成;改动文件 ESLint 干净。

ADR 新增 D-A3.2 附录记录本轴与它量出的缺口。Refs #4081

🤖 Generated with Claude Code

https://claude.ai/code/session_01TqqZmPS5a4gJGBoCTwipFr


Generated by Claude Code

…d time gets a storage form off SQL (ADR-0053 D-A3.2)

The wall-clock half of the shared conformance table, plus the gap it measured
on its first run.

`TEMPORAL_TIME_ROWS` / `TEMPORAL_TIME_CASES` get their OWN table rather than a
third `kind` on the existing one: a time shares no comparand vocabulary with
the other two — no relative token resolves to a wall clock — and the bare-day
whole-day rule (#3777) must not reach it, which the table now ASSERTS rather
than assumes. "The rule leaked into the wrong field type" is precisely the
class of defect a conformance matrix exists to catch. The fixture is a
business day carrying the boundaries #3994 measured: both window edges, the
pair straddling the millisecond-suffix width change, midnight, 23:59:59.999.

What it found: ADR-0053 D-C gave Field.time a canonical form on every SQL
dialect, but driver-memory and driver-mongodb were never extended. Both
declared TemporalFieldKind = 'datetime' | 'date', so indexTemporalFields never
classified a time column and coerceTemporalValue never touched one — the
column kept whatever each writer produced, and mingo and BSON both compare
across types by bracket, so a text bound matched no Date-written row in either
direction, for every operator. Measured on driver-memory: 8 of the 9 shared
cases returned only the text-written half, a business-hours window answering
[d_mid, f_close] instead of [c_open, d_mid, e_mid_ms, f_close]. That is
#4047's failure one field type over, and it survived #4047 because that work
extended datetime and date without revisiting time. On mongo it was also a
documentation failure: that module's canon table has listed time as
HH:MM:SS[.fff] text since #3994, and nothing implemented it — declared but
never enforced.

Both drivers now carry storageTimeValue, mirroring canonicalTimeOfDay:
HH:MM:SS with .fff only when non-zero, a Date/epoch/full-timestamp folding to
its UTC time-of-day (never the host's), and totality — '25:00' passes through
rather than being rewritten. Text on both, mongo included: a wall clock is not
an instant, so a BSON Date would invent a calendar day and a zone the author
never wrote. The variable width is what makes text storage correct rather than
merely convenient — `.` sorts below every digit, so lexicographic order stays
chronological across both widths.

Six consumers sweep the new table. The mongo end-to-end sweep needs a real
server and skips where no binary is available, so the conversion itself is
pinned separately by a pure mongodb-time-storage.test.ts that runs everywhere.

spec 7087 / driver-sql 574 / driver-memory 230 / sqlite-wasm 166 /
service-analytics 422 / formula 298, all green; 8 of the memory time cases
fail without this change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqqZmPS5a4gJGBoCTwipFr
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 12:49pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling size/l labels Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec.

109 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/driver-memory)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/glossary.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/driver-memory, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/driver-memory)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/driver-memory, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/driver-memory, @objectstack/driver-mongodb, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

claude added 2 commits July 30, 2026 11:59
…kind, not a copy of its members

`translateFieldOperators` spelled its `kind` parameter out as a literal
`'datetime' | 'date'` instead of importing `TemporalFieldKind`. Widening the
canon to include `time` therefore left the two definitions out of step and the
call site stopped compiling — caught by CI's workspace build, which is the
gate the package-level test run does not exercise.

Fixed by pointing the signature at the one definition, so the next temporal
type is added once rather than everywhere it was transcribed. No behaviour
change: the parameter already received exactly what the resolver returns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqqZmPS5a4gJGBoCTwipFr
The Field.time suite I appended to this file never ran: the datetime suite's
`afterAll` stopped the shared `MongoMemoryServer`, so the time suite's
`beforeAll` called `getUri()` on a stopped instance and failed the whole file
with `Incorrect State … gotState: 'new'` — its 9 cases reported as skipped,
which reads like the "no binary available" skip and hides that nothing was
verified.

A server shared by two suites cannot be torn down by whichever finishes first,
so the stop moves to a file-level `afterAll`; each suite still disconnects its
own client.

Also pins the FILTER half of the time canon (`translateFilter` with a time
kind resolver) alongside the existing write-half tests. Both are pure, so the
comparand path is verified in environments where the end-to-end sweep cannot
run — this sandbox's proxy returns 403 for the MongoDB binary download, so the
server-backed cases only execute in CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqqZmPS5a4gJGBoCTwipFr
@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 12:42
Both sides appended to the end of matches-filter-temporal-conformance.ts:
main added the note explaining why the token axis cannot apply to an RLS
`check` (it is a CEL expression, so a `{token}` string never reaches this
evaluator), and this branch added the Field.time sweep. They are
complementary, so both are kept — with one sentence added to the note
recording that the same reasoning covers the wall-clock cases, which carry no
token spelling at all because no date macro resolves to a time of day.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqqZmPS5a4gJGBoCTwipFr
@os-zhuang
os-zhuang merged commit 6038de7 into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0053-temperature-consistency-akyja5 branch July 30, 2026 13:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants