You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
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
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.
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.
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"
]
}
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Triage: p3 ·
domain:server·area:formula·pm:blockedon 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).
validate_expressiontool answers ok where the authoring door, after PR fix(formula,lint)!: a formula whose label() names a field that declares no options is refused at author time (#28659) #28714, refuses. The door still refuses at save, so nothing wrong is stored. The cost is an agent's wasted round trip.mainyet. This seat dispatches it then.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
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 issession_01FEkQ5pqvaBsS9WCP8ecER5Account:
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:serverSeat:
domain:server#2Ruling-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(thevalidate_expressionhandler),packages/mcp/src/stdio-data-bridge.tsand the HTTP bridge (the field projection the hint reads), their tests; changesetContainer & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: mediumClause-②: no expected — the tool now answers what the door answers; the dev measures and declares (a grown
describe_objectanswer would be an additive widening)Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the dev hands the tool's hint the
optionFieldsmember 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 landsThread-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 onpackages/mcp/src/beforepr_createResume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
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 testTest Files 49 passed (49), Tests 626 passed (626); new mcp-validate-expression.option-labels.test.ts 13/13. runtime:pnpm --filter @objectstack/runtime testTest 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 typecheckexit 0;pnpm --filter @objectstack/runtime typecheckexit 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
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Landing record · #28715 · PR #28774
domain:serverseat 2 ·session_0186vfjHHMsRXC9EUT9hTFMo· 2026-11-01T19:33Zfc286441git merge-base --is-ancestor fc286441 origin/maingit ls-remote origin refs/heads/gh-readonly-queue/*matching 28774git grep -c optionFieldsOf origin/main -- packages/mcp/src/mcp-http-tools.tsvalidate_expressionrefuseslabel()over a field without options exactly as the authoring door does: the same code and sentence, from the one validator, on both bridges.describe_object's answer; picklist-bound and inline-options selects read ok; other sites.Release: claim
6561442620(session_01FEkQ5pqvaBsS9WCP8ecER5, branchclaude/project-thread-d7vyq6) · landed.pm:dispatchedremoved; assignee cleared; the card closed on merge.Generated by Claude Code