Rebase fork onto upstream v1.6.8 (waves / on-chain / approval reconciliation) #33

Closed
opened 2026-06-20 09:51:44 +00:00 by padreug · 3 comments
Owner

Tracking issue for the eventual rebase of this fork (based on upstream v1.6.1) onto upstream v1.6.8 — 7 releases ahead. Assessment done 2026-06-20.

Verdict

Well-positioned, not a fast-forward. The migration layer is clean by design; the work is a bounded manual merge of the purchase flow plus a one-time "adopt ticket waves" adaptation. Budget ~1 focused session.

Clean — carries over with zero/near-zero conflict

  • migrations.py is byte-identical to both v1.6.1 and v1.6.8 → migration rebase is a no-op. (Keep this invariant.)
  • No column collisions. Upstream's v1.6.8 features (ticket waves, on-chain/SatsPay, ticket images) serialize into existing extra JSON — no new DB columns. Our migrations_fork.py real columns (status, location, categories, nostr_event_id, nostr_event_created_at, payment_hash, user_id) are a separate namespace.
  • Net-new fork files (zero conflict): all nostr_*.py, transport_rpcs.py, nostr_sync.py, migrations_fork.py, tests.
  • set_ticket_paid survives in v1.6.8 (same name/signature) and is already wave-aware — our per-event lock + publish_or_delete_nostr_event() graft re-applies cleanly; tasks.py and the free-ticket path keep working.

Overlap — manual reconciliation (8 files; effort in 2)

File upstream Δ fork Δ note
views_api.py +440 +533 the hard one — both rewrote api_ticket_create
models.py +126 +101 mostly additive fields
services.py +291 +39 small graft re-applies
crud.py +45 +183 mostly additive queries
__init__.py +3 +77 small
static/js/{index,display}.* large medium take upstream wholesale, re-apply minimal fork bits

Semantic adaptations to plan

  1. Pricing moved into ticket waves. v1.6.8 reads selected_wave.price_per_ticket / .allow_fiat / .currency; our fork reads event.price_per_ticket (top-level fields still exist). Mechanical remap, but every pricing read in our additions (fiat, multi-ticket, free tickets) must thread through wave selection. Free tickets resolve to a wave or use the event-level fallback set_ticket_paid already supports.
  2. Approval workflow is fork-only. v1.6.8 has no status/proposed/approve. Re-insert our events.status + api_event_approve + the api_ticket_create gate by hand into upstream's rewritten file.
  3. On-chain/SatsPay is new upstream surface — decide whether to adopt; if yes, make our fiat/free/Nostr additions coexist with it.

Recommendations

  • Keep the fork-migrations discipline — it's why this is tractable.
  • The views_api.py gap only widens with each upstream release; rebase sooner if we want waves/on-chain, else cherry-pick specific upstream fixes.
  • #31 (free tickets) adds slightly to the gap but remaps trivially — not a reason to hold it.
