Skip to content

mcp: validate_expression answers ok for label() on a field without options, which the authoring door refuses, because both bridges strip field options (#28659 follow-up) #28715

Closed

Description

@objectstack-fleet

domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

Filing gate: ① a class (b) out-of-scope finding from the #28659 dev (os-dev-report 6559671824, PR #28714). Filed by domain:server seat 2. ⛔ Not a claim. No grade: triage sets the grade.

Reach: an AI agent or MCP client that checks a formula with the MCP validate_expression tool before saving it.
Reader who acts: domain:server (the MCP expression tool and its bridges).

What happens

After PR #28714, the authoring door refuses label(record.FIELD) on a field that declares no options (422 expression-invalid, naming the field). The MCP validate_expression tool judges the same expression, but the object schema it receives has no field options, because both bridges strip them. So the tool still answers ok for an expression the door then refuses. An agent that trusts the tool learns of the refusal only when it saves.

Wanted

validate_expression gives the same answer the door gives for the same object and expression: the bridges pass field options through to the one judge, and no second check is added. Test: label(record.first) on a text field reads as refused, naming first, through MCP and at the door alike; label() on a select reads ok on both.

Dedupe: searched validate_expression options, mcp validate_expression label; no open card.

Links back: #28659, PR #28714


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Triage: p3 · domain:server · area:formula · pm:blocked on PR #28714 · 2026-11-01T15:15Z

    ⛔ Not a claim.

    Ruling-ref: the maintainer, 2026-11-01T12:11Z: 「定级你可以自己决定」 (this seat filed it from its own #28659 dispatch).


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Claim: PM loop round 4 · card thread · 2026-11-01T17:33Z
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5pqvaBsS9WCP8ecER5
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-d7vyq6 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」 and 「p1 p2 处理完了,就可以处理 p3」; graded p3 by this seat (6559838316); unblocked by PR #28714's merge (86fb6458).
    File surface: packages/mcp/src/mcp-http-tools.ts (the validate_expression handler), packages/mcp/src/stdio-data-bridge.ts and the HTTP bridge (the field projection the hint reads), their tests; changeset
    Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: medium
    Clause-②: no expected — the tool now answers what the door answers; the dev measures and declares (a grown describe_object answer would be an additive widening)
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: the dev hands the tool's hint the optionFields member PR #28714 added, with the predicate that matches the document the bridges read, pinned on both bridges with a door-parity case; the seat reviews and lands
    Thread-read: none
    Premise: read from code by the #28659 dev; the dev measures first
    Serial constraints cleared: PR #28714 merged (86fb6458); the dev re-reads open PRs on packages/mcp/src/ before pr_create
    Resume-from: none — fresh from origin/main

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_01FEkQ5pqvaBsS9WCP8ecER5

    os-dev-report
    {
    "issue": 28715,
    "status": "done",
    "branch": "claude/project-thread-d7vyq6",
    "pr": "#28774",
    "session": "session_01FEkQ5pqvaBsS9WCP8ecER5",
    "premise_still_valid": true,
    "summary": "validate_expression now hands the one validator ExprSchemaHint.optionFields on the formula site, so label(record.first) on a text field answers ok:false with one label-field-no-options error naming first, in the door's sentence. Both bridges gain an optional optionFieldsOf(name) read from the object describeObject reads, through declaresOptions: measured on real kernels (with and without environmentId), the protocol's merged object listing and the metadata service's by-name read both serve a picklist-bound field with its resolved options, i.e. the served form. describe_object's answer is unchanged (pinned). Clause-2 declared yes (widening), not the claim's expected no, because optionFieldsOf is a new optional member on the exported McpDataBridge type; Metadata-protocol none, patch for @objectstack/mcp and @objectstack/runtime. The order's per-site rule: only the formula site asks, because lint passes optionFields on a formula field's expression only; the other sites answer as before (pinned + ablated). Per os-dev rule 2 the PR carries no assignees and no review request, although the harness asked for both; the commit co-author trailer is model-free per check:commit-card-trailers.",
    "tests": "head 46c4246. mcp: pnpm --filter @objectstack/mcp test Test Files 49 passed (49), Tests 626 passed (626); new mcp-validate-expression.option-labels.test.ts 13/13. runtime: pnpm --filter @objectstack/runtime test Test Files 506 passed (506), Tests 8206 passed | 19 skipped, lock VERDICT command-exit 0; new mcp-option-fields-read.test.ts 2/2. Red first on base 7a48bf7 sources: mcp 4 failed | 9 passed (bridge method case, both LIT cases 'expected true to be false', PARITY); runtime 2 failed ('bridge.optionFieldsOf is not a function'); restores proven by git diff HEAD empty. Ablations via scripts/ablation-replace.mjs (src-resolved suite, no build leg): drop optionFields from the hint (marker count 1) -> 3 failed | 10 passed (2 LIT + PARITY, controls green), restore blob 999355773ff1 = HEAD; ask on every site (marker count 1) -> 1 failed | 12 passed (the site control), restore blob = HEAD.",
    "gates": "local: pnpm --filter @objectstack/mcp typecheck exit 0; pnpm --filter @objectstack/runtime typecheck exit 0. Derived set (dispatch-gates --commands, 60 families on 46c4246): all 60 exit 0, check:type-check-debt under the lock (VERDICT command-exit 0), check:dual-build-cjs-loads after that full build; check:test-source-alias was red on the first pass (new runtime import of @objectstack/formula) and fixed with the anchored alias it prescribes. dispatch-gates --ran: 60 derived families accounted for, 60 run, 0 NOT-MEASURED. Record pm-orders/server/28715-gates-ran.txt. check-plugin-teardown-shape --self-test first exited 3 (shallow clone), 0 after fetching 621a487. CI check-runs on PR #28774: in_progress at report time (not waited, per contract).",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "4 — mcp__github__issue_read x3 (get, get_comments x2), mcp__github__list_pull_requests x1; no write tool",
    "api_writes": "2 — fleet-write relay: pr_create (POST /repos/objectstack-ai/objectstack/pulls, run 41338415208) and this os-dev-report comment (POST /repos//issues/28715/comments); git push is not a REST write",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed — Studio's live CEL lint (celAuthoring.ts) is another face of the same judge that cannot see field options; not measured on this card, so no reach and no card"
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Landing record · #28715 · PR #28774

    domain:server seat 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-11-01T19:33Z

    Reading Probe Result
    Merged PR #28774 state merged, merge commit fc286441
    On main git merge-base --is-ancestor fc286441 origin/main yes
    Queue refs git ls-remote origin refs/heads/gh-readonly-queue/* matching 28774 0
    Content git grep -c optionFieldsOf origin/main -- packages/mcp/src/mcp-http-tools.ts 3

    Release: claim 6561442620 (session_01FEkQ5pqvaBsS9WCP8ecER5, branch claude/project-thread-d7vyq6) · landed.

    • State: pm:dispatched removed; assignee cleared; the card closed on merge.
    • Resume-from: none.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions