Rules: offer patterns match the everyday word for a vacancy, so acknowledgements and rejections become offers #16

Closed
opened 2026-10-01 10:47:58 +00:00 by tiagoagueda · 1 comment
Owner

Found on 2026-09-29 in a read-only review of postulo-imap at cc09c6381, running classify on ordinary acknowledgement, rejection and invitation sentences in each language.

offer is the first kind tried in every rule file, and several of its patterns are not specific to an offer of employment. Some are the ordinary words for a job advert, which most automatic mail from job boards and recruiting systems contains; others match any sentence that is "pleased to offer" something, an interview included. Because offer outranks every other kind, the message's real kind is never reached, and the suggestion says would move it to Offer for an acknowledgement or a rejection.

  • Where:

    • src/postulo_imap/rules/es.json:15: oferta (de trabajo|de empleo|laboral).
    • src/postulo_imap/rules/it.json:15: offerta di (lavoro|impiego|assunzione).
    • src/postulo_imap/rules/pl.json:15-16: oferta (pracy|zatrudnienia), propozycja (zatrudnienia|wsp[óo][łl]pracy).
    • src/postulo_imap/rules/pt.json:13-16: temos o prazer de lhe (oferecer|propor), proposta de (trabalho|emprego|contrata[çc][ãa]o), oferta de emprego.
    • src/postulo_imap/rules/en.json:18: job offer.
    • src/postulo_imap/rules/fr.json:13: nous avons le plaisir de vous proposer.
    • src/postulo_imap/rules/de.json:13: freuen uns.{0,40}anbieten zu k[öo]nnen.
    • tests/test_imap.py:260-317, test_the_rules_recognise_each_kind_in_each_language: one sentence that must match per kind and language, and none that must not be an offer.
  • What happens: run on the snapshot, each line is classify(text.lower()):

    • "Gracias por tu candidatura a la oferta de empleo Analista de datos. La hemos recibido." → offer (es), matched oferta de empleo.
    • "Lamentamos comunicarte que no continuaremos con tu candidatura a la oferta de empleo X." → offer (es).
    • "Grazie per la tua candidatura all'offerta di lavoro Analista." → offer (it).
    • "Ci dispiace comunicarti che non proseguiremo per l'offerta di lavoro Analista." → offer (it).
    • "Dziękujemy za aplikację. Oferta pracy: Analityk danych." → offer (pl).
    • "Recebemos a sua candidatura à oferta de emprego Analista de Dados." → offer (pt).
    • "Lamentamos informar que a sua candidatura à oferta de emprego Analista não foi selecionada." → offer (pt).
    • "We regret to inform you that you were not selected for the job offer Data Analyst." → offer (en).
    • "Nous avons le plaisir de vous proposer un entretien le 3 octobre" → offer (fr).
    • "Temos o prazer de lhe propor uma entrevista no dia 3 de outubro." → offer (pt).
    • "Wir freuen uns, Ihnen einen Gesprächstermin anbieten zu können." → offer (de).
    • A subject line "Propozycja współpracy", which is how a recruiter's first approach is often titled → offer (pl).

    French, German and Dutch acknowledgements that name the vacancy (offre d'emploi, Stellenangebot, vacature) are read correctly, because those files do not list the bare word: fr.json:15 asks for offre d'emploi ferme.

  • Why it matters: the suggestion carries suggested_status="offer" and the event kind offer (src/postulo_imap/classifying.py:40-46), so accepting it moves the application to Offer. A person applying in Spain, Italy, Poland or Portugal will meet this on most automatic replies; they either decline, and lose the acknowledgement or the rejection the message really was, or accept a wrong status. An interview invitation read as an offer also loses its proposed dates, which are only collected for the interview kind (src/postulo_imap/classifying.py:126).

  • Fix:

    • Remove the bare vacancy terms from the offer lists, or require an offer verb or qualifier beside them, as fr.json does.
    • Make the "pleased to offer" patterns name the post (le poste, die Stelle, a posição, el puesto) instead of accepting any object.
    • Drop propozycja współpracy, or move it to a kind that suggests no status.

Done when

  • tests/test_imap.py has a parametrised test of sentences that must not be an offer, per language: an acknowledgement that names the vacancy, a rejection that names the vacancy, and an interview invitation worded as "pleased to offer". Each must come back as acknowledged, rejected and interview. With the sentences above it fails today in es, it, pl, pt, en, fr and de.
Found on 2026-09-29 in a read-only review of postulo-imap at cc09c6381, running `classify` on ordinary acknowledgement, rejection and invitation sentences in each language. *offer* is the first kind tried in every rule file, and several of its patterns are not specific to an offer of employment. Some are the ordinary words for a job advert, which most automatic mail from job boards and recruiting systems contains; others match any sentence that is "pleased to offer" something, an interview included. Because offer outranks every other kind, the message's real kind is never reached, and the suggestion says *would move it to Offer* for an acknowledgement or a rejection. - **Where:** - `src/postulo_imap/rules/es.json:15`: `oferta (de trabajo|de empleo|laboral)`. - `src/postulo_imap/rules/it.json:15`: `offerta di (lavoro|impiego|assunzione)`. - `src/postulo_imap/rules/pl.json:15-16`: `oferta (pracy|zatrudnienia)`, `propozycja (zatrudnienia|wsp[óo][łl]pracy)`. - `src/postulo_imap/rules/pt.json:13-16`: `temos o prazer de lhe (oferecer|propor)`, `proposta de (trabalho|emprego|contrata[çc][ãa]o)`, `oferta de emprego`. - `src/postulo_imap/rules/en.json:18`: `job offer`. - `src/postulo_imap/rules/fr.json:13`: `nous avons le plaisir de vous proposer`. - `src/postulo_imap/rules/de.json:13`: `freuen uns.{0,40}anbieten zu k[öo]nnen`. - `tests/test_imap.py:260-317`, `test_the_rules_recognise_each_kind_in_each_language`: one sentence that must match per kind and language, and none that must not be an offer. - **What happens:** run on the snapshot, each line is `classify(text.lower())`: - "Gracias por tu candidatura a la oferta de empleo Analista de datos. La hemos recibido." → `offer` (es), matched `oferta de empleo`. - "Lamentamos comunicarte que no continuaremos con tu candidatura a la oferta de empleo X." → `offer` (es). - "Grazie per la tua candidatura all'offerta di lavoro Analista." → `offer` (it). - "Ci dispiace comunicarti che non proseguiremo per l'offerta di lavoro Analista." → `offer` (it). - "Dziękujemy za aplikację. Oferta pracy: Analityk danych." → `offer` (pl). - "Recebemos a sua candidatura à oferta de emprego Analista de Dados." → `offer` (pt). - "Lamentamos informar que a sua candidatura à oferta de emprego Analista não foi selecionada." → `offer` (pt). - "We regret to inform you that you were not selected for the job offer Data Analyst." → `offer` (en). - "Nous avons le plaisir de vous proposer un entretien le 3 octobre" → `offer` (fr). - "Temos o prazer de lhe propor uma entrevista no dia 3 de outubro." → `offer` (pt). - "Wir freuen uns, Ihnen einen Gesprächstermin anbieten zu können." → `offer` (de). - A subject line "Propozycja współpracy", which is how a recruiter's first approach is often titled → `offer` (pl). French, German and Dutch acknowledgements that name the vacancy (`offre d'emploi`, `Stellenangebot`, `vacature`) are read correctly, because those files do not list the bare word: `fr.json:15` asks for `offre d'emploi ferme`. - **Why it matters:** the suggestion carries `suggested_status="offer"` and the event kind `offer` (`src/postulo_imap/classifying.py:40-46`), so accepting it moves the application to Offer. A person applying in Spain, Italy, Poland or Portugal will meet this on most automatic replies; they either decline, and lose the acknowledgement or the rejection the message really was, or accept a wrong status. An interview invitation read as an offer also loses its proposed dates, which are only collected for the `interview` kind (`src/postulo_imap/classifying.py:126`). - **Fix:** - Remove the bare vacancy terms from the offer lists, or require an offer verb or qualifier beside them, as `fr.json` does. - Make the "pleased to offer" patterns name the post (`le poste`, `die Stelle`, `a posição`, `el puesto`) instead of accepting any object. - Drop `propozycja współpracy`, or move it to a kind that suggests no status. ## Done when - `tests/test_imap.py` has a parametrised test of sentences that must not be an offer, per language: an acknowledgement that names the vacancy, a rejection that names the vacancy, and an interview invitation worded as "pleased to offer". Each must come back as `acknowledged`, `rejected` and `interview`. With the sentences above it fails today in es, it, pl, pt, en, fr and de.
tiagoagueda added this to the 0.5.0 milestone 2026-10-01 10:47:58 +00:00
Author
Owner

Fixed by pull request #25.

Fixed by pull request #25.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-imap#16
No description provided.