diff --git a/android-client/PLAN.md b/android-client/PLAN.md index dedaf86..de7982e 100644 --- a/android-client/PLAN.md +++ b/android-client/PLAN.md @@ -843,11 +843,24 @@ Les trois verbes d'un coup, et depuis l'autre bout : **créer** (4), **modifier* (1), **supprimer** (1). Le `1 deleted` est celui qui comptait — la disparition locale ne prouvait rien, c'est la pierre tombale qui devait voyager. -Les étapes 1 à 3 de cette section sont donc closes. **Reste le 409** : depuis -que l'enregistrement ne tire plus avant de publier, c'est lui seul qui garantit -qu'une écriture du téléphone n'écrase pas le poste, et il n'a toujours jamais -tourné. Le provoquer : synchroniser depuis le poste, puis enregistrer depuis le -téléphone sans synchroniser d'abord. +Les étapes 1 à 3 de cette section sont donc closes. + +### Le conflit rend 422, pas 409 — corrigé 2026-08-21 + +Le chemin de reprise a enfin tourné, et il ne reconnaissait pas ce qu'il +recevait. Un poste qui publie entre notre lecture et notre écriture nous vaut un +**422**, pas un 409 : l'enregistrement échouait au lieu de reprendre. + +Gitea rend 409 quand le sha envoyé ne correspond plus, et 422 quand il manque ou +que la demande est jugée irrecevable — dont le cas « ce fichier existe déjà » +d'une création. Les deux disent la même chose pour nous : **le sha n'est plus le +bon**. Relire et recommencer est la bonne réponse aux deux, et elle est sans +danger — la reprise republie avec le sha frais, donc elle n'écrase jamais rien ; +un corps réellement mal formé échouerait de nouveau et sortirait au bout de +trois essais, avec le texte de Gitea. + +C'est exactement ce qu'un chemin jamais exercé cache : il était écrit, il +compilait, il était même commenté — et il ne se déclenchait pas. ### Ce qui devient facultatif diff --git a/android-client/PMA.SyncClient.pas b/android-client/PMA.SyncClient.pas index bb3490e..dd75d1d 100644 --- a/android-client/PMA.SyncClient.pas +++ b/android-client/PMA.SyncClient.pas @@ -40,7 +40,7 @@ type ssRefused, // 403 : HTTPS exige par le serveur ssHttpError, // autre code ssNetworkError, // rien n'a repondu - /// 409 : le sha envoye n'est plus celui du fichier - un autre appareil a + /// 409 ou 422 : le sha envoye n'est plus celui du fichier - un autre appareil a /// publie entre notre lecture et notre ecriture. L'appelant doit relire, /// refusionner et renvoyer, pas reessayer tel quel. ssConflict @@ -232,7 +232,19 @@ begin // prochaine ecriture - sans lui il faudrait relire pour publier. Result.ETag := ShaFromPutResponse(LResync.DataString); end; - 409: Result.Status := ssConflict; + // 409 ET 422 : DANS LES DEUX CAS LE SHA N'EST PLUS LE BON. + // + // Gitea rend 409 quand le sha envoye ne correspond plus, et 422 quand + // il manque ou qu'il juge la demande irrecevable - dont le cas « ce + // fichier existe deja » d'une creation. Mesure a l'appui : un poste + // qui publie entre notre lecture et notre ecriture nous a valu un + // 422, pas un 409, et l'enregistrement echouait au lieu de reprendre. + // + // Relire et recommencer est la bonne reponse aux deux, et elle est + // sans danger : la reprise republie avec le sha frais, donc elle + // n'ecrase jamais rien. Un vrai corps mal forme echouerait de nouveau + // et sortirait au bout de trois essais, avec le texte de Gitea. + 409, 422: Result.Status := ssConflict; else Result.Status := ssHttpError; // LE CORPS, TOUJOURS. Il etait remplace par un message fige sur 401 diff --git a/mainApk.pas b/mainApk.pas index 8b0fb79..307b6cd 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -832,7 +832,8 @@ begin if LPut.Status = ssConflict then begin - Log('save: 409 - another device published, re-reading'); + Log(Format('save: %d - another device published, re-reading', + [LPut.HttpCode])); LPlain := ''; Continue; end;