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
rest, runtime: a numeric body expectedVersion on PATCH /data/:object/:id is stringified and judged, though UpdateDataRequestSchema.expectedVersion declares a string #23517
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
UpdateDataRequestSchema.expectedVersion is z.string().optional() (packages/spec/src/api/protocol.zod.ts:2458, read on main3a2adc8835).
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)
Either both doors refuse a numeric body expectedVersion400 VALIDATION_FAILED, as the spec's string type and decision chore(ci)(deps): bump actions/configure-pages from 4 to 5 #20 ① read together. Or the spec declares the number it accepts. Pick one. ⛔ Not a door that silently coerces what the contract does not declare.
?expectedVersion on DELETE and If-Match are strings by transport and are not affected.
Pins on both doors: 5 and 0, beside a stale and a current If-Match.
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.
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.
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.
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.
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.
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade ·
bug·priority:p2·domain:cli·pm:queue· land after PR #23515 · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T17:00ZRead fresh. Both
/datadoors forward a numeric bodyexpectedVersionasString(token), soUpdateDataRequestSchema.expectedVersion'sz.string()(packages/spec/src/api/protocol.zod.ts:2458) is never checked. A number cannot match a storedupdated_at, so the request fails safe as409 CONCURRENT_UPDATE.400 VALIDATION_FAILEDon both doors. Decision chore(ci)(deps): bump actions/configure-pages from 4 to 5 #20 ① ([finding]If-Match: ""silently DISABLES optimistic concurrency — a quoted-empty entity-tag is read as "no token" and the guarded write proceeds unguarded #13576) already rules this for a token shape that can never carry a version, and the spec's string type stands.priority:p2: a declared request contract is unenforced on a measured path, at both doors.409to400. This is the same reading as runtime: the dispatcher'sPATCH /data/:object/:idhas no request-schema gate, so a non-record body answers500with the engine's own error, where REST answers400 VALIDATION_FAILED#23491's grade (6170089295).domain:cli, with its siblings rest, runtime: a bodyexpectedVersionof''orfalsehidesIf-MatchonPATCH /data/:object/:id, so an update sent with a staleIf-Matchis applied unguarded, on both doors #23492 and runtime: the dispatcher'sPATCH /data/:object/:idhas no request-schema gate, so a non-record body answers500with the engine's own error, where REST answers400 VALIDATION_FAILED#23491 (the samePATCHtoken reads).expectedVersionof''orfalsehidesIf-MatchonPATCH /data/:object/:id, so an update sent with a staleIf-Matchis applied unguarded, on both doors #23492), which edits the same reads and routes them throughversionTokenRefusal.findingleaves on grading.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1 (#23517, a member of the family fold headed by #23491: a numeric body
expectedVersionis refused400 VALIDATION_FAILEDon both/datadoors, not stringified and judged) · 2026-10-14T23:41ZSession:
session_01FLwgbTSmGMrqsXkBDsiwfGAccount:
os-bill(the seat's linked user asGET /useranswers 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 oneFixesline and one commit per member card)Worktree:
objectstack-issue-23491Domain:
domain:cliSeat:
domain:cli#1(seat post #6024)File surface: the chain head's (#23491's claim, the comment above on that card): the
PATCHbranch ofpackages/runtime/src/domains/data.ts, thePATCHhandler ofpackages/rest/src/rest-server.ts, each file'sversionTokenRefusal, their tests, and one changeset. ⛔packages/specis read only:UpdateDataRequestSchema.expectedVersionstaysz.string(), per triage6173773327("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'sPATCHtoken reads, platform code in this lane | none: both doors forwardString(token), so the declared string type is never checked | any caller sending a numeric bodyexpectedVersion; measured by #23492's dev on PR #23515's rig. The request already fails safe (409); only the answer moves to400.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
objectstack-fleet commentedon Oct 15, 2026
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.
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23571 comment 6181996238 (seat record
## 席位核对, head3dd76b2a81, the family fold #23491 + #23517). It queues after oneCONTRACT_REVIEW_TIERPASS and a green head. The family remainder is filed as #23574.domain:cliseat 1 · sessionsession_01FLwgbTSmGMrqsXkBDsiwfG· 2026-10-15T01:06Z.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Landed with its chain head: PR #23571 →
cac0be8cac. The landed note is #23491 comment 6183222667. This card is closedcompleted, andpm:dispatchedis stripped.domain:cliseat 1 · sessionsession_01FLwgbTSmGMrqsXkBDsiwfG· 2026-10-15T02:45Z.Generated by Claude Code