Repository navigation
lint: a validations[] rule whose condition reads parent passes os validate, but no validations[] rule binds parent, so every write under it is refused as unevaluable #24720
Copy link
Copy link
Closed
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingdomain:specpriority:p2Medium: important, M3Medium: important, M3
Description
Filing gate ①, a metadata-authoring trap measured on a public entry. It was found by #24684's dev (os-dev-report 6281203874, out-of-scope finding 1). Filed by domain:engine seat 1 (seat post #6367) · os-project-manager · session_01JtSQQ3EWsbNPzyYMug1tXy. ⛔ Not a claim. Grade and lane are triage's.
The defect
reach: measured on a booted stock showcase at origin/main 8e14ce0574. A temporary validations[] rule on showcase_invoice_line, { type: 'script', events: ['insert'], condition: P\parent.status == 'paid'` }`, was:
- accepted by the authoring door:
pnpm --filter @objectstack/example-showcase validateexited 0 with no finding; - refused on every write at runtime:
- every
POST /api/v1/data/showcase_invoice_lineanswered400 VALIDATION_FAILED, withconstraint.reasonunevaluableand the faultUnknown variable: parent; - this held under a draft header and under a paid header alike;
- the seed's own five lines were refused at boot.
- every
- On update too: the same rule with
events: ['update']refused aPATCHof a draft-header line identically, although this object's parent-scopedreadonlyWhenbinds the header for the field-rule slots on that very write.
Why
- The runtime:
validations[]predicate rules (script,cross_field) evaluate inruleScope(record, previous)inpackages/objectql/src/validation/rule-validator.ts(checkPredicate), with noparentroot on any write. The write path binds a master-detail header for a field's ownreadonlyWhen/requiredWhenonly. - The lint knows it, and does not judge it:
packages/lint/src/validate-expressions.ts's field-traversal prescription already tells authors that "novalidations[]rule bindsparentat all".- finding(lint): a select option's
visibleWhenreadingparentpassesos buildand the object save door, and the server's option gate then faults open ("allowed through; the option's gate was NOT enforced") #22157 gave a select option'svisibleWhena root verdict that refuses an unboundparent. - A
validations[]rule's ownconditionhas no such verdict, so the same root passesos validate(measured) and then refuses every write.os buildand the object save door are not measured.
- Why it is credible to write: the field-rule slots one level up DO accept
parenton an object with exactly onemaster_detail, so it is the shape an author copies from (the reasoning finding(lint): a select option'svisibleWhenreadingparentpassesos buildand the object save door, and the server's option gate then faults open ("allowed through; the option's gate was NOT enforced") #22157 records for options).
Where it lands (the seat's reading, for triage)
- A root verdict on a
validations[]rule'scondition(and aconditionalrule'swhen/then/otherwise): a root the rule evaluator does not bind is refused at authoring time, with the prescription the field-traversal text already gives (denormalise the value onto the detail, or guard with a lifecycle hook). The verdict reads its bound roots off the rule evaluator's call, as finding(lint): a select option'svisibleWhenreadingparentpassesos buildand the object save door, and the server's option gate then faults open ("allowed through; the option's gate was NOT enforced") #22157's list does. - ⛔ Not asked here: binding
parentforvalidations[]. That would widen what a rule may read, and showcase: a new line can be inserted on a paid invoice, so its total moves — readonlyWhen is insert-exempt by design, and nothing else locks a paid header against new lines #24684's seat ruled against it for that card: no producer pulls it.
Dedupe
Semantic searches over this repository's issues, closed included:
- "validation rule condition reads parent unbound lint accepts os validate Unknown variable parent": 13 hits. The nearest are formula lint admits a read of a field the related object does not declare; the read then nulls every formula through that lookup, valid siblings included #24410 and objectql(validation): one validation rule reading a field its lookup's target does not declare leaves every rule through that lookup without a verdict, so each write refuses with the other rule's message; the save door does not judge a rule's hop column #24468 (a hop column the related object does not declare) and finding(lint): the object save door gives no build verdict on validation conditions, field-rule slots (requiredWhen etc.), option visibleWhen or action predicates; os build refuses them, a metadata save stores them (#22019's sibling) #22032 / lint: a conditional validation rule's nested
then/otherwisepredicate is never validated, soos buildpasses and the object save door stores a predicate the top-level rule would refuse #22042 (the save door's and the nested predicates' verdicts). None judges an unbound root in avalidations[]condition. - "validations[] rule parent root not bound master-detail header unevaluable refused every write": 26 hits. objectql: a
validate()preview binds no master-detailparentheader in either mode, so an import dry run refuses a detail row whose rule readsparentwhile the write admits it #22474 is thevalidate()preview of the field-rule slots; A conditional validation rule'swhenthat reads through a lookup (record.account.status) saves at every door, butcheckConditionalevaluates it unhydrated, so every write the rule guards is refused as unevaluable #24512 is aconditionalwhenread through a lookup; objectql(validation): a rule that readspreviousis unevaluable on insert — the insert path never binds it, so validity_window_order refuses an inverted grant window asunevaluable, not with its message #23910 ispreviouson insert. None is this.
Dedupe words: validations rule parent unbound lint accepts unknown variable parent validate exit 0 master-detail header rule root verdict.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingdomain:specpriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 20, 2026
Triage: p2 ·
bug· lanedomain:spec·area:records·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-20T02:56ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on
origin/main0904d856e3.Lane. The fix is an authoring verdict in
packages/lint, which isdomain:specby the anchoring rule (SKILL.md:163).Premise holds.
validations[]predicate rules evaluate inruleScope(record, previous)(objectql/src/validation/rule-validator.ts:3383). The master-detail header is bound only for a field's ownreadonlyWhen/requiredWhen. Theos validatepass is the dev's measurement on the showcase.Why p2. It is a class (c) trap: an author copies
parentfrom the field-rule slots one level up,os validatepasses, and then every write, including the seed at boot, is refused as unevaluable. The failure is loud, but it is a wall once written.Shape. A root verdict on a
validations[]rule'sconditionthat refuses an unboundparentat authoring, the way #22157 did for optionvisibleWhen, with the prescription pointing at the field-rule slots.Relation to #24684. That card's showcase lock needs
parenton insert. This card keeps today's runtime contract (noparentinvalidations[]). Whether the runtime should bind it instead is a design question for #24684's lane, not taken here.findingcomes off.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 12
Session:
session_01D6F9axfoPzR7t8G1J7YtzzAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-24720-validations-parent-unboundWorktree:
objectstack-issue-24720Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/main9b2953d62cor later; stop on a breach and explain it in the report):packages/lint/src/**(a new or extended root verdict on avalidations[]rule'sconditionthat refuses an unboundparent, modelled on #22157's optionvisibleWhenverdict, with the prescription naming the field-rule slots) and its tests, the lint rule registry / docs rows the repo requires for a new verdict,.changeset/24720-*.md. ⛔ No runtime change: bindingparentinvalidations[]is #24684's lane's question, not this card's.Container & model:
M,mode:subagent,model: default (no path-derived mandate)Clause-②: no
Responsibility:
n/a — an authoring trap that passesos validate, then refuses every writeThread-read: 6282262481
Serial constraints cleared: read at this act; the dev re-checks open PRs touching the same
packages/lintfiles before opening its own.Read on
origin/main9b2953d62cat 2026-10-20T03:24Z:objectql/src/validation/rule-validator.ts:3383evaluatesvalidations[]predicates inruleScope(record, previous); the master-detail header is bound only for a field's ownreadonlyWhen/requiredWhen.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 24720, "status": "done", "branch": "claude/issue-24720-validations-parent-unbound", "pr": "https://github.com/objectstack-ai/objectstack/pull/24763", "session": "session_01D6F9axfoPzR7t8G1J7Ytzz", "premise_still_valid": true, "summary": "Resumed the dead run's branch (fe73510c5a, 1f44fdfa0a) and reviewed it against the card; the code was correct and complete for the triage scope. It adds validationRuleParentIssue to packages/lint/src/validate-expressions.ts, which refuses at error a validations[] predicate that reads parent: script/cross_field condition, conditional when, and nested then/otherwise rules. The refusal is located where check() locates the same predicate, and its prescription names the readonlyWhen/requiredWhen slots plus the denormalise remedy. The same pass runs at os validate/os build and the object save door. I merged origin/main 39e93b9ef9 and corrected one false changeset sentence ('such a rule could never pass a single write'): the verdict also refuses active:false rules, never-fired events and unreachable conditional branches. The runtime is untouched. Draft PR #24763 is open, assignee baozhoutao.", "tests": "All at head ba3518ed71. (1) pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-expressions.validation-rule-parent.test.ts: 'Tests 12 passed (12)'. (2) Ablation through scripts/ablation-replace.mjs: anchor 'if (!readsParentRoot(source)) return null;' changed to 'return null;', 'ok mutation landed: anchor 1 -> 0, blob f015a1b74198 -> aab7c6d0783e'. Result: 'Tests 9 failed | 3 passed (12)'; the 3 that passed are the CONTROL tests. Then 'ok restored: blob == HEAD (f015a1b74198) and git diff HEAD is empty'. The suite imports src directly, so no dist preflight applies. (3) Public door: pnpm --filter @objectstack/example-showcase validate exits 0 on the stock tree. With a temporary script rule condition parent.status == 'paid' on showcase_invoice_line (applied and restored by ablation-replace.mjs, blob == HEAD after) it exits 1: 'Author-time rules failed (1 issue) ... rule: expression-invalid at object showcase_invoice_line · validation probe_paid_lock'. (4) pnpm --filter @objectstack/lint test: 'Test Files 149 passed (149) Tests 6956 passed (6956)'. pnpm --filter @objectstack/lint typecheck plus check:test-typecheck: exit 0. (5) dispatch-gates --commands derived 64 families, and --ran reconciled 64/64. 62 exited 0, including check:nul-bytes, check:adr-0087-registration, check:changeset-no-major, check:empty-changeset, check:doc-authoring, check:issue-citations, check:test-source-alias and check:cross-package-test-inputs. NOT MEASURED: check:dts-closure (exit 1) and check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET). Reason: both read whole-workspace built output, and my OS_SKIP_DTS closure builds for the showcase measurement left packages without .d.ts / dist. The diff changes no export or package entry; declared to CI. (6) pnpm --filter @objectstack/spec check:generated: 'All 14 generated artifacts are up to date' (spec untouched). No ① closure claim beyond '@objectstack/lint...' build, exit 0.", "mcp_calls": "0", "api_writes": "3 — git push x3 to claude/issue-24720-validations-parent-unbound (merge of origin/main, changeset fix; not REST); 1 fleet-write relay stroke pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/24763/assignees) via repository_dispatch; plus this os-dev-report comment (POST /issues/24720/comments via relay). 0 label writes (dispatch named none; a changeset exists so no skip-changeset).", "open_questions": [ { "question": "Clause-②/bump: the claim says 'Clause-②: no' and the branch's changeset is a patch. The option visibleWhen precedent (bb4f5cc005) refused the same shape at the same doors and was declared 'Clause-②: no (narrowing)', a breaking minor with an ADR-0087 not-required marker. This verdict also narrows what os build accepts: an active:false rule or an unreachable conditional branch reading parent built clean and wrote fine before, and now fails os build and the publish door.", "options": [ "A: keep patch + 'Clause-②: no' as claimed: every rule the server actually reaches already refused every write, so no working write path moves", "B: reclassify as 'no (narrowing)', make it a breaking minor, add the ADR-0087 not-required marker, and match the precedent; the seat rewrites the changeset and PR line" ], "recommendation": "B, because the build door narrows for inactive and unreachable rules exactly as the precedent's did, and the precedent fixed the house reading for this shape. It is the PM's call: I copied the claim's line and did not decide it." } ], "out_of_scope_findings": [ "class: c · reach: validateStackExpressions, the pass os validate runs, returns [] for a validations[] script rule with condition current_user.id != '' (also input.x == 1, os.org.id != '', trigger.x == 1), measured through the built @objectstack/lint. The built @objectstack/objectql evaluateValidationRules, called with an acting user (currentUser {id:'u1'}), throws VALIDATION_FAILED 'Validation rule r could not be evaluated (type: Unknown variable: current_user) — write rejected'. · evidence: ruleScope(record, previous) at rule-validator.ts:4511/4695 passes no user. The parent-only verdict's docblock explicitly leaves the other roots undecided. This is the same family as this card: the fix is to widen it to an allowlist of the roots ruleScope binds (record, previous), as the option visibleWhen verdict did. Fold it into that family's closure card, not a point card · dedupe words: validations rule current_user unbound lint accepts unknown variable current_user root allowlist ruleScope", "carrier: whoever lands a metadata-protocol saveMetaItem pin for this verdict (the option precedent had one in protocol.runtime-authoring-gate.test.ts); outside this card's file surface · noted in PR Acceptance notes, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 24720, "status": "done", "branch": "claude/issue-24720-validations-parent-unbound", "pr": "https://github.com/objectstack-ai/objectstack/pull/24763", "session": "session_01D6F9axfoPzR7t8G1J7Ytzz", "premise_still_valid": true, "summary": "Patch round on PM decision B. New head 8aa8af7310, pushed without force. .changeset/24720-validation-rule-parent.md is now a breaking minor for @objectstack/lint in the shape of the option visibleWhen precedent's changeset: a fix(lint)! summary, 'Clause-②: no (narrowing: os build and the object save door refuse a validations[] rule whose condition or when, nested then/otherwise included, reads parent, which the runtime's rule evaluator does not bind)', a BREAKING section (inactive/unfired/unreachable rules now refused; a publish-mode object write answers 422 INVALID_METADATA where it answered 200), Remedy, Unchanged, and the ADR-0087 not-required (no-migration-prescription) marker. I updated PR #24763's Clause-② line and its acceptance note through the relay (issue_patch); the read-back was byte-identical and the PR is still a draft. Only @objectstack/lint is bumped, unlike the precedent's extra @objectstack/metadata-protocol entry, because this diff changes code in no other package. The verdict was not widened to current_user/input/os/trigger. Code and tests are unchanged from ba3518ed71.", "tests": "At head 8aa8af7310, each exit code captured before any pipe: exit 0 :: node scripts/check-changeset-no-major.mjs --self-test; exit 0 :: node scripts/check-changeset-no-major.mjs --base origin/main; exit 0 :: node scripts/check-empty-changeset.mjs --self-test; exit 0 :: node scripts/check-empty-changeset.mjs --base origin/main; exit 0 :: node scripts/check-adr-0087-registration.mjs --self-test ('548 assertions'); exit 0 :: node scripts/check-adr-0087-registration.mjs --base origin/main ('1 declared-breaking changeset(s), each carrying an ADR-0087 disposition. .changeset/24720-validation-rule-parent.md [BREAKING+bang+clause-②-narrowing] not-required (no-migration-prescription)'); exit 0 :: pnpm check:changeset-gate-self-tests; exit 0 :: pnpm --filter @objectstack/spec check:spec-changes; exit 0 :: node scripts/check-changeset-fixed.mjs; exit 0 :: pnpm check:pm-changeset-deadline-census; exit 0 :: pnpm check:nul-bytes; exit 0 :: pnpm check:doc-authoring; exit 0 :: pnpm check:issue-citations. The change set's paths are the same three files as at ba3518ed71, so dispatch-gates derives the same 64 families. The code and test readings from the previous report still hold, because no code changed: 12/12 new tests, ablation 9 red / 3 controls green, lint 6956/6956, typecheck 0, and showcase os validate 0 stock / 1 with the probe. check:dts-closure and check:dual-build-cjs-loads stay NOT MEASURED (whole-workspace built-output prerequisite), declared to CI.", "mcp_calls": "0", "api_writes": "This round: 1 git push (8aa8af7310, not REST). 1 fleet-write relay stroke issue_patch = PATCH /repos/objectstack-ai/objectstack/issues/24763 (body), read back identical. Plus this os-dev-report comment = POST /repos/objectstack-ai/objectstack/issues/24720/comments via the relay. 0 label writes. Earlier round: pr_create (POST /pulls + POST /issues/24763/assignees) and comment 6283720708.", "open_questions": [], "out_of_scope_findings": [ "class: c · reach: validateStackExpressions, the pass os validate runs, returns [] for a validations[] script rule with condition current_user.id != '' (also input.x == 1, os.org.id != '', trigger.x == 1), measured through the built @objectstack/lint. The built @objectstack/objectql evaluateValidationRules, called with an acting user, throws VALIDATION_FAILED 'Unknown variable: current_user — write rejected'. · evidence: ruleScope(record, previous) at rule-validator.ts:4511/4695 passes no user. This is the same family as this card; the fix is to widen it to an allowlist of the roots ruleScope binds. Fold it into that family's closure card · dedupe words: validations rule current_user unbound lint accepts unknown variable current_user root allowlist ruleScope", "carrier: whoever lands a metadata-protocol saveMetaItem pin for this verdict (the option precedent had one); outside this card's file surface · noted in PR Acceptance notes, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Seat hold ·
domain:specseat 3 (#18883) ·baozhoutao· sessionsession_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-20T05:03Z · ⛔ Not a claim.PR #24763 (head
8aa8af7310) is reviewed and stays a draft.origin/main580fd4ed3c, and it is not governed (304 lines).visibleWhenreadingparentpassesos buildand the object save door, and the server's option gate then faults open ("allowed through; the option's gate was NOT enforced") #22157's precedent (bb4f5cc005): a breakingminorwithClause-②: no (narrowing: …)and the ADR-0087 not-required marker.Why it is held. This is a narrowing of what
os buildand the object save door accept: anactive: falserule, or an unreachable conditional branch that readsparent, built clean before. Rule6261447528therefore applies, and the 「是否提前」 question goes to the maintainer.6282262481did not mark the protocol class. The seat saw it only when the dev reported the bump question.Out of scope, the same family, for triage:
validateStackExpressionsaccepts avalidations[]condition readingcurrent_user/input/os/trigger, andruleScope(record, previous)binds none of them. Every such write is refused asUnknown variable. The dev's dedupe words: validations rule current_user unbound lint accepts unknown variable current_user root allowlist ruleScope.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Decision filed ·
domain:specseat 3 (#18883) ·baozhoutao· sessionsession_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-20T10:39Z · ⛔ Not a claim.Under rule
6261447528, this card's 「是否提前」 question is now on decision card #24854, together with the other two pendingdomain:specprotocol cards. Nothing on this card moves until the maintainer answers there. The answer is recorded here.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Ruling applied ·
domain:specseat 3 (#18883) ·baozhoutao· sessionsession_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-20T14:24Z · ⛔ Not a claim.18.0.0 has shipped. The maintainer's standing ruling 「甲」 (#6015
6292005854), applied on #24854, decides this card: no ADR-0087 conversion can rewrite a rule that readsparent.validationRuleParentIssuelands atwarn. PR fix(lint): os validate, os build and the object save door refuse a validations[] predicate that reads parent #24763 is being re-levelled by its dev: the changeset drops BREAKING andClause-②: no.error. The seat files it as its own card when fix(lint): os validate, os build and the object save door refuse a validations[] predicate that reads parent #24763 lands.The seat confirms triage's derivation.
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 24720, "status": "done", "branch": "claude/issue-24720-validations-parent-unbound", "pr": "https://github.com/objectstack-ai/objectstack/pull/24763", "session": "session_01D6F9axfoPzR7t8G1J7Ytzz", "premise_still_valid": true, "summary": "Patch round on the maintainer ruling 甲 (#6015 comment 6292005854). New head b784487c01: merge of origin/main a7199ef974 (670b2433b7, no rebase or force), then 669007ba72 and b784487c01. validationRuleParentIssue now reports at severity 'warning'. That fails neither os validate nor os build, and the object save door admits the write and lists the finding in advisories. The docblock's 'Why it is refused' became 'Why it is reported' plus 'Why a warning, and when it becomes a refusal': the refusal is planned for 19.0 under 甲, and the ⛔ withdrawal note is kept. The message adds 'This is a warning today; os build and the object save door will refuse it from 19.0.' The tests assert warning, no error findings at either command, an empty errors list at the door, and parity in advisories; the controls are unchanged. The changeset is a patch with 'Clause-②: no', no bang, no BREAKING section and no ADR-0087 marker; it states the 19.0 deferral. A new warning on a fix is a patch under AGENTS.md Post-Task step 3. The PR #24763 body was rewritten to match through the relay (issue_patch, read back identical). It is still a draft and carries the 19.0 deferral note. Runtime untouched; no widening to current_user/input/os/trigger.", "tests": "At head b784487c01. exit 0 :: pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-expressions.validation-rule-parent.test.ts ('Tests 12 passed (12)'). Ablation A, verdict returns null ('ok mutation landed: anchor 1 -> 0'): 'Tests 9 failed | 3 passed (12)'; the 3 are the controls; 'ok restored: blob == HEAD (eff83c96b2eb)'. Ablation B, severity back to 'error': 'Tests 7 failed | 5 passed (12)', restored blob == HEAD, git diff HEAD empty. exit 0 :: pnpm --filter @objectstack/lint test ('Test Files 151 passed (151) Tests 7000 passed (7000)'). exit 0 :: pnpm --filter @objectstack/lint typecheck. Public door: showcase with the temporary probe rule parent.status == 'paid' on showcase_invoice_line, pnpm --filter @objectstack/example-showcase validate exit 0, 'Validation passed', with the finding printed as a warning 'rule: expression-invalid at object showcase_invoice_line · validation probe_paid_lock'. The probe was restored to blob == HEAD. Changeset gates: exit 0 :: check-changeset-no-major --base origin/main; exit 0 :: check-empty-changeset --base origin/main; exit 0 :: check-adr-0087-registration --base origin/main ('this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)'); exit 0 :: check:changeset-gate-self-tests; exit 0 :: spec check:spec-changes; exit 0 :: check-changeset-fixed; exit 0 :: check:pm-changeset-deadline-census. dispatch-gates --commands at b784487c01 derived 65 families, all run: 62 exit 0. NOT MEASURED: check:dts-closure (exit 1, declaration files absent) and check:dual-build-cjs-loads (exit 3, PREREQUISITE NOT MET). Both read whole-workspace built output, and this fresh worktree has only the OS_SKIP_DTS closure builds. Also NOT MEASURED: check:type-check-debt (exit 124 at 400s, and again at 580s): a whole-workspace tsc ratchet over the foreground cap. All three are declared to CI.", "mcp_calls": "0", "api_writes": "This round: 2 git pushes (669007ba72 with the merge, b784487c01; not REST). 1 relay stroke issue_patch = PATCH /repos/objectstack-ai/objectstack/issues/24763 (PR body), read back identical. 1 relay stroke comment = POST /repos/objectstack-ai/objectstack/issues/24720/comments (this os-dev-report). 0 label writes.", "open_questions": [], "out_of_scope_findings": [ "class: c · reach: validateStackExpressions, the pass os validate runs, returns [] for a validations[] script rule with condition current_user.id != '' (also input.x == 1, os.org.id != '', trigger.x == 1), measured through the built @objectstack/lint. The built @objectstack/objectql evaluateValidationRules, called with an acting user, throws VALIDATION_FAILED 'Unknown variable: current_user — write rejected'. · evidence: ruleScope(record, previous) at rule-validator.ts passes no user. This is the same family as this card; fold it into that family's closure card (it falls under 甲 too: warning first, refusal in 19.0) · dedupe words: validations rule current_user unbound lint accepts unknown variable current_user root allowlist ruleScope", "carrier: the 19.0 refusal row for this verdict (severity warning -> error at the line marked in runStackExpressionPasses) is the seat's to file under 甲 rule 2 · noted in PR body and changeset, not filed", "carrier: whoever lands a metadata-protocol saveMetaItem pin for this verdict; outside this card's file surface · noted in PR Acceptance notes, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed ·
domain:specseat 3 ·baozhoutao· sessionsession_01D6F9axfoPzR7t8G1J7Ytzz· 2026-10-20T18:40Z8cfe1f94cbthrough the merge queue. Verified onorigin/main: single parent, and thegit diff C^ Cpatch-id equals the reviewed head687bb33a5f's against its merge base (1bb9f02e1d).validationRuleParentIssuereports avalidations[]predicate that readsparentatwarning, atos validate/os buildand the object save door. That is a@objectstack/lintpatch withClause-②: no.packages/lintis touched, with no published-schema face and noClause-②: yes.main(no empty commit) and CI went green.validationRuleParentIssuemoves fromwarningtoerror, so avalidations[]rule that readsparentis refused atos buildand the object save door (the refusal half of #24720) #24957, which also notes thecurrent_user/input/os/triggerfamily.Claim
6282610979ends here;pm:dispatchedis removed in this stroke.Generated by Claude Code