Skip to content

docs(par-public): trois portes, et des chemins que le code confirme (0.1.63) - #154

Merged
stephrobert merged 1 commit into
mainfrom
docs/par-public
Aug 23, 2026
Merged

docs(par-public): trois portes, et des chemins que le code confirme (0.1.63)#154
stephrobert merged 1 commit into
mainfrom
docs/par-public

Conversation

@stephrobert

Copy link
Copy Markdown
Owner

Toute la documentation tenait dans deux README qui parlaient en même temps à
l'apprenant, à l'auteur de catalogue et au formateur. Aucun des trois n'y
trouvait son chemin, et certaines sections décrivaient un produit qui
n'existe pas
.

Ce qui était faux, et la preuve pour chacun

Affirmation Preuve par le code
~/.local/share/dsoxlab/progress.db git grep progress.db -- src/ : rien. sessions/store.py:10.dsoxlab.db, une base par catalogue
~/.config/dsoxlab/config.yaml git grep 'config.yaml|XDG_CONFIG' -- src/ : rien. C'est la cible de #78, pas un chemin lu
« base SQLite conforme à la spécification XDG » même preuve : elle est dans le dépôt de labs
incus et kvm présentés comme des runtimes runtimes/manager.py : SHELL → ShellRuntime, VM/KVM/INCUS → VmRuntime. Deux runtimes ; le backend vient de meta.yml: infra.provider
carte d'architecture annonçant IncusRuntime et KvmRuntime grep '^class ' runtimes/*.py : ces classes n'existent pas
runtime.host dans l'exemple de lab.yaml models/lab.py ne parse que runtime.targets[].host : le champ est ignoré en silence
aide --lab-home : « Racine du dépôt linux-training » une chaîne affichée nommait un catalogue précis, contraire à l'agnosticisme
« validate-structure vérifie que chaque lab référencé existe » il itère sur discover_labs() : un lab déclaré mais absent passe sans un mot

Deux emplacements réels n'étaient documentés nulle part : ~/.cache/dsoxlab/<id>/
(inventaire et ssh_config) et ~/.ssh/config.d/<id>.conf. Ils le sont.

Les trois portes

docs/README.md aiguille ; learner.md (installer, choisir, jouer, lire sa
note), catalog-author.md (contrat, schémas, validators, pièges) et
trainer.md (infrastructure, providers, comptes, snapshots) nomment leur public
en tête. files.md (où dsoxlab écrit) et commands.md (table générée) sont la
référence commune. Chaque page existe en EN et FR.

Les deux README passent de 460 et 423 lignes à 150 : quoi, installer, jouer,
puis les trois portes. La carte d'architecture, corrigée, rejoint CONTRIBUTING,
son vrai public.

Le contrôle qui empêche la dérive de recommencer

C'est le cœur de l'issue : sans lui, cette PR répare une fois et le problème
revient. Il étend le mécanisme existant (scripts/generer-doc.py, déjà joué
par le hook pre-commit) plutôt que d'en ouvrir un second à maintenir.

Il relève les emplacements réels en appelant les fonctions que la CLI
appelle
(store.record_hint, config.set_active_lab, terraform.workdir,
inventory.*_path, locking.lock_path, logging_setup.chemin_journal,
demo.destination, update_check.cache_path) dans un sous-processus au HOME
jetable, puis regarde ce qui a réellement été créé. Un chemin cité par une page
doit correspondre.

Une page peut citer un chemin pour dire qu'il n'existe pas, mais la dispense
est nominative : elle nomme la page autorisée. Une dispense globale aurait
rouvert la porte. Et absents_devenus_reels() tient l'autre bout : le jour où
#78 rendra config.yaml réel, le test exigera la mise à jour de la page qui
l'annonce absent.

Il a servi le lendemain de sa pose

Au rebase sur la 0.1.62, il a signalé tout seul :

✘ docs/files.md cite « ~/.local/bin/dsoxlab », que le code ne produit nulle part
✘ docs/files.fr.md cite « ~/.local/bin/dsoxlab », que le code ne produit nulle part

Exact : #90 venait de retirer l'écriture du wrapper. Les pages disent désormais
qu'il n'est plus écrit, ce qui a son utilité pour qui en a un qui traîne d'une
version ancienne, et le chemin rejoint la dispense nominative. C'est la première
dérive attrapée par le contrôle, un jour après son existence.

Type of change

  • Documentation
  • Tests (le contrôle et ses gardes)

Checklist

Always

  • uv run ruff check src/dsoxlab tests tests_e2e fuzz scripts — All checks passed!
  • uv run mypy src/dsoxlab — no issues in 60 source files
  • uv run pytest620 passed ; tests_e2e — 16 passed
  • Domain-agnostic : une chaîne affichée qui nommait linux-training est corrigée
  • Parité EN/FR tenue par un test ; zéro tiret cadratin dans les pages françaises

