diff --git a/archivist/config.jsonc b/archivist/config.jsonc index a2a1e6c..179eeb5 100644 --- a/archivist/config.jsonc +++ b/archivist/config.jsonc @@ -43,6 +43,10 @@ // the first page, pages[0:3] searches pages 1 to 3 (expr slice // syntax, end exclusive), any list of strings works; omitted = the // whole document. + // frDate(text) parses a French natural-language date ("le 19 janvier + // 2026"; the day is optional and "1er" / abbreviated months are + // accepted) into a native date, for documents whose date is not + // written in a Go layout format. // period(value, unit, shift, layout?) renders a period instead of a // raw date: unit = `month`|`quarter`|`half`|`year`, shift = -1/0/+1 // for the previous / containing / next period (rent receipt: 0, @@ -59,13 +63,25 @@ // --- Generic extraction, runs for every document ------------------------- // Emission date, e.g. "Paris, le 15/01/2026" -> "15/01/2026" (parsed // into a native date; named emissionDate to avoid clashing with the - // expr date() builtin) + // expr date() builtin). + // Every format probe is guarded by its own "when": an unguarded + // date(firstMatch(...)) on a document that does not carry the format + // is a rule error, and a single rule error routes a perfectly + // classifiable document to pending/ (US-15). { - "when": "true", + "when": "firstMatch(`[0-9]{2}/[0-9]{2}/[0-9]{4}`, pages[0]) != ``", "set": [ { "field": "emissionDate", "eval": "date(firstMatch(`[0-9]{2}/[0-9]{2}/[0-9]{4}`, pages[0]), `02/01/2006`)" } ] }, + // Fallback: French natural-language date, e.g. "le 19 janvier 2026", + // when the page carries no numeric date. + { + "when": "firstMatch(`[0-9]{2}/[0-9]{2}/[0-9]{4}`, pages[0]) == `` && firstMatch(`(?:le )?[0-9]{1,2} [A-Za-zÀ-ÿ]{3,} [0-9]{4}`, pages[0]) != ``", + "set": [ + { "field": "emissionDate", "eval": "frDate(firstMatch(`(?:le )?[0-9]{1,2} [A-Za-zÀ-ÿ]{3,} [0-9]{4}`, pages[0]))" } + ] + }, // --- Bank statements (relevés de compte) ---------------------------------- {