Repository navigation
skills(objectstack-query): teach the now-anchored comparand { $now: true, addDays } - #26407
Conversation
…rue, addDays }
rules/filters.md gains one subsection, Now-Anchored Comparands, placed under
Field References (the anchor is legal exactly where a { $field } reference
is and borrows its addDays grammar): the shape, the one example (overdue by
each record's own grace days, the offset column holding negative days),
where it is accepted (the six scalar comparisons on a date / datetime field)
and what is refused. SKILL.md points at it from the rules list and the
cross-field comparisons entry. evals/filters-pagination-search.json gains
case 6, the overdue-by-grace-days prompt.
The two touched CEILINGS rows of scripts/check-skills-token-ratchet.mjs rise
by the measured remainder under the maintainer's ruling A (nothing in either
file restates another passage, so nothing was cut first): rules/filters.md
2149 -> 2482, the eval file 955 -> 1175.
Claude-Session: https://claude.ai/code/session_01JQwxbX21W6nMhxhqhmbFEH
Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-10-27T02:53Z — independent contract review of PR #26407 (card #26301, Served-tier: Inputs read over REST (curl, bearer token from the environment, never printed): ① Derived judgments(a) Every new sentence against the spec on
(b) Cuts. Nothing is deleted anywhere in the diff ( (c) Ratchet rows. Measured with the script's own convention, (d) Evals. Case 6 appended; ids 1–6 unique and sequential; the file parses as JSON; every (e) Wanted lines met, nothing beyond. The card wants "one subsection in (f) PR body. Lines 1–2 are the harness attribution comment and the (g) Report and claim. os-dev-report 6432431995 (2026-10-27T02:42Z) carries every key of the os-dev.md L360–382 template plus Check-runs on ② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS |
维护者速读改了什么: 席位核对ACCEPT ·
Generated by Claude Code |
…-r9vctw # Conflicts: # scripts/check-skills-token-ratchet.mjs
席位核对ACCEPT (addendum, pinned to the merge head) · Generated by Claude Code |
…-r9vctw # Conflicts: # scripts/check-skills-token-ratchet.mjs
席位核对ACCEPT (second addendum, pinned to the merge head) · Generated by Claude Code |
席位核对ACCEPT (third addendum, pinned to the merge head) · Generated by Claude Code |
Requested by Warren · project thread
Fixes #26301
Clause-②: no
Metadata-protocol: none
Skills-docs: updated here
维护者速读
skills/objectstack-query/rules/filters.md在 Field References 之后新增一节「Now-Anchored Comparands」:{ $now: true, addDays: OFFSET }的形状、唯一示例(按每条记录自己的宽限天数判逾期,偏移列存负数天)、哪里接受(六个标量比较、date/datetime 字段)、哪些被拒(无addDays、小数或字串偏移、多余键、非日期目标、$in/$nin/$between位置,SQL 下推拒点路径或非数值偏移列),并点明不必用存储公式字段加钩子。SKILL.md的规则清单与「Cross-field comparisons」各加一句指向它(在余量内,不抬上限)。eval 文件加第 6 题。两行 token 上限按实测抬高,裁决原文写在行旁。$field与日期宏;AI 作者要「按每条记录自己的宽限天数判逾期」时会去建存储公式字段再写钩子。skills/objectstack-query/rules/filters.md新节(接受/拒绝清单对照packages/spec/src/data/filter.zod.ts的NowAnchorSchema与filter.test.ts的 Analytics datasets: no filter compares a datetime column against now minus an SLA held on a related record #25808 用例);②scripts/check-skills-token-ratchet.mjs两行上限及注释引的裁决;③evals/filters-pagination-search.json第 6 题。node scripts/check-skills-token-ratchet.mjs→ 末行81 authored bundle file(s) within their ceilings,其中rules/filters.md is 2482 tokens (ceiling 2482; headroom 0)、filters-pagination-search.json is 1175 tokens (ceiling 1175; headroom 0)。skills/**),请 approve 或直接 Merge when ready。What changes
Card #26301, the audit's row Q1 (the comparand
{ $now: true, addDays: FIELD }, in the filter grammar since the 18.0 floor, taught nowhere inskills/objectstack-query/**):rules/filters.md— one subsection, "Now-Anchored Comparands", placed directly under Field References and before Relation Filters. Why there and not just before Date Filtering Patterns: the anchor is legal exactly where a{ $field }reference is and borrows itsaddDaysgrammar, so the author who has just read how a comparand can be another column meets its now-anchored twin on the next screen; the date-token section teaches placeholders that take a literal N only. The section carries, in the spec's words (NowAnchorSchema,filter.zod.ts, and the Analytics datasets: no filter compares a datetime column against now minus an SLA held on a related record #25808 cases infilter.test.ts/engine-now-anchor.test.ts): the shape; the one example (overdue by each record's own grace period,due_at < now + grace_days_offset, the offset column holding NEGATIVE days); thataddDaysis required and always added (an integer of any sign,-30keeping the time of day where{30_days_ago}names a calendar day;{now}for the bare instant; or a{ $field }naming a number field of the same record, NULL counting as zero days); that the filter cannot negate a positive column, so the signed offset is what gets stored; what is refused withINVALID_FILTER/ 400 (noaddDays, a fractional or string offset, an extra key — there is nosubDays— a target that is notdate/datetime, any$in/$nin/$betweenposition; SQL push-down also refuses a dotted or non-number offset field); and that the filter alone answers the question, not a stored formula field plus a hook (the card's "who pays").SKILL.md— two pointers, inside the file's headroom (priced 4124 → 4168, ceiling 5547): the rules list names "now-anchored comparands" among whatfilters.mdcovers, and the Cross-field comparisons entry gains one clause naming the anchor beside{ $field }, pointing at the new section. Line 1 (the version stamp PR chore: version packages #25640 owns) is untouched.evals/filters-pagination-search.json, in the file's existing shape (the earlier five entries are byte-identical): the overdue-by-grace-days prompt, with the schema stated (adatetimeand a number field holding negative days); expected output is the anchor as the whole comparand of$lt, and names the three wrong routes (a stored formula field plus a hook,{N_days_ago}, a{ $field: 'due_at', addDays }column-to-column comparison).must_containpins$now: true,addDays,$field: 'grace_days_offset',$lt;must_not_containpinssubDaysandtype: 'formula'.references/_index.mdis generator-owned (gen:skill-refs) and already listsdata/filter.zod.ts; not touched.Token-ratchet rows (
scripts/check-skills-token-ratchet.mjs), per the maintainer's ruling on the seat's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, tap A (2026-10-27 01:21Z), verbatim and untranslated: 「A:先削重复,余额按实测提高」. Step one, cut duplicates first: measured onorigin/maina66c9ff4,rules/filters.mdcarries no passage that restates another in the file (the operator table'scase-blindcells and the Case-sensitivity paragraph are a table row and its rule, not a restatement; the Relation Filters limits and the two-step route are stated once each;$field's comparison-position rule appears once here and once inSKILL.md, a different file), and the eval file repeats nothing — so there was nothing to cut and no surviving-home list to give. Step two, raise by the measured remainder:rules/filters.md2149 → 2482 (+334 landed on 2148, 1 absorbed by headroom, ceiling +333);evals/filters-pagination-search.json955 → 1175 (+220, zero headroom). Both rows re-pinned at zero headroom; the comments beside them quote the ruling.Two readings (lines, and tokens as the ratchet counts them,
ceil(utf8 bytes / 4); theSKILL.mdtoken figures here are the raw file, the ratchet's priced count excludes the version line):rules/filters.mdSKILL.mdevals/filters-pagination-search.json(not .md, reported for the raise)SKILL.md+references/**/*.md+rules/**/*.md, 5 files)Nothing removed: the card names no stale line in this package.
Sequencing (zero verbs beside these numbers): PR #25640 owns line 1 of every
skills/*/SKILL.md, untouched here; the sibling audit PRs #26385, #26388, #26390, #26392 and #26393 edit other packages' rows of the ratchet script, and this branch was cut froma66c9ff4, after #26392 landed; no open PR touchesskills/objectstack-query/**.skip-changeset: the published skills packages carry nopackage.json; nothing is released from any package.Tests
node scripts/check-skills-token-ratchet.mjs— exit 0:81 authored bundle file(s) within their ceilings, the two raised rows at headroom 0,SKILL.mdat headroom 1379 (no raise).node scripts/check-skills-token-ratchet.mjs --self-test— exit 0,79 cases pass.pnpm --filter @objectstack/spec run check:skill-docs,check:skill-refs,check:skill-examples— each exit 0 (check:skill-examplesafter building@objectstack/spec,@objectstack/clientand@objectstack/client-reactunderscripts/pm/os-verify-lock.sh, slotissue-26301, 312 s for the whole closure including@objectstack/formulaand@objectstack/lint); the new code block infilters.mdis awhere:fragment and is deliberately not markedos:check, like every other fragment in the file.must_containstring occurs in it, neithermust_not_containstring does.NowAnchorSchema(packages/spec/src/data/filter.zod.ts), its Analytics datasets: no filter compares a datetime column against now minus an SLA held on a related record #25808 cases infilter.test.ts(the six operators accept it;$in/$nin/$betweenrefuse it; missing, fractional and string offsets and an extra key refuse),engine-now-anchor.test.ts(the resolver pins$now; a numeric target and a text or undeclared offset column refuse) and the$nowsection ofcontent/docs/protocol/objectql/query-syntax.mdx(NULL offset = zero days; a dotted offset is refused on SQL push-down). No ablation: no tested behaviour changed.Acceptance notes
addDayson a{ $field }reference ({ $field: 'due_date', addDays: { $field: 'grace_days' } }, in the grammar since 18.0's floor as well) is likewise untaught in Field References; the audit's row Q1 cites that section as teaching$fieldalone and names only the anchor. Observation only, outside this card's "Wanted"; not filed (read-only inference, no public-door probe).skills/**inside the package's ceilings" cannot hold at the measured headroom (filters.md1, eval 0); the claim's file surface already names the two ratchet rows under the ruling above.Fixes #26301follows immediately.Skills-docs: updated hereis written because it is true, not because it is owed (Metadata-protocol: none).Verification
Gate list derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the final tree (a66c9ff4base, head13e75c8c), each run locally with the exit code captured before any pipe;--ranreconciliation below.Reconciliation (
node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack, exit 0):52 derived, 51 run, 1 NOT-MEASURED, 0 UNRUN. The one NOT MEASURED ispnpm check:dual-build-cjs-loads: its prerequisite is a whole-repo build (28 packages withoutdist/on this worktree after the targeted closure); this diff touches no package source, and CI'sLint & Repo Gatesruns it — a declared narrowing.check:pm-dispatch-gatesran detached on the final head: under six minutes of wall (launched after the 51-gate pass ended at 02:32Z, finished 02:38Z), 1901 cases pass (fast tier; 7 slow sections deferred), exit 0. No gate was red on any head.Every derived command with its exit code on 13e75c8 (54 lines: the 52 derived, plus `check:skill-refs` and `check:skill-examples` the card asks for)
node scripts/check-ci-filter-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs— exit 0node scripts/check-closing-keyword-parity.mjs --self-test— exit 0node scripts/check-comment-mask-corpus.mjs— exit 0node scripts/check-declaration-mirrors.mjs— exit 0node scripts/check-declaration-mirrors.mjs --self-test— exit 0node scripts/check-doc-route-spelling.mjs --advisory— exit 0node scripts/check-doc-route-spelling.mjs --self-test— exit 0node scripts/check-dts-emitted.mjs --self-test— exit 0node scripts/check-scripts-symbol-anchors.mjs— exit 0node scripts/check-scripts-symbol-anchors.mjs --self-test— exit 0node scripts/check-self-test-wired.mjs— exit 0node scripts/check-self-test-wired.mjs --self-test— exit 0node scripts/check-self-test-workflow-commands.mjs— exit 0node scripts/check-self-test-workflow-commands.mjs --self-test— exit 0node scripts/check-skills-token-ratchet.mjs— exit 0node scripts/check-skills-token-ratchet.mjs --self-test— exit 0node scripts/check-whole-set-label-write.mjs— exit 0node scripts/check-whole-set-label-write.mjs --self-test— exit 0node scripts/ci/assert-turbo-remote-cache.mjs --self-test— exit 0node scripts/ci/prune-turbo-cache.mjs --self-test— exit 0node scripts/pm/bare-root-worklist.mjs --self-test— exit 0pnpm --filter @objectstack/lint run check:doc-formula-expressions— exit 0pnpm --filter @objectstack/spec run check:skill-docs— exit 0pnpm check:agent-test-spelling— exit 0pnpm check:bash32-floor— exit 0pnpm check:cli-command-ids— exit 0pnpm check:corpus-claim-drift— exit 0pnpm check:cross-package-test-inputs— exit 0pnpm check:doc-authoring— exit 0pnpm check:driver-memory-census— exit 0pnpm check:dts-closure— exit 0pnpm check:dual-build-cjs-loads— NOT MEASURED (exit 3, PREREQUISITE NOT MET)pnpm check:entry-guard— exit 0pnpm check:gitlink-declared— exit 0pnpm check:lean-entry-closure— exit 0pnpm check:merge-driver— exit 0pnpm check:nul-bytes— exit 0pnpm check:parse-guard— exit 0pnpm check:pm-governed-merges— exit 0pnpm check:pm-skill-id-lint— exit 0pnpm check:pnpm-filter-targets— exit 0pnpm check:pnpm-flag-spellings— exit 0pnpm check:ratchet-remedy-authority— exit 0pnpm check:refd-timer-probe— exit 0pnpm check:role-word— exit 0pnpm check:skill-compatibility— exit 0pnpm check:skill-frame-sync— exit 0pnpm check:skill-identifier-liveness— exit 0pnpm check:sourcemap-no-sources-content— exit 0pnpm check:watch-hint-literal— exit 0pnpm check:pm-dispatch-gates— exit 0pnpm --filter @objectstack/spec run check:skill-refs— exit 0pnpm --filter @objectstack/spec run check:skill-examples— exit 0Token ratchet on 13e75c8
skills/objectstack-query/SKILL.md is 4168 tokens (ceiling 5547; headroom 1379). Its release-stamp line (version: "18.1.0", 20 bytes) is written by the version script, not an author, and is not priced.skills/objectstack-query/evals/filters-pagination-search.json is 1175 tokens (ceiling 1175; headroom 0).skills/objectstack-query/rules/filters.md is 2482 tokens (ceiling 2482; headroom 0).81 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.--self-test:79 cases pass.check:skill-examples on 13e75c8
264 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of themGenerated by Claude Code