fix(ops): la sauvegarde des contrats archivait le mauvais repertoire

OBS-006. Trois racines etaient baties sur os.getcwd() : le magasin de
documents, les journaux et les sauvegardes. La vague G a corrige la
premiere, parce qu'elle bloquait aussi OPS-011, et a laisse les deux autres.
C'est la lecon deja consignee deux fois : un motif fautif corrige dans une
seule couche reste dans les autres.

Le plus serieux n'est pas le motif, c'est l'ecart qu'il a ouvert.
backup.py gardait sa propre constante DOCUMENTS_DIR sur os.getcwd(), donc
il ignorait DOCUMENTS_ROOT -- la variable que la vague G a introduite et que
docs/deployment.md dit maintenant de regler pour sortir les televersements
des repertoires de version. Des qu'un exploitant suit cette consigne, le
script archive un repertoire ou l'application n'a jamais rien ecrit. Et
comme il repond a un repertoire absent par une ligne d'information et un
code de sortie 0, une tache planifiee qui surveille le code de sortie voit
vert indefiniment.

Autrement dit : plus l'exploitant suivait correctement la documentation de
deploiement, plus surement ses sauvegardes de contrats etaient vides.

Les trois racines viennent desormais d'app/storage.py, resolues a l'appel et
non a l'import, et la sauvegarde imprime la source qu'elle a utilisee. Le
message d'absence nomme le chemin ou elle a cherche : "No documents
directory found" se lisait comme "il n'y a pas de documents" plutot que
comme "je regarde au mauvais endroit".

Le test qui porte est celui qui ouvre l'archive : un zip vide est un fichier
de taille non nulle, donc verifier qu'un fichier a ete produit ne prouvait
rien. Verifie par mutation.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
GGThed
2026-08-11 18:34:52 -04:00
co-authored by Claude Opus 5
parent 66f2838402
commit bda23dbb67
6 changed files with 287 additions and 11 deletions
+29
View File
@@ -95,8 +95,37 @@ DISCORD_REDIRECT_URI=https://your-domain/auth/discord/callback
# application. Set it to a path OUTSIDE the deployment directory if you move
# to a release-directory layout, or a deployment will take the documents with
# it (OPS-011, app/storage.py).
#
# IMPORTANT: the backup script reads this same variable. Before wave J it
# did not, and archived `./documents` regardless — so setting this here and
# nowhere else produced empty contract backups that still exited 0.
DOCUMENTS_ROOT=
# Where the log files go. Empty means `logs/` beside the application. Both
# defaults are anchored on the application, not on the directory the process
# was started from, which is what they used to be (OBS-006).
LOG_DIR=
# Where the backup script writes its archives. Empty means `backups/` beside
# the application.
BACKUP_DIR=
# =============================================================================
# Optional — rate limiting
# =============================================================================
# Where the rate limiter keeps its counters. Empty means `memory://`, which
# is correct for a single Waitress process and is what this deployment runs.
#
# Set it to a shared backend (redis://…) BEFORE running more than one worker:
# in-memory counters are per-process, so N workers let through N times every
# configured limit, with nothing to show for it in the logs.
#
# Note that shared storage does not by itself make the limits sound: they are
# keyed on the client IP, which is forgeable until TRUSTED_PROXY is set
# correctly (SEC-WEB-002 / OPS-002 — see above).
RATELIMIT_STORAGE_URI=
# Tables are created at startup when missing. Set to false once Alembic owns
# the schema (DB-002/DB-004): create_all() never ALTERs, so a column added to
# a model is silently absent from an existing database.