fix(adt): reuse an object's existing open transport on write instead of 409-ing (#144) - #145
fix(adt): reuse an object's existing open transport on write instead of 409-ing (#144)#145zooloo303 wants to merge 2 commits into
Conversation
When the caller supplies no transport, fall back to the request the object is already bound to (LockResult.CorrNr) instead of binding the write to a new request and hitting 409 ExceptionResourceLockConflict. The fallback re-checks transportable-edit policy so it never bypasses --allow-transportable-edits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Good catch on the re-check — this closes a real gap in the original #144 fix (a transport only discovered after Lock could otherwise bypass On our fork (txape10/vibing-steampunk) we applied this same approach — re-validating the transportable-edit policy before adopting Not asking you to fold that in here — just flagging it as a related gap in case it's useful when this lands, since it's the same class of bug this PR fixes elsewhere. |
…isee#144) Applies the same resolveWriteTransport fallback to every remaining write path that locks an object and then binds the update to the caller's transport, so an object already captured in an open request is not rejected with a spurious 409 ExceptionResourceLockConflict: - writeClassMethodUpdate - CLAS method-level surgical update - writeSourceUpdate - INTF and DDLS/BDEF/SRVD branches - writeSourceUpdate - class testclasses include - UpdateFromFile - file-based deploy of an existing object Each site re-runs the transportable-edit policy on the resolved request via the shared helper, so auto-reuse still cannot bypass --allow-transportable-edits or the --allowed-transports whitelist. The writeSourceCreate paths are deliberately left alone: a newly created object is not yet captured in a request, so LockResult.CorrNr is empty and the fallback would be a no-op. Reported-by: @txape10 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks — and good confirmation that the re-check is worth keeping; that was the part I You're right about
All of them go through the same Two notes on where I drew the line:
Being straight about verification: the commit-1 paths are live-verified against an on-prem |
Summary
Fixes #144. When editing an object that is already captured in an open transport
request of the current user, vsp binds the write to a new request, and SAP
rejects it with:
ADT / Eclipse reuse the lock's existing request automatically. This does the same:
when the caller supplies no
transport, fall back to the request SAP already returnson the LOCK response as
LockResult.CorrNr.Change
New helper
resolveWriteTransport(supplied, lockCorrNr, opName)(
pkg/adt/transport_reuse.go), wired in right after the lock in every update paththat locks an object and then binds the write to the caller's transport:
Commit 1
WriteProgram,WriteClass(pkg/adt/workflows.go)EditSourceWithOptions(pkg/adt/workflows_edit.go)Commit 2 — the remaining paths, so the fix is comprehensive rather than partial:
writeClassMethodUpdate— CLAS method-level surgical update (pkg/adt/workflows_source.go)writeSourceUpdate— INTF and DDLS/BDEF/SRVD brancheswriteSourceUpdate— classtestclassesincludeUpdateFromFile— file-based deploy of an existing object (pkg/adt/workflows_deploy.go)The
writeSourceCreatepaths are deliberately left alone: a newly created object isnot yet captured in a request, so
LockResult.CorrNris empty and the fallback wouldbe a no-op.
Safety
The fallback re-runs
checkTransportableEditon the resolved request at every callsite, so auto-reuse cannot bypass
--allow-transportable-editsor the--allowed-transportswhitelist. An explicitly-supplied transport is used unchanged(already gated at the top-level mutation gate). A local object (no open request) is
unchanged (empty transport).
Tests
TestResolveWriteTransportcovers explicit-wins, local/no-op, fallback-when-allowed,and the safety-critical case where the fallback is blocked because transportable
edits are disabled.
go build ./...,go vet ./pkg/adt/andgo test ./...are green.Verified live against an on-prem system for the commit-1 paths: editing an object
already bound to an open request now succeeds without the caller supplying the
transport (previously a 409), and the object is left clean afterwards. The commit-2
sites are one-line call-site wirings of the same already-tested helper and have not
been separately exercised live — happy to do that on any of them if you'd like it
before this lands.
Scope
Now covers all update paths. Deletes are not included:
DeleteObjectdoesn't lock(it receives a
lockHandlefrom its callers), so the same reuse would have to land ateach locking caller — a separate change from the write paths, and out of scope here.
Note: this touches the same write paths as #125 / #108; it composes cleanly with them
(verified by stacking all three locally and exercising the combined path live).
Thanks to @txape10 for independently confirming the re-check approach on their fork and
flagging
writeClassMethodUpdate— commit 2 closes that gap and the rest of the class.