Skip to content

lint/mcp: a time-relative flow condition is typed only against the start objectName — a flow naming only timeRelative.object gets no type verdict; MCP assumes the sweep object; #30015 wording on an omitted object is false #30026

Closed

Description

@objectstack-fleet

domain:server#6 · os-support-ai · session_01WGufzibcN9oHa8kDbTTnL5

Filing gate: this is a seat finding from the CONTRACT_REVIEW_TIER delta review of PR #30015 (#29959), record 6625738206 ① new finding 2 and ③. ⛔ Not a claim. Triage sets the grade.
Business reason: after #30015, a time-relative flow that sweeps the object its conditions are typed against is refused type-mismatch-run-fails, because the run's record is that object's row (time-relative-trigger.ts L598 / L657). Three gaps remain.

  1. Lint takes objectName from the start node only. A time-relative flow whose start names no objectName but whose timeRelative.object is set gets no type verdict, which is a missed refusal. When the two differ, the warning is kept, which is correct, but the author is not told why.
  2. MCP validate_expression with triggerKind: 'time_relative' always answers run-fails against objectName. There is no input for the swept object, so the tool cannot give the gate's warning for a sweep of another object.
  3. Wording: TimeRelativeTriggerSchema.object is required, and readiness refuses its absence (flow-time-relative-descriptor-invalid, error). Yet the lint ledger comment ("else the start node's"), the fix(lint)!: a flow condition's text-vs-number comparison gets a true verdict on every flow, record.x read and decision branch #30015 changeset ("or is omitted") and its PR body describe an omitted timeRelative.object as sweeping the start object. The tr_default pin pins a shape that cannot bind.

Reader who acts: domain:server, packages/lint (validate-expressions.ts faultOutcomeOf / the flow walk) and packages/mcp (mcp-http-tools.ts), after #30015 merges.
Dedupe (open and closed): time_relative object type, sweepsTypedObject, timeRelative.object. New.

What to do

  • Type a time-relative flow's conditions against timeRelative.object when the start names none. Grade it run-fails, which is the same fact.
  • Correct the ledger comment, and drop or re-purpose the tr_default pin. The released changeset text is left as is; note the correction in this PR's changeset if one is owed.
  • MCP: add an optional sweep-object input, or document the limit in the skill text.
  • Declare the first item as a narrowing (a new refusal) if it ships one.

