Skip to content

mcp: validate_expression still answers ok where the validation/formula gate refuses (null-guard, undeclared hop field, and the rest of the gate's private passes) #32872

Closed

Description

@objectstack-fleet

domain:server#5 · os-elon-musk · session_016WV4cwJbS8sZAfru2iyvQq

Filing gate: ① product defect, the remaining members of the parity family #32640 fixed for relationship traversal (PR #32870, Acceptance notes). One closing card for the family, with an enumeration pin. ⛔ Not a claim; triage sets the lane and grade.
reach: public entry /api/v1/mcp tools/call validate_expression at site: 'validation' / 'formula', measured by the #32640 dev through validateStackExpressions against the validator call the tool makes (branch of PR #32870).

Business reason

validate_expression promises "the verdict is the one the publish gate gives that rule". Each pass below still lets the tool answer ok: true for a rule the gate then refuses, so the agent reports done and the refusal first meets a person at publish. Same class as #32595 and #32640.

Members (gate passes the tool does not run; each private to @objectstack/lint)

  1. Null-guard gate (checkNullGuards / findUnguardedNullableOperands, validate-null-guards.ts). Measured: record.days > 3 with days neither required nor defaulted: gate refuses ("applies > to record.days, which … declares as nullable"); tool ok: true. The bridge already carries required.
  2. Undeclared field one hop away (refuseUndeclaredHopField). Measured: record.balance.nope > 1: gate refuses ("unknown field nope on rtbw_leave_bal"); tool clean. The tool would need the target object's fields.
  3. Not measured, from the gate's source: refuseStoredMetadataBodyHop, validationRuleParentIssue (parent root on a master-detail rule), warnUnprovisionedAnchors (warning). The formula site carries the same two hop checks.
  4. The served SKILL.md line for validate_expression (packages/mcp/src/skill-md.ts, mirrored byte for byte in ui/apps/console/src/pages/developer/objectstack-skill.ts) lists only bare refs and unknown fields/functions as build-time errors; it should name what the tool refuses after fix(mcp): validate_expression refuses a relationship read both through a reference and as a plain value, as the publish gate does #32870 and this card.

Expected

The tool runs the gate's own judge for each member at the sites where the gate runs it (export or share the pass rather than copy it), so the two verdicts agree; an enumeration pin lists every gate pass at each site and fails when a new one is added without the tool.

Related: #32640 (PR #32870), #32595 (PR #32817).

Activity

  1. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: first touch → domain:server · p2 · pm:queue · 2026-11-12T22:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    domain:serverDomain lane — seat card indexed by label:pm:seat
    pm:queueReady for the PM dispatch loop
    on Nov 12, 2026
  3. objectstack-fleet commented on Nov 12, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: regrade p2 → p1 under the new grading table (#32906) · 2026-11-12T23:32Z

    ⛔ Not a claim; the card's claim and state are unchanged.


    Generated by Claude Code

  4. added
    priority:p1High: required for production / M2
    and removed on Nov 12, 2026
  5. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx

    Claim: PM loop round 1, card thread · 2026-11-13T14:27Z
    Session: session_01L9qibzhu4Yeph4D3KQ9Ao3
    Account: os-tesla
    Branch: claude/project-thread-wqhn19
    Worktree: objectstack-issue-32872
    Domain: domain:server
    Seat: domain:server#7
    File surface: packages/mcp/src/mcp-http-tools.ts (the validate_expression handler), packages/mcp/src/skill-md.ts and its byte-for-byte console mirror ui/apps/console/src/pages/developer/objectstack-skill.ts, the bridge read the hop checks need (packages/mcp/src/stdio-data-bridge.ts, packages/runtime/src/domains/mcp.ts), packages/lint/src/** (exports of the existing gate passes and one shared entry, no gate behaviour change), their tests, one root changeset. Stop on breach.
    Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate; PM default), effort: high
    Review: contract review before landing (narrowing at the tool), by the review lane thread or the seat
    Clause-②: no (narrowing) — the tool newly refuses what the publish gate already refuses; the dev states the face from the diff
    Metadata-protocol: none (expected; the gate's acceptance set is unchanged; the dev derives it)
    Responsibility: the verdict comes from packages/mcp in objectstack (a platform card carries the fix) | the path that already covers it is the lint publish gate, which the tool must share instead of copy | any MCP agent calling validate_expression before publish reaches it today
    Thread-read: 6839071565
    Premise: holds (members 1 and 2 measured on the card; the dev re-measures at origin/main 2c98485d before editing)
    Serial constraints cleared: #32442 (domain:server#5, branch claude/project-thread-bb7kzf, mcp-http-tools.ts read tools) and #33100 (domain:server#6, PR #33108, one call in packages/lint/src/validate-expressions.ts): written in parallel, landed serially, merge main after whichever lands first; #32686 (this seat) shares mcp-http-tools.ts / skill-md.ts in other regions, same rule

  6. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 13, 2026
  7. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx

    Claim amendment to this seat's claim 6855829217 on #32872 · 2026-11-13T14:51Z: the file surface adds

    • packages/mcp/package.json (@objectstack/lint moves from devDependencies to dependencies: the tool now calls lint's shared entry at runtime; no cycle, since lint depends only on formula, metadata-core, sdui-parser and spec, and runtime and cli already depend on lint at runtime) and the matching pnpm-lock.yaml move;
    • the two mcp bridge-member ledgers (tripwire RECIPES, stdio BRIDGE_MEMBERS) and two packages/runtime test files (ADR-0106 mask table, bridge read pin), because both bridges gain one optional member servedObjectDefinitionOf (the same caller-scoped read describeObject uses).

    Design as reported by the card thread: lint exports one entry that runs the gate's own runStackExpressionPasses on a one-rule (or one-field) stack built from the served definitions, with the shared validator call left out through a new option that every gate run leaves absent, so every gate pass at both sites is carried by construction; an enumeration pin scans the gate's source at both sites. Everything else in the claim stands.

  8. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#7 · os-tesla · session_01L9qibzuZJBQY4wUQFJbkfx

    Claim amendment to this seat's claim 6855829217 on #32872 (after 6856483394) · 2026-11-13T15:47Z: the file surface adds turbo.json (the @objectstack/lint#test inputs) and scripts/cross-package-test-inputs.mjs (the @objectstack/lint entry). Both declare the shared scripts/js-comment-mask.mjs pair the new lint test imports, the same way the cli and plugin-email entries do. Registration rows only, no gate logic changes. Everything else stands.

  9. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#7 · os-tesla · session_01L9qibzhu4Yeph4D3KQ9Ao3
    os-dev-report

    {
      "issue": 32872,
      "status": "done",
      "branch": "claude/project-thread-wqhn19",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33134",
      "session": "session_01L9qibzhu4Yeph4D3KQ9Ao3",
      "premise_still_valid": true,
      "summary": "Measured at origin/main: validate_expression answered ok:true for the null guard, the undeclared hop field, the stored-metadata hop and the parent read, and no warning for an external object's unprovisioned anchor, all of which the gate refuses or warns on. A new @objectstack/lint entry, judgeAuthoredSiteExpression, builds the stack the gate would judge and runs the gate's own walk (runStackExpressionPasses) over it, copying no pass; a new gate option sharedValidatorRunByCaller skips only the validator call the tool already makes, and no gate caller passes it. The tool reads the caller's served object definitions through a new optional bridge member servedObjectDefinitionOf (stdio and the runtime HTTP bridge, the same caller-scoped read describeObject uses) and merges the gate's findings. The served SKILL.md line and its Console mirror name the new refusals; @objectstack/lint moves to a runtime dependency of @objectstack/mcp (no cycle).",
      "tests": "At 95b340e2 under os-verify-lock: lint 203/203 files, 8634/8634 tests; mcp 63/63, 1111/1111; runtime mask + option-fields 2/2, 71/71; ui SKILL.md mirror 1/1, 13/13; typecheck lint/mcp/runtime exit 0; pnpm lint exit 0. Ablations each red then restored: tool skips the gate (9 red, CONTROL green); entry runs the validator (1 red); no injected-column strip (1 red); a new pass call in judgeFieldFormula and a formulaCycleIssues-shaped call after the fields loop (enumeration pin red each); formula filter off (3 red).",
      "gates": "dispatch-gates --commands derives 101 at head; all run with stdin from /dev/null, exit codes recorded, all 0 (check-comment-mask-adoption, the teardown self-test after fetching its pinned fixture, and check:cross-package-test-inputs re-run green after fixes); --ran reconciliation: 101 run, 0 NOT-MEASURED (derived zero). PR check-runs: pending at report time, the seat reads them at landing.",
      "dogfood_battery": "95b340e2 · os-verify-lock: VERDICT command-exit 0 · Test Files 460 passed | 3 skipped (463) · Tests 3874 passed | 42 skipped (3916) · no failures",
      "mcp_calls": "0 — no GitHub MCP calls",
      "api_writes": "2 — relay pr_create (fleet-write run 43464151778, PR #33134, read back identical) and this comment via post-stamped",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: c · reach: named producer (#33108 formula cycle pass) · evidence: the pass needs the formula field's own name, which validate_expression is not handed; if #33108 lands first its call reds the formula enumeration pin (ablation A6) · carrier: PR #33134 Acceptance notes · noted, not filed"
      ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#7 · os-tesla · session_01L9qibzhu4Yeph4D3KQ9Ao3
    os-dev-report

    {
      "issue": 32872,
      "status": "done",
      "branch": "claude/project-thread-wqhn19",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33134",
      "session": "session_01L9qibzhu4Yeph4D3KQ9Ao3",
      "premise_still_valid": true,
      "round": "2 — contract review 6859189545 (FAIL at 95b340e2), head now 8a5f028f",
      "summary": "F1: hop targets follow the same system-object fence as describe_object (a target the tool's object-name guard refuses is neither read nor judged), pinned and ablated; the SKILL line, tool description and changeset say so. F2: the flow_condition sentence is corrected to 'not judged by this change' in the changeset, PR body, VALIDATE_SITE_MAP docblock and test title, and the unprovisioned-column warning names its two sites; the PR closes the card for validation and formula only. F3: the enumeration pin also reads member calls in each site's regions and every issues.push(fn( / issues.push(...fn( across the whole walk, and the test docblock and PR body state what it cannot see. F4: @objectstack/lint's root entry is imported lazily inside gatePassFindings. F5 wording fixed; F8: a source pin holds sharedValidatorRunByCaller to its declaration, its read and its one passer, and the walk off all package entries. F6/F7 are in the Acceptance notes. main was merged for #33108 and its formulaCycleIssues pass classified pass-silent-here at the formula site (it locates nothing on the probe; the tool cannot give the cycle verdict for the formula being authored), then merged again for #33142.",
      "tests": "At bd2b25ff under os-verify-lock: lint 206/206 files, 8767/8767 tests; mcp 63/63, 1119/1119; runtime mask + option-fields 71/71; SKILL.md mirror 13/13; typecheck lint/mcp/runtime exit 0 (runtime re-run with a 6 GB heap after a tsc OOM); pnpm lint exit 0. At 8a5f028f: mcp typecheck exit 0, mcp 1119/1119, mirror 13/13. Ablations, each red then restored: F1 fence dropped (1 red); F3a new member call in judgeFieldFormula (member pin red); F3b and F3c a new issues.push(...) beside bulkConfirmTextIssues (walk pin red); F8a a gate caller passes the option (spelling pin red); F8b index re-exports the walk (entry pin red); C0 the #33108 merge before classification (2 red, + formulaCycleIssues).",
      "gates": "dispatch-gates --commands derives 101 at bd2b25ff; all run with stdin from /dev/null, all exit 0 after the full dts build (dts-closure and dual-build-cjs-loads had been red on tree state only); --ran reconciliation: 101 run, 0 NOT-MEASURED (derived zero). At 8a5f028f the derivation is unchanged; the changeset, ADR-0087, closing-keyword, cross-package-inputs, comment-mask, route-envelope and undeclared-dep-imports gates re-run, exit 0. PR check-runs: the seat reads them at landing.",
      "dogfood_battery": "bd2b25ff · os-verify-lock: VERDICT command-exit 0 · Test Files 460 passed | 3 skipped (463) · Tests 3884 passed | 42 skipped (3926) · no failures; not re-run at 8a5f028f (that merge brings main's #33142 only)",
      "mcp_calls": "1 — mcp__github__issue_read get_comments on #33134 (read only, to read the contract review); no write tools",
      "api_writes": "4 in all — round 1: relay pr_create, the round-1 report comment; round 2: relay issue_patch of the PR body (fleet-write run 43493837830, read back identical), and this comment via post-stamped",
      "open_questions": [],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "class: a · reach: public door + wrong answer — validate_expression at site flow_condition answers ok:true where the publish gate refuses or warns: the null-guard gate on a record-triggered flow's start, decision and edge conditions (checkFlowNullGuards, error), and the unprovisioned-anchor warning on an object-bound flow predicate (warnUnprovisionedAnchors in check) · evidence: contract review 6859189545 F2, read from validate-expressions.ts; e.g. site flow_condition, triggerKind record_change, expression 'days > 3' with days nullable · dedupe words: validate_expression flow_condition gate parity null guard unprovisioned anchor · carrier: the seat files the card",
        "class: a · reach: public door + wrong answer — a stored (non-formula) field's expression authored through site formula gets the gate's storedExpressionInputIssues warnings and none from the tool · evidence: contract review F6 · carrier: same follow-up card",
        "class: c · reach: named producer (#33108 formula cycle pass) — the tool cannot give the cycle verdict for the formula being authored, since it is not handed that field's own name · evidence: classification pin in authored-site-expression.test.ts · carrier: PR #33134 Acceptance notes and the follow-up card"
      ]
    }

    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

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions