feat(privacy): Finish takes in edits nobody signed once the person agrees (ADR 0019)

Finishing a partly readable studyset counts the edits a device without
the keys wrote readable while it was made private, by kind (flashcards,
notes, learning paths, PDFs, studysets), and asks: taken in, they are
sealed with the tree's key as the person's; left, they stay locked (the
short reading of 22 Oct, finding 11). In English and German. Tests on the
real gateways both ways, and of the dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-22 10:38:43 +02:00
commit 991bef47eb
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
5 changed files with 518 additions and 0 deletions

View file

@ -2076,6 +2076,21 @@
"publishTagsSent": "Die Namen der Tags, die mitgehen und die die Instanz erfährt: {names}",
"@publishTagsSent": {"placeholders": {"names": {"type": "String"}}},
"publishTagsSentNone": "Es gehen keine Tags mit.",
"privacyAdoptTitle": "Unsignierte Änderungen übernehmen?",
"privacyAdoptBody": "Während es privat gemacht wurde, hat ein Gerät ohne deine Schlüssel es geändert: {parts}. Übernommen, werden sie als deine versiegelt; sonst bleiben sie gesperrt, wie alles, was die Instanz geschrieben haben könnte.",
"@privacyAdoptBody": {"placeholders": {"parts": {"type": "String"}}},
"privacyAdoptTake": "Übernehmen",
"privacyAdoptLeave": "Gesperrt lassen",
"privacyEditsCards": "{count, plural, =1{1 Karteikarte} other{{count} Karteikarten}}",
"@privacyEditsCards": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsNotes": "{count, plural, =1{1 Notiz} other{{count} Notizen}}",
"@privacyEditsNotes": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsPaths": "{count, plural, =1{1 Änderung an Lernpfaden} other{{count} Änderungen an Lernpfaden}}",
"@privacyEditsPaths": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsPdfs": "{count, plural, =1{1 PDF} other{{count} PDFs}}",
"@privacyEditsPdfs": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsStudysets": "{count, plural, =1{1 Lernset} other{{count} Lernsets}}",
"@privacyEditsStudysets": {"placeholders": {"count": {"type": "int"}}},
"studysetLockedTitle": "Gesperrt",
"studysetLockedBody": "Dieses Lernset ist privat, und sein Schlüssel öffnet sich auf diesem Gerät nicht: Es wurde mit Schlüsseln verschlüsselt, die dein Konto nicht mehr hat. Es lässt sich nur noch löschen.",
"studysetVisibilityPartly": "Privat, teils lesbar",

View file

@ -2442,6 +2442,21 @@
"publishTagsSent": "The names of the tags that go with it, which the instance learns: {names}",
"@publishTagsSent": {"placeholders": {"names": {"type": "String"}}},
"publishTagsSentNone": "No tags go with it.",
"privacyAdoptTitle": "Take in edits nobody signed?",
"privacyAdoptBody": "While it was made private, a device without your keys changed it: {parts}. Taken in, they are sealed as yours; left, they stay locked, as anything the instance could have written.",
"@privacyAdoptBody": {"placeholders": {"parts": {"type": "String"}}},
"privacyAdoptTake": "Take them in",
"privacyAdoptLeave": "Leave them locked",
"privacyEditsCards": "{count, plural, =1{1 flashcard} other{{count} flashcards}}",
"@privacyEditsCards": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsNotes": "{count, plural, =1{1 note} other{{count} notes}}",
"@privacyEditsNotes": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsPaths": "{count, plural, =1{1 change to learning paths} other{{count} changes to learning paths}}",
"@privacyEditsPaths": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsPdfs": "{count, plural, =1{1 PDF} other{{count} PDFs}}",
"@privacyEditsPdfs": {"placeholders": {"count": {"type": "int"}}},
"privacyEditsStudysets": "{count, plural, =1{1 studyset} other{{count} studysets}}",
"@privacyEditsStudysets": {"placeholders": {"count": {"type": "int"}}},
"studysetLockedTitle": "Locked",
"studysetLockedBody": "This studyset is private, and its key doesn't open on this device: it was encrypted with keys your account no longer has. It can only be deleted.",
"studysetVisibilityPartly": "Private, partly readable",

View file

