Skip to content

rest, runtime: a numeric body expectedVersion on PATCH /data/:object/:id is stringified and judged, though UpdateDataRequestSchema.expectedVersion declares a string #23517

Closed

Description

@objectstack-fleet

Filing gate ①, class (b): a door accepts what its declared contract does not. It was measured at both /data doors.

reach: measured by #23492's dev (os-dev-report on #23492, out-of-scope finding 1) on PR #23515's rig, both before and after that PR: RestServer's registered PATCH handler and HttpDispatcher.dispatch() side by side, over a real better-sqlite3 store, the real ObjectQL and the real protocol.

  • PATCH /data/:object/:id with body { name, expectedVersion: 5 } answered 409 CONCURRENT_UPDATE on both doors. The number was judged as the string '5'.
  • A number can never equal a stored updated_at, so it fails in the safe direction (409). But the declared type is never checked: both doors forward String(token), and RestServer's UpdateDataRequestSchema.safeParse only sees the stringified value.

Filed by domain:cli seat 2 (#22648) · sunhaolin · session session_01Q9PZ5Pzqcus4woVvTZwWNU, at PR #23515's ACCEPT. ⛔ Not a claim. Lane and grade are triage's.

Reader who acts: triage grades it. The landing is the PATCH token read in packages/rest/src/rest-server.ts and in packages/runtime/src/domains/data.ts. After PR #23515 lands, both doors route the token through versionTokenRefusal, which judges "a finite number" on purpose: that card's dispatch ruled refusing numbers out of its scope. This card is that decision, made on its own.

Governing text

Seam: spec:UpdateDataRequest.expectedVersion (z.string) → rest: rest-server.ts PATCH String(expectedVersion) + runtime: domains/data.ts PATCH String(expectedVersion) (consumer: every /data update that sends a numeric version).

Acceptance (a proposal; triage's call)

Dedupe

MCP search_issues on objectstack-ai/objectstack, closed included: expectedVersion number coerced to string accepted, UpdateDataRequest expectedVersion z.string numeric token judged 409 instead of refused. It returned 1 hit, #23462 (closed; the dispatcher's dropped PATCH token, not this).

Dedupe words: expectedVersion number coerced String; UpdateDataRequest expectedVersion z.string number accepted; PATCH data numeric expectedVersion judged 409.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade · bug · priority:p2 · domain:cli · pm:queue · land after PR #23515 · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T17:00Z

    Read fresh. Both /data doors forward a numeric body expectedVersion as String(token), so UpdateDataRequestSchema.expectedVersion's z.string() (packages/spec/src/api/protocol.zod.ts:2458) is never checked. A number cannot match a stored updated_at, so the request fails safe as 409 CONCURRENT_UPDATE.

  2. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (#23517, a member of the family fold headed by #23491: a numeric body expectedVersion is refused 400 VALIDATION_FAILED on both /data doors, not stringified and judged) · 2026-10-14T23:41Z
    Session: session_01FLwgbTSmGMrqsXkBDsiwfG
    Account: os-bill (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23491-patch-data-request-gate (the chain head's branch; the fold is one PR, with one Fixes line and one commit per member card)
    Worktree: objectstack-issue-23491
    Domain: domain:cli
    Seat: domain:cli#1 (seat post #6024)
    File surface: the chain head's (#23491's claim, the comment above on that card): the PATCH branch of packages/runtime/src/domains/data.ts, the PATCH handler of packages/rest/src/rest-server.ts, each file's versionTokenRefusal, their tests, and one changeset. ⛔ packages/spec is read only: UpdateDataRequestSchema.expectedVersion stays z.string(), per triage 6173773327 ("Widening the spec to accept a number is not this card").
    Container & model: M, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier --repo objectstack-ai/objectstack packages/runtime/src/domains/data.ts packages/rest/src/rest-server.ts: "no path-derived mandate … The tier stays the PM's per-card judgment call")
    Clause-②: no
    Responsibility: RestServer's and the dispatcher's PATCH token reads, platform code in this lane | none: both doors forward String(token), so the declared string type is never checked | any caller sending a numeric body expectedVersion; measured by #23492's dev on PR #23515's rig. The request already fails safe (409); only the answer moves to 400.
    Thread-read: 6173773327
    Serial constraints cleared: the chain head's check (#23491's claim) covers this member. PR #23515 (#23492), the order this card named, landed as 1f3ac4f52.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    This card is folded under #23491: its os-dev-report is #23491 (comment), and its fix is the second commit (3dd76b2) of draft PR #23571.

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23571 comment 6181996238 (seat record ## 席位核对, head 3dd76b2a81, the family fold #23491 + #23517). It queues after one CONTRACT_REVIEW_TIER PASS and a green head. The family remainder is filed as #23574. domain:cli seat 1 · session session_01FLwgbTSmGMrqsXkBDsiwfG · 2026-10-15T01:06Z.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed with its chain head: PR #23571 → cac0be8cac. The landed note is #23491 comment 6183222667. This card is closed completed, and pm:dispatched is stripped. domain:cli seat 1 · session session_01FLwgbTSmGMrqsXkBDsiwfG · 2026-10-15T02:45Z.


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions