docs: document the branch and promotion model

Committed verbatim from the working tree, where it had been sitting
uncommitted. Written by Patrick, not by the agent: this commit only puts
it under version control so the promotion chain it describes can be
corrected against reality in the next one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Patrick Schurig 2026-08-02 10:29:00 +02:00
parent f0a3aafda0
commit f839f5d435

182
AGENTS.md
View File

@ -1,16 +1,184 @@
# AGENTS.md — etm-powersync-plugins-modbus
Plugins Modbus ETM (fork GPL) : compteurs, bornes, relais.
Contient abbb2x, abbterra, eastron, waveshare-relay-d8.
Tous les plugins Modbus supportés par ETM : plugins propres et forks de plugins amont.
Compteurs, bornes de recharge, relais, onduleurs.
- **Licence** : GPL-3.0 (+ LGPL pour libnymea-modbus / libnymea-sunspec) · **Miroir public** : OUI
- **Agent** : aucun en beta — plugins déjà publiés, repo de maintenance/référence.
- **Licence** : GPL-3.0 pour les plugins, LGPL-3.0 pour `libnymea-modbus` / `libnymea-sunspec`
- **Miroir public** : OUI
- **Paquets** : publiés sur `repos.etm-powersync.fr`, trois canaux
L'inventaire des plugins est l'arborescence du dépôt. Ne pas se fier à une liste écrite ici : elle
serait périmée, et un agent en conclurait que le reste n'existe pas.
Ce dépôt est autoportant : tout ce qui est nécessaire pour y travailler est ici.
## Placement du travail non amont
Une fois qu'un développement — plugin, correctif, extension vendor — n'est ni upstream officiel ni
destiné à y retourner à court terme, il vit dans le dépôt produit ETM correspondant
(`etm-powersync-plugins-modbus` ou `etm-powersync-plugins`), vendoré depuis sa source si elle existe
ailleurs (`VENDORED.md` avec commit et date), développé directement sinon. Le fork correspondant
(`nymea-plugins-modbus` ou `nymea-plugins`) ne garde que ce qui reste candidat à une contribution
amont.
## Branches et canaux
```
feature/* ──► landing-silo ──► experimental-silo ──► master
(nightly) (testing) (stable)
```
Vers la droite on promeut, vers la gauche on redescend un correctif. Une correction ne saute
jamais un cran.
`experimental-silo` n'est pas une branche de travail : elle ne reçoit que ce qui a déjà survécu au
nightly. Le travail se fait dans `feature/*`.
### Critères de promotion
| Passage | Critère |
|---|---|
| commits dans `feature/*` | `verify` en local, l'agent boucle seul |
| `feature/*` → `landing-silo` | PR, `verify` vert sur le runner, AC de la spec couverts par des tests |
| `landing-silo` → `experimental-silo` | build complet propre, banc nocturne vert |
| `experimental-silo` → `master` | validation matérielle nommée : appareil, firmware, configuration |
Le dernier critère n'est pas automatisable et ne doit pas l'être.
### Correctifs
**Avant de créer une branche : reproduire le bug et déterminer la branche la plus proche de
`master` où il apparaît.** C'est elle qui décide du point de départ, pas l'urgence ressentie.
| Le bug se reproduit… | Départ | Ensuite |
|---|---|---|
| jusque dans `master` | `hotfix/*` depuis `master` | fusion dans `master`, puis redescente dans `experimental-silo`, puis dans `landing-silo` |
| dans `experimental-silo`, pas dans `master` | `fix/*` depuis `experimental-silo` | redescente dans `landing-silo` |
| seulement dans `landing-silo` | `fix/*` depuis `landing-silo` | rien, il remonte par la promotion normale |
Ne jamais corriger en aval un bug présent en amont : le correctif remontera un jour, mais la
branche amont reste cassée entre-temps et la promotion suivante réintroduit l'ancien code par
dessus. Symptôme : « le correctif ne tient pas ».
Si une fusion casse le nightly, **révoquer la fusion** dans `landing-silo` pour rendre le canal de
nouveau utilisable, puis corriger tranquillement dans la branche `feature/*` d'origine. Ne pas
corriger en avant sous pression.
Trois préfixes, pas davantage : `feature/*`, `fix/*`, `hotfix/*`.
### Versionnement des paquets
Tout paquet issu d'un dépôt produit ETM porte un suffixe `+etmN` sur la version amont qu'il modifie
ou remplace (ex. `1.15.2+etm1`), à tous les canaux de promotion (`landing-silo`/nightly,
`experimental-silo`/testing, `main`/stable). Ce suffixe garantit la préséance apt/dpkg sur le paquet
upstream identique.
Ne jamais le remplacer par un tiret (`-etmN`) : `-` a un sens réservé en version Debian (champ
`debian_revision`) et entre en conflit avec une éventuelle révision Debian amont.
## Agents
Les agents travaillent dans `feature/*` et `fix/*`. Jamais de commit direct dans `landing-silo`,
`experimental-silo` ou `master` : ces branches ne reçoivent que des fusions.
Une spec, une branche, un jeu de critères d'acceptation.
Un agent qui estime qu'un refactor s'impose sur un plugin publié le signale et s'arrête. Il ne le
fait pas.
## Invariants locaux
1. NE PAS renommer les paquets PUBLIÉS : `powersync-plugin-eastron`,
1. **NE PAS renommer les paquets PUBLIÉS** : `powersync-plugin-eastron`,
`powersync-plugin-abbb2x`, `nymea-plugin-abbterra`. Casse l'upgrade des box beta.
Valable sur toutes les branches : un renommage dans `landing-silo` finit par atteindre `master`.
2. `abbterra` est volontairement sous nom amont (transition upstream propre) — ne pas « corriger ».
3. Matrice validée beta : SDM72 / SDM120 (eastron), Waveshare D8.
4. Aucun composant propriétaire ici.
4. Aucun composant propriétaire ici. Aucun ne doit y entrer.
Carte globale et frontières : voir `../AGENTS.md`.
## Miroir public — ne doit jamais être commité
Données client : adresses de site, noms, numéros de série, relevés, adresses IP d'installations
réelles. Identifiants et jetons. Documentation constructeur sous réserve de confidentialité — elle
se cite en référence (titre, version, section) dans la table de provenance des registres, jamais
en contenu.
Les captures, journaux et dumps de registres joints à un correctif sont expurgés avant commit.
---
## Repository Guidelines
These conventions apply to every `*-plugins-modbus` repository. They are not a style preference:
plugins from all of them load into the **same nymea-core**, so they share its ABI, its Qt version,
its plugin metadata format and its interface definitions. A repository that diverges produces
plugins that do not interoperate.
**Target: nymea-core `<version>`.** Where these guidelines and the core repository's `AGENTS.md`
disagree, the core repository wins and this section is corrected.
This section is identical, byte for byte, across every `*-plugins-modbus` repository, and is the
part that can be contributed upstream. Anything specific to one repository belongs above it.
### Plugin anatomy
One directory per vendor, holding its sources, headers, plugin metadata (`*.json`), translations
and packaging fragments. Plugin IDs, translation filenames and resource prefixes follow the
directory name.
Shared code stays in the shared libraries. Never move code between an LGPL library and a GPL
plugin without addressing the licence change explicitly.
### Build
Requires `plugin.pri`, provided by `libnymea1-dev`, or passed explicitly via `PLUGIN_PRI=`.
```
qmake <project>.pro && make -j"$(nproc)" # whole repository
cd <vendor> && qmake <vendor>.pro && make # single plugin — the short loop, preferred
```
Select the Qt version before calling qmake. When building against a nymea source tree rather than
a system-wide install, `PKG_CONFIG_PATH`, `CPATH`, `LIBRARY_PATH`, `LD_LIBRARY_PATH` and a `PATH`
extended with the `nymea-plugininfocompiler` build directory are also required.
Verbose logs: `QT_LOGGING_RULES="*.debug=true"`.
### Style
Qt conventions: 4-space indent, `CamelCase` classes, `lowerCamelCase` functions and members with
the `m_` prefix, Qt containers and signals over STL, log output wrapped in
`NYMEA_LOGGING_CATEGORY`, and `foreach` rather than range-based `for` to keep C++11 compatibility.
Refresh translations whenever user-visible text changes.
### Register provenance
**Never infer a register address.** Every address comes from the manufacturer's documentation or
from a read performed against a real device. A value taken from a third-party implementation is a
hypothesis until verified on hardware, and is documented as such.
Addresses, scale factors and endianness belong in the vendor's register description, not scattered
as literals through the implementation.
### Hardware validation
Compiling is not verifying. Any claim of validation names the device, its firmware version and its
configuration. Without hardware, say so and describe the validation still required rather than
implying it was performed.
Where a Modbus server can be simulated, prefer a captured register dump replayed against the
plugin over a hand-written mock: a dump carries the quirks a mock will not.
### Device writes
A write can damage equipment or void a warranty. Write paths are reviewed more strictly than read
paths: state what is written, under which conditions, and what happens if the plugin stops
mid-operation.
### Commits and pull requests
Imperative subjects under ~72 characters.
Pull request titles: `Plugin name: Add support for xyz` or `New plugin: Plugin name`.
State whether the change was tested on hardware, and if not, name someone who can confirm it.
Update the plugin's `README.md` and the translations.
Call out packaging impacts — Qt 5 and Qt 6 packaging are maintained separately.