Tracking issue for the eventual rebase of this fork (based on upstream **v1.6.1**) onto upstream **v1.6.8** — 7 releases ahead. Assessment done 2026-06-20. ## Verdict Well-positioned, **not** a fast-forward. The migration layer is clean by design; the work is a bounded manual merge of the purchase flow plus a one-time "adopt ticket waves" adaptation. Budget ~1 focused session. ## Clean — carries over with zero/near-zero conflict - `migrations.py` is **byte-identical** to both v1.6.1 and v1.6.8 → migration rebase is a no-op. (Keep this invariant.) - **No column collisions.** Upstream's v1.6.8 features (ticket **waves**, **on-chain/SatsPay**, ticket images) serialize into existing `extra` JSON — no new DB columns. Our `migrations_fork.py` real columns (`status`, `location`, `categories`, `nostr_event_id`, `nostr_event_created_at`, `payment_hash`, `user_id`) are a separate namespace. - Net-new fork files (zero conflict): all `nostr_*.py`, `transport_rpcs.py`, `nostr_sync.py`, `migrations_fork.py`, tests. - `set_ticket_paid` **survives** in v1.6.8 (same name/signature) and is already wave-aware — our per-event lock + `publish_or_delete_nostr_event()` graft re-applies cleanly; `tasks.py` and the free-ticket path keep working. ## Overlap — manual reconciliation (8 files; effort in 2) | File | upstream Δ | fork Δ | note | |---|---|---|---| | `views_api.py` | +440 | +533 | **the hard one** — both rewrote `api_ticket_create` | | `models.py` | +126 | +101 | mostly additive fields | | `services.py` | +291 | +39 | small graft re-applies | | `crud.py` | +45 | +183 | mostly additive queries | | `__init__.py` | +3 | +77 | small | | `static/js/{index,display}.*` | large | medium | take upstream wholesale, re-apply minimal fork bits | ## Semantic adaptations to plan 1. **Pricing moved into ticket waves.** v1.6.8 reads `selected_wave.price_per_ticket / .allow_fiat / .currency`; our fork reads `event.price_per_ticket` (top-level fields still exist). Mechanical remap, but every pricing read in our additions (fiat, multi-ticket, **free tickets**) must thread through wave selection. Free tickets resolve to a wave or use the event-level fallback `set_ticket_paid` already supports. 2. **Approval workflow is fork-only.** v1.6.8 has no `status`/`proposed`/`approve`. Re-insert our `events.status` + `api_event_approve` + the `api_ticket_create` gate by hand into upstream's rewritten file. 3. **On-chain/SatsPay is new upstream surface** — decide whether to adopt; if yes, make our fiat/free/Nostr additions coexist with it. ## Recommendations - Keep the fork-migrations discipline — it's why this is tractable. - The `views_api.py` gap only widens with each upstream release; rebase sooner if we want waves/on-chain, else cherry-pick specific upstream fixes. - #31 (free tickets) adds slightly to the gap but remaps trivially — not a reason to hold it.
Author
Owner

