Relecture : une ancienne annotation incomplète est écartée, pas la relecture entière

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
IliesAllaliandClaude Opus 5.5 committed 2026-10-25 20:05:48 +01:00
1 parent eebb8f2cb1
commit ddc2231a8a
2 files changed
+23 -2

No files matched your search

+5 -2
View File
@@ -34,6 +34,8 @@ const sessionParamsSchema = z.object({
// remplissait la base à 12 Mo par envoi
const MAX_CHANGE_JSON_CHARS = 64_000
const MAX_PENDING_SESSIONS_PER_TREE = 200
// Annotations proposées avant la 1.5.1 : écartées à la relecture si elles ne se posent pas
const SKIPPABLE_ANNOTATION_ERRORS = new Set(['invalid_annotation_change', 'invalid_annotation_photo_path', 'unsupported_change_action_for_annotation'])
const boundedJson = z.unknown().optional().refine(
(value) => value === undefined || JSON.stringify(value).length <= MAX_CHANGE_JSON_CHARS,
{ message: 'change_too_large' },
@@ -1500,8 +1502,9 @@ export const contributionRoutes: FastifyPluginAsync = async (app) => {
)
approvedCount += 1
} catch (error) {
// Lien vers une personne ajoutée mais refusée : le lien est écarté, pas la relecture
if (error instanceof ContributionRouteError && error.code === 'unresolved_reference') {
// Lien vers une personne ajoutée mais refusée, ou annotation d'avant la 1.5.1 que le serveur ne
// peut pas poser (contenu incomplet) : la proposition est écartée, pas la relecture
if (error instanceof ContributionRouteError && (error.code === 'unresolved_reference' || SKIPPABLE_ANNOTATION_ERRORS.has(error.code))) {
decision = 'rejected'
rejectedCount += 1
} else {
@@ -116,6 +116,24 @@ describe.skipIf(!TEST_DB)('propositions de la famille sur l\'arbre, vraie base',
expect((await annotations()).length).toBe(before + 1)
})
it("une ancienne proposition d'annotation incomplète est écartée sans bloquer le reste de la relecture", async () => {
const before = (await annotations()).length
const session = await prisma.contributionSession.create({
data: {
treeId, submittedByLabel: 'Cousine', mode: 'tree_access', status: 'pending', title: 'Avant la 1.5.1',
changes: { create: [
{ entityType: 'annotation', action: 'create', afterJson: { type: 'drawing', x: 0, y: 0 } },
{ entityType: 'annotation', action: 'create', afterJson: { type: 'text', x: 5, y: 5, content: 'Mamie' } },
] },
},
})
const reviewed = await review(session.id, 'approved')
expect(reviewed.status).toBe(200)
expect(reviewed.body.approvedCount).toBe(1)
expect(reviewed.body.rejectedCount).toBe(1)
expect((await annotations()).length).toBe(before + 1)
})
it("une photo qui n'est pas de cet arbre est refusée dès l'envoi", async () => {
const res = await propose(family, [{ entityType: 'annotation', action: 'create', after: photoAnnotation('/trees/un-autre-arbre/annotation-photos/abc') }])
expect(res.status).toBe(400)