When behavior changes

  • CHANGELOG EN + FR ; version 0.1.63 ; uv.lock régénéré

When a command or option is added, removed or changed

  • Trois chaînes i18n corrigées simultanément EN et FR (opt_lab_home,
    fullhelp_runtimes, la ligne run <id>) : elles décrivaient elles aussi
    un produit qui n'existe pas, et la documentation les aurait contredites.

When .github/workflows/ is touched — N/A

When the declarative contract changes — N/A

Mutation

Réintroduire ~/.local/share/dsoxlab/progress.db dans README.md fait rougir
test_aucune_page_ne_cite_un_chemin_inexistant, en nommant la page et le
chemin ; restauré, tout repasse. La mutation est gelée en test permanent
(test_le_controle_refuse_les_chemins_de_l_issue_86), qui rejoue les trois
lignes fausses de l'issue.

Deux décisions qui te reviennent

  • Le site généré n'est pas fait, et c'est une question ouverte.
    Documentation pointe désormais sur docs/README.md dans le dépôt, au lieu de
    l'index générique d'un blog. Recommandation : garder ce Markdown comme source
    unique et, si un site est voulu, publier ces mêmes fichiers via MkDocs Material
    sur GitHub Pages (aucune réécriture, un workflow), plutôt qu'un générateur qui
    imposerait son arborescence. Homepage reste le blog : l'issue ne visait que
    Documentation.
  • La table des commandes a quitté le README pour docs/commands.md. La page
    PyPI perd donc la liste et gagne un lien. Si tu la veux de retour dans le
    README, c'est une ligne de configuration du générateur.

Un bruit confirmé deux fois

tests/test_services.py::test_deux_services_se_joignent_par_leur_nom et
test_post_start_execute_vraiment_dans_le_conteneur sont instables sous
charge
, observés indépendamment sur cette branche et sur #153. Ils dépendent de
vrais conteneurs Docker, et rien ici n'y touche. Une issue les suit.

Related issues

Closes #86
Voisine de #120, déjà livrée. ~/.config/dsoxlab/config.yaml est décrit comme
à venir (#78), pas comme existant.

🤖 Generated with Claude Code

…0.1.63)

Toute la documentation tenait dans deux README qui parlaient en même temps à
l'apprenant, à l'auteur de catalogue et au formateur. Aucun des trois n'y
trouvait son chemin, et certaines sections décrivaient un produit qui n'existe
pas.

Les affirmations fausses, chacune vérifiée contre le code :

- `~/.local/share/dsoxlab/progress.db` et `~/.config/dsoxlab/config.yaml`
  n'existent nulle part. La base est `<catalogue>/.dsoxlab.db`, une par
  catalogue, et aucun fichier de configuration utilisateur n'est lu.
- « une base SQLite locale conforme à la spécification XDG » : elle est dans le
  catalogue, précisément pour que la progression le suive.
- `incus` et `kvm` annoncés comme des runtimes. Il y en a deux, `shell` et
  `vm` ; le backend vient de `meta.yml: infra.provider`, pas du lab.
- une carte d'architecture nommant `IncusRuntime` et `KvmRuntime`, deux classes
  qui n'existent pas.
- un `runtime.host` dans l'exemple de `lab.yaml` le plus en vue, champ
  qu'aucun code ne lit, et que le contrat documente comme un piège.
- l'aide de `--lab-home` nommait « le dépôt linux-training » comme s'il était
  le seul catalogue, dans les deux langues.

Le contrôle qui empêche la dérive de recommencer étend le mécanisme existant
plutôt que d'en ouvrir un second : `scripts/generer-doc.py`, qui produisait
déjà la table des commandes depuis la CLI, relève maintenant les emplacements
réels **en appelant les fonctions que la CLI appelle**, sur un HOME jetable, et
refuse tout chemin qu'une page cite et que le code ne produit pas. Prouvé par
mutation : réintroduire `progress.db` dans un README rend deux tests rouges.

Un chemin peut être cité pour dire qu'il n'existe pas, mais par la seule page
dont c'est le sujet, et un test vérifie l'autre bout : le jour où #78 rendra
`config.yaml` réel, la page qui l'annonce absent deviendra fausse, et le test
le dira.

Les pages, chacune nommant son public en tête : apprenant, auteur de catalogue,
formateur, plus deux références communes (où dsoxlab écrit, les commandes). Les
deux README restent la porte d'entrée et se lisent en trente secondes. Aucun
générateur de site n'est introduit : cette décision appartient au propriétaire
du dépôt.

Closes #86
@stephrobert stephrobert added this to the 0.2.0 — Productization milestone Aug 23, 2026
@stephrobert
stephrobert merged commit 88c22e5 into main Aug 23, 2026
18 checks passed
@stephrobert
stephrobert deleted the docs/par-public branch August 23, 2026 23:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P1] La documentation ne décrit pas le produit : chemins faux, aucune séparation par public, URLs génériques

1 participant