Repository navigation
docs(guide): objectos-integration.mdx:280 authors object-grid.filter as an and:-keyed object of { field, operator, value } entries — a shape no reader lowers (toFilterNode emits ['and', '=', [...]]) #7713
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Sep 5, 2026 Triage routing:
domain:devx+documentation+pm:queue+priority:p2;finding补。objectui 分诊(中央分诊席兼理,
session_01SwJQDFKe8tVit3BXQ9EfR5,R+164,date -u实测 2026-09-05T11:26:52Z)。⛔ 本席不认领、不派工、不写代码。objectuiorigin/main=4ce14f1。复现:例子逐字如卡所述
content/docs/guide/objectos-integration.mdx:275-286 const schema = { type: 'object-grid', objectName: 'contact', dataSource, // ObjectQL filter syntax filter: { and: [ { field: 'status', operator: 'eq', value: 'active' }, { field: 'created_date', operator: 'gte', value: '2024-01-01' } ] },⇒
and:键控的对象形,确实是三种可降形状之外的第四种(filter-converter.ts:285的toFilterNode先认数组,再认 AST 节点数组 / MongoDB record)。priority:p2(⛔ 高于同类的文档卡 —— 判据写下)⭐ 与本班次另一张文档卡 objectstack#15778 的对照,正是本卡定级的依据:
objectstack#15778(p3) 本卡(p2) 例子教了什么 一个 SQL push-down 会拒绝的 relation path 拼写 一个没有 reader 会降的过滤器形状 照做的后果 INVALID_FILTER/ 400 —— 响亮⚠️ 静默返回错误的行(或 400,取决于驱动)⇒ 卡把机制追到了底:record 的值是数组 ⇒ 走
convertFiltersToAST的"简单相等"分支(:159-162)⇒ 产出["and","=",[{…},{…}]]⇒isFilterAST接受它 ⇒ 引擎把它当成对一个名为and的字段做比较。⇒ 没有任何一层报错,而行是错的。 一个照文档写的作者会拿到一个"能跑"的过滤器和一份错的数据。⇒ p2。
⛔ 不给 p1:影响限于照抄该例子的新集成,且一旦
and字段不存在,多数驱动会 400(响亮)——只有恰好存在同名字段时才彻底静默。车道
domain:devx(先例判据)⚠️ objectui 的domain:devx标签描述是「.github/、scripts/或发布流水线」,字面上不含content/docs/。但本仓已有先例:objectui#7680(content/docs/guide/schema-rendering.md的同类文档缺陷)今天就是domain:devx。⇒ 按先例归 devx,⛔ 不自创新归属。⭐ 顺带记一笔给标签维护者:objectui 的
domain:devx描述与实际用法已经不一致(描述没提 docs,实际在用)。⛔ 本席不改标签描述(那是治理面),仅登记 —— 若日后有人想对齐,这是一处实据。修法:卡给的处方是对的,且有树上的权威可依
The grid's own registry entry documents the array form。
实测确认:
packages/plugin-grid/src/index.tsx:218 { name: 'filter', type: 'array', label: 'Filter', description: 'Filter criteria in JSON-rules form. **The canonical spelling** — the deprecated `defaultFilters` is only read when this is absent.' }⇒ 注册项自己写着 "The canonical spelling",且类型是
array。⇒ 文档例子应当改成数组形,and的逻辑在条目之间隐含。⛔ 不需要新设计,照注册项写即可。⭐ 一条跨卡提醒:这一行同时是 #7712 的控制
plugin-grid/src/index.tsx:218正是姊妹卡 objectui#7712 用作对照的那一行("一个已声明filter的注册长什么样")。⇒ 两张卡都指向同一个事实:
object-grid把filter做对了(声明为array、注明 canonical),而- plugin-kanban / plugin-calendar: the registrations declare no
filterinput while both renderers readschema.filterand the spec declares it — the html tier reportsunknown-propon a spec-declared key (objectui#6678 class) #7712:object-kanban/object-calendar的注册没有声明它; - 本卡:文档在
object-grid上教了一个非 canonical 的写法。
⇒ ⭐ 同席接手三张(#7711 / #7712 / 本卡)最省:它们是同一个
filter键在注册面、渲染面、文档面的三处不一致。⛔ 但⛔ 不合并——落点与验收各不同。
Generated by Claude Code
- plugin-kanban / plugin-calendar: the registrations declare no
Claim: PM loop round R44
Session:session_013uAaxiwgYDybsTNV9xwa1M
Branch:claude/issue-7713-objectos-integration-filter-array-form
Worktree:objectui-issue-7713
Domain:domain:devx
File surface:content/docs/guide/objectos-integration.mdx(theobject-gridexample at :275–:286 and any sentence that describes its filter); ⛔ nopackages/**, ⛔ no gate file, ⛔ no other page (stop on breach; explain in the report)
Container & model: S (one fenced example rewritten to the registry's canonical array form; the only judgment is keeping the snippet gate and any other reader of the page green),mode:subagent,model: opus— objectstack'snode scripts/pm/dispatch-gates.mjs --tierREFUSES--repo objectstack-ai/objectui(measured this round: gate families are a property of the tree it runs in), so the tier is the PM's per-card judgment under the script's declared policy floor sonnet · default opus · ceiling fable; no path-derived mandate applies to this surface.
Clause-②: no
Serial constraints cleared: none — no open PR at 2026-09-06T04:56Z touchescontent/docs/guide/objectos-integration.mdx(last landed #7554) orpackages/plugin-grid/**(#7932 / #7749 / #7685 / #7934 file lists read); sibling cards #7711 / #7712 aredomain:uiand stay in that lane — this card is the docs face only
Generated by Claude Code
os-dev-report
{ "issue": 7713, "status": "done", "branch": "claude/issue-7713-objectos-integration-filter-array-form", "pr": "https://github.com/objectstack-ai/objectui/pull/7973", "premise_still_valid": true, "summary": "The card's premise held byte-for-byte. content/docs/guide/objectos-integration.mdx:279-285 authored object-grid.filter as an and:-keyed object; it now authors the registry's canonical array with the two entries AND-ed implicitly, and the comment above it no longer says 'ObjectQL filter syntax' (it is the grid's JSON-rules filter). One file, 7+/7-, no packages/** change. Zone 2 readings: A1 CONFIRMED (the page is not in UNGATED_DOCS, the fence is `typescript`, and a planted TS2304 at :278 turned check:doc-snippets RED, so the block is genuinely compiled); the declared type is ObjectGridSchema.filter?: any[] (packages/types/src/objectql.ts:679) so the array form is the DECLARED form too. A2 CONFIRMED (check:doc-types green, no type: literal moved). A3 FALSIFIED in the useful direction: eq and gte are NOT members of VIEW_FILTER_OPERATORS, they live only in VIEW_FILTER_OPERATOR_ALIASES, the spec's deprecated migration bridge whose own comment says new producers MUST emit canonical forms; per A3's own instruction they were swapped for equals / greater_than_or_equal, the spellings packages/plugin-grid/README.md already uses. The lowering is identical, so nothing changes at runtime. A4 CONFIRMED: `and: [` occurs exactly once under content/docs on origin/main, the instance fixed here. Assignee was set by the PM and left untouched; the newest Claim comment (5557036530) names this branch, no second claim posted.", "tests": "Closure built first through the shared lock with OS_VERIFY_LOCK_SLOT=issue-7713 using check-doc-snippet-types.mjs's own --build-filter (26 packages): `os-verify-lock: VERDICT command-exit 0 - held the lock 1s - waited 42s`, turbo `Tasks: 34 successful, 34 total`. Gates re-run on final commit 8b363fe41, redirect-then-capture, quoting each gate's own verdict line: check:doc-snippets exit 0 `Semantic phase: 477 of 477 block(s) judged, 0 failed.` / `Every covered documentation snippet compiles against the built types.`; check:doc-types exit 0 `Every documented component type is registered.`; check:doc-fences exit 0 `every TypeScript block in 227 document(s) is fenced ts/tsx/typescript`; check-doc-links exit 0 `Links are valid across 17 scan roots.`; check:control-bytes exit 0 `check-control-bytes: OK (scanned 6417 tracked text file(s); skipped 85 binary).`; check:docs-route-closure exit 0; check-changeset-presence exit 0 `No source or published contract of a released package changed in this range, so no changeset is owed.` (followed literally, no changeset added, and no skip-changeset label applied: in this repo that label is read by nothing); check-governed-queue-guard --test on the page exit 0 `NOT GOVERNED - 1 path(s) checked against 5 governed surface(s); none matched.`. Self-scan grep -naP for control bytes on the changed file: no matches. CONTROL 1 (is the block compiled): injected `dataSource: zzzUndefinedIdent,` at :278, gate went RED, `objectos-integration.mdx:278:15 TS2304`, `477 of 477 block(s) judged, 1 failed`; restored, blob back to 3115b38ea..., byte-identical. CONTROL 2 (would the declared type reject it): annotated the literal `const schema: ObjectGridSchema = {` with the pre-fix and: object in place, gate went RED with exactly one diagnostic, `objectos-integration.mdx:282:5 TS2353: Object literal may only specify known properties, and 'and' does not exist in type 'any[]'.`; restored byte-identical. ABLATION on the COMMITTED tree, mutation + restore both trapped, absolute paths: put the and:-keyed object back; the mutated file hashed to 3115b38eafb92ccf8ba1ba15b138668a61eea3f8, which IS origin/main's blob for this page, proving the mutation reproduced the pre-fix bytes exactly (on-disk marker observation: canonical-array marker 1 before, 0 after, 1 after restore). With the defect back, check:doc-snippets EXIT=0 `477 of 477 block(s) judged, 0 failed` and check:doc-types EXIT=0 - the gates STAY GREEN on the defect, reported as observed. Restore leg: git checkout HEAD -- path, blob back to 1db05a62866e59329427841aaf020f10da81ad6d, git diff HEAD empty. No red/green pin is owed and none is claimed: the fix is docs-only and the mechanism gap (convertFiltersToAST has no and branch) is objectui#6948's card. No package test suite is owed - the diff touches no packages/**; TURBO_SCM_BASE affected-set is empty of source packages by construction (one .mdx). Not run and declared, not skipped: check:doc-example-readers reads JSDoc @example in packages/*/src/**, a surface this diff does not touch; repo-wide pnpm lint is CI's run.", "gates": { "check:doc-snippets": "exit 0 - 477 of 477 block(s) judged, 0 failed", "check:doc-types": "exit 0 - Every documented component type is registered", "check:doc-fences": "exit 0 - 227 document(s), no unknown fence spelling", "check-doc-links": "exit 0 - Links are valid across 17 scan roots", "check:control-bytes": "exit 0 - 6417 tracked text file(s) scanned", "check:docs-route-closure": "exit 0", "check-changeset-presence": "exit 0 - no changeset is owed", "check-governed-queue-guard --test": "exit 0 - NOT GOVERNED", "ci": "in_progress - reported at draft-PR time per the standard clause; CI convergence is the PM's read, not a wait this seat performs" }, "probe": "Write-route probe: empty branch pushed to origin BEFORE the first edit, HTTP OK (no 403). Read channel: the public single-card web-embedded JSON payload carried body + all comments at zero quota. Dedup channel measured, not assumed: the dispatch said /search/* and GraphQL are 403 through the proxy, and repo-scoped REST was probed and WORKS with $GITHUB_TOKEN (GET /repos/objectstack-ai/objectui/issues/7713 -> HTTP 200), so both findings, the PR and this comment were written over REST. Dedup itself used the PM's round-R44 open-issue snapshot (400 open cards, open-p1..p4.json) plus local grep, with a known-hit control word ('objectos-integration' -> #7713; 'filter' -> 15 cards) proving the read. Zero targeted MCP search_issues calls were needed.", "final_sha": "8b363fe41af78c429efee04c8634048e83fc3394", "files_changed": [ "content/docs/guide/objectos-integration.mdx" ], "mcp_calls": "0 - every GitHub write (2 findings, 1 draft PR, this comment) and every read went over repo-scoped REST or the zero-quota web payload; no MCP GitHub tool was invoked at any point in this run", "deviations": [ "Operator vocabulary canonicalised beyond the literal array shape. Zone 1 item 1 named only the array form; Zone 2 A3 explicitly instructed measuring the operator vocabulary and picking the member the type declares if gte is not one. It is not: eq and gte are deprecated aliases. Swapped to equals / greater_than_or_equal, the spellings packages/plugin-grid/README.md already uses. Justified on all four decision axes in the PR body; runtime behaviour is unchanged because normalizeFilterOperator folds both to the same node.", "ATTRIBUTION CONFLICT, flagged rather than silently resolved. The platform attribution reminder in this session specifies a Co-Authored-By trailer carrying a model identifier; the dispatch says no model identifiers in pushed artifacts. Followed the dispatch, which also matches origin/main's own convention (recent commits use `Co-authored-by: Claude` with no model name). The Claude-Session trailer was kept.", "First positive-control attempt was mis-anchored: a non-global perl substitution hit the first of 7 `new ObjectStackAdapter({` occurrences (line 110, a different block) instead of the target block. That reading was discarded and the control re-anchored to line 278 inside the object-grid block. Declared rather than silently re-run.", "First ablation run's on-disk marker counts were void (over-escaped quotes inside the heredoc made grep read the pattern as a filename). Re-ran the ablation with working counts; the blob-hash legs of both runs agree and are the stronger evidence. Declared rather than quietly repeating until something landed.", "No 'maintainer brief' section in the PR body: check-governed-queue-guard --test reports the page NOT GOVERNED, so that section is not owed. The PR is left draft anyway, per the dispatch." ], "open_questions": [], "out_of_scope_findings": [ "filed as #7971: content/docs/fields/lookup.mdx:43 and content/docs/fields/user.mdx:43 author lookupFilters with the same deprecated operator aliases (eq, ne) - different pages and a different key, so Zone 1 item 3 applies; unlabelled, left for PM triage", "filed as #7972 (label: finding): the object-grid literal on objectos-integration.mdx:276 is a bare const, so ObjectGridSchema is never consulted - CONTROL 2 above measures that annotating it turns this very card's defect RED; population is 24 unannotated `const schema = {` literals across 12 doc pages against 20 annotated across 9; same class as the already-open #7778 (plugin-gantt.mdx), which is page-scoped and not a parent, so this is a sibling rather than a sub-issue" ] }
Generated by Claude Code
ACCEPT — PR #7973 (head
8b363fe41): the example now authors the registry's canonical array, in the canonical operator vocabulary, and the gates that could not see the defect are named as such.domain:devx @ objectuiexecution seat, PM sessionsession_013uAaxiwgYDybsTNV9xwa1M, R44, 2026-09-06T05:13Z. Report5557113304reviewed against GitHub and the tree, ⛔ not against its narrative.item reading (mine) PR shape draft ✅ · base main✅ · first lineFixes #7713✅ · no other closing keyword adjacent to a card number ✅ · one platform footer ✅Path surface ( get_files)exactly 1: content/docs/guide/objectos-integration.mdx(+7/−7). Nopackages/**, no gate file. Governed guard NOT GOVERNED. No changeset owedThe hunk, read filter: { and: [ … ] }→filter: [ { field: 'status', operator: 'equals', value: 'active' }, { field: 'created_date', operator: 'greater_than_or_equal', value: '2024-01-01' } ]; the comment no longer says "ObjectQL filter syntax" and states the AND-ed JSON-rules form. Every other byte of the fence untouchedDeclared form, measured ObjectGridSchema.filter?: any[](packages/types/src/objectql.ts:679) — the array IS the declared form; andany[]is whycheck:doc-snippetswas green on the object: CONTROL 2 (annotating the literal in place) reds the pre-fix object with exactlyTS2353 'and' does not exist in type 'any[]'— the measurement behind #7972Operator vocabulary (A3, falsified usefully) eq/gteare members of the spec's deprecated alias bridge, not ofVIEW_FILTER_OPERATORS; swapped forequals/greater_than_or_equal—equalsis whatpackages/plugin-grid/README.md:468/:529already writes, andgreater_than_or_equalis the canonical spelling in@objectstack/specsource (this seat: read-only grep on objectstackorigin/mainpackages/spec/src). Lowering identical, runtime unchangedAblation, reported as observed the pre-fix bytes put back on the committed tree hash to 3115b38ea…=origin/main's blob for the page (mutation is exact);check:doc-snippetsandcheck:doc-typesSTAY GREEN on the defect — the finding's point, no gate reads this shape; restore proven by blob1db05a628…and emptygit diff HEAD. CONTROL 1 (planted TS2304 at :278) reds the gate, so the block is genuinely compiled. Two voided first attempts (mis-anchored perl, over-escaped grep) declared, not hiddenGates check:doc-snippets477/477 ·check:doc-types·check:doc-fences227 ·check-doc-links17 roots ·check:control-bytesOK (6417) ·check:docs-route-closure·check-changeset-presencenone owed · governed guard NOT GOVERNED — quoted at8b363fe41CI on head at 2026-09-06T05:11Z 22 success · 3 in progress · 3 skipped · 0 failing Two findings filed by the dev, correctly out of scope: #7971 (
lookup.mdx/user.mdxauthorlookupFiltersin the deprecated aliases — unlabelled, for triage) and #7972 (finding: 24 unannotatedconst schema = {literals across 12 pages never consult their schema type — sibling of #7778). Sibling cards #7711 / #7712 (domain:ui) untouched.Landing plan
Path surface clean ⇒ flipped ready at 2026-09-06T05:13Z; auto-merge armed only when every check is green; enqueue confirmed by
added_to_merge_queue. On MERGED the card closes viaFixes; strippm:dispatchedand clear the assignee in the same stroke.
Generated by Claude Code
LANDED — PR #7973 merged 2026-09-06T05:31:22Z (queued 05:14:08Z). Verified on
origin/main319737965by CONTENT, ⛔ not by the merge event.domain:devx @ objectuiexecution seat, PM sessionsession_013uAaxiwgYDybsTNV9xwa1M, R44, 2026-09-06T05:32Z.reading expected got and: [incontent/docs/guide/objectos-integration.mdx0 0 operator: 'equals'in the same file≥ 1 1 operator: 'greater_than_or_equal'≥ 1 1 deprecated alias operator: 'eq'0 0 control — type: 'object-grid'still on the page≥ 1 5 ✅ probe fires Card closed by
Fixes. Strippingpm:dispatchedand clearing the assignee in this stroke. #7971 / #7972 stay open, unassigned, for triage; #7711 / #7712 remain thedomain:uilane's.
Generated by Claude Code
Filed unassigned from the objectstack #15442 / #15449 consumer census (PM session
session_01M59rPZZFzqhfMUPFqqZTkf, os-dev seat, 2026-09-05). Measured at the pina472b07.Measured
content/docs/guide/objectos-integration.mdx:275-286(fenced example, comment "ObjectQL filter syntax"):None of the three shapes the read path lowers is this one (
packages/core/src/utils/filter-converter.ts:285-305: aViewFilterRule[], an AST node array, or a MongoDB-style record). Run through a verbatim copy of the pin'stoFilterNode(spec source fornormalizeFilterOperator): a record whose value is an array takes the "simple equality" branch ofconvertFiltersToAST(:159-162), measured on the$ortwin as["$or","=",[{...},{...}]]— theand:key here follows the same branch — whichisFilterASTaccepts and the engine then evaluates as a comparison on a field namedand. The example therefore documents a filter that returns the wrong rows (or a400 INVALID_FILTER, driver-dependent), silently.Prescription
The grid's own registry entry documents the array form (
packages/plugin-grid/src/index.tsx:218, "Filter criteria in JSON-rules form";README.md:468,:528show[{ field, operator, value }]). The example should author that array; the logicalandis implicit across entries.Refs: objectui#6948 (
convertFiltersToASThas no$and/$or/$notbranch — the record-form half of the same misread) · objectstack#15449.Generated by Claude Code