Found during adversarial review of #3.
The graph-style resumable protocol handler (adapters/microsoft-graph-style/scripts/drive_upload.star, on_upload_chunk) does get session -> validate start == next -> read partial blob -> concat -> put blob -> update session. The collection store serializes individual statements (SetMaxOpenConns(1)) but not this read-modify-write sequence, and the engine intentionally runs concurrent requests through the adapter VM in parallel (internal/starlark/vm.go, note C1). Two chunk PUTs racing on the same session (e.g. a timeout retry firing alongside the original) can both read the same stale next offset, both pass validation, and the last write wins: a corrupted assembled blob or a silently duplicated chunk where the protocol should return 416.
Fix options: a per-session mutex in the Go runtime keyed by service+session id, or a compare-and-swap primitive exposed to Starlark. Either way, add a test that fires two chunks concurrently to pin the behavior.
Low urgency: clients that upload sequentially (which real Graph requires anyway) never hit it.
Found during adversarial review of #3.
The graph-style resumable protocol handler (adapters/microsoft-graph-style/scripts/drive_upload.star, on_upload_chunk) does get session -> validate start == next -> read partial blob -> concat -> put blob -> update session. The collection store serializes individual statements (SetMaxOpenConns(1)) but not this read-modify-write sequence, and the engine intentionally runs concurrent requests through the adapter VM in parallel (internal/starlark/vm.go, note C1). Two chunk PUTs racing on the same session (e.g. a timeout retry firing alongside the original) can both read the same stale next offset, both pass validation, and the last write wins: a corrupted assembled blob or a silently duplicated chunk where the protocol should return 416.
Fix options: a per-session mutex in the Go runtime keyed by service+session id, or a compare-and-swap primitive exposed to Starlark. Either way, add a test that fires two chunks concurrently to pin the behavior.
Low urgency: clients that upload sequentially (which real Graph requires anyway) never hit it.