Skip to content

fix(tempo): commit http charges after session settlement - #865

Open
jxom wants to merge 3 commits into
mainfrom
jxom/session-settlement-accounting
Open

jxom wants to merge 3 commits into
mainfrom
jxom/session-settlement-accounting

Conversation

@jxom

@jxom jxom commented Sep 4, 2026

Copy link
Copy Markdown
Member

Commit HTTP session charges after scheduled settlement succeeds, preserving atomic balance checks during concurrent requests. Failed settlement returns 402 without consuming the request charge. Update the close-failure fixture for expiring nonces.

@pkg-pr-new

pkg-pr-new Bot commented Sep 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/mppx@865

commit: 61b4002

@jxom
jxom marked this pull request as ready for review September 4, 2026 05:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T06:14:34.858140Z 61b4002 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3bd9e8ae3b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

)
// Settlement failures must not consume a content charge.
settlementTxHash =
(await parameters.settleCharged(projected).catch((cause) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Serialize settlement before retrying the atomic charge

When concurrent HTTP requests for the same channel both preview a due settlement, they can both execute settleCharged before either charge is committed. The request that loses the subsequent counter comparison loops and invokes this side effect again; with a { units: 1 } schedule, two requests can therefore submit three settlement transactions and fire the settlement callback three times, while a nonce collision may instead reject one request with 402. Reserve or serialize the settlement attempt per channel so a failed charge CAS does not repeat an already-started on-chain operation.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 61b4002fb5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +477 to +482
const refreshed = await store.updateChannel(channel.channelId, (current) =>
current
? {
...current,
settledOnChain: ChannelStore.keepGreater(current.settledOnChain, state.settled),
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record the schedule boundary when reconciling settlement

When a broadcast response is lost but the transaction confirms, the next attempt updates only settledOnChain and returns at the subsequent isSettlementDue check without recording lastSettlementAt, lastSettlementSpent, or lastSettlementUnits. Once a later voucher creates unsettled value, unit and interval schedules therefore count from channel creation, while amount schedules fall back to subtracting the cumulative on-chain settlement from HTTP spend; this can trigger the next settlement immediately or calculate negative progress. Record the current spend/unit/time boundary whenever this readback discovers that the abandoned attempt advanced the on-chain settled amount.

Useful? React with 👍 / 👎.

Comment on lines +458 to +460
const reserved = await store.updateChannel(channel.channelId, (current) => {
if (!current || (current.settlementAttempt?.validBefore ?? 0) > now) return current
return { ...current, settlementAttempt: { id, validBefore } }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid rewriting the channel while waiting for settlement

When concurrent requests find another unexpired settlementAttempt, this callback returns current, but ChannelStore.fromStore().updateChannel interprets every non-null return as a set, so each waiter rewrites the full channel record and notifies listeners every 100 ms until the settlement finishes. A burst of requests during a slow settlement can therefore generate thousands of unnecessary database writes and repeatedly wake SSE waiters. Acquire the reservation through a true no-op-capable atomic operation, or wait for an update/expiry without calling updateChannel on every poll.

Useful? React with 👍 / 👎.

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.

1 participant