docs(skills): date-bucket engine sentences name what each arm emits - #21677
Conversation
The dashboards rule said Postgres buckets with date_trunc and MongoDB with $dateTrunc; the drivers emit a label (to_char / date_format / strftime / $dateToString, in memory bucketDateKey), never an instant. The 'week' row now reads the ISO week label YYYY-Www every arm answers, and the aggregation rule's push-down sentence names the same expression family instead of DATE_TRUNC. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CB6W87z22K2yjUCDyVrJRk
Contract reviewServed-tier: Read-only shape otherwise: the diff against the merge base 55e6f14, card #21588 with every comment, the driver arms on ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读(终稿)— PR #21677(#21588)· skills seat 1 · 2026-10-04T03:22Z改了什么: 两个对外发布技能里描述「日期分桶引擎」的三句话。① 为什么改: 技能是 AI 作者的直接依据。原文说 Postgres 用 风险与代价(含回滚): 纯技能文本,不碰 席位意见: 建议批准。三句各自对照代码核过; 你要做的(一个动作): 在 PR #21677 上给一次 APPROVED review;批准后由席位清标、ready、挂 auto-merge 入队。 |
Fixes #21588
Clause-②: no
Three sentences in two published skills describe the date-bucket engine, and each one named something the runtime does not do. This PR rewrites exactly those three sentences, read arm by arm from the driver code on
origin/mainat55e6f14f8d, and nothing else in either file.skills/objectstack-ui/rules/dashboards.md'week'row: "ISO date of the bucket (YYYY-MM-DD)"YYYY-Www"skills/objectstack-ui/rules/dashboards.mddate_trunc, MySQLdate_format, SQLitestrftime, MongoDB$dateTrunc, in-memory fallback. All emitted by the analytics service, not the client."2026-01), not an instant: Postgresto_char, MySQLdate_format, SQLitestrftime, MongoDB$dateToString, in-memorybucketDateKey."skills/objectstack-query/rules/aggregation.mdDATE_TRUNCetc.)"to_char/date_format/strftime/$dateToString, neverdate_trunc)" — the push-down / in-memory-fallback clause and "including the column keys" are kept as they wereThe ruling on the card (triage comment 5969875145) fixed the engine sentence and said no other sentence in
dashboards.mdmoves; the engine seat's carrier addition (5973137901) measured the'week'row and the aggregation sentence as the same family, and the dispatching seat folded all three into this one governed PR (claim comment 5975736098).Reading 1 — what each arm emits, read from the code
Every arm answers a string label, never a truncated instant; the week label is the ISO week
YYYY-Wwwon all five.packages/drivers/driver-sql/src/sql-driver.ts:6161–6169(buildDateBucketExpr)to_char((col)::timestamptz AT TIME ZONE 'UTC', FORMAT)for a datetime column,to_char((col)::date::timestamp, FORMAT)for aField.date; formatsYYYY,YYYY-MM,YYYY-MM-DD,YYYY"-Q"Q,IYYY"-W"IW2026-01,2026-Q1,2026-W23sql-driver.ts:6172–6180date_format(convert_tz(col, @@session.time_zone, '+00:00'), FORMAT)(barecolfor aField.date);%Y,%Y-%m,%Y-%m-%d,%x-W%v; quarter isconcat(date_format(…, '%Y'), '-Q', quarter(…))2026-01,2026-W23sql-driver.ts:6183–6208strftime(FORMAT, ARG)with%Y,%Y-%m,%Y-%m-%d; quarter from%Yand(%m - 1) / 3 + 1; week by the Thursday rule,strftime('%Y', ARG, '-3 days', 'weekday 4') || '-W' || printf('%02d', (cast(strftime('%j', ARG, '-3 days', 'weekday 4') as integer) - 1) / 7 + 1)(PR #21629, merged, onorigin/main)2026-01,2026-W23packages/drivers/driver-mongodb/src/mongodb-aggregation.ts:246–275{ $dateToString: { format, date: { $convert: { input: '$FIELD', to: 'date', onError: null, onNull: null } } } }with%Y,%Y-%m,%Y-%m-%d,%G-W%V; quarter is$concatof%Y,-Qand a$switchover%m. The docblock at:194is headed "Labels, not instants — and therefore no$dateTrunc"2026-01,2026-W23packages/core/src/utils/datetime.ts:313bucketDateKey(week viaisoWeekLabelFromCalendarDay,:389); the engine's fallbackpackages/objectql/src/in-memory-aggregation.ts:375delegates to it, andpackages/objectql/src/engine.ts:17615picks push-down vs fallback fromsupports.queryDateGranularityYEAR,YEAR-MM,YEAR-MM-DD,YEAR-Qn,ISOYEAR-Wwwbuilt from the calendar parts in the reference zone — the writer the drivers' expressions are held equal to (checkDateBucketParity)2026-01,2026-W23The rendered dashboard label is the key:
packages/services/service-analytics/src/dimension-labels.ts:321–333formatDateBucketreturns a key the writer wrote at that granularity as written (bucketKeyToCalendarRange(value, granularity) !== null), andsrc/__tests__/dataset-granularity-postprocess.test.ts:66pinsweek: '2026-W29'throughqueryDataset. So the'week'row's "ISO date of the bucket (YYYY-MM-DD)" was wrong on every face, and the engine sentence named two expressions no arm emits.Reading 2 — token ratchet and line count, before / after
node scripts/check-skills-token-ratchet.mjs(ceil(utf8 bytes / 4)), measured on the worktree before the edit and ate381bcd9e1after it:skills/objectstack-ui/rules/dashboards.md6243 tokens (ceiling 6252; headroom 9)6243 tokens (ceiling 6252; headroom 9)skills/objectstack-query/rules/aggregation.md1845 tokens (ceiling 2357; headroom 512)1860 tokens (ceiling 2357; headroom 497)Per sentence: the
'week'row 52 → 34 bytes; the engine sentence 185 → 202 bytes over the same three lines; the aggregation sentence 244 → 303 bytes over the same four lines. Net fordashboards.md: 0 tokens, 0 lines, −1 byte. No ceiling moved.Gates
All runs at
e381bcd9e1(the branch's only commit); each runner log records the sha it started at.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives 23 commands from the change set (2 paths vs merge base55e6f14f8). All 23 exit 0. The 8node scripts/check-*.mjsruns pluscheck:doc-formula-expressions,check:agent-test-spellingandcheck:corpus-claim-driftran underscripts/pm/os-verify-lock.sh(VERDICT command-exit 0, held 120s). The remaining 12pnpm check:*scanners ran unlocked — a declared narrowing: the lock's own--statustext placescheck:*gate scripts outside its coverage, and two consecutive lock calls answered queue-timeout (exit 99, 360s each) behind a holder at 13+ minutes.check:doc-formula-expressionsfirst answered exit 3 PREREQUISITE NOT MET (@objectstack/formula/@objectstack/lintnot built — nothing measured). The production closure (spec,types,core,client,client-react,formula,sdui-parser,lint) was built under the lock (VERDICT command-exit 0, held 133s;git statusclean afterwards), and the re-run exits 0: "22 record-scoped formula example(s) across 460 files / 1381 TS blocks judged clean by @objectstack/formula".pnpm --filter @objectstack/spec run check:skill-docsexits 0: "✅ Skill docs in sync".pnpm --filter @objectstack/spec run check:skill-examplesexits 0 (run unlocked after a third queue-timeout, same declared narrowing): "✅ 260 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them". The diff sits outside every fence (dashboards.md fences close at 316 and reopen at 354; aggregation.md's close at 72 and reopen at 95), so no example changed.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ranover the 23 commands with their exit codes: "23 derived famil(ies) accounted for — 23 run, 0 NOT-MEASURED (a DERIVED zero — all 23 recorded an exit code and none of them is 3)". The tool warns the tree is 3 commits behindorigin/main(417443eb27, fetched after the runs); re-deriving against that merge-base yields the same 23 commands, and the three incoming commits (fix(cli): a narrowed os migrate --apply records no deployment flag, and an unknown --object is refused #21662, fix(objectql,spec)!: a hook's handler name resolves inside the hook's own package only (#21604) #21653, fix(objectql): a seed row keeps its authored created_at on insert, as the replay already does #21661) touch noskills/**path, so the branch was not merged forward for a two-file documentation change.pnpm lintnarrowing, with the three pieces of evidence: ①eslint.config.mjsfiles:globs cover only{ts,tsx,mts,cts,js,jsx,mjs,cjs}(lines 971–1238), so neither.mdfile is in the population; ②pnpm exec eslint --no-inline-config --format jsonover the two files answers 2 files, 0 errors, 1 warning each — "File ignored because no matching configuration was supplied."; ③ the config enables noparserOptions.projector typed rules (line 328), so this diff moves no untouched file's verdict.check:nul-bytesis among the 23.维护者速读(草稿)
改了什么 — 两个已发布技能里描述日期分桶引擎的三句话。dashboards 规则的「Engine support」句原说 Postgres 用
date_trunc、MongoDB 用$dateTrunc、由 analytics service 发出;改为按五个臂点名驱动真实发出的表达式(Postgresto_char、MySQLdate_format、SQLitestrftime、MongoDB$dateToString、内存bucketDateKey),并写明桶键是标签(如2026-01)不是时刻。同一张表的'week'行由「ISO date of the bucket (YYYY-MM-DD)」改为 ISO 周标签YYYY-Www。aggregation 规则的下推句把DATE_TRUNC换成同一表达式族。不改任何代码,不改产品行为。为什么改 — 技能是 AI 作者读的权威面。写错引擎会让作者按
date_trunc语义(时间戳形的桶键)去比较或解析桶值,而运行时五个臂实际都返回字符串标签;'week'行与运行时每个臂返回的2026-W29不符。每个臂都在origin/main(55e6f14f8d)上逐条读过代码,见上文 Reading 1。风险与代价(含回滚) — 纯文档改动,8 行替换 8 行。token 棘轮:dashboards.md 净 0(6243/6252 不变,行数不变),aggregation.md +15(1860/2357)。23 条派生门禁加
check:skill-docs、check:skill-examples全绿。回滚 = revert 本 PR 的单个 commit。席位意见 — (留空)
你要做的 — 对这个 Tier H
skills/**PR 给一次 APPROVED review;之后由domain:skills#1席位落地。Acceptance notes
Noted, not filed (code comments, no behaviour, no carrier):
packages/services/service-analytics/src/dimension-labels.ts:302— theformatDateBucketTSDoc example list still readsweek → "2026-04-13" (ISO date of the bucket), while the body just below (:327–:333) returns aYYYY-Wwwkey as written and relabels only a raw non-key value as its own day key. Comment drift only; the behaviour is pinned by the tests cited above.packages/objectql/src/in-memory-aggregation.ts:59— the header comment namesdate_trunc(...)as the SQL path's NULL-propagating expression; the SQL path emitsto_char/date_format/strftime, whose NULL propagation is the same point. Comment drift only.Generated by Claude Code