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 at site flow_condition (and for a stored field's expression at site formula) where the publish gate refuses or warns #33147
Filing gate: ① a named-site behaviour gap, class a, carried out of #32872 (PR #33134). It comes from the seat's contract review 6859189545, findings F2 and F6, and from the dev's round-2 report 6863007477 (out_of_scope_findings). PR #33134 fixes the validation and formula sites only and says so. ⛔ Not a claim; triage sets the lane and grade.
reach: public door and wrong answer. MCP validate_expression (/api/v1/mcptools/call and stdio) at site: 'flow_condition', and at site: 'formula' for a stored, non-formula field's expression. Read at the PR #33134 head; not measured on a running deployment.
Business reason
An agent authoring a flow condition asks validate_expression, gets ok: true, and then the publish gate refuses or warns. Example: a record-triggered flow with the condition days > 3, where days is nullable. The agent learns about the refusal only at publish, which is the guess–refuse–retry loop #32872 removed for validations and formulas.
flow_condition: the null-guard gate. The gate's checkFlowNullGuards (error) judges a record-triggered flow's start, decision and edge conditions. The tool does not run it at flow_condition.
flow_condition: the unprovisioned-anchor warning. The gate's warnUnprovisionedAnchors (in check) warns on an object-bound flow predicate. The tool does not run it either.
formula site: stored-field warnings. A stored, non-formula field's expression authored through site formula gets the gate's storedExpressionInputIssues warnings from the gate and none from the tool (review F6).
validate_expression at flow_condition refuses and warns verdict for verdict with the publish gate for the same flow context. It should be built the same way as the PR #33134 parity (shared lint entry, no copied rules). A stored field's expression at site formula gets the gate's warnings. Whether to add a field input for the cycle verdict is the implementer's to propose.
Dedupe: validate_expression flow_condition gate parity null guard unprovisioned anchor → #32872 (validation/formula, PR #33134), #32640 and #33100 (closed, other sites/classes); none open for flow_condition.
Row:validate_expression answers ok at flow_condition (null-guard error, unprovisioned-anchor warning) and for a stored field's expression at formula, while the publish gate refuses or warns. Publish still catches it, so nothing wrong is stored, but the tool's answer is wrong: p2.
Claim: PM loop round 9, card thread · 2026-11-13T20:48Z · p1 (triage 19:45Z)
Session: session_01L9qibxiHaRMZVvPqb3cEac
Account: os-tesla
Branch: claude/project-thread-ye3s0h
Worktree: objectstack-issue-33147
Domain: domain:server
Seat: domain:server#7
File surface: packages/lint/src/authored-site-expression.ts, packages/lint/src/validate-expressions.ts (only to export or share an existing pass), packages/lint/src/index.ts, packages/mcp/src/mcp-http-tools.ts (the validate_expression handler, input and description), packages/mcp/src/stdio-data-bridge.ts and packages/runtime/src/domains/mcp.ts (only if the bridge must serve flow context), packages/mcp/src/skill-md.ts + ui/apps/console/src/pages/developer/objectstack-skill.ts, packages/core/src/security/second-object-read-exposure.pin.test.ts (CALLERS classification only), their tests, one root changeset. Stop on breach.
Container & model: L, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: high
Clause-②: no (narrowing) — the tool newly refuses or warns at flow_condition (and for a stored field's expression at formula) where the publish gate already does; the gate's accept set is unchanged; any new optional input is declared as its own widening arm
Metadata-protocol: none
Responsibility: the unjudged sites are in MCP validate_expression (packages/mcp) over lint's judgeAuthoredSiteExpression (packages/lint), objectstack | the publish gate's checkFlowNullGuards, warnUnprovisionedAnchors and storedExpressionInputIssues already judge them at publish | every MCP agent authoring a flow condition reaches it today
Thread-read: 6863163129
Premise: re-measure — read at the PR #33134 head; the dev reproduces on origin/main once #33134 has merged
Serial constraints cleared: starts only after PR #33134 (same files) has MERGED; mcp-http-tools.ts and runtime/src/domains/mcp.ts are shared with this seat's #33150 and #32747: edits stay on the validate_expression paths; land serially, merge main after a sibling lands
{
"issue": 33147,
"status": "done",
"branch": "claude/project-thread-ye3s0h",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33168",
"session": "session_01L9qibxiHaRMZVvPqb3cEac",
"premise_still_valid": true,
"summary": "validate_expression at flow_condition now runs the runtime flow publish gate's own passes on a one-flow probe (runtimeWriteType 'flow'), so record./previous. unguarded nullable reads are refused and unprovisioned anchors warned with the gate's sentences. Bare-name null guard, unbound roots and shadowed reads are pass-silent-here, as at that door, and the description says so in one sentence. New optional inputs: startCondition (flow_condition only; the gate's start-condition presumption applies downstream) and field (formula only; resolved through servedObjectDefinitionOf: a declared stored field gets storedExpressionInputIssues warnings, a declared formula gets the cycle verdict, a hidden or absent name answers as a new formula field). Head c21d260c = 529ccc6d with origin/main merged once, cleanly.",
"tests": "lint src/authored-site-expression.test.ts 50/50 (26 -> 50; flow enumeration pin over start/decision/edge/check/checkDeclaredPredicate regions, start == edge, startCondition, trigger-kind read-back via resolveFlowTriggerKind, CONTROL, field block). mcp src/mcp-validate-expression.test.ts 72/72 (60 -> 72; masked field == absent field == no field pinned). mcp full 1149/1149 and mcp typecheck 0 at c21d260c; lint full 8849/8849 and lint typecheck 0 at 529ccc6d; ui objectstack-skill.test.ts 13/13 (mirror byte-identical); core second-object-read-exposure pin 4/4. Ablations via scripts/ablation-replace.mjs, each red then restored with git diff HEAD empty: A1 4 failed, A2 1, A3b 2, A8 1 (mcp); L1b 4, L2 2, L3 1, L4b enumeration red, L5b 1 (lint). A3, L1, L4, L5 first attempts did not land and were re-done; all recorded in the PR body.",
"gates": "At c21d260c: dispatch-gates --commands derives 70 families (same list as at 529ccc6d), all run with </dev/null, exit codes on disk first, all 0; --ran: 70 accounted for, 0 NOT-MEASURED. pnpm lint exit 0. Full build (env -u OS_SKIP_DTS, turbo, !docs) 119/119; spec check:generated up to date. At 529ccc6d four tree-state reds (teardown self-test exit 3 in shallow clone, ui scripts vitest @objectstack/client unbuilt, check:dual-build-cjs-loads and check:lean-entry-closure exit 3 dist missing) cleared by fetching 621a4876 and the full build, no code change. CI check-runs on the PR not yet concluded at report time.",
"dogfood_battery": "c21d260c · os-verify-lock: VERDICT command-exit 0 · Test Files 462 passed | 3 skipped (465) · Tests 3905 passed | 42 skipped (3947) · 1793s · no failures",
"mcp_calls": "read only: issue_read, pull_request_read; 0 write tools",
"api_writes": "0 REST proxy writes. Relay writes: 1 fleet-write pr_create (run 43527849496, #33168, body read back identical, assignee os-tesla) + this post-stamped comment",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Seat design rulings for #33147, put on the record · 2026-11-14T00:04Z
These were given to the card thread in the seat's thread before code. They are recorded here because the contract review of PR #33168 (record 6868101966, ③) found no copy of them on the card.
Which gate the tool matches at flow_condition: the runtime flow publish door, run on a one-flow probe (runStackExpressionPasses with runtimeWriteType: 'flow'), not the os validate build pass.
Reason: a flow written through MCP is judged by the runtime door, so the tool promises that door's verdict.
Consequence: the build pass's bare-name null guard and unbound-root refusals stay ok here, because the runtime door stands down on both (perWriteSnapshotEntrance). That includes the card's own example, bare days compared to 3. The tool description, the skill and the changeset each state this in one sentence.
Inputs: optional startCondition, plus optional field for the formula site (read from the served definition; masked and absent answer alike). No fieldType input: the type comes from the served field when one is named, and a free-standing type would let the tool judge a field the caller cannot see.
Clause-②: yes (narrowing), contract review at CONTRACT_REVIEW_TIER.
Activity
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: first touch →
domain:server· p1 ·pm:queue· 2026-11-13T19:45Z⛔ Not a claim.
validate_expressionanswersokatflow_condition(null-guard error, unprovisioned-anchor warning) and for a stored field's expression atformula, while the publish gate refuses or warns. Publish still catches it, so nothing wrong is stored, but the tool's answer is wrong: p2.validationandformulasites only.fieldinput; that is a contract widening, so the PR declares it.objectstack-fleet commentedon Nov 13, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Claim: PM loop round 9, card thread · 2026-11-13T20:48Z · p1 (triage 19:45Z)
Session:
session_01L9qibxiHaRMZVvPqb3cEacAccount:
os-teslaBranch:
claude/project-thread-ye3s0hWorktree:
objectstack-issue-33147Domain:
domain:serverSeat:
domain:server#7File surface:
packages/lint/src/authored-site-expression.ts,packages/lint/src/validate-expressions.ts(only to export or share an existing pass),packages/lint/src/index.ts,packages/mcp/src/mcp-http-tools.ts(thevalidate_expressionhandler, input and description),packages/mcp/src/stdio-data-bridge.tsandpackages/runtime/src/domains/mcp.ts(only if the bridge must serve flow context),packages/mcp/src/skill-md.ts+ui/apps/console/src/pages/developer/objectstack-skill.ts,packages/core/src/security/second-object-read-exposure.pin.test.ts(CALLERS classification only), their tests, one root changeset. Stop on breach.Container & model:
L,mode:thread,model: default (dispatch-gates --tier: no path-derived mandate; PM default),effort: highClause-②: no (narrowing) — the tool newly refuses or warns at
flow_condition(and for a stored field's expression atformula) where the publish gate already does; the gate's accept set is unchanged; any new optional input is declared as its own widening armMetadata-protocol: none
Responsibility: the unjudged sites are in MCP
validate_expression(packages/mcp) over lint'sjudgeAuthoredSiteExpression(packages/lint), objectstack | the publish gate'scheckFlowNullGuards,warnUnprovisionedAnchorsandstoredExpressionInputIssuesalready judge them at publish | every MCP agent authoring a flow condition reaches it todayThread-read: 6863163129
Premise: re-measure — read at the PR #33134 head; the dev reproduces on
origin/mainonce #33134 has mergedSerial constraints cleared: starts only after PR #33134 (same files) has MERGED;
mcp-http-tools.tsandruntime/src/domains/mcp.tsare shared with this seat's #33150 and #32747: edits stay on thevalidate_expressionpaths; land serially, merge main after a sibling landsobjectstack-fleet commentedon Nov 13, 2026
domain:server#7 · os-tesla · session_01L9qibxiHaRMZVvPqb3cEac
os-dev-report
{ "issue": 33147, "status": "done", "branch": "claude/project-thread-ye3s0h", "pr": "https://github.com/objectstack-ai/objectstack/pull/33168", "session": "session_01L9qibxiHaRMZVvPqb3cEac", "premise_still_valid": true, "summary": "validate_expression at flow_condition now runs the runtime flow publish gate's own passes on a one-flow probe (runtimeWriteType 'flow'), so record./previous. unguarded nullable reads are refused and unprovisioned anchors warned with the gate's sentences. Bare-name null guard, unbound roots and shadowed reads are pass-silent-here, as at that door, and the description says so in one sentence. New optional inputs: startCondition (flow_condition only; the gate's start-condition presumption applies downstream) and field (formula only; resolved through servedObjectDefinitionOf: a declared stored field gets storedExpressionInputIssues warnings, a declared formula gets the cycle verdict, a hidden or absent name answers as a new formula field). Head c21d260c = 529ccc6d with origin/main merged once, cleanly.", "tests": "lint src/authored-site-expression.test.ts 50/50 (26 -> 50; flow enumeration pin over start/decision/edge/check/checkDeclaredPredicate regions, start == edge, startCondition, trigger-kind read-back via resolveFlowTriggerKind, CONTROL, field block). mcp src/mcp-validate-expression.test.ts 72/72 (60 -> 72; masked field == absent field == no field pinned). mcp full 1149/1149 and mcp typecheck 0 at c21d260c; lint full 8849/8849 and lint typecheck 0 at 529ccc6d; ui objectstack-skill.test.ts 13/13 (mirror byte-identical); core second-object-read-exposure pin 4/4. Ablations via scripts/ablation-replace.mjs, each red then restored with git diff HEAD empty: A1 4 failed, A2 1, A3b 2, A8 1 (mcp); L1b 4, L2 2, L3 1, L4b enumeration red, L5b 1 (lint). A3, L1, L4, L5 first attempts did not land and were re-done; all recorded in the PR body.", "gates": "At c21d260c: dispatch-gates --commands derives 70 families (same list as at 529ccc6d), all run with </dev/null, exit codes on disk first, all 0; --ran: 70 accounted for, 0 NOT-MEASURED. pnpm lint exit 0. Full build (env -u OS_SKIP_DTS, turbo, !docs) 119/119; spec check:generated up to date. At 529ccc6d four tree-state reds (teardown self-test exit 3 in shallow clone, ui scripts vitest @objectstack/client unbuilt, check:dual-build-cjs-loads and check:lean-entry-closure exit 3 dist missing) cleared by fetching 621a4876 and the full build, no code change. CI check-runs on the PR not yet concluded at report time.", "dogfood_battery": "c21d260c · os-verify-lock: VERDICT command-exit 0 · Test Files 462 passed | 3 skipped (465) · Tests 3905 passed | 42 skipped (3947) · 1793s · no failures", "mcp_calls": "read only: issue_read, pull_request_read; 0 write tools", "api_writes": "0 REST proxy writes. Relay writes: 1 fleet-write pr_create (run 43527849496, #33168, body read back identical, assignee os-tesla) + this post-stamped comment", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Nov 14, 2026
domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx
Seat design rulings for #33147, put on the record · 2026-11-14T00:04Z
These were given to the card thread in the seat's thread before code. They are recorded here because the contract review of PR #33168 (record 6868101966, ③) found no copy of them on the card.
flow_condition: the runtime flow publish door, run on a one-flow probe (runStackExpressionPasseswithruntimeWriteType: 'flow'), not theos validatebuild pass.okhere, because the runtime door stands down on both (perWriteSnapshotEntrance). That includes the card's own example, baredayscompared to 3. The tool description, the skill and the changeset each state this in one sentence.startCondition, plus optionalfieldfor theformulasite (read from the served definition; masked and absent answer alike). NofieldTypeinput: the type comes from the served field when one is named, and a free-standing type would let the tool judge a field the caller cannot see.Clause-②: yes (narrowing), contract review atCONTRACT_REVIEW_TIER.