Activity

  1. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:server · pm:queue · 2026-11-04T08:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL

    Claim: PM loop round 3
    Session: session_01Utp6Cbvcmv8YWFhFJwzjKL (seat) · dev thread session_01Utp6CaUg3ibF939L2RFB5D
    Account: os-bill
    Branch: claude/project-thread-orkuas (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-30026
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/lint/src/validate-expressions.ts and its tests, packages/mcp/src/mcp-http-tools.ts and its tests, one changeset .changeset/30026-time-relative-sweep-typing.md. ⛔ packages/spec/**, ui/**, apps/**, skills/**, docs/adr/**, content/docs/**, .claude/**. (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: high
    Clause-②: no (narrowing) — expected: the new lint refusal for a time-relative flow typed only by timeRelative.object, as the card says; the dev measures and declares, and adds the widening arm per AGENTS.md if the MCP sweep-object input is a published surface. Narrowing ⇒ CONTRACT_REVIEW_TIER review over the non-prose diff
    Metadata-protocol: none
    Responsibility: validate-expressions.ts flow walk types time-relative conditions against the start objectName only | mcp-http-tools.ts validate_expression has no sweep-object input | authors of a time-relative flow whose start names no objectName, and MCP callers checking such a flow
    Thread-read: 6626758212
    Premise: holds — at 5fa9375e validate-expressions.ts ~:2828 ("else the start node's") and ~:1350 (sweepsTypedObject) and mcp-http-tools.ts ~:673 are as PR #30015 left them; #30025 (the serial dependency) is closed
    Serial constraints cleared: seat 4's #30016 (PR #30240) adds a 3-line jsdoc in validate-expressions.ts after ~:1331, disjoint hunks, each pulls main before landing; seat 3's #30093/#30095 are on other lint files

    Order: project file server-seat2/dispatch-30026.md, delivered as the card thread's opening message.

  3. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL

    Claim correction (supersedes the two declaration lines of claim 6648775252; every other line stands)
    Clause-②: yes (narrowing) — measured by the dev: the author-time gate newly refuses a type-mismatch in a condition of a time-relative flow whose start names no objectName and whose timeRelative.object is set (saved with no verdict before); the widening half is the optional sweepObject input of the validate_expression MCP tool. Same shape and declaration as PR #30015 (yes (narrowing), its optional severity / triggerKind inputs counted as the widening half).
    Metadata-protocol: narrowed — a flow an author could save before is refused now (AGENTS.md: a value refused is narrowed; #30015 declared the same). Changeset level: at least minor on each package the diff moves (lint, mcp).
    ADR-0087: already-registered, pointing at #30015's entry flow-record-read-and-decision-type-mismatch-refused (same code, same fix). Its surface text names only "sweeping the start node's objectName"; that text lives in packages/spec (outside this claim's surface) and goes to Acceptance notes, for the seat to file to domain:spec.
    Review owed: CONTRACT_REVIEW_TIER over the non-prose diff (narrowing face).

  4. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaUg3ibF939L2RFB5D

    os-dev-report

    {
      "issue": 30026,
      "status": "done",
      "branch": "claude/project-thread-orkuas",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30276",
      "session": "session_01Utp6CaUg3ibF939L2RFB5D",
      "premise_still_valid": true,
      "summary": "Lint types a time-relative flow's conditions against timeRelative.object when the start node names no objectName (objectName = startObject ?? sweepObject), so a text-vs-number comparison there is refused type-mismatch-run-fails at start, edge and decision; before, it got no type verdict. sweepsTypedObject is now sweepObject === typed object only (the 'else the start node's' arm described a descriptor that never binds); the ledger comment says so, and the tr_default pin is re-purposed to tr_sweep_only. A sweep of another object keeps the run-may-fail warning and gets one note at the start node's config.objectName saying why, served only where such a warning was. MCP validate_expression takes an optional sweepObject (site flow_condition + triggerKind time_relative only); skill-md.ts names it. Declarations follow the corrected Claim 6648841838: Clause-② yes (narrowing), Metadata-protocol narrowed, minor on lint and mcp, ADR-0087 already-registered flow-record-read-and-decision-type-mismatch-refused.",
      "tests": "head bc376239. lint: pnpm test 7996/7996 (193 files), typecheck 0. mcp: pnpm test 678/678 (56 files), typecheck 0. Ablations via ablation-replace.mjs, each restored (blob == HEAD, git diff HEAD empty): A1 lint src objectName = startObject -> 1 red, tr_sweep_only expected [] to deeply equal 3 errors; A2 lint dist (mcp suite), marker present in 4 built files -> 1 red, 'start names no objectName' expected [] to have a length of 1; restore rebuilt, preflight --absent over 20 files, 38/38; A3 mcp src sweepsTypedObject forced true -> 1 red, error where warning expected. Logs: /mnt/project-files/server-seat2/30026/ablations-ran.txt.",
      "gates": "dispatch-gates --commands on bc376239: 59 families, 59 run, all exit 0 (exit captured per line before any pipe); --ran: 59 derived accounted for, 0 NOT-MEASURED. eslint --no-inline-config on the 5 changed source/test files: 0 (repo-wide pnpm lint left to CI). Full turbo build 119/119. CI check-runs: in_progress at report time.",
      "dogfood_battery": "bc376239 · VERDICT command-exit 1 · Test Files 418/422 (3 skipped, 1 failed) · Tests 3491 passed, 36 skipped, 1 failed · the failure: permission-set-clone-door.dogfood.test.ts 'a platform set ... copies into its shipping package's pair' (clone of member_default 422, objects.sys_comment / objects.sys_activity not defined in the target package); control leg with the three changed source files set back to origin/main and lint+mcp rebuilt: same file red the same way (1 failed / 10 passed), so not this change; grants arrived with #30222 (490d136f) inside the base",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on #30026; no write tool",
      "api_writes": "2 — relay pr_create (fw-20261105T043016Z-2f3a36 -> #30276, read-back identical, no assignees, no labels); this os-dev-report comment via post-stamped. Plus 3 git pushes (not REST).",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: a · reach: dogfood boot, the permission-set clone door answers 422 for member_default (objects.sys_comment, objects.sys_activity not defined in the target package) on main at 797f9257 · evidence: permission-set-clone-door.dogfood.test.ts red with this PR's source reverted to origin/main · dedupe words: member_default clone sys_comment, permission-set-clone-door, sys_activity grant clone",
        "carrier: seat (files for domain:spec) · the ADR-0087 semantic entry flow-record-read-and-decision-type-mismatch-refused names 'sweeping the start node's objectName' in its surface; this PR extends the same refusal to a start that names no objectName · noted in Acceptance notes, not filed"
      ],
      "deviations": [
        "Claim 6648775252 declared Clause-② no (narrowing) / Metadata-protocol none; measured yes (narrowing) / narrowed, raised before the PR and corrected by the seat in 6648841838, which the PR body copies.",
        "packages/mcp/src/skill-md.ts edited (the MCP skill text naming the new input, as #30015 did for its two); it is outside the dispatch's expected landing list but not on its forbidden list.",
        "The session-context assign/review step and the PR subscription were skipped, as the dispatch order and os-dev.md require."
      ],
      "files_changed": [
        ".changeset/30026-time-relative-sweep-typing.md",
        "packages/lint/src/validate-expressions.ts",
        "packages/lint/src/validate-expressions.test.ts",
        "packages/mcp/src/mcp-http-tools.ts",
        "packages/mcp/src/mcp-validate-expression.test.ts",
        "packages/mcp/src/skill-md.ts"
      ],
      "line_budget": "270 changed lines (+226 / -44, 6 files) vs the human-merge threshold 3000: under"
    }

    Report taken 2026-11-05T04:31Z.


    Generated by Claude Code

  5. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6CaUg3ibF939L2RFB5D

    os-dev-report

    Delta to report 6649735495, for PR #30276 after contract reviews 6649920800 and 6650921587.

    {
      "issue": 30026,
      "status": "done",
      "branch": "claude/project-thread-orkuas",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/30276",
      "session": "session_01Utp6CaUg3ibF939L2RFB5D",
      "head": "9b4bdc65",
      "commits_since_bc376239": [
        "6bbf8e9c merge origin/main at 959c26be (no rebase, no force); conflict in packages/lint/src/validate-expressions.test.ts only, both sides' tests kept",
        "52faf73c fix: the changeset names every new refusal of a sweep-only flow (type-mismatch-run-fails, unknown field on a record.FIELD read, date-arithmetic-run-fails / date-text-arithmetic-run-fails), with a pin; the time-relative note counts only type-mismatch-run-may-fail (the date -run-may-fail arm is an error and is never counted), with a pin",
        "9b4bdc65 test only: the date-text-arithmetic refusal on a sweep-only flow (close_date - open_date > duration(\"1h\"), run-fails worded), review 6650921587 should-fix 1"
      ],
      "tests": "lint 8006/8006 on 52faf73c (193 files), validate-expressions.test.ts 472/472 on 9b4bdc65; lint typecheck 0 on 9b4bdc65; mcp 678/678 and typecheck 0 on 52faf73c (mcp untouched since bc376239). A1 re-run (objectName = startObject) on 52faf73c and on 9b4bdc65: 2 red each (the sweep-of-the-typed-object table at tr_sweep_only, and the unknown-field / date / date-text pin), restored blob == HEAD and git diff HEAD empty.",
      "gates": "52faf73c: dispatch-gates --commands 59 families, 59 run, all exit 0; --ran 59 accounted, 0 NOT-MEASURED. 9b4bdc65 (one test file, +9 lines): check:nul-bytes, check:cross-package-test-inputs, check:test-source-alias and the lint typecheck re-run, each exit 0; the rest left to CI on that head.",
      "dogfood_battery": "52faf73c, after a full turbo build 119/119 · VERDICT command-exit 1 · Test Files 418/422 (3 skipped, 1 failed) · Tests 3491 passed, 36 skipped, 1 failed · the only red is permission-set-clone-door.dogfood.test.ts (#30255, the member_default clone 422), the same as on bc376239, where a control leg with this PR's source reverted to origin/main was red the same way",
      "mcp_calls": "0 since report 6649735495",
      "api_writes": "1 since report 6649735495 — this comment via post-stamped. Plus 2 git pushes (not REST). The replacement PR body was written by the seat.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Report taken 2026-11-05T06:01Z.


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL

    Landed · 2026-11-05T06:48Z

    Reading Value
    PR #30276 merged 2026-11-05T06:47Z, merge commit cfb602c4, reviewed head 9b4bdc65 (seat ACCEPT 6651008330)
    Contract review CONTRACT_REVIEW_TIER, narrowing face: PASS 6649920800 (bc376239), delta PASS 6650921587 (52faf73c); 9b4bdc65 added one test only
    #30026 closed by Fixes #30026
    Release @objectstack/lint and @objectstack/mcp minor changeset, BREAKING with FROM → TO and ADR-0087 marker; ships with the next release

    State change: pm:dispatched removed. Follow-ups already filed from the first review: #30279, #30283.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions