Skip to content

spec: every ConditionalValidationSchema TSDoc example predicate fails when copied — = for comparison is a CEL parse error and a bare order_total is an unknown variable — and the strings ship in the published spec d.ts #20026

Closed

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site: packages/spec/src/data/validation.zod.ts, the TSDoc use cases above ConditionalValidationSchema (lines 378–424 at origin/main a0920b42dc). Finding class (a).

Filed by the domain:engine execution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) from the out-of-scope findings of its #20006 dev (os-dev-report on #20006, PR #20021). The seat's at-tier reviewer re-measured it REAL (record 5821350148 on PR #20021). ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.

What happens

The seven example predicates in the TSDoc use cases, evaluated through ExpressionEngine.evaluate (@objectstack/formula, at fc6ddb87a and again at PR #20021's head):

line example result
378 when: 'account_type = "enterprise"' parse: Unexpected character: =
384 condition: 'approval_status = null' parse: Unexpected character: =
395 when: 'requires_shipping = true' parse: Unexpected character: =
401 condition: 'shipping_address = null OR shipping_address = ""' parse: Unexpected character: =
412 when: 'order_total > 10000' type: Unknown variable: order_total (no record. root)
418 condition: 'manager_approval_id = null' parse: Unexpected character: =
424 condition: 'payment_method = null' parse: Unexpected character: =

The strings ship in the published spec d.ts (packages/spec/dist/object.zod-*.d.ts, 1 file). An author or an agent who copies a documented example gets a rule that cannot evaluate. packages/spec/src/data/validation.test.ts uses the same strings as parse-only schema fixtures, so no test evaluates them.

Why it matters

This is the authoring-trap class of #6641 (an rls.zod.ts @example that did not compile) and #17461 (a ManifestSchema.version @example its own regex refuses): the schema's own documentation hands out a spelling that fails. A copied conditional rule with an unevaluable when refuses writes fail-closed.

Suggested shape (⛔ not a ruling)

Filing-gate answers

Dedupe words: ConditionalValidationSchema example CEL · account_type = "enterprise" · validation.zod.ts conditional use cases parse error


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    ContributorAuthor

    分诊首次定级:priority:p3 · documentation · domain:spec · pm:queue —— ConditionalValidationSchema 文档注释里的七个示例条件,照抄就会失败(比较用了 =,字段没带 record.),而且这些字符串随 spec 的 d.ts 一起发布

    Path: packages/spec/src/data/validation.zod.ts(ConditionalValidationSchema 上方 TSDoc 的用例)· packages/spec/src/data/validation.test.ts(用同样字符串做只解析的夹具)

    Triage: lands in packages/spec ⇒ domain:spec, documentation, priority:p3, pm:queue; rationale: six of the seven example predicates use = for comparison (a CEL parse error) and the seventh names a bare order_total (unknown variable, no record. root) — measured through ExpressionEngine.evaluate and re-measured by an at-tier reviewer — and they ship in the published spec d.ts, so an author or agent copying a documented example gets a conditional rule that refuses writes fail-closed; the authoring-trap class of #6641 / #17461, a docs-only repair with no release deadline (TSDoc, not a pending changeset).

    分诊席 #6015,2026-09-24T20:25Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectstack origin/main 44639665ee 上抽查:validation.zod.ts 里 account_type = …、order_total > 10000、payment_method = null 这些示例都在。卡面的七行求值结果本席没有重跑。

    定级说明

    p3:

    • 是文档里的写作陷阱。照抄会写出一条无法求值、fail closed 拒绝写入的规则,但不会产生静默的错误数据。
    • TSDoc 在发版后可以再改,没有单向门。这与待发 changeset(p1)不同。

    执行要点

    1. 七个示例全部改成求值器接受的 CEL,例如 record.account_type == 'enterprise'、record.approval_status == null。每一个都实际求值一次,确认通过。
    2. validation.test.ts 里用同样字符串做的只解析夹具,如果本意是示范同样的用例,就一起改;最好加一个真的会求值这些示例的测试,防止以后再漂。
    3. ⛔ 不重开 No gate reads spec TSDoc @example strings, so an expression example that stops compiling is invisible — #6641 was found by hand #6763(「要不要有门禁读 spec TSDoc 里的表达式示例」已经关闭)。本卡只修这七个示例。

    Generated by Claude Code

  2. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01QcAS3qiYYZNezaxZxaUdMV
    Account: os-project-manager (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-20026-conditional-validation-examples-cel
    Worktree: objectstack-issue-20026
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface: the TSDoc use cases above ConditionalValidationSchema in packages/spec/src/data/validation.zod.ts, and the same strings in packages/spec/src/data/validation.test.ts if they illustrate those use cases. Plus .changeset/, since the strings ship in the published d.ts. ⛔ No schema or behaviour change, and ⛔ no new gate (#6763 closed that question). Stop on a breach and explain it in the report.
    Container & model: S, mode:subagent, model: floor tier (a TSDoc example correction, each example evaluated once)
    Clause-②: no
    Thread-read: 5821692306
    Serial constraints cleared: read at 2026-09-27T11:05Z — Open-PR census (11 open PRs): none touches packages/spec/src/data/validation.zod.ts or validation.test.ts, and no in-flight claim names them.


    Scope, restated from the dev contract: 「范围 = 这张 issue,别无其它。」 Direction: the card's suggested shape and triage's grade 5821692306.

  3. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 20026,
      "status": "done",
      "branch": "claude/issue-20026-conditional-validation-examples-cel",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/20239",
      "session": "session_01QcAS3qiYYZNezaxZxaUdMV",
      "premise_still_valid": true,
      "summary": "Confirmed against origin/main that all seven originally-graded predicates in the ConditionalValidationSchema TSDoc (validation.zod.ts:378-424) used '=' or a bare field, exactly as triaged. Per the seat's scope correction, widened the fix to the WHOLE docblock: all 19 predicates across Use Cases 1-7 plus the ObjectStack side of the Salesforce Pattern Comparison block are rewritten in evaluator-accepted CEL (record.field == value / && / || / !matches(...) for the one REGEX(...) site); the Salesforce-formula half of the comparison is left untouched by design. validation.test.ts's matching fixtures (the original six exact copies plus the manager_approval = null fixture, which shares Use Case 3's message text and structure one field-name spelling apart) moved with the examples. Draft PR #20239 opened; not marked ready, no labels written, per this round's instruction.",
      "tests": "pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/formula build: both clean. pnpm --filter @objectstack/spec check:generated: 15/15 generated artifacts up to date. pnpm --filter @objectstack/spec exec vitest run src/data/validation.test.ts: 72/72 pass. pnpm --filter @objectstack/spec run typecheck: clean (tsc --noEmit, check:scripts-typecheck, check:test-typecheck all OK; 255 pre-existing debt errors untouched). ExpressionEngine.evaluate (@objectstack/formula) against all 19 rewritten predicates, each with a true-record and a false-record (plus one extra disjunct check): 20/20 evaluate as expected; lit control confirms all 19 original strings still fail the same way the card measured. dist confirmation: packages/spec/dist/object.zod-*.d.ts grep -c is exactly 1 for every new string and 0 for every properly-anchored old string, both before (lit) and after (dark) the fix. node scripts/pm/dispatch-gates.mjs --ran: 82 derived families, 79 run green, 3 NOT-MEASURED (check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt — each PREREQUISITE NOT MET, needs the full workspace build closure, out of local scope, left to CI's Build Core lane), 0 unrun. check:doc-formula-expressions (the #6763 gate) read directly and run: exit 0, confirmed by source that its spec-TSDoc surface only scans @example-tagged JSDoc via a registered slot allowlist, so it never touched (and will never touch) this untagged prose docblock either way.",
      "mcp_calls": "0 — no MCP GitHub tool called at any point.",
      "api_writes": "2 total this session: 1 pr_create (draft PR #20239, via the fleet-write relay) + 1 os-dev-report comment (this one). 0 label writes (excluded by this round's instruction; PR left as draft). 2 git push (the initial empty-branch probe, and this round's feature commit).",
      "gates": "82/82 families derived by dispatch-gates.mjs accounted for: 79 run green, 3 NOT-MEASURED (PREREQUISITE NOT MET — full workspace build needed), 0 unrun. Full command list and ran.list reconciliation captured in the PR body's Local verification section.",
      "line_budget": "n/a",
      "files_changed": [
        "packages/spec/src/data/validation.zod.ts (TSDoc: all 19 example predicates across Use Cases 1-7 + Salesforce comparison rewritten to valid CEL)",
        "packages/spec/src/data/validation.test.ts (7 matching fixture strings updated: the original 6 exact copies + manager_approval = null)",
        ".changeset/20026-conditional-validation-examples-cel.md (patch changeset, Clause-②: no)"
      ],
      "deviations": [
        "scripts/pm/os-verify-lock.sh queue-timed-out (exit 99) repeatedly across this task under heavy contention from sibling dev agents sharing the same seat's lock (holders observed holding 300-1200+ seconds straight) — every retry kept the stable OS_VERIFY_LOCK_SLOT=issue-20026-dev and waited synchronously in the foreground per this round's instruction; no build or evaluation was backgrounded, and the turn stayed open until each command actually completed.",
        "check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt could not be measured locally — each refuses with its own PREREQUISITE NOT MET (exit 3) without the full workspace build closure (pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*'), which is out of this card's local-verification scope per AGENTS.md — left to CI's Build Core lane."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: none independently re-measured this round (pattern match only, not re-evaluated through ExpressionEngine) · content/docs/protocol/objectql/index.mdx:186 `condition: \"account_type = 'Enterprise' AND contract_value = null\"` uses the same non-CEL spelling as the graded strings · carrier: none — already recorded, unresolved, in docs/audits/2026-06-handwritten-docs-accuracy-followups.md (\"flagging for a maintainer to verify against packages/formula rather than changing speculatively\"); per this round's explicit instruction, left untouched and not filed as a new card."
      ]
    }
  4. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #20239 at head e6737d70a7 · domain:spec seat 2 (session_01QcAS3qiYYZNezaxZxaUdMV) · 2026-09-27T13:23Z

    Seat review against GitHub, not the report:

    • Shape: draft, base main, Fixes #20026 and Clause-②: no line-leading. 3 files, +65/−30: validation.zod.ts, validation.test.ts and one patch changeset.
      • The PR had no assignee: the resume order's "no label writes" also withheld the assignee write. The seat sets os-project-manager in this act.
    • Delivered, under the seat's scope correction (the card's title says every example predicate, and the claim's surface is the whole docblock above ConditionalValidationSchema):
      • all 19 predicates in Use Cases 1–7 and on the ObjectStack side of the Salesforce comparison are rewritten in CEL (record.FIELD == VALUE, &&, ||, matches);
      • the Salesforce-formula side is left as it was;
      • the validation.zod.ts hunks are comment lines only (measured: no +/- line outside *);
      • the seven matching test fixtures moved with the examples.
    • Evidence (the report's):
      • ExpressionEngine.evaluate gives 20/20 as expected on true and false records;
      • the lit control shows all 19 old strings still fail;
      • the dist d.ts carries each new string ×1 and each old string ×0;
      • spec build, check:generated, the validation tests (72/72) and typecheck are green.
    • Out-of-scope finding: content/docs/protocol/objectql/index.mdx:186 → Acceptance notes. It is already recorded in docs/audits/2026-06-handwritten-docs-accuracy-followups.md, and no reach was measured.
    • Next: at-tier contract review of this head. The path limb fires on packages/spec/src/data/validation.zod.ts (TSDoc only), and the review must judge each rewritten predicate: in particular, the escaping of the matches pattern as a copied TS string literal. needs:contract-review goes on the PR in this act.
  5. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    REWORK round 1 — PR #20239 at head e6737d70a7, from the at-tier record on the PR (FAIL) · domain:spec seat 2 (session_01QcAS3qiYYZNezaxZxaUdMV) · 2026-09-27T13:33Z

    Blocking, per the record's items 1–3, and nothing else:

    1. The matches example does not parse when copied.
      • The TSDoc literal '…!matches(record.tax_id, "^\\d{2}-\\d{7}$")' yields the CEL source "^\d{2}-\d{7}$", and cel-js refuses \d as an invalid escape sequence. That is this card's own defect class.
      • The fix is the record's escape-free pattern "^[0-9]{2}-[0-9]{7}$" (probed: null → true, 12-3456789 → false, 1234 → true).
      • The report's "20/20 as expected" and the PR body's transcript row for this predicate were not measured on the copied literal. The re-run must evaluate each predicate as the runtime string a reader gets from copying the TSDoc text into a .ts string literal, and the transcript must show that.
    2. Changeset sentences that are false at the head.
      • "cel-js parses = as the start of an assignment" becomes "rejects a lone = as an unexpected character; CEL equality is ==".
      • "both branches evaluate as expected for all 19" and the matches table row are fixed after item 1.
    3. Test fixtures left behind under the widened scope. They are verbatim docblock predicates keyed to the same names and messages, which meets the PR body's own criterion:
      • validation.test.ts :635 is_taxable = true, :640 tax_code = null;
      • :704/:709/:715 region = "EU", gdpr_consent_given = false, tos_accepted = false;
      • :727/:732 user_role = "manager", approval_amount > 50000;
      • :554/:559/:564 country = "US", state = "CA", tax_id = null.
      • Rewrite them in the docblock's CEL (the tax_id one with the escape-free pattern), and correct the PR body's acceptance note to match.

    Passed in the same record, and unchanged by this round: the other 18 predicates (same field, direction and null semantics); the Salesforce side untouched; validation.zod.ts TSDoc only; patch with Clause-②: no.

    Next: the dev's round, then a fresh at-tier record on the new head.

  6. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 20026,
      "status": "done",
      "branch": "claude/issue-20026-conditional-validation-examples-cel",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/20239",
      "session": "session_01QcAS3qiYYZNezaxZxaUdMV",
      "premise_still_valid": true,
      "summary": "REWORK round 1 addressing all three blocking items from the contract-review FAIL (comment 5856311938 on PR #20239, order of record 5856314403 on #20026). (1) The matches() regex used \\d, which parses fine as raw TSDoc comment text but breaks (Invalid escape sequence: \\d) once a reader pastes the literal into a real .ts string literal, since that paste adds one level of JS unescaping the comment never went through — rewritten to the escape-free [0-9] character class in validation.zod.ts, which needs no escaping at any copy depth. (2) Corrected two false changeset sentences (cel-js has no assignment operator; it rejects a lone = outright, CEL equality is ==) and fixed the 'all 19 evaluate' claim plus the matches table row, both now true after item 1. (3) Ten more validation.test.ts fixtures whose test name/message verbatim-copy Use Cases 4/5/6/7 moved to match the docblock's CEL, by the same criterion already applied to the first seven — 17 fixture strings moved in total. Nothing else touched: the other 18 predicates, the Salesforce-formula side, and the patch/Clause-②:no shape are unchanged from the reviewed head. New head sha b7abe173cf44a53aaffe3427171ea47715066d86; PR body replaced (not appended) with the corrected, re-measured transcript; read back byte-identical, draft preserved.",
      "tests": "Re-measured every predicate using the method the review demanded: each when:/condition: literal is extracted from validation.zod.ts byte for byte (comment prefix stripped, quote characters kept) and handed to Node's OWN parser (eval) to apply the exact JS string-literal unescaping a reader's copy-paste would trigger — never hand-retyped. All 19 extracted+unescaped runtime strings evaluate as expected (true-branch and false-branch) via ExpressionEngine.evaluate. Specific re-check on the matches() site: the OLD literal ('...\\\\d{2}-\\\\d{7}$...') run through this same simulation reproduces exactly the review's measured failure (Invalid escape sequence: \\d); the NEW literal ('...[0-9]{2}-[0-9]{7}$...') evaluates correctly on all 4 probe records (null→true, '12-3456789'→false, '1234'→true, 'not-a-tax-id'→true), matching the review's own probe numbers exactly. pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/formula build: clean. pnpm --filter @objectstack/spec check:generated: 15/15 up to date. pnpm --filter @objectstack/spec exec vitest run src/data/validation.test.ts: 72/72 pass. pnpm --filter @objectstack/spec run typecheck: clean, 255 pre-existing debt errors untouched. dist confirmation: packages/spec/dist/object.zod-*.d.ts grep -c is exactly 1 for every one of the 19 new strings and 0 for every one of the 19 old strings, including BOTH escape variants of the matches() predicate (\\\\d and \\d) — zero occurrences of either. The 3 changeset self-tests (empty-changeset, adr-0087-registration, changeset-no-major) green against the corrected changeset. node scripts/pm/dispatch-gates.mjs --ran: 82 derived families, 79 run green, 3 NOT-MEASURED (check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt — each PREREQUISITE NOT MET without the full workspace build closure, out of local scope, left to CI), 0 unrun.",
      "mcp_calls": "0 — no MCP GitHub tool called at any point.",
      "api_writes": "2 this round: 1 issue_patch (PR #20239 body replaced, via the fleet-write relay, read back byte-identical) + 1 os-dev-report comment (this one). 0 label writes, PR left as draft — both per this round's explicit instruction. Plus 1 git push (this round's rework commit, new head b7abe173cf).",
      "gates": "82/82 families derived by dispatch-gates.mjs accounted for: 79 run green, 3 NOT-MEASURED (PREREQUISITE NOT MET — full workspace build needed), 0 unrun. Same 3 files as before (validation.zod.ts, validation.test.ts, the changeset), so the derived family set is unchanged from the prior round; all re-run fresh against this round's content.",
      "line_budget": "n/a",
      "files_changed": [
        "packages/spec/src/data/validation.zod.ts (1 line: matches() regex \\\\d{2}-\\\\d{7} → escape-free [0-9]{2}-[0-9]{7})",
        "packages/spec/src/data/validation.test.ts (10 more fixture lines moved: country/state/tax_id, is_taxable/tax_code, region/gdpr_consent_given/tos_accepted, user_role/approval_amount)",
        ".changeset/20026-conditional-validation-examples-cel.md (2 false sentences corrected, matches table row fixed, fixtures paragraph rewritten for all 17 moved strings)"
      ],
      "deviations": [
        "scripts/pm/os-verify-lock.sh queue-timed-out once this round before acquiring on retry; every wait was synchronous in the foreground under the stable OS_VERIFY_LOCK_SLOT=issue-20026-dev, nothing backgrounded, matching this round's explicit instruction.",
        "check:dual-build-cjs-loads, check:lean-entry-closure and check:type-check-debt remain NOT MEASURED locally (PREREQUISITE NOT MET, need the full workspace build closure) — unchanged from the prior round, out of local-verification scope per AGENTS.md, left to CI's Build Core lane."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: none independently re-measured · content/docs/protocol/objectql/index.mdx:186 `condition: \"account_type = 'Enterprise' AND contract_value = null\"` uses the same non-CEL spelling as the graded strings · carrier: none — already recorded, unresolved, in docs/audits/2026-06-handwritten-docs-accuracy-followups.md; confirmed still out of scope by this round's review (item ③), left untouched per this round's explicit instruction not to touch it."
      ]
    }
  7. objectstack-fleet commented on Sep 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record — PR #20239 merged through the merge queue at 2026-09-27T15:14Z as e0f17a376a · domain:spec seat 2 (session_01QcAS3qiYYZNezaxZxaUdMV) · 2026-09-27T15:15Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions