Skip to content

Pre-1.0 Doorkeeper for SessionOutcome in#1747

Open
DanGould wants to merge 1 commit into
payjoin:masterfrom
DanGould:sessionoutcome-doorkeeper
Open

Pre-1.0 Doorkeeper for SessionOutcome in#1747
DanGould wants to merge 1 commit into
payjoin:masterfrom
DanGould:sessionoutcome-doorkeeper

Conversation

@DanGould

@DanGould DanGould commented Jul 16, 2026

Copy link
Copy Markdown
Member

150 lines of release hygiene that seals the persisted SessionOutcome format before 1.0 freezes it

  • drop a never-read witness payload
  • make the enum is non_exhaustive

so that after 1.0's db compatibility commitment we can add terminal outcomes (like the settlement classifier's in #1692) additively in 1.x instead of via a semver break plus a db migration. no behavior changes, and the cost is one more rc.

Pre-change:

  • The witness payload is dead data (no accessor, no ffi method, no history getter reads it)
  • SessionOutcome is currently exhaustive, unlike SessionEvent, so after 1.0 you can't add a terminal variant or retrofit #[non_exhaustive] without a breaking change

Co-authored by Claude Code

Pull Request Checklist

Please confirm the following before requesting review:

@coveralls

coveralls commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 29564057454

Coverage decreased (-0.03%) to 86.161%

Details

  • Coverage decreased (-0.03%) from the base build.
  • Patch coverage: 20 uncovered changes across 1 file (31 of 51 lines covered, 60.78%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
payjoin-cli/src/app/v2/mod.rs 20 0 0.0%
Total (3 files) 51 31 60.78%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
payjoin-cli/src/app/v2/mod.rs 1 57.39%

Coverage Stats

Coverage Status
Relevant Lines: 15984
Covered Lines: 13772
Line Coverage: 86.16%
Coverage Strength: 344.92 hits per line

💛 - Coveralls

@benalleng benalleng added this to the payjoin-1.0 milestone Jul 16, 2026

@spacebear21 spacebear21 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a nice path that leaves the door open for non-breaking 1.x Monitor fixes. However, there are 4 distinct components to this PR and I think each deserves standalone attention:

  1. ACK Reserve the SessionOutcome::Othervariant - this is the actually useful part, but the justification in the docstring and commit message argues for the wrong thing. "binaries pinned to this persisted format can still parse event logs written by a later minor release that does emit it" is a fine side-effect but forwards-compatibility is not the thing we actually care about (even the docs in persist.rs say "Forward compatibility in general is not appropriate"). Backwards compatibility is the goal. The reason to reserve Other isn't data compat at all, it's API semver: reserving the name now makes the classifier additive by construction. That argument doesn't appear in the PR.
  2. cACK Change SessionOutcome::Success to a unit variant. This one requires historical context: the original monitor (0c67af7) recorded an empty witness on the non-segwit path, the path where it actually would have mattered to store those as the only way to reconstruct the final payjoin transaction (see comment). #1218 then deleted that path entirely, so the stored event payload is indeed dead code now. However, #1692 would restore non-segwit detection, which would make this event payload undead once again. I think an argument can be made for only storing a Success(Txid) instead of the full script_sig/witnesses. This would also make this PR self-consistent: as written we record the txid of a transaction we don't recognize (Other(Txid)) and nothing for the payjoin we do.
  3. NACK Make SessionOutcome #[non_exhaustive]. This reverses 8c92050, which explicitly named SessionOutcome in the keep-exhaustive list, without engaging with that rationale, so I'm not sure whether this is intentional or an accidental omission/hallucination. The SessionOutcome::Other variant already grants exactly one named extension. I think any additional unforeseen outcomes should break at compile time instead of leading to unexpected behavior (e.g. as written any future unrecognized outcome would render as "Session closed" in payjoin-cli, with no compile error).
  4. NACK Add success() and aborted() constructors on SessionOutcome. I don't understand the rationale for this. This seems to simply accomodate a payjoin-cli implementation detail for history display? I'm not even sure that implementation is correct, currently it looks like the sender just hardcodes aborted() it to display "Session aborted" if a replay error occurred.

@DanGould
DanGould force-pushed the sessionoutcome-doorkeeper branch from b476aa0 to 506891d Compare July 17, 2026 06:42
The persisted SessionEvent format freezes at the payjoin-cli 1.0
database-backwards-compatibility commitment, so reshape the receiver's
terminal SessionOutcome while a format break is still free.

Change Success(Vec<(ScriptBuf, Witness)>) to Success(Txid). The
witness payload was recorded so the receiver could reconstruct the
final Payjoin on the non-segwit path, but payjoin#1218 removed that path
entirely, leaving the enum payload as dead code. The Receiver settlement
classifier (payjoin#1692) will restore non-segwit detection, which would make
the payload live again, but sufficient record of a settlement is the txid
of the transaction that settled it rather than the witness list. The
wallet that observed the spend already holds the full transaction.
Recording Success(Txid) also keeps the terminal variants consistent
where the outcome for the transaction we recognize carries the same
evidence as the one we do not.

Add Other(Txid), mapped to SessionStatus::Failed, for contested
outpoints settled by an unrecognized transaction. Nothing produces it
yet. The reason to reserve it now is API semver, not data
compatibility. 8c92050 deliberately kept SessionOutcome exhaustive.
A wildcard match arm has no meaningful semantics for a terminal outcome,
and the compile error on a new variant is a feature. So adding a
variant after 1.0 would be a semver-breaking change that we want. Naming
Other before the freeze makes the settlement classifier additive by
construction while keeping the enum exhaustive. (Forward
compatibility of the persisted data is explicitly not a goal. See the
persist module docs, we want unknown state to error.)

Update payjoin-cli to match the new shapes exhaustively. no wildcard
arms, per 8c92050 surfacing the settlement txid in the history and
cancel output, and pin the sealed JSON encodings of the terminal
events in a serialization-shape test. StatusText becomes String rather
than &'static str in order to accomodate the txid in format!.
@DanGould
DanGould force-pushed the sessionoutcome-doorkeeper branch from 506891d to 92dfe80 Compare July 17, 2026 07:44
@DanGould

DanGould commented Jul 17, 2026

Copy link
Copy Markdown
Member Author
  1. ACK Reserve the SessionOutcome::Other variant
  2. NACK Make SessionOutcome #[non_exhaustive]

Adopted. docstring & commit message now refer to semver compat & exhaustive rationale so that we don't regress.

  1. cACK Change SessionOutcome::Success to a unit variant.

Adopted as suggested including the #1218 reference AND the rationale for only Txid in the variant in the commit history. It keeps it simpler to let an underlying wallet handle saving the witnesses while our lib only stores the Txid as a link to that wallet state.

  1. NACK Add success() and aborted() constructors on SessionOutcome

Reverted as suggested, please ignore. payjoin-cli does seem limited here in that it presents Closed(Aborted) as a placeholder rather than saying the session state is unknown. Seems like the RowStatus should be an Option or an Enum to make known when session state is really unknown in the display.


Just one commit now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants