Skip to content

feat(premium): English wording of the monthly renewal offer (builds on #789) - #790

Merged
TheMorpheus407 merged 6 commits into
developfrom
fix/stage2-final-renewal-english
Oct 19, 2026
Merged

TheMorpheus407 merged 6 commits into
developfrom
fix/stage2-final-renewal-english

Conversation

@TheMorpheus407

@TheMorpheus407 TheMorpheus407 commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #789 (its commits are contained here, merged again at its head ecd4bf1); the change of this PR is the commit feat(premium): an English wording of the monthly renewal offer.

The final multi-model check of the stage-2 texts (legal/agb-fassung-2026-10-16/pruefung-final/BERICHT.md, objection 2) found that AGB 1.4 promises the details of the order dialog in English on the English interface, while the dialog of the monthly renewal showed its offer text only in German. The PO session decided to fix it in the system (ENTSCHEIDUNGEN.md).

  • PremiumRenewalOffer and both renewal-offer routes carry text_en: the same offer and declarations, sentence by sentence and line by line, with the same price, terms version and declaration version; the Daily wording too. The German text stays the binding one and is unchanged.
  • The offer id covers text_en as well, so a client that showed another English wording cannot confirm the offer. Offers open in a browser at the deploy get "the renewal offer has changed" once, as after any change of the offer.
  • The consent takes an optional language ("de" or "en", absent means German). A renewal confirmed in English is confirmed with the English offer and declarations as shown and ticked and the binding German wording next to it; this follows the Widerrufsbelehrung 2026-10 ("we confirm the declarations you actually made") and the same rule as the purchase declaration in fix(purchase): stage 2 after the final text check: state holidays, no stage-1 offer after the date, declaration language #789. German consents keep their confirmation.

The English wording is new text in the order dialog. It should go into the renewed check of the changed sentences together with the text package.

Visible change before the effective date

In the English interface the renewal dialog shows the English offer once the frontend PR is deployed; the confirmation of an English consent then carries both wordings. Nothing changes in German.

Tests

  • the_renewal_offer_has_an_english_wording_of_the_same_shape: same lines and paragraphs as the German text, price, terms version, both § 356 declarations, declaration version, Daily wording; the id differs from a hash without text_en.
  • a_renewal_ticked_in_english_is_confirmed_in_english_and_german: none and de give the German confirmation only, en gives the English one with the German wording.

Checks and counter-checks: see the comment below.

🤖 Generated with Claude Code

TheMorpheus407 and others added 6 commits October 19, 2026 05:15
…-start boundary

§ 193 BGB moves the end of the withdrawal period past the holidays at the customer's place,
which the platform does not know. The end was moved only past weekends and nationwide
holidays, so in states with their own holidays (Epiphany, Corpus Christi, All Saints' Day,
Reformation Day and others) a Premium period could begin within the legal period without the
checkbox. Every day that is a statutory holiday in any state, in the whole state or in a part
of it, now moves the end, so the computed end is never earlier than the legal one anywhere in
Germany and AGB 11.1 holds without exception (final multi-model check, objection 5, way b).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The mail and the notice say the new terms apply to every order from the effective date on.
An offer issued shortly before it stayed valid for its 20 minutes and kept AGB r4 even when
it was accepted after midnight. From the effective date on, the acceptance of such an offer
of the backend or PayPal is refused as changed (`offer_changed`), without a charge, and the
dialog replaces it with a new offer of stage 2 (the path of #838). Offers of the Daily cohort
and of other services are unaffected, as in `issue`.

The moment the order is received, the database clock that the confirmation names as "Bestellt
am", is now taken before the checks and decides both the expiry and the stage, so an order
confirmed at or after the effective date is never one of stage 1.

Final multi-model check, objections 4 and 6 (first part).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t was ticked in

The Widerrufsbelehrung 2026-10 says the wording actually used is stored with the order and
repeated in the contract confirmation. On the English interface the learner ticks the English
Premium declaration, but the confirmation repeated the German one.

The acceptance takes an optional `declaration_language` ("de" or "en"; absent means German).
For an offer of stage 2 with a declaration given in English, the confirmation, which is stored
with the order and its time of receipt, repeats the English declaration and gives the binding
German wording next to it (AGB 1.4). German, stage 1 and orders without a declaration keep
their confirmation.

The recorded submission leaves the field out, so it keeps the four fields that the
authorization of a retained-learning purchase compares exactly; no migration is needed.

Final multi-model check, objection 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGB 1.4 says the English interface shows the details of the order dialog in English, while
the German text stays binding. The dialog of the monthly renewal showed its offer text only in
German. The renewal offer now carries `text_en`, the same offer and declarations sentence by
sentence in English, with the same price, terms version and declaration version; the offer id
covers it, so a client that showed another wording cannot confirm the offer.

The consent takes an optional `language` ("de" or "en"; absent means German). A renewal
confirmed in English is confirmed with the English offer and declarations as shown and ticked
and the binding German wording next to it (Widerrufsbelehrung 2026-10: "we confirm the
declarations you actually made"). German consents keep their confirmation.

Final multi-model check, objection 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ptance

The counter-check that decides the stage with the moment of the issue instead of the moment of
the order survived: the test configured the effective date before it issued the offer, so both
moments lay after it. Now the date lies between the two, as it does at midnight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to the renewal wording

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TheMorpheus407

Copy link
Copy Markdown
Contributor Author

Checks on head 50ba40d (tree a277c1f), the merge of #789 at ecd4bf1 into this branch, run locally on the identical tree in a cargo target of its own, each under a 4 GB memory cap, nix with max-jobs 1, cores 2:

Check Result
treefmt --ci pass
clippy --all-targets -D warnings pass
scripts/test-unit.py --suite unit 812 passed, 0 failed
scripts/test-unit.py --suite postgres (full suite, all targets) 200 passed, 0 failed
tests/backend-safety.py 18 scenarios pass
VM tests paypal, premium, heart, premium-confirmation-timing, user all pass
Hosted checks 11 of 11 green

Counter-checks of the renewal change, 3 of 3 caught (run on b33c69d, whose renewal code is unchanged in 50ba40d): an English consent confirmed in German only; text_en left out of the offer id; the English wording dropping a declaration. The counter-checks of the purchase part are on #789.

🤖 Generated with Claude Code

@TheMorpheus407
TheMorpheus407 added this pull request to the merge queue Oct 19, 2026
Merged via the queue into develop with commit b6313c5 Oct 19, 2026
11 checks passed
@TheMorpheus407
TheMorpheus407 deleted the fix/stage2-final-renewal-english branch October 19, 2026 05:56
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