Constater dans chat.db qu'un message est réellement parti.
Atlas, panier « Ensuite », 24 août 2026. MessagesSendTool proclamait
« Message sent » sur la seule foi du code retour d'osascript — or Messages
accepte le texte puis échoue parfois en silence (le « Not Delivered » que
seul l'écran montre). La base ~/Library/Messages/chat.db, elle, dit vrai :
is_sent, is_delivered et error sur chaque rangée sortante.
Lecture seule, trois issues explicites — jamais un [] qui confond « pas
trouvé » avec « pas le droit de regarder » :
unreadable : Accès complet au disque manquant (le remède est dans le
détail) ;
not_found : rien d'aussi récent pour ce destinataire ;
found : la rangée, avec son verdict.
Functions:
find_outgoing
find_outgoing(
recipient: str,
sent_after: datetime,
*,
db_path: str = _DEFAULT_DB_PATH,
) -> Constat
La dernière rangée SORTANTE vers ce destinataire depuis sent_after.
Calque la jointure de poll_new_messages (imessage_daemon.py) mais côté
is_from_me = 1 et SANS filtre sur text — NULL possible sur les
macOS récents (attributedBody).
Source code in src/diapason/channels/imessage_status.py
| def find_outgoing(
recipient: str,
sent_after: datetime,
*,
db_path: str = _DEFAULT_DB_PATH,
) -> Constat:
"""La dernière rangée SORTANTE vers ce destinataire depuis ``sent_after``.
Calque la jointure de poll_new_messages (imessage_daemon.py) mais côté
``is_from_me = 1`` et SANS filtre sur ``text`` — NULL possible sur les
macOS récents (attributedBody).
"""
try:
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
except sqlite3.OperationalError as exc:
return Constat(issue="unreadable", detail=str(exc))
try:
row = conn.execute(
"SELECT m.guid, m.is_sent, m.is_delivered, m.error "
"FROM message m "
"JOIN chat_message_join cmj ON cmj.message_id = m.ROWID "
"JOIN chat c ON c.ROWID = cmj.chat_id "
"WHERE m.is_from_me = 1 AND m.date >= ? "
"AND c.chat_identifier = ? "
"ORDER BY m.date DESC LIMIT 1",
(_dt_to_apple_ns(sent_after), _normaliser_handle(recipient)),
).fetchone()
except sqlite3.OperationalError as exc:
# Base ouverte mais requête refusée (TCC partiel, schéma inattendu).
return Constat(issue="unreadable", detail=str(exc))
finally:
conn.close()
if row is None:
return Constat(issue="not_found")
guid, is_sent, is_delivered, error = row
return Constat(
issue="found",
guid=str(guid or ""),
is_sent=bool(is_sent),
is_delivered=bool(is_delivered),
error=int(error or 0),
)
|
status_by_guid
status_by_guid(
guid: str, *, db_path: str = _DEFAULT_DB_PATH
) -> Constat
Re-vérifier plus tard, quand le « Not Delivered » tardif est possible.
Source code in src/diapason/channels/imessage_status.py
| def status_by_guid(guid: str, *, db_path: str = _DEFAULT_DB_PATH) -> Constat:
"""Re-vérifier plus tard, quand le « Not Delivered » tardif est possible."""
try:
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
except sqlite3.OperationalError as exc:
return Constat(issue="unreadable", detail=str(exc))
try:
row = conn.execute(
"SELECT guid, is_sent, is_delivered, error FROM message "
"WHERE guid = ? LIMIT 1",
(guid,),
).fetchone()
except sqlite3.OperationalError as exc:
return Constat(issue="unreadable", detail=str(exc))
finally:
conn.close()
if row is None:
return Constat(issue="not_found")
g, is_sent, is_delivered, error = row
return Constat(
issue="found",
guid=str(g or ""),
is_sent=bool(is_sent),
is_delivered=bool(is_delivered),
error=int(error or 0),
)
|
remede_fda
Le remède quand chat.db est illisible, pour les contenus d'outils.
Source code in src/diapason/channels/imessage_status.py
| def remede_fda() -> str:
"""Le remède quand chat.db est illisible, pour les contenus d'outils."""
return (
"Full Disk Access is missing: System Settings → Privacy & Security → "
"Full Disk Access → add Diapason."
)
|