Repository navigation
docs(skills): a bare field ref in a predicate faults, it does not read null - #31028
objectstack-fleet[bot] wants to merge 3 commits into
Conversation
…d null Three skills said a bare field ref (`done` instead of `record.done`) evaluates to null and silently hides an action or never fires a rule. On main it faults: an error validation rule, requiredWhen and an option visibleWhen refuse the write naming the rule, readonlyWhen holds its field locked, a formula reads null with a warning, and in the console an action's visible hides it, disabled greys it out and a field visibleWhen shows the field, each with a console warning. RLS / sharing predicates read a bare name as the column, so the data skill no longer lists them. Growth is paid by deleting restated prose in the same files. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjPD6BESVmRJphXXyw
|
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head 99852c0 · 2026-11-06T18:38Z The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent. No review seat ( |
|
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 Contract reviewServed-tier: Read on ① Derived judgmentsTeaching-text only. No schema, no package export, no runtime accept-set moves. The public surface that moves is the published
② Semver level
③ Boundary flags
④ Design judgment
Evals: the Budget: all three files are within their unchanged ceilings. Line breaks cost the same bytes as spaces, so no rewrap is counted as payment. Every removed clause has a named surviving home. Residue (outside this card's three-file surface, not findings against this PR; filing candidates):
Check-runs on the head: 40 total, 23 success, 13 skipped, 4 in progress ( Implemented-by: VERDICT: PASS |
…onlyWhen does on the form An option visibleWhen that faults refuses only a write that picks that option, and forms keep offering it. A readonlyWhen that faults on a bare ref keeps the field editable on the form, the save succeeds, and the server drops the change with a warning. Paid by dropping the form-side visibleWhen clause (the ui skill states it) and a self-restating "from any non-system write" in the readonly bullet. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J8VVAjPD6BESVmRJphXXyw
|
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 Contract-review-claim: session_01J8VVAj7CvjkGXvgXzd6RZ7 · head a7da761 · 2026-11-06T19:00Z Delta review against the PASS at head 99852c0 (comment 6692714830, should-fixes S1 and S2). The delta is one commit answering both, plus the PR body. The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent. |
|
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 Contract reviewServed-tier: This is a delta review. The head is one commit ( ① Derived judgmentsThe change is teaching text only. No schema, export or runtime accept-set moves. The two re-worded symptoms are judged against main:
② Semver level
Its sentence "In the console … a field ③ Boundary flags
④ Design judgment
Deletion A: "from any non-system write" in the
Deletion B: "a form shows a
should-fix 1:
should-fix 2:
Budget. The ceiling and both counts were re-measured by hand, using ceil(bytes/4) minus the 20-byte release-stamp line, as the script does for a stamped SKILL.md:
Evals. The delta touches no eval. The prior finding stands: no case in the three skills grades the old "evaluates to null" claim. Check-runs on The residue the prior record named, all outside this card, still stands:
Implemented-by: VERDICT: PASS |
|
domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 维护者速读
席位核对 — ACCEPT · domain:skills#3 · head
|
Requested by Irene · project thread
Fixes #30893
Clause-②: no
Metadata-protocol: none
dispatch-gatesmandates the contract-review model tier forskills/**(clause ①). The maintainer's standing order in this project (2026-11-03) waives it; this PR was developed below that tier, and the dispatching seat runs the contract review.维护者速读
objectstack-platform/references/operations.md、objectstack-data、objectstack-ui)不再说「谓词里裸字段引用求值为null、静默隐藏或永不触发」,改为按 main 的代码逐个站点描述它的故障表现。done是Unknown variable故障:error校验规则、requiredWhen拒绝写入并点名规则;选项visibleWhen只拒绝选了该选项的写入(表单仍提供该选项);readonlyWhen字段在表单上仍可编辑,保存显示成功,服务端丢弃改动并记 warn;公式读null并记 warn;控制台里动作visible隐藏、disabled置灰、字段visibleWhen照常显示,均有 console.warn。@objectstack/skills一个 patch;回滚即 revert。33bc8ae5)后 data 6068→6078、ops 3108→3106、ui 3544→3533,上限行都不动;增长由同文件删除重复句付账(见下文 Token ratchet)。skills/objectstack-ui/SKILL.mdL267-272 与skills/objectstack-data/SKILL.mdL450-457;与卡片描述不同的三处见 "Deviations from the card"。skills/**是 Tier H,需要os-zhuang或hotlong批准。What changes
skills/objectstack-platform/references/operations.md, Verify your work: a bare field ref "faults, so anerrorvalidation rule refuses each write naming the rule and an action'svisiblehides it". The dashboard-binding half and theos validate/os buildadvice are unchanged.skills/objectstack-data/SKILL.md, Verify your work: the bare ref faults; "anerrorvalidation rule orrequiredWhenrefuses the write naming it, an optionvisibleWhenonly a write picking the option (forms still offer it); areadonlyWhenfield stays editable and the save succeeds without its change (logged); a formula readsnull(logged)". RLS / sharing predicates are no longer listed (see deviation 3). The form-side fieldvisibleWhenis left to the ui skill, which states it.skills/objectstack-ui/SKILL.md, Verify your work: the bare ref "faults on every record: the action hides (visible) or greys out (disabled), the field shows; the console logs the fault". The lead-in now reads "otherwise met only at runtime" (the predicate trap is no longer silent)..changeset/30893-bare-field-ref-symptom.md:'@objectstack/skills': patch, withClause-②: noandMetadata-protocol: none. Noskip-changeset.grepofskills/objectstack-{platform,data,ui}/evals/*.jsonfor null / hide / hidden / never / bare /record.done/ fail-open/closed finds no case grading this symptom; no eval changes.skills/objectstack-formula/SKILL.mdis untouched, as ordered.Each claim and the code read on
maindonefaults (Unknown variable: done), it does not readnullpackages/formula/src/stdlib.tsbuildScopebindsrecord/previous/inputand namespaces only, no field flattening; the "evaluates tonull" wording is the #1928-era comment onfirstUndeclaredReferenceinpackages/formula/src/cel-engine.tserrorvalidation rule: write refused, naming the rule;warning/info: logged, write proceedspackages/objectql/src/validation/rule-validator.tsdocblock "Fail-CLOSED for unevaluable predicates (#4649)",evaluateValidationRules; probe belowrequiredWhen: write refused, naming field and rulevisibleWhen: only a write that picks the gated option is refused; forms keep offering the optionevaluateOptionVisibilityoverpickedGatedOptions(only written fields, only picked values whose option carriesvisibleWhen); the docblock's D3 render side ("a faulting option predicate leaves the option offered"); probe belowreadonlyWhenwith a bare ref: the form keeps the field editable, the save succeeds, the server drops the change with a warningisReadonlyWhenLocked(anyunknownVariableOf(res.error)→return true) andstripReadonlyWhenFields("ignoring incoming change");packages/objectql/src/cel-fault.tsunknownVariableOf; probe below. Form:ui/packages/core/src/evaluator/fieldRules.tsREADONLY_WHEN_FAULTED = false(ADR-0137 D3). Lint's ownreadonlyWhenfault text inpackages/lint/src/validate-expressions.tssays the same: "the field looks writable, the save reports success, and the value silently never lands"null, warning logged once per object and fieldpackages/objectql/src/engine-top-level.tsapplyFormulaPlan(rec[fp.name] = null; onFault?.(…));packages/objectql/src/engine-readable-ids-permission-formula.tsreportFormulaFault(logger.warn)visiblein the console: fails CLOSED, the action hides,console.warnnames itui/packages/react/src/hooks/useExpression.tsuseConditionwiththrowOnError(warns once, returnsfalse); callersui/packages/components/src/renderers/action/action-group.tsxuseMemberVisible,action-menu.tsxuseMenuActionVisible,ui/packages/app-shell/src/views/DeclaredActionsBar.tsxuseDeclaredActionShown(objectui#11212)disabled: fail-softtrue, so the action greys out, with a console warninguseConditionwithoutthrowOnError→ui/packages/core/src/evaluator/ExpressionEvaluator.tsevaluateCelConditionfast path (evalFieldPredicate(source, record, true, …));ui/packages/core/src/evaluator/fieldRules.tswarnPredicateFailure(console.warn)visibleWhenon a form: fails OPEN, the field shows, fault reportedui/packages/app-shell/src/providers/ExpressionProvider.tsxevaluateVisibility(objectui#6443) viaisObjectFieldVisible;ui/packages/react/src/utils/visibilityDiagnostic.tsreportUnresolvableVisibilityPredicate(console.warn); the render side of ADR-0137 D3 per the rule-validator docblockpackages/formula/src/cel-to-filter.tscompileCelToFilteroperand case'id'("Bare identifier = a single record field (RLS convention)");record.regionand bareregionlower to the same columnProbe: a throwaway vitest file in
packages/objectql/src/validation/(deleted, not committed) againstmainprinted, fordone == truewithdonedeclared:script,severity: 'error':ValidationError"Validation rule 'r1' could not be evaluated (type: Unknown variable: done) — write rejected."severity: 'warning': no throw; logged "write proceeded: the rule is advisory".requiredWhen:ValidationError"Field 'note' requiredWhen could not be evaluated (type: Unknown variable: done) — write rejected."visibleWhen:ValidationError"Option 'b' of field 'stage' visibleWhen could not be evaluated (type: Unknown variable: done) — write rejected."readonlyWhen: warned "treating the field as LOCKED" and "Field 'amt' is read-only (readonlyWhen) — ignoring incoming change"; the payload came back{}.Deviations from the card
The order says main's code wins over the card's paraphrase; the seat accepted these before the PR.
visiblefails closed, not open. The card saysevaluateVisibilityshows the control and reports. Onmainthat function is the field-visibleWhengate and the published export; the action renderers calluseCondition(…, { throwOnError: true }), which hides the action and warns (objectui#11212). The skills say the action hides; only the field fails open.readonlyWhenwith a bare ref locks, it does not refuse. The card points at ADR-0137 D2 (refuse). A baredoneraisesUnknown variable, whichisReadonlyWhenLockedtakes as the Parent-scopedreadonlyWhenis unenforced server-side — the field lock fails open, so a paid invoice's frozen lines can be rewritten over the API #4889 unbound-root case and LOCKS: the change is ignored and logged.@objectstack/lint's fault-outcome ledger (validate-expressions.ts) listsreadonlyWhenas refusing; that holds for its other faults, not this one.compileCelToFilter, where a bare name is the column, so a bare ref is not the symptom described there.Token ratchet
Measured with
node scripts/check-skills-token-ratchet.mjsonmainat33bc8ae5and on this head (mainmerged in). No ratchet row moves; nothing was re-wrapped to make room. Before the merge, onbcf8a37e0, the data file read 6078 → 6076; #30995 has since cut it onmain.mainskills/objectstack-data/SKILL.mdskills/objectstack-platform/references/operations.mdskills/objectstack-ui/SKILL.mdDeletions that pay the growth, each with its surviving home:
objectstack-data/SKILL.md: "but it does not replaceos validate" (after "run it too"). Home: the same sentence's "additionally checks", andobjectstack-platform/references/operations.mdVerify "(os lintis a separate style/convention pass and does not replaceos validate.)".objectstack-ui/SKILL.md: "Don't report a view/action/dashboard done untilos validatepasses." Home: the same section's opener "run the author-time gate before reporting done", and operations.md "Rule of thumb: never report a metadata change as done untilos validatepasses."objectstack-data/SKILL.md(review S1/S2 commit): the Verify passage's "a form shows avisibleWhenfield". Home:objectstack-ui/SKILL.mdVerify, "the field shows; the console logs the fault", and this file's "UsevisibleWhento hide irrelevant fields in ObjectUI forms".objectstack-data/SKILL.md(same commit): "from any non-system write" in thereadonly: truebullet, which restated the sentence's own subject ("A non-system write (REST/UI, …) has the field stripped").operations.md: the intro's "(ADR-0021)" after the dashboard clause. Home: item 3 of the same section, "Widget-binding integrity (ADR-0021)". The intro also drops its "ObjectStack" lead word.Serial. PR #31019 also edits
skills/objectstack-platform/references/operations.md(other lines: theos dev/os validaterows, "Both run the same gates:", theos deployrow) and raises that file's ratchet row. Whichever of the two lands second mergesmainand re-measures.Verification
Head
a7da7616: the edit commit87e83df5, a merge oforigin/mainat33bc8ae5(no conflict, no rebase), and one commit for the contract review's two should-fixes inobjectstack-data/SKILL.md(S1 optionvisibleWhenscope, S2readonlyWhenform side).mainhas moved 3 commits since, none touchingskills/**or the ratchet script, so it was not merged again.Local gates on a7da761 (this head): 46 derived, 46 run with exit 0, 0 NOT MEASURED (`dispatch-gates --ran`)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 46 commands for the 4 changed files. All ran afterpnpm install --frozen-lockfileand a fullpnpm buildof the merged tree (exit 0), each under a 900 s timeout withNODE_OPTIONS=--max-old-space-size=8192and its exit code captured before any pipe.check-skills-token-ratchet.mjs,check:skill-docs,check:skill-refs,check:skill-identifier-liveness,check:doc-authoring,check:dts-closure,check:dual-build-cjs-loadsandcheck-comment-mask-corpus.mjs.--ranprinted:46 derived famil(ies) accounted for — 46 run, 0 NOT-MEASURED.87e83df5(pre-merge) and99852c06(the reviewed head) also ran all 46 with exit 0;a7da7616changes onlyobjectstack-data/SKILL.mdand the changeset text, on the same merged tree.node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0 (3 commits) before each push.Human Minimum
packages/specholds no runtime logic. (No schema touched.)main, one pull request. (mainmerged in, no rebase.)packages/specnot touched; nothing to regenerate.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01J8VVAjPD6BESVmRJphXXyw