Every opportunity created by the workflow now carries the CTag
"Auto: Durch Suchagent-Treffer erstellt" (id 6a83292a186dce7b2), set via
cTagsIds directly in the create POST. The tag id is resolved at runtime
by name (EspoClient.ensure_ctag, same pattern as team_id; self-healing
after a CRM rebuild); the read-back verification now also checks the tag.
No backfill: existing opportunities and the saved "Via cowork-api
erstellt" list filter are untouched.
Live-verified end to end: synthetic trigger mail, opportunity
6a832b8f29cc86bdf created with cTagsNames containing the tag (test
artifact removed afterwards). 65/65 pytest.
Also adds the complete German technical documentation of the workflow
(docs/projekt-matching-dokumentation.md, sections 1-13 + S68 appendix).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Root cause chain (evidence: 25+ failed traces on nproj/3022414):
straight quote in page text ends the guided-decoding JSON string
early -> grammar deadlock -> whitespace loop until context/token
limit -> chat_json fails 3x (~35 min) -> IMAP conn idles out ->
move_to_trash raises -> mail never trashed -> reprocessed forever.
- ingest/mailer: MailBox.ensure_alive() reconnect before finalize;
move_to_trash failure falls back to flag_checked, run continues
- stages: page_text() feeds only div.content minus skill-tag cloud
to the LLM and maps quote chars to apostrophes (the actual
degeneration trigger, live-verified: extract now OK in 21 s)
- llm: requirements maxItems 40; max_tokens 8192 caps degenerate
runs at ~100 s instead of ~10 min
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>