@ -12237,6 +12237,60 @@ abstract class AppLocalizations {
/// **'No tags go with it.'**
String get publishTagsSentNone;
/// No description provided for @privacyAdoptTitle.
///
/// In en, this message translates to:
/// **'Take in edits nobody signed?'**
String get privacyAdoptTitle;
/// No description provided for @privacyAdoptBody.
///
/// In en, this message translates to:
/// **'While it was made private, a device without your keys changed it: {parts}. Taken in, they are sealed as yours; left, they stay locked, as anything the instance could have written.'**
String privacyAdoptBody(String parts);
/// No description provided for @privacyAdoptTake.
///
/// In en, this message translates to:
/// **'Take them in'**
String get privacyAdoptTake;
/// No description provided for @privacyAdoptLeave.
///
/// In en, this message translates to:
/// **'Leave them locked'**
String get privacyAdoptLeave;
/// No description provided for @privacyEditsCards.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 flashcard} other{{count} flashcards}}'**
String privacyEditsCards(int count);
/// No description provided for @privacyEditsNotes.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 note} other{{count} notes}}'**
String privacyEditsNotes(int count);
/// No description provided for @privacyEditsPaths.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 change to learning paths} other{{count} changes to learning paths}}'**
String privacyEditsPaths(int count);
/// No description provided for @privacyEditsPdfs.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 PDF} other{{count} PDFs}}'**
String privacyEditsPdfs(int count);
/// No description provided for @privacyEditsStudysets.
///
/// In en, this message translates to:
/// **'{count, plural, =1{1 studyset} other{{count} studysets}}'**
String privacyEditsStudysets(int count);
/// No description provided for @studysetLockedTitle.
///
/// In en, this message translates to:

View file

@ -7759,6 +7759,75 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get publishTagsSentNone => 'Es gehen keine Tags mit.';
@override
String get privacyAdoptTitle => 'Unsignierte Änderungen übernehmen?';
@override
String privacyAdoptBody(String parts) {
return 'Während es privat gemacht wurde, hat ein Gerät ohne deine Schlüssel es geändert: $parts. Übernommen, werden sie als deine versiegelt; sonst bleiben sie gesperrt, wie alles, was die Instanz geschrieben haben könnte.';
}
@override
String get privacyAdoptTake => 'Übernehmen';
@override
String get privacyAdoptLeave => 'Gesperrt lassen';
@override
String privacyEditsCards(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Karteikarten',
one: '1 Karteikarte',
);
return '$_temp0';
}
@override
String privacyEditsNotes(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Notizen',
one: '1 Notiz',
);
return '$_temp0';
}
@override
String privacyEditsPaths(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Änderungen an Lernpfaden',
one: '1 Änderung an Lernpfaden',
);
return '$_temp0';
}
@override
String privacyEditsPdfs(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count PDFs',
one: '1 PDF',
);
return '$_temp0';
}
@override
String privacyEditsStudysets(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count Lernsets',
one: '1 Lernset',
);
return '$_temp0';
}
@override
String get studysetLockedTitle => 'Gesperrt';

View file

@ -7686,6 +7686,75 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get publishTagsSentNone => 'No tags go with it.';
@override
String get privacyAdoptTitle => 'Take in edits nobody signed?';
@override
String privacyAdoptBody(String parts) {
return 'While it was made private, a device without your keys changed it: $parts. Taken in, they are sealed as yours; left, they stay locked, as anything the instance could have written.';
}
@override
String get privacyAdoptTake => 'Take them in';
@override
String get privacyAdoptLeave => 'Leave them locked';
@override
String privacyEditsCards(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count flashcards',
one: '1 flashcard',
);
return '$_temp0';
}
@override
String privacyEditsNotes(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count notes',
one: '1 note',
);
return '$_temp0';
}
@override
String privacyEditsPaths(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count changes to learning paths',
one: '1 change to learning paths',
);
return '$_temp0';
}
@override
String privacyEditsPdfs(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count PDFs',
one: '1 PDF',
);
return '$_temp0';
}
@override
String privacyEditsStudysets(int count) {
String _temp0 = intl.Intl.pluralLogic(
count,
locale: localeName,
other: '$count studysets',
one: '1 studyset',
);
return '$_temp0';
}
@override
String get studysetLockedTitle => 'Locked';