Repository navigation
Description
Filed by the triage seat from two maintainer rulings (2026-08-25 decision-inbox batch adjudication, objectui batch 4; acceptance verbatim: 「同意」). Family-folded: same file surface (the spec-side ComponentPropsMap), same defect class (a props-map entry disagreeing with the authority the platform already ruled), both members ruled — five fold gates pass; per-key criteria below keep them independently checkable.
Key 1 — ComponentPropsMap['object-grid'].data (ruling ui#6207-A)
Today z.array(z.unknown()).optional() ("Static inline rows — bypasses the object query"), while ViewDataSchema — the authority objectui#5090 ruled and pinned the declaration against — is an object discriminated on provider (object/api/value/schema). Measured on @objectstack/spec@17.2.0: { provider: 'value', items: [] } is refused by the props-map entry while being the pinned-legal form.
Ruled: the props-map entry converges onto ViewDataSchema. The bare-array form is the deprecated staticData shortcut (the #4648 carve-out already refuses to publish it). Migration check before landing: sweep generated artifacts/templates for bare-array data authors; if any exist, the change carries their migration note.
Key 2 — ComponentPropsMap['element:number'].filter (ruling ui#6206-B)
Today record | object ("Filter criteria"), while every other filter input across the component tree is the platform's array-of-rules form (ViewFilterRule entries — object-grid, object-metric, record:related_list, plugin-list, data-list). The registration declares array; the renderer passes through to adapter.aggregate({ filter }) / adapter.find(object, { $filter }) opaquely.
Ruled: one filter orthography platform-wide — the spec entry aligns to the ViewFilterRule array form. Measurement-first (binding): verify the adapter/runtime behaviour on array filters for this element's read path before editing; if the runtime genuinely cannot take the array form here, STOP and report the fork back to triage — do not land a declaration the runtime refuses (that would recreate the defect in the opposite direction).
Acceptance (per key, independently checkable)
ComponentPropsMap['object-grid'].safeParse({ data: { provider: 'value', items: [] } })→ success; bare-array authored form handled per the migration note.ComponentPropsMap['element:number'].filteraccepts the ViewFilterRule array form (with the runtime measurement recorded in the PR).- Downstream (objectui, not this card): the formatZodError 把 union 分支的拒绝信息压成 "Invalid input" —— #4001 策展的散文在 CLI 路径上到不了作者 #4971 exemption entries
object-grid.data:objectandelement:number.filter:arrayinregistry-inputs-spec-parity.test.tsbecome deletable — ui#6207/ui#6206 arepm:blockedon this card and their unlock re-verification is exactly that deletion, after a released spec version reaches the objectui pin (consumer-installable criterion).
Clause-②: yes — both keys change the published contract's accept set; contract-review tier applies at dispatch. Serial check at claim: name any in-flight spec cards touching the ComponentPropsMap surface.
Refs: objectui#6207 · objectui#6206 (measurements, reproduce commands, and the ruling comments) · objectui#5090 / PR #5108 · objectui#4971 · objectui#4648.
Status (PM, 2026-08-25, round R6) — Key 1 landed via PR #12120 (merged 13:45Z). Key 2 forked back under ruling ui#6206-B's own measurement-first clause: the pinned runtime refuses the raw ViewFilterRule[] form on this element's aggregate read path (measurement recorded in PR #12120 and the card report above).
Blocked-by: objectstack-ai/objectui#6302
Unblock re-verification: when objectui#6302 lands (adapter lowers rule-arrays on the aggregate path) and a spec-consumable pin bump follows, Key 2 re-enters the queue on this card.
Activity
os-litant commentedon Aug 25, 2026
Claim: PM loop round R6
Session:
session_01NDGG54XF5gbTLdQzCtnaVVBranch:
claude/issue-12039-componentpropsmap-rulingsWorktree:
objectstack-issue-12039Domain:
domain:specFile surface:
packages/spec/src/ui/component.zod.ts(object-grid.data + element:number.filter entries) + tests + migrations tail-append + changeset;packages/spec/src/ui/view.zod.tsEXCLUDED (H17: on-hold #8346 declares it Restart-touch — dev stops and reports if it turns out to be needed) (stop on breach; explain in the report)Container & model: M,
mode:subagent,model: claude-fable-5— dispatch-gates 2026-08-25 @0b04839: "no path-derived mandate … a card changing contract accept/reject behaviour or widening the public surface is claude-fable-5"; clause-② content leg + ruling implementation ⇒ fable mandatoryClause-②: yes
Serial constraints cleared: registry.ts tail-append shared with batch siblings #11842 (certain) and #11832 (conditional) — same-file serial WAIVED this batch by maintainer instruction (2026-08-25, chat, verbatim: 「并行5个子任务,加快进度」) under the 4-point substitute discipline. component.zod.ts sole writer this batch. Rulings implemented: ui#6207-A and ui#6206-B (maintainer batch adjudication recorded on those cards 2026-08-25 06:24Z; 6206-B's measurement-first precondition is binding and quoted in the dispatch order). No pin assertions on sibling behavior.
Generated by Claude Code
os-litant commentedon Aug 25, 2026
{ "issue": 12039, "status": "needs_decision", "branch": "claude/issue-12039-componentpropsmap-rulings", "pr": "https://github.com/objectstack-ai/objectstack/pull/12120", "premise_still_valid": true, "summary": "Key 1 (object-grid.data, ui#6207-A) implemented and shipped as a draft PR: ComponentPropsMap['object-grid'].data converged from z.array(z.unknown()) onto ViewDataSchema; ADR-0087 semantic entry object-grid-data-view-data-converged; ruled migration check ran — zero bare-array data authors in examples/, skills/, create-objectstack, content/docs/, spec fixtures; ADR-0122 fallout handled (ObjectGridPropsParsed declared, Iso839 pin deleted with receipt, count 835->834 post-merge). Key 2 (element:number.filter, ui#6206-B) NOT edited: the binding measurement-first precondition measured the pinned runtime REFUSING the raw ViewFilterRule[] form on the element's primary (analytics) read path, so per the ruling's own text this is a fork back to triage — see open_questions. Both premises re-verified at BASE 8d60dcd (data was bare array at component.zod.ts:2266; filter was FilterConditionSchema at :1703); ui#6207/ui#6206 confirmed OPEN with pm:blocked.", "tests": "Union at final commit 8fcbd6b (after merging origin/main @ a933ed7): spec full suite 'pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2' -> 'Test Files 425 passed (425) / Tests 11340 passed (11340)'; 'check:generated' -> '✓ All 14 generated artifacts are up to date' (check:test-typecheck ✓); spec typecheck green. Key-2 measurement executable: lowerAnalyticsWhere({where:[{field:'stage',operator:'equals',value:'won'}]}) THREW '[analytics] received a 'where' array that is not a filter'; AST tuples accepted -> {stage:'won'}; isFilterAST(ViewFilterRule[]) = false. Type-level reverse verification on rebuilt dist .d.ts: bare-array data -> TS2322 naming the ViewData union (red); provider object -> exit 0 (green). Reverse direction observed as predicted (red), no inversion.", "gates": { "head": "8fcbd6b", "verdict_source": "each gate's own printed verdict line; exit codes captured before any pipe (run-gates scripts write per-gate logs)", "dispatch_named": { "check:changeset-gate-self-tests": 0, "check:cross-package-test-inputs": 0, "@objectstack/lint check:doc-formula-expressions": 0, "@objectstack/spec check:empty-state": 0, "@objectstack/spec check:liveness": 0, "@objectstack/spec check:strictness-ledger": 0, "@objectstack/spec check:variant-docs": 0, "check:merge-driver": 0, "check:published-files": 0, "check:query-options-erasure": 0, "check:slot-lookup": 0, "check:spec-parsed-alias": 0, "scripts/check-adr-0087-registration.mjs": 0, "check:nul-bytes": 0 }, "rederived_additional": { "note": "node scripts/pm/dispatch-gates.mjs re-run with no paths at 8fcbd6b; stderr line confirms answer taken from objectstack-ai/objectstack at 8fcbd6b", "all_exit_0": [ "check:doc-anchors", "check:doc-authoring", "@objectstack/lint check:doc-security-posture", "check:docs-audit-scope", "check:docs-redirects", "check:published-readme-links", "check:quick-reference-counts", "check:react-page-adapter-contract", "check:role-word", "check:objectui-changeset", "check:test-source-alias", "check:type-source-resolution", "check:engine-double-contract", "check:where-matcher", "check-changeset-no-major", "check-ci-filter-parity", "check-cross-package-test-inputs(ci)", "check-doc-frontmatter", "check-doc-route-spelling", "check-docs-section-name", "check-empty-changeset", "check-plugin-teardown-shape", "check-section-landing-index", "docs-audit/check-affected-docs", "docs-audit/check-drift-comment", "release-rehearsal-clone --self-test" ], "post_workspace_build_exit_0": [ "check-dev-prereqs", "check:type-check-coverage", "check:type-check-debt (--re-measure, after turbo build of the 70-task package closure: 70 successful)" ] } }, "line_budget": { "skills_diff": "none — no skills/** file touched", "branch_delta_vs_origin_main": "9 files changed, 200 insertions(+), 10 deletions(-)" }, "files_changed": [ ".changeset/object-grid-data-view-data-converged.md", "content/docs/references/ui/component.mdx", "packages/spec/api-surface/ui.json", "packages/spec/export-origins/ui.json", "packages/spec/src/migrations/entries/semantic/18.object-grid-data-view-data-converged.ts", "packages/spec/src/migrations/registry.ts", "packages/spec/src/type-alias-convention.pin.test.ts", "packages/spec/src/ui/component.test.ts", "packages/spec/src/ui/component.zod.ts" ], "deviations": [ "Key 2 not implemented — the ruling's own binding fork condition triggered (runtime refuses the array form on the primary read path); reported as needs_decision, not silently flipped.", "Declared file-surface increment: packages/spec/src/type-alias-convention.pin.test.ts (not in the claim's file list) — forced by the convergence itself: ViewDataSchema's input≠infer removes ObjectGridPropsSchema from the pin family; handled per that file's own prescription (Iso839 deleted with receipt, ObjectGridPropsParsed declared).", "Declared narrowing: repo-wide farm (pnpm lint et al.) left to CI; local runs = affected package full suite + every dispatch-named gate + every additionally path-derived family from the dispatch-gates recompute.", "Key-2 runtime measurement executed via tsx on service-analytics src (built dist does not export lowerAnalyticsWhere); the same refusal class is pinned in the package's own filter-array-lowering.test.ts UNLOWERABLE table, and the dependency closure was built first.", "Two verify-lock runs exceeded the 600s foreground cap and were moved to background by the harness; both completed under the lock with VERDICT command-exit lines read from their logs (no watcher-parked turn end).", "registry.ts tail-append discipline: entries are per-file (conflict-free by construction); merged origin/main post-sibling-landing, gen:migration-registry re-run produced zero drift; the one real conflict (pin-count self-test) resolved to the joint truth 834 with both receipts kept." ], "open_questions": [ { "question": "element:number.filter (ui#6206-B) — Option B's binding measurement failed at the current objectui pin (190fbd01): the renderer passes filter opaquely; ObjectStackAdapter.aggregate sends it RAW as analytics `where`; the platform analytics door refuses non-AST arrays (measured executable: [{field,operator,value}] throws '[analytics] received a `where` array that is not a filter'; AST tuples accepted; both strategies share the door; analytics is foundational — 'the CLI always loads it'). The adapter's rule-array lowering (translateFilterArray) exists but runs only on the find() path, which aggregate() reaches only when analytics is absent — and deliberately not on a server rejection. Landing ViewFilterRule[] in spec now would be the 'declaration the runtime refuses' the ruling forbids. How should Option B be sequenced?", "options": [ "A. Sequence the consumer first: objectui card — ObjectStackAdapter.aggregate lowers rule-shaped arrays before the wire (reusing translateFilterArray, already used one method over on find()); land, bump .objectui-sha; THEN converge the spec entry to z.array(ViewFilterRuleSchema) as ruled, on a follow-up card Blocked-by the pin bump.", "B. Converge the spec entry now anyway — forbidden by the ruling's own text (recreates the defect in the opposite direction).", "C. Flip to the record form (original Option A) — forbidden by the dispatch (不许悄悄倒向 record 形); would need a re-ruling.", "D. Align the spec entry to the WIRE vocabulary instead (FilterCondition | FilterArray AST) — differs from both ruled options; also needs a re-ruling." ], "recommendation": "A. Four axes: real business need — measured: designer/registry tier already declares 'array' for every filter input and authors write rule arrays in view configs; the element errors today only because one adapter path skips a lowering it performs elsewhere. Long-term soundness — Option B's one-orthography goal stands; the lowering belongs in the consumer that owns the authoring→wire translation (contract-first: no wire-tier loosening, no spec-side fallback). AI-hard-to-get-wrong — one array orthography platform-wide beats a per-block record exception; the current state (registry says array, spec says record, wire refuses raw arrays on one path) is the maximally confusing state for an AI author. Startup scope — smallest change set: one adapter method reuses existing machinery; no new capability surface, no new spec shape." } ], "out_of_scope_findings": [] }Generated by Claude Code
os-litant commentedon Aug 25, 2026
os-dev-report (re-post: the HTML-comment marker on the previous comment was eaten by the body sanitizer; this literal-text form is the scannable copy — same JSON)
{ "issue": 12039, "status": "needs_decision", "branch": "claude/issue-12039-componentpropsmap-rulings", "pr": "https://github.com/objectstack-ai/objectstack/pull/12120", "premise_still_valid": true, "summary": "Key 1 (object-grid.data, ui#6207-A) implemented and shipped as a draft PR: ComponentPropsMap['object-grid'].data converged from z.array(z.unknown()) onto ViewDataSchema; ADR-0087 semantic entry object-grid-data-view-data-converged; ruled migration check ran — zero bare-array data authors in examples/, skills/, create-objectstack, content/docs/, spec fixtures; ADR-0122 fallout handled (ObjectGridPropsParsed declared, Iso839 pin deleted with receipt, count 835->834 post-merge). Key 2 (element:number.filter, ui#6206-B) NOT edited: the binding measurement-first precondition measured the pinned runtime REFUSING the raw ViewFilterRule[] form on the element's primary (analytics) read path, so per the ruling's own text this is a fork back to triage — see open_questions. Both premises re-verified at BASE 8d60dcd (data was bare array at component.zod.ts:2266; filter was FilterConditionSchema at :1703); ui#6207/ui#6206 confirmed OPEN with pm:blocked.", "tests": "Union at final commit 8fcbd6b (after merging origin/main @ a933ed7): spec full suite 'pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2' -> 'Test Files 425 passed (425) / Tests 11340 passed (11340)'; 'check:generated' -> '✓ All 14 generated artifacts are up to date' (check:test-typecheck ✓); spec typecheck green. Key-2 measurement executable: lowerAnalyticsWhere({where:[{field:'stage',operator:'equals',value:'won'}]}) THREW '[analytics] received a 'where' array that is not a filter'; AST tuples accepted -> {stage:'won'}; isFilterAST(ViewFilterRule[]) = false. Type-level reverse verification on rebuilt dist .d.ts: bare-array data -> TS2322 naming the ViewData union (red); provider object -> exit 0 (green). Reverse direction observed as predicted (red), no inversion.", "gates": { "head": "8fcbd6b", "verdict_source": "each gate's own printed verdict line; exit codes captured before any pipe (run-gates scripts write per-gate logs)", "dispatch_named": { "check:changeset-gate-self-tests": 0, "check:cross-package-test-inputs": 0, "@objectstack/lint check:doc-formula-expressions": 0, "@objectstack/spec check:empty-state": 0, "@objectstack/spec check:liveness": 0, "@objectstack/spec check:strictness-ledger": 0, "@objectstack/spec check:variant-docs": 0, "check:merge-driver": 0, "check:published-files": 0, "check:query-options-erasure": 0, "check:slot-lookup": 0, "check:spec-parsed-alias": 0, "scripts/check-adr-0087-registration.mjs": 0, "check:nul-bytes": 0 }, "rederived_additional": { "note": "node scripts/pm/dispatch-gates.mjs re-run with no paths at 8fcbd6b; stderr line confirms answer taken from objectstack-ai/objectstack at 8fcbd6b", "all_exit_0": [ "check:doc-anchors", "check:doc-authoring", "@objectstack/lint check:doc-security-posture", "check:docs-audit-scope", "check:docs-redirects", "check:published-readme-links", "check:quick-reference-counts", "check:react-page-adapter-contract", "check:role-word", "check:objectui-changeset", "check:test-source-alias", "check:type-source-resolution", "check:engine-double-contract", "check:where-matcher", "check-changeset-no-major", "check-ci-filter-parity", "check-cross-package-test-inputs(ci)", "check-doc-frontmatter", "check-doc-route-spelling", "check-docs-section-name", "check-empty-changeset", "check-plugin-teardown-shape", "check-section-landing-index", "docs-audit/check-affected-docs", "docs-audit/check-drift-comment", "release-rehearsal-clone --self-test" ], "post_workspace_build_exit_0": [ "check-dev-prereqs", "check:type-check-coverage", "check:type-check-debt (--re-measure, after turbo build of the 70-task package closure: 70 successful)" ] } }, "line_budget": { "skills_diff": "none — no skills/** file touched", "branch_delta_vs_origin_main": "9 files changed, 200 insertions(+), 10 deletions(-)" }, "files_changed": [ ".changeset/object-grid-data-view-data-converged.md", "content/docs/references/ui/component.mdx", "packages/spec/api-surface/ui.json", "packages/spec/export-origins/ui.json", "packages/spec/src/migrations/entries/semantic/18.object-grid-data-view-data-converged.ts", "packages/spec/src/migrations/registry.ts", "packages/spec/src/type-alias-convention.pin.test.ts", "packages/spec/src/ui/component.test.ts", "packages/spec/src/ui/component.zod.ts" ], "deviations": [ "Key 2 not implemented — the ruling's own binding fork condition triggered (runtime refuses the array form on the primary read path); reported as needs_decision, not silently flipped.", "Declared file-surface increment: packages/spec/src/type-alias-convention.pin.test.ts (not in the claim's file list) — forced by the convergence itself: ViewDataSchema's input≠infer removes ObjectGridPropsSchema from the pin family; handled per that file's own prescription (Iso839 deleted with receipt, ObjectGridPropsParsed declared).", "Declared narrowing: repo-wide farm (pnpm lint et al.) left to CI; local runs = affected package full suite + every dispatch-named gate + every additionally path-derived family from the dispatch-gates recompute.", "Key-2 runtime measurement executed via tsx on service-analytics src (built dist does not export lowerAnalyticsWhere); the same refusal class is pinned in the package's own filter-array-lowering.test.ts UNLOWERABLE table, and the dependency closure was built first.", "Two verify-lock runs exceeded the 600s foreground cap and were moved to background by the harness; both completed under the lock with VERDICT command-exit lines read from their logs (no watcher-parked turn end).", "registry.ts tail-append discipline: entries are per-file (conflict-free by construction); merged origin/main post-sibling-landing, gen:migration-registry re-run produced zero drift; the one real conflict (pin-count self-test) resolved to the joint truth 834 with both receipts kept.", "Report marker: the previous report comment's HTML-comment marker was stripped by the body sanitizer (read back and confirmed); this comment is the corrected, literal-text-marked copy." ], "open_questions": [ { "question": "element:number.filter (ui#6206-B) — Option B's binding measurement failed at the current objectui pin (190fbd01): the renderer passes filter opaquely; ObjectStackAdapter.aggregate sends it RAW as analytics `where`; the platform analytics door refuses non-AST arrays (measured executable: [{field,operator,value}] throws '[analytics] received a `where` array that is not a filter'; AST tuples accepted; both strategies share the door; analytics is foundational — 'the CLI always loads it'). The adapter's rule-array lowering (translateFilterArray) exists but runs only on the find() path, which aggregate() reaches only when analytics is absent — and deliberately not on a server rejection. Landing ViewFilterRule[] in spec now would be the 'declaration the runtime refuses' the ruling forbids. How should Option B be sequenced?", "options": [ "A. Sequence the consumer first: objectui card — ObjectStackAdapter.aggregate lowers rule-shaped arrays before the wire (reusing translateFilterArray, already used one method over on find()); land, bump .objectui-sha; THEN converge the spec entry to z.array(ViewFilterRuleSchema) as ruled, on a follow-up card Blocked-by the pin bump.", "B. Converge the spec entry now anyway — forbidden by the ruling's own text (recreates the defect in the opposite direction).", "C. Flip to the record form (original Option A) — forbidden by the dispatch (不许悄悄倒向 record 形); would need a re-ruling.", "D. Align the spec entry to the WIRE vocabulary instead (FilterCondition | FilterArray AST) — differs from both ruled options; also needs a re-ruling." ], "recommendation": "A. Four axes: real business need — measured: designer/registry tier already declares 'array' for every filter input and authors write rule arrays in view configs; the element errors today only because one adapter path skips a lowering it performs elsewhere. Long-term soundness — Option B's one-orthography goal stands; the lowering belongs in the consumer that owns the authoring→wire translation (contract-first: no wire-tier loosening, no spec-side fallback). AI-hard-to-get-wrong — one array orthography platform-wide beats a per-block record exception; the current state (registry says array, spec says record, wire refuses raw arrays on one path) is the maximally confusing state for an AI author. Startup scope — smallest change set: one adapter method reuses existing machinery; no new capability surface, no new spec shape." } ], "out_of_scope_findings": [] }Generated by Claude Code
os-litant commentedon Aug 25, 2026
ACCEPT (Key 1 half-delivery) — PR #12120 (R6, reviewer of record: spec seat, session
session_01NDGG54XF5gbTLdQzCtnaVV).Checklist conclusion (verified against GitHub + local git diff): draft ✓ · base
main✓ ·Part of #12039first line (correct — this card stays open past the merge; Key 2 remains) ✓ · 9 files +200/−10:data→ViewDataSchema.optional()exactly per ruling ui#6207-A (quoted verbatim in the PR), acceptance-criterion test present ({ provider: 'value', items: [] }accepted — the exact value the old entry refused — plus bare-array refused at thedatapath), ADR-0087 semantic entryobject-grid-data-view-data-converged+ regenerated registry, ADR-0122 pin departure with receipt (835→834), api-surface/export-origins carry the newObjectGridPropsParsedexport ✓ ·element:number.filteruntouched ✓ ·view.zod.tsNOT touched (H17 #8346 exclusion honored — import only) ✓ · ruled migration check ran: zero bare-arraydataauthors across examples/skills/create-objectstack/docs/fixtures ✓ · no governed path ✓.Key 2 (ruling ui#6206-B): the binding measurement-first precondition failed as the ruling anticipated — at objectui pin
190fbd01the pinned runtime refuses rawViewFilterRule[]on the element's primary (analytics) read path; the mechanism chain (renderer opaque pass-through → adapter sends raw on the aggregate path →lowerAnalyticsWherethrows → analytics is the default deployment's path) is recorded in the PR body with executable evidence. The dev stopped per the ruling's own text instead of forcing or silently flipping — correct outcome, not a failed dispatch. Fork recorded in the decision comment below.Contract review (clause-② content leg, Key 1: accept-set change on a published props-map entry): fuse reading
get_session.external_metadata.last_served_model = claude-fable-5=CONTRACT_REVIEW_TIER(this seat, self-dispatched-card path). Verdict: PASS — the convergence lands exactly the ruled authority (ViewDataSchema, #5090-pinned), no narrowing beyond the ruling's scope (staticDataretained as the ruling left it), migration prescription registered. Clearingneeds:contract-reviewboth carriers in this write batch.Landing posture: per the opposing-fact-during-ruled-implementation clause, PR #12120 does NOT get auto-merge yet — it stays draft as the maintainer's objection window while the Key-2 fork decision is open (decision comment follows). CI green + reviewed; one label-flip away from the queue once the fork is answered or waved through.
Generated by Claude Code
os-litant commentedon Aug 25, 2026
[决策] Key 2(
element:number.filter,裁决 ui#6206-B)实测分叉 —— 如何给 Option B 排序?分叉事实(dev 实测,机制链在 PR #12120 正文,可执行证据齐全):裁决 B 的绑定前置「Measurement-first is binding」实测失败 —— objectui pin
190fbd01上,渲染器把 filter 不透明下传,ObjectStackAdapter.aggregate()走 analytics 路径时原样发送;analytics 门对非 AST 数组响亮拒绝(lowerAnalyticsWherethrows);analytics 是基础能力(CLI 恒加载)⇒ 拒绝路径就是默认部署路径。规则数组的 lowering 机器(translateFilterArray)同文件已存在,但只接在find()路径上 —— 这是 objectui 适配器一条路径漏接 lowering,不是运行时语义上不能收数组。现在落 spec 声明 = 裁决自己禁止的「运行时拒绝的声明」。选项:
ObjectStackAdapter.aggregate()在上线前对 rule 形数组做 lowering(复用find()路径既有机器)→ 落地 → pin bump → 然后 spec entry 按原裁决收敛z.array(ViewFilterRuleSchema),Blocked-by pin bump。不改任何已裁语义,只加前置顺序。四维分析:
array;作者照 manifest 补全写数组,今天在这个 element 上会渲染成错误态 —— 这是真实用户可达的缺陷,修的是适配器漏接的 lowering,不是投机面。IHttpServer.setFallbackHandler的 Hono 实现 + dispatcher 端点派发步 + 路由台账登记 #5090/正字法裁决一脉;C/D 都要推翻或旁绕已裁方向。推荐:A。 若同意,本席将:在 objectui 立消费方卡(出处 + 可执行判据 + Blocked-by 关系),本卡 Key 2 半边转
pm:blocked等 pin bump,PR #12120(Key 1,已复核全绿)翻 ready 入队。置信缺口:实测钉在 pin
190fbd01;裁到之时若 pin 已前移或适配器已在上游修掉,判据重跑一遍再执行(实测命令在 PR 正文,可复跑)。PR #12120(Key 1)现按异议窗口条款悬置 draft —— 本卡答复即放行。回一个字母即可。
Generated by Claude Code
12 remaining items
baozhoutao commentedon Sep 1, 2026
Unlock note — the ruled Key-2 prerequisite has landed: the objectui pin now contains objectui#6828
From the
domain:devxseat (sessionsession_01WLJQhde67SeTccsmnBVarV), which executed #14027. For thedomain:specseat, which owns this card's Key-2 half — ⛔ no label or state changed here; the release decision is the unlock sweep's / your lane's.Measured on
origin/mainafter PR #14165 merged (83be4601):.objectui-sha=d8ec8d6d4f011b11c8eb1e6dbd364ef206711391(objectui main, 2026-09-01 08:23Z)git show $(cat .objectui-sha):packages/data-objectstack/src/aggregate-filter-lowering.test.tssucceeds — the objectui#6828 fix and its 22-pin test file are at the pin.Per the 2026-08-25 ruling's own caveat, the spec-side convergence to
z.array(ViewFilterRuleSchema)should re-run the recorded refusal measurement at THIS pin before converging. The machine-readable blocker line recorded on this card (comment 5486863947) pointed at the pin bump; that predicate is now satisfied.Generated by Claude Code
os-zhuang commentedon Sep 2, 2026
Unlock scan by the
domain:specseat (session_01GDA48PuRFrHyRfdkBz8m21):pm:blocked→pm:queue.Release double-check per the state-machine rules: ① the most recent transition comment (5486691783, 2026-09-01T00:26Z) set the condition to
Blocked-by: #14027(the console-pin bump), refined by comment 5486863947 to "the pin must carry objectui#6828"; #14027 is CLOSED and the devx seat's unlock note (comment 5492894409) measured the pin — re-verified by this seat onorigin/mainata39b02a6:.objectui-sha=d8ec8d6d4f01…,packages/data-objectstack/src/aggregate-filter-lowering.test.tsPRESENT at that pin, andtranslateFilterArray(params.filter)present inpackages/data-objectstack/src/index.tsat that pin (1 hit). ② No PR merged against this card after that comment. File-surface re-check on the merged ref:packages/spec/src/ui/component.zod.tslast moved by #14165 (the pin bump) and #14158 — neither touched theelement:numberentry, so the Key-2 convergence is still owed.What re-enters the queue is Key 2 ONLY (Key 1 landed via PR #12120): converge
ComponentPropsMap['element:number'].filterto theViewFilterRulearray form per ruling ui#6206-B and the 2026-08-25 Option-A sequencing ruling (comment 5409255480), with that ruling's own caveat carried into the dispatch order — re-run the recorded refusal measurement (executable commands in PR #12120's body) at THIS pin before converging. Clause-② yes ⇒ CONTRACT_REVIEW_TIER. TypeBugplaces it in the Bug tier of the selection order; it claims fresh when a slot frees (5/5 in flight at this write). No assignee residue to clear.Generated by Claude Code
claude commentedon Sep 2, 2026
Claim: PM loop,
domain:specseat (seat post #6017) — Key 2 only (Key 1 landed via PR #12120)Session:
session_01GDA48PuRFrHyRfdkBz8m21Branch:
claude/issue-12039-element-number-filter-arrayWorktree:
objectstack-issue-12039-key2Domain:
domain:specFile surface:
packages/spec/src/ui/component.zod.ts(theelement:numberentry'sfilteronly) + its tests + ADR-0087 semantic entry (tail-append underpackages/spec/src/migrations/entries/semantic/, regeneratedregistry.ts) + changeset + regenerated references/api-surface products as the gates demand.packages/spec/src/ui/view.zod.tsEXCLUDED (H17: on-hold #8346 declares it Restart-touch —ViewFilterRuleSchemais imported, never edited; dev stops and reports if an edit there turns out to be needed).Container & model: S,
mode:subagent, servedclaude-fable-5-1(Clause-② content leg: accept-set change on a published props-map entry ⇒ contract-review tier; fuse literal readsclaude-fable-5, posture recorded on #14303).Clause-②: yes.
Ruling implemented: ui#6206-B (one filter orthography platform-wide —
z.array(ViewFilterRuleSchema)) under the 2026-08-25 Option-A sequencing ruling (comment 5409255480). Prerequisite satisfied and re-verified this seat:.objectui-shaonorigin/main=d8ec8d6d…, which carries objectui#6828 (comment 5502817852). The ruling's own caveat is binding in the dispatch order: re-run the recorded refusal measurement (executable commands in PR #12120's body) at THIS pin before converging; runtime still refusing ⇒ STOP and report the fork, no declaration change.Serial constraints:
component.zod.tshas no in-flight writer in this lane (seat post §3); no ADR-0087 registry tail-append in flight in this lane after PR #14335 lands (relay: this PR's registry entry regenerates after that merge).Generated by Claude Code
claude commentedon Sep 2, 2026
os-dev-report
{ "issue": 12039, "status": "done", "branch": "claude/issue-12039-element-number-filter-array", "pr": "https://github.com/objectstack-ai/objectstack/pull/14404", "head": "8068a7f31", "premise_still_valid": true, "summary": "Key 2 only (Key 1 landed via PR #12120). Step 0 passed on all four readings at objectui pin d8ec8d6d before any edit: (1) the adapter's aggregate() analytics branch lowers an array filter through translateFilterArray (index.ts:4924-4926, objectui#6828); (2) aggregate-filter-lowering.test.ts is present at the pin and pins rule-object arrays (single rule to AST tuple, isFilterAST false-then-true, alias mapping, and-join, spread-into-logical-node, cross-path parity); (3) elements.tsx passes filter opaquely to adapter.aggregate; (4) the objectstack analytics door is unchanged by design (isFilterAST(rule array)=false, isFilterAST(AST)=true, lowerAnalyticsWhere throws on the raw rule array, lowers AST tuples to { stage: 'won' }) — so no fork, the chain is authored array -> adapter lowering -> AST -> accepted. Then ComponentPropsMap['element:number'].filter converged from FilterConditionSchema to z.array(ViewFilterRuleSchema).optional() per ruling ui#6206-B under the 2026-08-25 Option-A sequencing ruling, with ADR-0087 semantic entry element-number-filter-rule-array (registry regenerated via gen:migration-registry; Key 1's and #14335's entries both present), a BREAKING minor changeset carrying the FROM -> TO block and the registered marker, ElementNumberPropsParsed declared with the Iso818 pin deleted and receipted (836 -> 835, ADR-0122), new orthography tests, and api-surface/export-origins/docs reference regenerated. Ruled migration sweep: exactly one in-repo record-form author — the spec fixture 'should accept full number props' — rewritten to the array form; zero in examples/, skills/, create-objectstack, content/docs/, packages/apps/ (the page.test.ts hits are dataSource.filter, a different key). Observed, not changed: element:record_picker.filter still reads FilterConditionSchema (component.zod.ts:2141). view.zod.ts untouched (H17). Branch was fast-forwarded onto origin/main d62f990a9 (#14335 merged) before the first edit, so no regen-merge was needed. needs:contract-review added to PR #14404 and to #12039 with comparative read-back. Draft PR, not flipped ready, no auto-merge, not enqueued.", "tests": "All on HEAD 8068a7f31 (tree clean), each under scripts/pm/os-verify-lock.sh with exit codes captured from redirection. pnpm --filter @objectstack/spec run typecheck: tsc --noEmit clean, check:scripts-typecheck clean, 'check:test-typecheck: OK — 54 file(s) / 262 error(s) / 146 pinned signature(s) held' (VERDICT command-exit 0, re-run after the last commit). Touched files: vitest run --maxWorkers=2 src/ui/component.test.ts src/type-alias-convention.pin.test.ts — Test Files 2 passed, Tests 238 passed. Full spec suite: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 — Test Files 450 passed | 1 skipped (451), Tests 12111 passed | 1 skipped (12112), 325.86s, VERDICT command-exit 0. check:generated — '✓ All 15 generated artifacts are up to date' (after --fix proved exactly three stale: api-surface, export-origins, docs). check:api-surface ✓, check:export-origins ✓, check:authorable-surface ✓ ('authorable-defaults/ verified against upstream d62f990a985e — 1236 default(s) unchanged', no anchor hand-edited), check:migration-registry ✓, scripts/check-adr-0087-registration.mjs ✓ ('1 declared-breaking changeset(s), each carrying an ADR-0087 disposition … registered element-number-filter-rule-array'), check:doc-authoring ✓ ('14375 customer-facing string(s) across 705 spec sources clean'), check:nul-bytes ✓ ('scanned 7843 text file(s) … no raw ASCII control bytes'). Derived union: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (stderr: derived at commit 8068a7f31) = 74 commands; 72 exit 0 — those that first printed PREREQUISITE NOT MET / dist-older-than-src were re-run green after building the lint closure and then the workspace (turbo run build --filter='./packages/*' --filter='./packages/*/*', 70/70 successful): doc-formula-expressions, doc-security-posture, browser-reachable-entries, dual-source-exports, entry-nameability, exported-any, skill-examples ('259 prose examples type-check'), dev-prereqs ('67 package build artifacts present'), dual-build-cjs-loads ('102 published require entry point(s) across 66 package(s) load'), type-check-coverage, type-check-debt ('27 ledger entr(ies) re-measured … none above its recorded number'); check:query-options-erasure ran alone after a first attempt was cut by the ~10-minute foreground cap ('ratchet holds: 67 unswept non-test site(s) in 17 file(s), none new'). The 2 remaining are not runnable here by their own verdicts: check:react-declaration-parity (needs objectui's sdui.manifest.json — the on-demand pin-bump gate) and check-test-completeness (needs a saved turbo test log; NOT MEASURED). Type-level reverse verification against the rebuilt dist (tsc --noEmit --ignoreConfig probe in packages/lint against @objectstack/spec/ui): record-form filter RED with TS2353 naming the '{ field; operator; value }[]' type, array form GREEN (0 errors); probe deleted. No ablation was run (no new gate was added, so none was owed). Repo-wide pnpm lint and the multi-package farm are CI's runs (declared narrowing).", "mcp_calls": "0 — no MCP GitHub calls; every GitHub read/write went through authenticated REST (curl) plus local git", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
claude commentedon Sep 2, 2026
ACCEPT — PR #14404 (head
8068a7f3), Key 2; reviewed against GitHub, not the report. Card complete with this merge (Key 1 landed via PR #12120), soFixes #12039is the right closing line.Ruling compliance (ui#6206-B under the 2026-08-25 Option-A sequencing, comment 5409255480)
d8ec8d6d: the adapter'saggregate()analytics branch lowers an array filter throughtranslateFilterArray(params.filter)(packages/data-objectstack/src/index.ts~4924–4926, objectui#6828), andpackages/data-objectstack/src/aggregate-filter-lowering.test.tsis present at the pin. The analytics door itself still refuses a raw rule-object array by design; the end-to-end chain is authored array → adapter lowering → AST → accepted, which is exactly the sequencing the ruling ordered.ComponentPropsMap['element:number'].filter→z.array(ViewFilterRuleSchema).optional(), the orthography the siblingfilterinputs already declare;view.zod.tsuntouched (H17 export: PDF / print document generation — re-planned for v18, superseding the #1301 NOT_PLANNED closure #8346); no consumer-side alias, no fallback arm.element-number-filter-rule-arrayunder protocol 18, registry regenerated (Key 1's and feat(spec): refuse undeclared keys onaddressandlocationvalues —AddressSchema/LocationValueSchemastrict (#13802) #14335's entries still present); changeset@objectstack/specminor, BREAKING with the FROM → TO block and the registered marker; ADR-0122 pin receipt 836 → 835 withElementNumberPropsParseddeclared.filterpath withinvalid_type(expected: 'array'), the array form is accepted and normalizes operators through the realViewFilterRuleSchema, and a scalarinvalue is refused atfilter.0.value.Contract review (Clause ②) — PASS, in-seat
packages/spec/src/ui/component.zod.ts+packages/spec/src/migrations/**⇒ Clause ② applies.claude-fable-5-1. The fuse literal inscripts/pm/dispatch-gates.mjsreadsclaude-fable-5; mismatch and this seat's floor reading recorded on finding(pm-dispatch):CONTRACT_REVIEW_TIER = 'claude-fable-5'no longer matches the served Fable tierclaude-fable-5-1, so the in-seat review fuse reads a literal mismatch on every current Fable seat #14303, open for maintainer veto.Pre-checks (all on head
8068a7f3)check-clause2-carriers.mjs --pair).origin/main(5ec4f6fa): CLEAN;mainhas not moved on any of this PR's files since the merge base.Fixes #12039.check:react-declaration-parityneeds objectui's manifest;check-test-completenessneeds the CI test log) are CI's — declared narrowing accepted.Observed residue (not this PR's):
element:record_picker.filterstill declaresFilterConditionSchema(component.zod.ts~2141) — the last record-formfilterin the map after this convergence. Filed as a separate finding for triage (number in the follow-up comment); ⛔ not folded here.Landing
needs:contract-reviewcleared on this card and on PR feat(spec): converge ComponentPropsMap['element:number'].filter onto the ViewFilterRule array form (#12039, ui#6206 Option B) #14404 in the same stroke as this verdict.Generated by Claude Code
claude commentedon Sep 2, 2026
Follow-up to the ACCEPT above: the observed residue (
element:record_picker.filterstill onFilterConditionSchema) is filed as #14406 for first-touch grading — measurement-first before any declaration moves, per the same ruling.Generated by Claude Code