Skip to content

01a10c6e - Keep a reply gift separate from sats received on it - #407

Merged
TaprootFreak merged 2 commits into
developfrom
fix/01a10c6e-reply-received
Oct 7, 2026
Merged

TaprootFreak merged 2 commits into
developfrom
fix/01a10c6e-reply-received

Conversation

@TaprootFreakAI

Copy link
Copy Markdown
Collaborator

EN:
A reply keeps the gift sent with it in sats, and later payments on that reply land in receivedSats instead of being added to the same number.
Top-level notes are unchanged: sats stays the collected total, and the new keys are omitted.
On boot, indexed zap receipts are moved off a reply's sats once; spend invoices that never became a receipt stay where they are.
An older app still reads only sats, so it shows the sent gift again and does not show the received amount, and its pay sheet on an existing reply waits on sats until the app polls sinceReceivedSats.

DE:
Eine Antwort behält das mitgeschickte Geschenk in sats. Spätere Zahlungen auf diese Antwort landen in receivedSats und werden nicht mehr zur selben Zahl addiert.
Notizen auf oberster Ebene bleiben unverändert: sats ist weiter die Summe, die neuen Schlüssel fehlen.
Beim Start werden indexierte Zap-Belege einmal von sats einer Antwort abgezogen. Spend-Belege, die nie ein Zap-Receipt wurden, bleiben stehen.
Eine ältere App liest nur sats, zeigt also wieder das gesendete Geschenk und nicht den empfangenen Betrag. Ihr Zahlungsblatt auf einer bestehenden Antwort wartet auf sats, bis die App sinceReceivedSats abfragt.

Details

sats on a reply is the amount the author sent with that reply. receivedSats and receivedAmountUsd, receivedAmountChf, receivedAmountEur, and receivedAmountPhp are later zaps and spend proofs on that reply. Those credits do not change sats, the sent fiat columns, or goal_funded_at.

A zap receipt joined on message_id credits sats when parent_id is null, and received_sats when parent_id is set. A second proof of the same invoice still credits once. A proof on a reply still hides the platform marker and does not create a nested visible reply.

GET /messages/:id?sinceReceivedSats= accepts only a non-negative integer. On a live reply it long-polls until receivedSats is greater. A top-level note ignores the parameter. If both sinceSats and sinceReceivedSats are set, the poll waits until both have moved. A hidden moderator read still returns immediately.

The boot repair runs only where received_sats is null. It sets received_sats from the sum of nostr_zap_receipt on that reply and subtracts that sum from sats, floored at 0. Received fiat is filled, and subtracted from the sent fiat columns, only when every receipt has a non-null indexed ingest amount for that currency. It does not read message_invoice and it does not use deleted child rows. Replies with no receipt get received_sats 0. The repair does not run again after the column is not null.

The query window for ingest is unchanged.

A reply keeps the amount sent with it in sats. Later zaps and a
spend proof on that reply credit receivedSats and the received fiat
columns. Top-level notes stay on sats and omit the new JSON keys.
Boot moves indexed zap-receipt sums off reply sats once, and does
not read spend invoices.
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

dfx pr guard

EN: Thanks for your contribution! This repository follows A38. A38 pass: author local-CI report not required because the author has write on this repository.

DE: Danke für deinen Beitrag! In diesem Repository gilt A38. A38 pass: Autor-Local-CI-Report nicht erforderlich, weil der Autor Write auf diesem Repository hat.

Details

The handbook still said a zap on a reply credits sats and that the
long-poll only waits on sats.
@TaprootFreakAI

Copy link
Copy Markdown
Collaborator Author

EN:
Ready after 1 review passes.
A reply keeps the gift its author sent separate from sats that later arrived on that same reply.

DE:
Bereit nach 1 Review-Durchläufen.
Eine Antwort hält das Geschenk, das ihr Autor gesendet hat, getrennt von den Sats, die später auf derselben Antwort ankamen.

Details

Head: 934e1008c9f5211d827b54355685c587f7fea8b1
Runs: conformity-a with logic-a. The second run may be omitted.
Lane conformity-a:
Provider: grok
Model: grok-4.6
Model number: grok-4.6
Result: pass
Prompt:

Review the complete PR diff for conformity with CONTRIBUTING.md.

Lane logic-a:
Provider: grok
Model: grok-4.6
Model number: grok-4.6
Result: pass
Prompt:

Review the complete PR diff for logical correctness.

Final result: passes 1, defects 0.
Set aside: none.

{
  "schema": "a38-review/v2",
  "head": "934e1008c9f5211d827b54355685c587f7fea8b1",
  "passes": 1,
  "defects": 0,
  "set_aside": "none",
  "lanes": [
    {"id": "conformity-a", "result": "pass", "status": "complete", "provider": "grok", "model": "grok-4.6", "model_number": "grok-4.6", "prompt": "Review the complete PR diff for conformity with CONTRIBUTING.md."},
    {"id": "logic-a", "result": "pass", "status": "complete", "provider": "grok", "model": "grok-4.6", "model_number": "grok-4.6", "prompt": "Review the complete PR diff for logical correctness."}
  ]
}

One review pass. Conformity and logic both finished with no defects on this head. Checks on this head were already green, and GitHub reports the pull request mergeable.

@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

EN:
Required CI is green, the review completion is present, and no merge conflicts exist; this pull request is ready for review.

DE:
Die Required CI ist grün, der Review-Abschluss liegt vor und es gibt keine Merge-Konflikte; dieser Pull Request ist bereit zum Review.

Details
{
  "base": "316d4fb2b04008628458c62c8aacc91ed4fda47c",
  "head": "934e1008c9f5211d827b54355685c587f7fea8b1",
  "phase": "applied",
  "pr": 407,
  "reasons": [],
  "repo": "21gifts/api",
  "state": "ready"
}

@github-actions
github-actions Bot marked this pull request as ready for review October 5, 2026 22:10
@TaprootFreakAI

Copy link
Copy Markdown
Collaborator Author

EN:
The second review pass found one open point.
A very long sinceReceivedSats query is read as a number, and the wait then ends with the note instead of a rejection.

DE:
Der zweite Review-Durchlauf hat einen offenen Punkt gefunden.
Eine sehr lange sinceReceivedSats-Abfrage wird als Zahl gelesen, und das Warten endet danach mit der Notiz statt mit einer Ablehnung.

Details

Head: 934e1008c9f5211d827b54355685c587f7fea8b1

The first review pass stands: no defects. This second pass does not change that result and does not take the pull request back to draft.

One point remains for a human to decide. In src/routes/messages.ts, a sinceReceivedSats value that is only digits is converted with Number. A long enough digit string becomes an unsafe integer or Infinity. On a reply, the wait then stays open until the timeout and the route answers 200 with the note, instead of 400. The same conversion already exists for sinceSats. The suggested fix is to require a safe non-negative integer after the conversion, and otherwise return the same 400.

@TaprootFreak
TaprootFreak merged commit dc1ab2d into develop Oct 7, 2026
4 checks passed
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.

2 participants