fix(ttx): merge appendPayload instead of overwriting TokenRequest/Transient#1914
Merged
Conversation
13f83f8 to
9697d0c
Compare
adecaro
added a commit
that referenced
this pull request
Jul 15, 2026
…velopment Following the appendPayload fix workflow (issue #1913 -> PR #1914), document the exact metadata expected on issues and PRs so future contributors/agents don't have to rediscover it: assignee, labels, milestone, the Panurus project, and — for issues only — the Issue Type field, which has no gh CLI flag and requires a GraphQL mutation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
9697d0c to
62d8dbf
Compare
adecaro
added a commit
that referenced
this pull request
Jul 15, 2026
…velopment Following the appendPayload fix workflow (issue #1913 -> PR #1914), document the exact metadata expected on issues and PRs so future contributors/agents don't have to rediscover it: assignee, labels, milestone, the Panurus project, and — for issues only — the Issue Type field, which has no gh CLI flag and requires a GraphQL mutation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
62d8dbf to
ae1d9aa
Compare
KElkhiyaoui
approved these changes
Jul 15, 2026
mergeTransient previously let the existing value silently win when a key was present on both sides. Detect divergence instead and fail the merge, since a differing value for the same key indicates a protocol inconsistency rather than a benign duplicate. Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
ff078ed to
9d13be4
Compare
AkramBitar
requested changes
Jul 15, 2026
AkramBitar
left a comment
Contributor
There was a problem hiding this comment.
LGTM.
I added to comments. Please have a look.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #1913.
Transaction.appendPayload(token/services/ttx/transaction.go) previously mergeda received
Payloadinto the current transaction by wholesale overwrite:This is the single call site used by
collectRemote(collectactions.go), invokedonce per action when
CollectActionsViewcollects a transfer action from a remotecounterparty.
Problem
TokenRequestoverwrite: replaced the entire token request instead of mergingin only new content. Safe today only because the collect-actions responder
happens to round-trip the initiator's full transaction state before replying — an
unchecked assumption. A protocol change, a partial/stale responder reply, or
multiple concurrent/interleaved remote actions could silently drop previously
collected actions with no error.
Transientoverwrite: unconditionally replaced the initiator's transient mapwith the (typically near-empty) remote one, silently discarding any transient data
set locally. Currently latent (no in-tree writer populates
Transaction.Transientyet) but a real bug waiting for its first caller.
payload.Request.Issues,TokenInfos,ValidationRecords, andt.Set(...)— none of which exist on thecurrent
Payload/token.Requestmodel. It predates a request-type refactor andcould not be reinstated as-is.
appendPayload, or for collecting more than one action.Fix
Replaced the overwrite with an explicit, checked merge:
TokenRequest: if the transaction has no actions yet, adopt the incomingrequest unconditionally (today's normal first-write path, unchanged behavior).
Otherwise, verify the incoming request's actions are a superset-extension of the
existing ones (same type + raw bytes, same order, for every existing action) before
adopting it. A violation now returns an explicit error instead of silently
corrupting/losing state.
Transient: entries from the incoming payload are merged in only for keys notalready present locally — existing values win, so nothing set on the initiator can
be clobbered by a remote round-trip.
transaction_internal_test.go) covering: first-writeadoption, superset-extension success, shorter/divergent-prefix violations (both
error), transient existing-wins merge, transient merge into a nil map, and a
combined
appendPayloadmerge.docs/services/ttx.md's Collect Actions Flowsection.
No behavior change for existing single-action integration call sites
(
integration/token/dvp,integration/token/fungibleswap) — they only everexercise the first-write path.
Test plan
go test ./token/services/ttx/...— new unit tests passmake unit-tests-race— no races, ttx package greenmake checks— license/fmt/vet/staticcheck cleanmake lint-auto-fix— 0 issues🤖 Generated with Claude Code