Upstream re-check on 2026-09-06 while planning guest checkout (#36), for whoever runs this rebase:

  • Upstream main is still v1.6.8; the big mover is the open PR #64 "v2.0.0" (+4204/−2203, last push 2026-08-30): basket checkout (/events/basket/{id}, one buyer email + optional name per basket, batched email per buyer, admin sale email, bulk resend), ticket types, per-event extra.payment_methods with per-method wallet selection, ticket deactivation, new migrations.py columns (payment_method, fiat_provider on tickets), and tasks.py removed (listener moved). Not merged; reassess after it lands rather than rebasing onto v1.6.8 then again onto v2.
  • #36 already ports pieces of v1.6.8 in upstream's shape so they should merge cleanly: make_qr_png + GET /api/v1/qr/{ticket_id} (without ticket-image compositing), the multipart text+HTML mailer (_deliver_ticket_notifications, NotificationDeliveryResult, TicketResendResult), and extra.payment_methods using v2's field name (effective_payment_methods helper; empty list = legacy rule).
  • Deliberate deviations to keep: the QR image URL is built from settings.lnbits_baseurl, not ticket_base_url (ours may point at the webapp); the nsec-DM Nostr path stays (upstream went NIP-05-only); _issue_free_tickets, frontend_url + origin allow-list, pre-generated ticket ids and extra["checkout"] are fork-only and listed in docs/upstream-candidates.md.
  • On-chain: upstream is SatsPay/watchonly (onchain_enabled/onchain_wallet_id/zeroconf/fasttrack); we will use native lnbits on-chain instead (separate issue), so drop those fields during the merge.
Upstream re-check on 2026-09-06 while planning guest checkout (#36), for whoever runs this rebase: - Upstream `main` is still v1.6.8; the big mover is the open **PR #64 "v2.0.0"** (+4204/−2203, last push 2026-08-30): basket checkout (`/events/basket/{id}`, one buyer email + optional name per basket, batched email per buyer, admin sale email, bulk resend), ticket types, **per-event `extra.payment_methods`** with per-method wallet selection, ticket deactivation, new `migrations.py` columns (`payment_method`, `fiat_provider` on tickets), and `tasks.py` removed (listener moved). Not merged; reassess after it lands rather than rebasing onto v1.6.8 then again onto v2. - #36 already ports pieces of v1.6.8 in upstream's shape so they should merge cleanly: `make_qr_png` + `GET /api/v1/qr/{ticket_id}` (without ticket-image compositing), the multipart text+HTML mailer (`_deliver_ticket_notifications`, `NotificationDeliveryResult`, `TicketResendResult`), and `extra.payment_methods` using v2's field name (`effective_payment_methods` helper; empty list = legacy rule). - Deliberate deviations to keep: the QR image URL is built from `settings.lnbits_baseurl`, not `ticket_base_url` (ours may point at the webapp); the nsec-DM Nostr path stays (upstream went NIP-05-only); `_issue_free_tickets`, `frontend_url` + origin allow-list, pre-generated ticket ids and `extra["checkout"]` are fork-only and listed in `docs/upstream-candidates.md`. - On-chain: upstream is SatsPay/watchonly (`onchain_enabled/onchain_wallet_id/zeroconf/fasttrack`); we will use native lnbits on-chain instead (separate issue), so drop those fields during the merge.
Author
Owner

Two notes for when this runs

1. Don't adopt upstream's SatsPay on-chain path. The assessment lists "On-chain/SatsPay is new upstream surface — decide whether to adopt" as an open question. Decided: we don't want SatsPay. On-chain goes through native lnbits on-chain instead — that's #41. So at rebase time, take upstream's on-chain surface as skipped, not merged, and keep the divergence noted in docs/upstream-candidates.md.

2. #34 should land after this, not before. #34 (the amount_tickets conflation) lives in api_ticket_create and the publisher — the same hunk this rebase rewrites, and the one the assessment calls "the hard one". Fixing it first means writing it twice and taking the conflict in code we'd just touched. The upstream review on #34 also shows waves change the shape of the fix: amount_tickets becomes a per-wave value rolled up by sum(wave.amount_tickets for wave in ticket_waves), so the capacity column proposed there should be re-decided against the wave model rather than designed against v1.6.1.

What does not need to wait: #51 and #35, both of which live in nostr_*.py and migrations_fork.py — the files this assessment lists as net-new fork surface with zero conflict. Worth doing #51 before the rebase specifically, since a rebase is exactly the kind of change that could break signer or publisher wiring silently, and right now that failure mode leaves no log line at all.

## Two notes for when this runs **1. Don't adopt upstream's SatsPay on-chain path.** The assessment lists "On-chain/SatsPay is new upstream surface — decide whether to adopt" as an open question. Decided: we don't want SatsPay. On-chain goes through native lnbits on-chain instead — that's #41. So at rebase time, take upstream's on-chain surface as *skipped*, not merged, and keep the divergence noted in `docs/upstream-candidates.md`. **2. #34 should land after this, not before.** #34 (the `amount_tickets` conflation) lives in `api_ticket_create` and the publisher — the same hunk this rebase rewrites, and the one the assessment calls "the hard one". Fixing it first means writing it twice and taking the conflict in code we'd just touched. The upstream review on #34 also shows waves change the shape of the fix: `amount_tickets` becomes a per-wave value rolled up by `sum(wave.amount_tickets for wave in ticket_waves)`, so the `capacity` column proposed there should be re-decided against the wave model rather than designed against v1.6.1. What does *not* need to wait: #51 and #35, both of which live in `nostr_*.py` and `migrations_fork.py` — the files this assessment lists as net-new fork surface with zero conflict. Worth doing #51 before the rebase specifically, since a rebase is exactly the kind of change that could break signer or publisher wiring silently, and right now that failure mode leaves no log line at all.
Author
Owner

Re-measured 2026-09-27 — supersedes the June assessment

The June numbers are three months stale (promo codes, guest checkout, free tickets, the whole nostr publish chain and #59 have landed since). Re-ran the analysis against current main and upstream/main.

Merge base is still 4bf867e = v1.6.1. Divergence: 8 commits upstream, 68 on the fork. Upstream squashes PRs, so "7 releases ahead" is a much smaller delta than it sounds.

The invariant holds

migrations.py: IDENTICAL to upstream — migration rebase is a no-op

Worth re-checking at merge time, but as of now the fork-migrations discipline has paid off exactly as intended.

Upstream's 8 commits are three separable features

commits what
A 777c107 8c1538f 35c20ed ticket waves, ticket image, UI fixes — the reason we're doing this
B e0ea0e3 da16b20 99b43ff f745370 on-chain via SatsPay — skip, see #41
C 891eaf1 extension translations (i18n)

f745370 belongs to B, which June couldn't have known — it's titled "fix: issue when calling internal webhook from extern" but touches nothing except the satspay-webhook URL. It's also what v1.6.8 points at.

Skipping SatsPay nearly halves the hard file

views_api.py   upstream total  +402/-38
                 of which B     +194/-4     <- dropped
                 leaving       ~+208/-34
services.py      of which B      +54/-0     <- dropped
models.py        of which B       +9/-0     <- dropped

Current conflict surface — 10 files

                        upstream        fork
views_api.py           +402/-38      +776/-56     <- hardest
static/js/index.js    +576/-108      +381/-9
static/js/index.vue   +577/-180      +345/-49
services.py            +232/-59      +298/-48
models.py              +125/-1       +221/-27
crud.py                 +41/-4       +187/-14
static/js/display.js    +97/-18       +22/-3
static/js/display.vue   +78/-42       +33/-10
__init__.py              +2/-1       +132/-3
config.json              +2/-2         +7/-2

Plus 9 upstream-only files to take wholesale (i18n, register/ticket JS, routes.json, ticket.jpg) and 30 fork-only files with zero conflict — every nostr_*, transport_rpcs.py, promo.py, qr.py, migrations_fork.py, all tests, fonts, docs.

Correcting one line of the June plan

static/js/{index,display}.* — take upstream wholesale, re-apply minimal fork bits

Not minimal. The fork put +381/+345 into index.js/index.vue, and it's a nameable feature set that has to survive: the approval workflow (status / proposed / approved / approveEvent / rejectEvent), promo-code management, fiat provider config, and location/categories. Budget this as the second hard file, not a footnote.

Take all of v1.6.8 as a single merge, then delete the SatsPay surface in its own follow-up commit. Rather than cherry-picking A and C while skipping B, because:

  • C sits on B's lines. The translation commit touches display.js/display.vue/index.js in regions B already modified. Cherry-picking around B means hand-resolving textual gaps that git would otherwise handle.
  • The removal becomes reviewable. An explicit "remove SatsPay on-chain surface" commit states the decision in the history; a cherry-pick gap is invisible six months later.
  • It makes the next rebase normal. Once our history contains upstream's, the following one is an ordinary merge instead of another archaeology exercise.

Target the v1.6.8 tag, not upstream/main. Main is one commit further (translations) with config.json already declaring 1.6.9 — an unreleased state. Taking the tag keeps our scheme honest: we become v1.6.8-aio.1. Translations can ride the next rebase, or be cherry-picked separately afterwards if wanted sooner.

Note the irony to document: v1.6.8 is f745370, a SatsPay commit. So "merge v1.6.8, then remove SatsPay" is precisely the shape of the work, and the no-SatsPay deviation wants a row in docs/upstream-candidates.md.

Suggested commit sequence

  1. merge upstream v1.6.8 — resolve the 10 files, nothing else
  2. remove SatsPay on-chain surface — explicit, with #41 referenced
  3. adapt pricing to ticket waves — thread wave selection through the fork's additions (fiat, multi-ticket, free tickets, promo pricing)
  4. re-apply approval workflow to the rewritten admin UI
  5. chore(release): v1.6.8-aio.1 — separately, after testing

Steps 3 and 4 are where the real thinking is. 1 and 2 are mechanical.

Prerequisite worth settling first

#34's remaining half (capacity always required, dropping 0 = unlimited, the organizer-form trap) was parked for this rebase because waves change the shape of it. It should be decided as part of step 3, not deferred again — under waves, amount_tickets becomes sum(wave.amount_tickets), so "capacity" stops being a single event-level number at all.

## Re-measured 2026-09-27 — supersedes the June assessment The June numbers are three months stale (promo codes, guest checkout, free tickets, the whole nostr publish chain and #59 have landed since). Re-ran the analysis against current `main` and `upstream/main`. Merge base is still `4bf867e` = **v1.6.1**. Divergence: **8 commits upstream, 68 on the fork.** Upstream squashes PRs, so "7 releases ahead" is a much smaller delta than it sounds. ### The invariant holds ``` migrations.py: IDENTICAL to upstream — migration rebase is a no-op ``` Worth re-checking at merge time, but as of now the fork-migrations discipline has paid off exactly as intended. ### Upstream's 8 commits are three separable features | | commits | what | |---|---|---| | **A** | `777c107` `8c1538f` `35c20ed` | ticket waves, ticket image, UI fixes — **the reason we're doing this** | | **B** | `e0ea0e3` `da16b20` `99b43ff` `f745370` | on-chain via SatsPay — **skip**, see #41 | | **C** | `891eaf1` | extension translations (i18n) | **`f745370` belongs to B, which June couldn't have known** — it's titled "fix: issue when calling internal webhook from extern" but touches nothing except the satspay-webhook URL. It's also what `v1.6.8` points at. ### Skipping SatsPay nearly halves the hard file ``` views_api.py upstream total +402/-38 of which B +194/-4 <- dropped leaving ~+208/-34 services.py of which B +54/-0 <- dropped models.py of which B +9/-0 <- dropped ``` ### Current conflict surface — 10 files ``` upstream fork views_api.py +402/-38 +776/-56 <- hardest static/js/index.js +576/-108 +381/-9 static/js/index.vue +577/-180 +345/-49 services.py +232/-59 +298/-48 models.py +125/-1 +221/-27 crud.py +41/-4 +187/-14 static/js/display.js +97/-18 +22/-3 static/js/display.vue +78/-42 +33/-10 __init__.py +2/-1 +132/-3 config.json +2/-2 +7/-2 ``` Plus **9 upstream-only files** to take wholesale (i18n, register/ticket JS, routes.json, ticket.jpg) and **30 fork-only files** with zero conflict — every `nostr_*`, `transport_rpcs.py`, `promo.py`, `qr.py`, `migrations_fork.py`, all tests, fonts, docs. ### Correcting one line of the June plan > `static/js/{index,display}.*` — take upstream wholesale, re-apply minimal fork bits Not minimal. The fork put **+381/+345** into `index.js`/`index.vue`, and it's a nameable feature set that has to survive: the approval workflow (`status` / `proposed` / `approved` / `approveEvent` / `rejectEvent`), promo-code management, fiat provider config, and location/categories. Budget this as the second hard file, not a footnote. ### Recommended strategy: merge, then remove — not cherry-pick Take **all** of `v1.6.8` as a single merge, then delete the SatsPay surface in its own follow-up commit. Rather than cherry-picking A and C while skipping B, because: - **C sits on B's lines.** The translation commit touches `display.js`/`display.vue`/`index.js` in regions B already modified. Cherry-picking around B means hand-resolving textual gaps that git would otherwise handle. - **The removal becomes reviewable.** An explicit "remove SatsPay on-chain surface" commit states the decision in the history; a cherry-pick gap is invisible six months later. - **It makes the *next* rebase normal.** Once our history contains upstream's, the following one is an ordinary merge instead of another archaeology exercise. Target the **`v1.6.8` tag**, not `upstream/main`. Main is one commit further (translations) with `config.json` already declaring `1.6.9` — an unreleased state. Taking the tag keeps our scheme honest: we become `v1.6.8-aio.1`. Translations can ride the next rebase, or be cherry-picked separately afterwards if wanted sooner. Note the irony to document: `v1.6.8` *is* `f745370`, a SatsPay commit. So "merge v1.6.8, then remove SatsPay" is precisely the shape of the work, and the no-SatsPay deviation wants a row in `docs/upstream-candidates.md`. ### Suggested commit sequence 1. `merge upstream v1.6.8` — resolve the 10 files, nothing else 2. `remove SatsPay on-chain surface` — explicit, with #41 referenced 3. `adapt pricing to ticket waves` — thread wave selection through the fork's additions (fiat, multi-ticket, free tickets, promo pricing) 4. `re-apply approval workflow to the rewritten admin UI` 5. `chore(release): v1.6.8-aio.1` — separately, after testing Steps 3 and 4 are where the real thinking is. 1 and 2 are mechanical. ### Prerequisite worth settling first #34's remaining half (capacity always required, dropping `0 = unlimited`, the organizer-form trap) was parked *for* this rebase because waves change the shape of it. It should be decided as part of step 3, not deferred again — under waves, `amount_tickets` becomes `sum(wave.amount_tickets)`, so "capacity" stops being a single event-level number at all.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/events#33
No description provided.