Skip to content

docs(skills): the schema-expressions guide says a faulted or stored-blank field rule refuses the submit (objectui#11256) - #11419

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-11256-schema-expressions-field-rule-submit-refusal
Oct 2, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-11256-schema-expressions-field-rule-submit-refusal

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #11256
Clause-②: no

Docs only, on the governed skills/** surface (Tier H: this PR stays a draft until an authorized APPROVED review; the seat lands it). One paragraph of skills/objectui/guides/schema-expressions.md changes — the one beginning "Renderer-side, and only here" in the section "Field-level conditional rules" — plus one empty-frontmatter changeset. No other passage is edited: the sibling card objectui#11414's region ("Which components read bind") is untouched, and origin/main (549aaa83) was merged into the branch before this PR opened, without conflict. Dispatched work (claim on the card, session https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ); draft is the delivered state.

What the passage said, and what it says now

Before, on main at 0858267e: "Evaluation is fail-open -- a broken predicate never hides content, never blocks submit and never locks a field -- so visibleWhen is never a security boundary on the client."

Now, restated from ADR-0137 (objectstack docs/adr/0137-predicate-fault-semantics-are-contract.md, Accepted), as PR objectui#11233 landed it for objectui#8069:

  • D3, render: a broken predicate is fail-open — it never hides content and never locks a field, so the field stays drawn.
  • D2, submit: a faulted or stored-blank field rule refuses the submit, naming the field and the rule. One judge per rule, as ruled on objectui#8069: the client judges visibleWhen; a faulted requiredWhen / readonlyWhen is the server's refusal, shown beside the input.
  • D1, authoring: a blank triad key is refused.
  • D4, gates: a blank gate stays "no gate", with a diagnostic.
  • Kept: visibleWhen is still never a security boundary on the client; the server is the authority.

The paragraph's first three lines (reactive re-evaluation via resolveFieldRuleState; the static required: true / readonly: true floor) are unchanged, and nothing was re-wrapped.

Mechanism assumptions, measured on the tree rather than taken from the card

  • ① The passage on objectui origin/main was byte-identical to the card's quotation (read at 0858267e before editing).
  • ② PR objectui#11233 (merge commit af9e9572, 2026-09-30) lands the D2 refusal on three submit paths — form.tsx (handleSubmit, before react-hook-form validation), the console FormPage (findSubmitRefusals) and WizardForm (gateFinalSubmit) — each reading faults.visibleWhen off resolveFieldRuleState. The refusal text is the form.visibleWhenFaulted key in packages/i18n/src/locales/en.ts: "Can't submit: the visibleWhen rule of {{fields}} could not be evaluated. The rule must be fixed before this form can be submitted." Pins: visibleWhen-fault-refuses-submit-8069.test.tsx, FormPage.visibleWhenFault-8069.test.tsx, wizardVisibleWhenFault-8069.test.tsx. The client refuses only visibleWhen; a faulted requiredWhen / readonlyWhen is let through to the server, whose D2 envelope (VALIDATION_FAILED, code: 'rule_violation', constraint.reason: 'unevaluable', constraint.rule naming the slot) lands beside the field — the end-to-end server pin in the same components test file. That is why the new text says "the client judges visibleWhen, the server the other two" rather than "the client refuses every field rule".
  • ③ "A blank triad key is refused at authoring": pinned by packages/types/src/__tests__/base-schema-predicate-envelope-7530.test.ts, describe FormFieldSchema.%s refuses a blank predicate (objectui#8069, ADR-0137 D1), which asserts the spec's own EVALUATED_EXPRESSION_SOURCE_REQUIRED message at the key. "A blank gate stays no gate, with a diagnostic": pinned by packages/core/src/evaluator/__tests__/fieldRuleFaults-8069.test.ts, describe ADR-0137 D4 — silencer 2: hasDeclaredPredicate folding a blank gate (the [blank] report), implemented by reportBlankGate in packages/core/src/evaluator/declaredPredicate.ts. Both verified on the tree; nothing is written as unverified.
  • ④ The later bullet "a field-level visibleWhen fails open. Do not generalise from one to another." (under "CEL predicates over a row record") describes the render-side direction (D3) and is still true; it is not edited (see Acceptance notes).

Line readings (lines; objectui has no token ratchet)

  • Changed file skills/objectui/guides/schema-expressions.md: 635 before → 638 after, net +3 (the budget's ceiling). The paragraph goes from 6 to 9 lines; no line exceeds 80 columns. The three lines buy the D2 / D1 / D4 content; none was bought by re-wrapping.
  • Whole package, every skills/objectui/**/*.md (16 files): 4808 → 4811.
  • Every skills/*/SKILL.md summed (one file, skills/objectui/SKILL.md): 142 → 142.
  • Both sides counted with wc -l over git ls-tree -r --name-only enumerations of origin/main (549aaa83) and this head (d4de5a59).

Gates — exit codes captured before any pipe; verdict lines quoted; run at the merged head d4de5a59 unless noted

  • node scripts/check-skills-paths.mjs → EXIT 0: "check-skills-paths: OK (89/90 stated path(s) resolve across 20 guide file(s); 1 baselined)."
  • node scripts/check-skill-eval-tokens.mjs --self-test → EXIT 0 (29 cases); node scripts/check-skill-eval-tokens.mjs → EXIT 0: "Every must_contain token is taught by its own skill bundle."
  • node scripts/check-skill-examples.mjs --build-filter → the 12 --filter=… words the gate derives; pnpm exec turbo run build FILTERS --concurrency=2 behind scripts/pm/os-verify-lock.sh (slot issue-11256; "VERDICT command-exit 0 · held the lock 86s · waited 138s"); turbo reported FULL TURBO — 29 of 29 tasks replayed from cache (the sibling worktree's identical-input build), with dist/ present in this worktree; then --self-test → EXIT 0 (60 cases) and the gate → EXIT 0: "Semantic phase: 18 of 18 ts fence(s) judged, 0 failed. JSON phase: 70 fence(s) parsed, 0 failed." Run at cbf60c87; the merge that followed changed nothing under skills/ or packages/ (git diff --name-only cbf60c87 d4de5a59 -- skills packages is empty), so the gate's inputs are byte-identical at the head.
  • Guide-reading pins (the two tests scripts/markdown-test-inputs.mjs lists as reading this guide): pnpm exec vitest run packages/types/src/__tests__/list-bind-only-11405.test.ts packages/components/src/__tests__/skill-guide-data-table-binding.test.tsx → "Test Files 2 passed (2) · Tests 28 passed (28)" (same locked run, at cbf60c87).
  • node scripts/check-control-bytes.mjs → EXIT 0 (9936 tracked text files); a grep -naP control-byte scan of the two changed files finds none.
  • node scripts/check-changeset-presence.mjs → EXIT 0: "No source or published contract of a released package changed in this range, so no changeset is owed." The empty-frontmatter changeset is the explicit declaration anyway; no skip-changeset label (objectui has no reader for it).
  • node scripts/check-changeset-no-major.mjs → EXIT 0; check-changeset-claims.mjs → EXIT 0; check-changeset-overwrite.mjs → EXIT 0: "No pre-existing changeset was modified or deleted."
  • CITATION_GATE_BASE=origin/main node scripts/check-new-cross-file-line-citations.mjs → "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only, exit 0".
  • node scripts/check-governed-queue-guard.mjs --test PATHS → EXIT 3 GOVERNED (skills-catalog), the expected verdict: draft until an authorized APPROVED review.
  • lint.yml and ci.yml: the diff is .md plus .changeset/** only, so their "Decide whether this change needs a full run" step reads should_run=false and both report without running the expensive steps. NOT MEASURED locally, by design: pnpm lint (repo-wide, CI's run; no lint input is in this diff).

Deviations

  • pnpm install in the fresh worktree was refused under the repo's engine-strict=true: jsdom@30.0.1 declares node ^22.22.2 || ^24.15.0 || 26 and above and the container's /opt/node22 is v22.22.0. Everything above ran on Node v22.22.2 downloaded from nodejs.org into this session's scratchpad (SHA256 verified against SHASUMS256.txt) and prepended to PATH for this worktree's commands only; the shared toolchain is untouched. CI's setup-node 22.x resolves to a current 22 release, so CI is unaffected.
  • The heavy run queued behind the shared verify lock (held by the sibling card's identical filtered build) and was waited for in the foreground.

Acceptance notes (observations, not filed)

  • The later bullet "a field-level visibleWhen fails open. Do not generalise from one to another." is render-side (D3) and remains true. With the submit refusal now stated two paragraphs above it, a hurried reader could take "fails open" as the whole story; the bullet's own topic is failure DIRECTION at render across surfaces, so it is left as is, as the card asks. carrier: none — noted, not filed.
  • git grep -n 'never blocks submit' origin/main returns nothing: objectui#11233 had already corrected content/docs/guide/metadata-diagnostics.md and content/docs/plugins/plugin-form.mdx, and this passage was the last shipped sentence teaching the old behaviour.

维护者速读(草稿)

改了什么:只改了已发布技能 skills/objectui/guides/schema-expressions.md 中「字段级条件规则」一节以「Renderer-side, and only here」开头的那一段,外加一个空 frontmatter 的 changeset。旧文说「坏掉的谓词永不阻止提交」;新文按 ADR-0137 重述:渲染期照常画出字段(不隐藏、不锁定),提交期求值失败或存储为空白的字段规则拒绝这次提交并点名字段与规则(visibleWhen 由客户端判,requiredWhen / readonlyWhen 由服务端判),空白三元键在编写期被拒,空白 gate 视为无 gate 并出一次诊断;「不是客户端安全边界、服务端仍是权威」保留。净增 3 行。

为什么改:PR objectui#11233(objectui#8069)已于 2026-09-30 把提交期拒绝落到三条提交路径,这份技能文档却还在教相反的行为;AI 按这份指南写元数据,会不预期提交被拒。

风险与代价(含回滚):纯文档,不发版(changeset 为空 frontmatter);风险只在措辞是否准确,每一句都对应树上的实现与 pin 测试(见上文)。回滚 = revert 本 PR。

席位意见:(留空)

你要做的:确认措辞后留下 APPROVED review;落地由席位执行。


Generated by Claude Code

claude added 2 commits October 2, 2026 00:44
…eld rule refuses the submit (objectui#11256)

The field-level conditional rules passage of
`skills/objectui/guides/schema-expressions.md` still taught that a broken
predicate "never blocks submit". Since objectui#8069 (ADR-0137 D2) a
faulted or stored-blank field rule refuses the submit, naming the field
and the rule, while render stays fail-open (D3). The paragraph beginning
"Renderer-side, and only here" now says so, keeps "never a security
boundary on the client", and adds that a blank triad key is refused at
authoring and a blank gate stays "no gate" with a diagnostic. Docs only;
an empty-frontmatter changeset declares no release.

Claude-Session: https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 1 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5120-retire-data-table-name-alias.md

  • names schema-expressions.md → skills/objectui/guides/schema-expressions.md — edited by this change

    The two published skill guides that taught the name spelling (skills/objectui/guides/data-integration.md, schema-expressions.md) migrate in this same release, so the platform never refuses a spelling it still ships.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with cf38a6cec (merge-base with origin/main): 1 file(s) changed outside .changeset/, read against 1959 pending declaration(s) that publish a body (2581 pending in total). · run

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: d4de5a59d4231733600a9af6390ebe343d65ce21
Local-runs: none

Face: governed rule text (skills/objectui/guides/schema-expressions.md, objectui skills/**), reviewed in-seat by the dispatching seat at the constant's tier. Inputs: objectui#11256 (body and every comment: the triage grade 5918695423, the seat's claim 5943339992, the dev report 5943586145), PR #11419's body, its file list (2 files, +17 / −3) and patch, and the check-runs on this head as read at this record; the rulings read from the trees: objectstack docs/adr/0137-predicate-fault-semantics-are-contract.md (D1–D5), objectui main cf38a6ce, objectstack main 4bf4e7e7.

① Derived judgments

  1. Scope: one paragraph (the one beginning 「Renderer-side, and only here」) in the 「## Field-level conditional rules」 section, +6 / −3; the sibling card's region (「### Which components read bind」) and every other passage are byte-identical; the claim's surface holds. RIGHT.
  2. 「At render a broken predicate is fail-open: it never hides content and never locks a field」 — ADR-0137 D3 verbatim in substance. RIGHT.
  3. 「At submit a faulted or stored-blank field rule refuses the submit, naming the field and the rule」 — ADR-0137 D2, including its sentence that a stored blank predicate takes the same path. RIGHT.
  4. 「(the client judges visibleWhen, the server the other two)」 — a new factual claim, read by this reviewer on both trees: objectui packages/components/src/renderers/form/form.tsx refuses the submit only from faultedVisibleWhenFieldNames (form.visibleWhenFaulted); ADR-0137's context states 「visibleWhen — the server never evaluates it at the FIELD level at all」; objectstack packages/objectql/src/validation/rule-validator.test.ts pins fieldRuleRefusal for requiredWhen and readonlyWhen (「a broken field-level requiredWhen … refuses (ADR-0137 D2)」). RIGHT.
  5. 「A blank triad key is refused at authoring」 — D1 (EVALUATED_EXPRESSION_SOURCE_REQUIRED). 「a blank gate stays "no gate", with a diagnostic」 — D4 (diagnosed, never a silent true); the wording is the card's and triage's, and the dev read the D4 pin from PR objectui#11233's tests. RIGHT.
  6. 「visibleWhen is still never a security boundary on the client; the server is the authority」 — kept, per ADR-0124 D1. RIGHT.
  7. Line budget: the file 635 → 638 (+3, the budget's ceiling), the bundle 4808 → 4811, SKILL.md sum 142 → 142; no re-wrap, every line within the file's 80-column prose habit. RIGHT.
  8. The later bullet 「a field-level visibleWhen fails open. Do not generalise from one to another.」 is render-side D3 and stays true; left untouched as the card requires and noted in the PR's Acceptance notes. RIGHT.

② Semver level

Docs-only in a governed surface; no package files[] content moves. The changeset is objectui's EMPTY-frontmatter form; the phantom skip-changeset label is correctly not applied. Clause-②: no is right. Consistent.

③ Boundary flags

  • Dev deviation: pnpm install refused under engine-strict (container Node v22.22.0 below jsdom@30.0.1's ^22.22.2); the dev downloaded Node v22.22.2 into the session scratchpad with its SHA256 verified, prepended it to PATH for that worktree's commands only, and removed it at cleanup; no tracked file touched; CI pins 22.x. Accepted as a container workaround; the Node floor is the third reading of it this shift, recorded on the seat post.
  • Dev deviation: the worktree base was the live origin/main (0858267e) rather than the dispatch-time 9547063 — the contract's rule, followed. Accepted.
  • Dev deviation: the heavy run queued behind the sibling's identical build and was awaited in the foreground. Accepted.
  • Out-of-scope notes: the 「fails open」 bullet (item 8); never blocks submit has no other shipped occurrence on objectui main. Nothing to file.
  • open_questions: none.
  • Check-runs on this head at this record: 28 success, 9 in_progress (eight Test shards and Spec Main Shape Gate), 0 failure; mergeable_state: behind (objectui main moved after the branch's merge) — a Tier H draft, brought up to date at landing. The landing waits on an authorized APPROVED review and on every check green on the landing head.

Implemented-by: claude/issue-11256-schema-expressions-field-rule-submit-refusal
Reviewed-by: session_01FNKm1SmPpuJASnbjxWGtsJ

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)

席位(skills 席 1,session_01FNKm1SmPpuJASnbjxWGtsJ)对照自读的 diff 与 ADR-0137 原文校正 dev 草稿后定稿,2026-10-02T01:12Z。

改了什么。 只改 skills/objectui/guides/schema-expressions.md 「Field-level conditional rules」一节里「Renderer-side, and only here」起头的那一段(文件 635 → 638 行,净增 3 行,恰为预算上限;整包 4808 → 4811)。原文教「坏谓词永不阻止提交」;新文按 ADR-0137 分两层:渲染期 fail-open(不隐藏内容、不锁字段);提交期对求值失败或存储为空白的字段级规则拒绝写入并点名字段与规则(客户端判 visibleWhen,服务端判另外两条);空白三元键在编写期被拒;空白 gate 视为「无 gate」并出诊断;保留「visibleWhen 不是客户端安全边界,服务端是权威」。另加一个空 frontmatter 的 changeset(不发版)。

为什么改。 PR objectui#11233(2026-09-30 合并)落地了 ADR-0137 D2:提交被拒并点名字段与规则。这份发布给作者(含 AI)的技能仍教相反的行为,照它写元数据的 agent 不会预期提交被拒。never blocks submit 在 objectui main 上已无其它出货出处,这一段是最后一处。

风险与代价(含回滚)。 纯文档改动,无代码、无发布包源码变动。风险只在措辞是否精确:席位逐句对照 ADR-0137 D1–D4 原文;新增的「客户端判 visibleWhen,服务端判另外两条」一句席位在两仓树上实测(objectui form.tsx 只对 visibleWhen 的故障拒提交;objectql rule-validator 对 requiredWhen/readonlyWhen 的故障拒写)。回滚 = revert 本 PR 的单个 commit。

席位意见。 建议批准。席内达档契约复核 PASS(见本 PR 评论)。同文件另一处(「Which components read bind」节)由兄弟卡 objectui#11414 / PR #11418 在改,两者区域不相交,后落地者合一次 main 即可;本 PR 的 mergeable_state: behind 只是 main 在它之后又动了,落地时席位先 update-branch。

你要做的(一个动作)。 在本 PR 上留一条 APPROVED review(os-zhuang / hotlong 任一)。之后由席位 update-branch、清标、翻 ready、挂 auto-merge 入队;不需要你合并。

@os-zhuang
os-zhuang marked this pull request as ready for review October 2, 2026 01:39
@os-zhuang
os-zhuang enabled auto-merge October 2, 2026 01:39
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 8b9f09e Oct 2, 2026
43 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-11256-schema-expressions-field-rule-submit-refusal branch October 2, 2026 01:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants