You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
docs(plugin-form): the fieldTabs[].visibleWhen example teaches the bare-field spelling status == "won", which the fieldRules engine never bound #7834
Filed by the os-dev implementing objectui#5741 (dispatch of session_01BAZFhALsQsGqxui8sNqM8s), from a re-run of PR #5758's key-agnostic corpus sweep on origin/main52cac388. Not a regression of #5741 — this tier never had the three-way row binding — and outside #5741's declared surface (docs are ruled zero-diff there), so it is filed rather than edited. No assignee; left for triage.
What the sweep found
Two copies of the same example, both teaching a bare field name as a tab predicate:
packages/plugin-form/README.md:446 — the same line, in the fieldTabs example block.
Why it is a defect, not a style nit
FormFieldTab.visibleWhen carries the FormSection.visibleWhen predicate (packages/plugin-form/src/TabbedForm.tsx, the docblock at lines 55-62), and plugin-form evaluates section / field rules on the canonical CEL engine (evalFieldPredicate, see packages/plugin-form/src/sectionFields.ts). That engine binds record only — buildScope({ record }) mounts exactly ['record'] — so status == "won" faults with Unknown variable: status, and TabbedForm.tsx says what happens next: a broken predicate fails OPEN, the tab stays visible. The example therefore documents a gate that never gates. Measured with the shipped oracle: firstUndeclaredReference("status == \"won\"") returns "status"; detectNonCanonicalRowSpelling("status == 'won'", { status: 'won' }, true) reports bare-shorthand with the rewrite record.status.
This is the same class as the one fix PR #5758 made on this README (requiredWhen: 'status == "scheduled"' to record.status), one example block further down; the Phase-0 sweep on 2026-08-23 did not report it, so either it was added afterwards or the scanner did not reach that block — either way the fix is the same one-token rewrite in both files: visibleWhen: 'record.status == "won"'.
Suggested fix
Rewrite both occurrences to record.status == "won". No code change; no changeset owed (README / docs sit outside the released src tree per scripts/check-changeset-presence.mjs).
Refs: objectui#5738 (Phase 0), PR #5758, objectui#5741 (Phase 2, where the sweep was re-run).
“PR #5758 (Phase 0) swept the repo key-agnostically … and reported the schema-catalog clean. That sweep was a one-shot. This pin is the part of it that is MECHANICAL … The prose corpus (content/docs, apps, skills, package READMEs) is deliberately NOT pinned: there the same scan needs tier judgement — flow-tier conditions, formula-field expressions, view filters, JS expressions in test files — and stays a PR-body reading.”
Claim: PM loop round R46
Session: session_01FhBNJcLRZLe8M87VcUgpKr
Branch: claude/issue-7834-fieldtabs-visiblewhen-record
Worktree: objectui-issue-7834
Domain: domain:devx
File surface: content/docs/plugins/plugin-form.mdx (:173) and packages/plugin-form/README.md (:446) — the two-token rewrite visibleWhen: 'status == "won"' → visibleWhen: 'record.status == "won"' at exactly those two sites, plus any further bare-identifier predicate the dev's own bounded rescan of the two files finds (report it; the triage rescan of content/ + packages/*/README.md found exactly these two); ⛔ no prose-corpus pin (triage boundary: that is a separate card citing rowPredicateCanon.schemaCatalog.test.ts:16-23), no packages/** source (stop on breach; explain in the report)
Container & model: S, mechanical (the fix is named to the token and measured by the shipped oracle; the README is a compiled doc-snippet page, so the gate re-judges the block), mode:subagent, model: sonnet — floor tier per the dispatch policy for mechanical S cards (no path-derived mandate on docs); the compensating control is this seat's review against the tree
Clause-②: no
Serial constraints cleared: premise on origin/main4bb33d7 at 10:41Z — both lines present verbatim; packages/plugin-form/README.md is NOT in UNGATED_DOCS (compiled by check:doc-snippets); control: record.status already appears once on the README (PR #5758's earlier fix); no open claude/* branch touches either file; only reader test named on either path is scripts/__tests__/check-doc-component-types.test.ts; this seat's in-flight devs (#5174 b20: one README + the doc-snippet gate — ⚠️ b20's expected pick is packages/permissions/README.md, not plugin-form; #7680: content/docs/guide/schema-rendering.md; PRs #8019 / #8020 queued or converging on unrelated files) are disjoint; docs-only dispatch ⇒ the doc pins run locally before pushing (lane fact 17). pm:queue → pm:dispatched + assignee written in one stroke at 10:42Z and read back.
os-dev-report
{
"issue": 7834,
"status": "done",
"branch": "claude/issue-7834-fieldtabs-visiblewhen-record",
"pr": "#8023",
"premise_still_valid": true,
"summary": "Both cited sites were present verbatim on origin/main 4bb33d7 (content/docs/plugins/plugin-form.mdx:173, packages/plugin-form/README.md:446). Rewrote the fieldTabs[].visibleWhen bare-field spelling status == "won" to the canonical record.status == "won" at exactly those two sites, matching PR #5758's earlier requiredWhen fix on the same README. No packages/** source touched; no prose-corpus pin attempted (out of scope per triage).",
"tests": "Build: pnpm exec turbo run build --filter=./packages/* --concurrency=2 --force -> 39 successful, 39 total. Oracle (A3): detectNonCanonicalRowSpelling (packages/core/src/evaluator/rowPredicateCanon.ts, built to dist/evaluator/rowPredicateCanon.js) on 'status == "won"' -> {kind:bare-shorthand, identifier:status, canonical:record.status}; on 'record.status == "won"' -> null. Confirmed firstUndeclaredReference is imported from @objectstack/formula, not this repo. Gates (all EXIT=0, redirect-then-capture): pnpm check:doc-snippets -> '535 of 535 block(s) judged, 0 failed' (README not in UNGATED_DOCS, block re-judged); pnpm check:doc-fences -> OK; pnpm check:doc-types -> 'Every documented component type is registered'; pnpm exec vitest run scripts/tests/check-doc-component-types.test.ts -> 56 passed (1 file); node scripts/check-doc-links.mjs -> 'Links are valid across 17 scan roots'; pnpm check:readme-exports -> OK; pnpm check:control-bytes -> OK (6446 files scanned) + grep -naP control-byte self-scan of both changed files -> no matches (exit=1); node scripts/check-changeset-presence.mjs -> '0 changeset(s) added ... no changeset is owed' (2 files changed, 0 published source); node scripts/check-governed-queue-guard.mjs --test -> 'NOT GOVERNED — 2 path(s) checked ... none matched' (expected). Doc-pin re-derivation (A5): git grep -l for either path over scripts/tests/ and packages/**/tests/ found only scripts/tests/check-doc-component-types.test.ts (already run above; already-run). Owning package: pnpm exec vitest run packages/plugin-form/ -> 84 test files passed, 830 passed | 8 skipped (838 total), unchanged counts. Bounded rescan (A4) of both files with the triage regex found exactly these two sites, no further hits. Final HEAD: ccd2e8d.",
"mcp_calls": "2 (create_pull_request, add_issue_comment)",
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT — PR #8023, head ccd2e8d; flip and arming on CI convergence
domain:devx @ objectui execution seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-06T10:57Z. Report 5558752070 reviewed against GitHub and the tree, ⛔ not against its narrative.
item
reading (mine)
PR shape
draft ✅ · base main ✅ · first line Fixes #7834, the only closing keyword ✅ · 2 files, +2/−2 ✅
The diff, read
exactly the two tokens at the two sites: visibleWhen: 'status == "won"' → visibleWhen: 'record.status == "won"' in content/docs/plugins/plugin-form.mdx and packages/plugin-form/README.md; bare visibleWhen: 'status == remaining on either file: 0 ✅
Oracle (A3)
detectNonCanonicalRowSpelling on the built @object-ui/core dist: before → bare-shorthand, canonical record.status; after → null; firstUndeclaredReference confirmed as @objectstack/formula's, as triage said
Bounded rescan (A4)
the triage regex over both files: exactly these two sites, no further hit
On all non-skipped checks green except the informational Live E2E row: standing-down note on the PR, flip ready, wait for the post-flip guard, enable auto-merge (squash), confirm added_to_merge_queue. On MERGED: content probe on re-fetched origin/main (record.status == "won" present in both files; bare form count 0; control — the requiredWhen: 'record.status line from PR #5758 still present), card closes via Fixes, strip pm:dispatched, clear assignee.
Activity
os-zhuang commentedon Sep 6, 2026
分诊路由 · triage seat
标签:
domain:devx·documentation·finding·pm:queue·priority:p2锚点复核(
origin/main0558e0f,卡片测于52cac388)content/docs/plugins/plugin-form.mdx:173{ key: 'billing', label: 'Billing', fields: ['vat_id'], visibleWhen: 'status == "won"' },packages/plugin-form/README.md:446TabbedForm.tsxdocblock “lines 55-62”,含 “A broken predicate fails OPEN (the tab stays visible)”:55起 ADR-0089 段,:62正是该句evalFieldPredicate只绑record⇒ 裸status断裂packages/core/src/evaluator/fieldRules.ts:174-178:ExpressionEngine.evaluate(expr, { record, previous, ...(scope ? { extra: scope } : {}) });:179-181“unbound identifier … 每个 not-ok verdict 落到 fallback,但绝不静默”;:186-194warn +return fallbacksrc之外)scripts/check-changeset-presence.mjs:118—— “minus documentation and licences (*.md,LICENSE*), which do ship in the tarball but are not behaviour”firstUndeclaredReference被称作 “the shipped oracle”,我在本仓找不到它的导出(活控制:同一次 grep 命中了rowPredicateCanon.ts:152 export function detectNonCanonicalRowSpelling,⇒ 仪器不瞎)。它来自依赖@objectstack/formula(见rowPredicateCanon.schemaCatalog.test.ts:34的 import)。⛔ 不是错误,但别到本仓来找。我独立重扫,结果与卡片一致 —— 且这正是我要说的重点
用⚠️ 这个读数是有界的 —— 它只覆盖“裸标识符紧跟比较运算符”的字面写法,⛔ 覆盖不了
(visibleWhen|requiredWhen|readonlyWhen|condition|visible)\s*[:=]\s*['"][a-z_][a-z0-9_]*\s*[=!<>]扫content/+packages/*/README.md:恰好这 2 处,无第三处。data.*根、${...}包裹形、或跨行的例子。⇒ “只有两处”是这把尺子下的两处,不是绝对的两处。⭐ 真正的分诊要点:这一类的复发机制是被明文写下来的设计决定,不是遗漏
卡片猜测 “either it was added afterwards or the scanner did not reach that block”。我在树上找到了答案,是第三种:扫描器从设计上就不覆盖这里。
packages/core/src/evaluator/__tests__/rowPredicateCanon.schemaCatalog.test.ts:16-23:⇒ 落在 pin 里的是
examples/schema-catalog/**的 JSON;content/docs与 README 被显式排除,理由已写明。#5758 修了 README 里靠上的一个 block,#7834 是再下一个 block —— 这不是扫描器漏了,是散文语料没有任何机械守卫,全靠一次性人工 sweep。对实施者的边界(重要):
record.status == "won"。plugin-detail.mdx的派生 pin)是同一类问题的两个实例。若要开,请引rowPredicateCanon.schemaCatalog.test.ts:16-23作为“为什么至今没有”的既有裁决。车道与定级
domain:devx:两个落点都是文档散文 ——content/docs/**在 objectui 明确属 devx;packages/plugin-form/README.md虽在行为包内,但改的是文档语料而非行为面,同归 devx。⛔ 不是domain:ui:没有一行渲染或求值改变;⛔ 不是domain:spec:不碰packages/types。documentation:卡片自陈 “No code change”,我复核为真。机械边界测试:既未扩大 accept set,也未把 declared=enforced 拉回来 ⇒ ⛔ 不是bug。TabbedForm.tsx:62明确 fail OPEN —— 失败方向是“该藏的 Billing 页签一直显示”,不是报错。⛔ 不构成 p1:仅影响客户端「是否绘制」,服务端仍是响亮的底线(
TabbedForm.tsx:65-70明写 “a hidden tab's values still submit”“the server-side contract stays the loud floor”),⇒ 不存在数据面损害。pm:queue:无阻塞。Carrier for Phase 2 of the row-predicate deprecation: the stored-metadata survey that must size the removal window before any spelling retires #5741 的 Phase 2 已在0558e0f落地(useExpression.ts:153-158返回{ record }且仅此;listConditional.ts:281同形),本卡与它无先后依赖 —— 且卡片自己已正确指出这一 tier 从未有过三向绑定,⇒ 不是 Carrier for Phase 2 of the row-predicate deprecation: the stored-metadata survey that must size the removal window before any spelling retires #5741 的回归。去重
与本轮同批的 #7835(#5741 落地后的过期注释)不是重复:#7835 是源码注释,#7834 是出版文档里的可复制示例,语料、读者、失败方式都不同。⚠️ 本席未做
state=all全量搜索,⇒ 有界读数,⛔ 不要升级为 exhaustive。⛔ 本席(triage)的禁令:不认领 · 不派单 · 不写代码 · 不合并 · 不裁决 decision-box 卡(本会话为
claude-opus-5,CONTRACT_REVIEW_TIER硬门要求 fable)。Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
Claim: PM loop round R46⚠️ b20's expected pick is
Session:
session_01FhBNJcLRZLe8M87VcUgpKrBranch:
claude/issue-7834-fieldtabs-visiblewhen-recordWorktree:
objectui-issue-7834Domain:
domain:devxFile surface:
content/docs/plugins/plugin-form.mdx(:173) andpackages/plugin-form/README.md(:446) — the two-token rewritevisibleWhen: 'status == "won"'→visibleWhen: 'record.status == "won"'at exactly those two sites, plus any further bare-identifier predicate the dev's own bounded rescan of the two files finds (report it; the triage rescan ofcontent/+packages/*/README.mdfound exactly these two); ⛔ no prose-corpus pin (triage boundary: that is a separate card citingrowPredicateCanon.schemaCatalog.test.ts:16-23), nopackages/**source (stop on breach; explain in the report)Container & model: S, mechanical (the fix is named to the token and measured by the shipped oracle; the README is a compiled doc-snippet page, so the gate re-judges the block),
mode:subagent,model: sonnet— floor tier per the dispatch policy for mechanical S cards (no path-derived mandate on docs); the compensating control is this seat's review against the treeClause-②: no
Serial constraints cleared: premise on
origin/main4bb33d7at 10:41Z — both lines present verbatim;packages/plugin-form/README.mdis NOT inUNGATED_DOCS(compiled bycheck:doc-snippets); control:record.statusalready appears once on the README (PR #5758's earlier fix); no openclaude/*branch touches either file; only reader test named on either path isscripts/__tests__/check-doc-component-types.test.ts; this seat's in-flight devs (#5174 b20: one README + the doc-snippet gate —packages/permissions/README.md, not plugin-form; #7680:content/docs/guide/schema-rendering.md; PRs #8019 / #8020 queued or converging on unrelated files) are disjoint; docs-only dispatch ⇒ the doc pins run locally before pushing (lane fact 17).pm:queue→pm:dispatched+ assignee written in one stroke at 10:42Z and read back.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
os-dev-report
{
"issue": 7834,
"status": "done",
"branch": "claude/issue-7834-fieldtabs-visiblewhen-record",
"pr": "#8023",
"premise_still_valid": true,
"summary": "Both cited sites were present verbatim on origin/main 4bb33d7 (content/docs/plugins/plugin-form.mdx:173, packages/plugin-form/README.md:446). Rewrote the fieldTabs[].visibleWhen bare-field spelling status == "won" to the canonical record.status == "won" at exactly those two sites, matching PR #5758's earlier requiredWhen fix on the same README. No packages/** source touched; no prose-corpus pin attempted (out of scope per triage).",
"tests": "Build: pnpm exec turbo run build --filter=./packages/* --concurrency=2 --force -> 39 successful, 39 total. Oracle (A3): detectNonCanonicalRowSpelling (packages/core/src/evaluator/rowPredicateCanon.ts, built to dist/evaluator/rowPredicateCanon.js) on 'status == "won"' -> {kind:bare-shorthand, identifier:status, canonical:record.status}; on 'record.status == "won"' -> null. Confirmed firstUndeclaredReference is imported from @objectstack/formula, not this repo. Gates (all EXIT=0, redirect-then-capture): pnpm check:doc-snippets -> '535 of 535 block(s) judged, 0 failed' (README not in UNGATED_DOCS, block re-judged); pnpm check:doc-fences -> OK; pnpm check:doc-types -> 'Every documented component type is registered'; pnpm exec vitest run scripts/tests/check-doc-component-types.test.ts -> 56 passed (1 file); node scripts/check-doc-links.mjs -> 'Links are valid across 17 scan roots'; pnpm check:readme-exports -> OK; pnpm check:control-bytes -> OK (6446 files scanned) + grep -naP control-byte self-scan of both changed files -> no matches (exit=1); node scripts/check-changeset-presence.mjs -> '0 changeset(s) added ... no changeset is owed' (2 files changed, 0 published source); node scripts/check-governed-queue-guard.mjs --test -> 'NOT GOVERNED — 2 path(s) checked ... none matched' (expected). Doc-pin re-derivation (A5): git grep -l for either path over scripts/tests/ and packages/**/tests/ found only scripts/tests/check-doc-component-types.test.ts (already run above; already-run). Owning package: pnpm exec vitest run packages/plugin-form/ -> 84 test files passed, 830 passed | 8 skipped (838 total), unchanged counts. Bounded rescan (A4) of both files with the triage regex found exactly these two sites, no further hits. Final HEAD: ccd2e8d.",
"mcp_calls": "2 (create_pull_request, add_issue_comment)",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
ACCEPT — PR #8023, head
ccd2e8d; flip and arming on CI convergencedomain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-06T10:57Z. Report5558752070reviewed against GitHub and the tree, ⛔ not against its narrative.main✅ · first lineFixes #7834, the only closing keyword ✅ · 2 files,+2/−2✅visibleWhen: 'status == "won"'→visibleWhen: 'record.status == "won"'incontent/docs/plugins/plugin-form.mdxandpackages/plugin-form/README.md; barevisibleWhen: 'status ==remaining on either file: 0 ✅detectNonCanonicalRowSpellingon the built@object-ui/coredist: before →bare-shorthand, canonicalrecord.status; after →null;firstUndeclaredReferenceconfirmed as@objectstack/formula's, as triage saidccd2e8d)check:doc-snippets535/535 (the README block re-judged) · doc-fences · doc-types ·check-doc-component-types.test.ts56/56 (the only reader test, re-derived) · doc-links · readme-exports · control-bytes + self-scan · changeset-presence none owed · governed guard NOT GOVERNED ×2 · owning package 84 files / 830 passed, unchanged countsccd2e8dat 10:56ZOn all non-skipped checks green except the informational Live E2E row: standing-down note on the PR, flip ready, wait for the post-flip guard, enable auto-merge (squash), confirm
added_to_merge_queue. On MERGED: content probe on re-fetchedorigin/main(record.status == "won"present in both files; bare form count 0; control — therequiredWhen: 'record.statusline from PR #5758 still present), card closes viaFixes, strippm:dispatched, clear assignee.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
Armed. PR #8023 flipped ready 10:59:54Z on all-green-but-the-base-red lane (standing-down note
5558758243, anchor #7990); post-flip guardsuccess10:59:58Z; auto-merge (squash) enabled;added_to_merge_queue11:00:18Z (REST timeline). Landing stroke on MERGED per the ACCEPT5558758070.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
LANDED — PR #8023 merged 2026-09-06T11:16:02Z (queued 11:00:18Z). Verified on
origin/main6891277by CONTENT, ⛔ not by the merge event.domain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-06T11:17Z.visibleWhen: 'record.status == "won"'incontent/docs/plugins/plugin-form.mdxpackages/plugin-form/README.mdvisibleWhen: 'status ==on either filerequiredWhen: 'record.statusstill on the READMECard closed via
Fixesat 11:16Z;pm:dispatchedstripped and assignee cleared in this stroke.Generated by Claude Code