docs: add improvement implementation plan (Phase A-F)
Detailed plan for 15 improvements across 6 phases covering security, stability, robustness, testability, modernization, and build. Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
1 parent
ee73b81b70
commit
e669e15e75
1 file changed
+466
@@ -0,0 +1,466 @@
|
||||
# Regelwerk — Implementierungsplan für DeepSeek V4 Flash
|
||||
|
||||
> **Ziel:** 15 Verbesserungen in 6 Phasen. Jede Änderung ist atomar, verifizierbar und einzeln commitbar.
|
||||
> **Wichtig:** Keine Änderung ohne vorheriges `gitnexus_impact`. Nach jedem Commit: Build + Tests + `gitnexus_detect_changes`.
|
||||
|
||||
---
|
||||
|
||||
## Phase A — Sicherheit (3 Änderungen)
|
||||
|
||||
### A1. Dangling Pointer in `regelmaschine.cpp` beheben
|
||||
|
||||
**Datei:** `src/core/regelmaschine.cpp`
|
||||
|
||||
**Vorher:**
|
||||
```cpp
|
||||
MSMem fallMem("regelFall FallMem", 1024*1024);
|
||||
gFallMemObject = &fallMem;
|
||||
```
|
||||
|
||||
**Nachher:**
|
||||
```cpp
|
||||
gFallMemObject = new MSMem("regelFall FallMem", 1024*1024);
|
||||
```
|
||||
Entsprechend am Ende der Funktion: Kein `delete` (Ownership liegt beim Global, wie `gPersistParamMemObject`).
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "gFallMemObject", direction: "upstream"})` — alle Zugriffsstellen identifizieren
|
||||
2. `gitnexus_impact({target: "regelFaelle", direction: "upstream"})` — Caller prüfen
|
||||
3. `src/core/regelmaschine.cpp` öffnen, Zeile mit `MSMem fallMem(...)` suchen
|
||||
4. `MSMem fallMem(...)` durch `gFallMemObject = new MSMem(...)` ersetzen
|
||||
5. Alle folgenden `&fallMem`-Referenzen durch `gFallMemObject` ersetzen
|
||||
6. Build: `cmake --build build -j$(sysctl -n hw.logicalcpu)`
|
||||
7. Tests: `ctest --test-dir build --output-on-failure`
|
||||
8. Integrationstest: `./build/tests/integration_test`
|
||||
9. Address Sanitizer: `cmake -B build-asan -G Ninja -DBUILD_TESTS=ON -DCMAKE_CXX_FLAGS="-fsanitize=address" && cmake --build build-asan && ./build-asan/tests/integration_test`
|
||||
10. `gitnexus_detect_changes()`
|
||||
11. Commit: `fix: dangling pointer gFallMemObject → heap allocation`
|
||||
|
||||
---
|
||||
|
||||
### A2. Thread-sichere Singleton-Initialisierung
|
||||
|
||||
**Datei:** `src/core/initrw.cpp`
|
||||
|
||||
**Vorher:**
|
||||
```cpp
|
||||
static bool fInit = false;
|
||||
if(fInit)
|
||||
return true;
|
||||
fInit = true;
|
||||
// ~40 mapXxx = makeMap(...)
|
||||
```
|
||||
|
||||
**Nachher:**
|
||||
```cpp
|
||||
#include <mutex>
|
||||
|
||||
static std::once_flag initFlag;
|
||||
bool alreadyDone = false;
|
||||
std::call_once(initFlag, [&]() {
|
||||
alreadyDone = true;
|
||||
// ~40 mapXxx = makeMap(...)
|
||||
});
|
||||
if(alreadyDone) return true;
|
||||
```
|
||||
Oder einfacher: `fInit` durch `std::atomic<bool>` ersetzen und den Check+Set mit `exchange` machen.
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "initRegelwerk", direction: "upstream"})`
|
||||
2. `src/core/initrw.cpp` öffnen, `#include <mutex>` hinzufügen
|
||||
3. `static bool fInit = false` → `static std::atomic<bool> fInit{false}`
|
||||
4. `if(fInit) return true;` → `if(fInit.load(std::memory_order_acquire)) return true;`
|
||||
5. `fInit = true;` → `fInit.store(true, std::memory_order_release);`
|
||||
6. Build + Tests + Integrationstest
|
||||
7. `gitnexus_detect_changes()`
|
||||
8. Commit: `fix: thread-safe initialization via std::atomic<bool>`
|
||||
|
||||
---
|
||||
|
||||
### A3. `strcpy`-Audit — kritische Stellen entschärfen
|
||||
|
||||
**Betroffene Dateien (priorisiert):**
|
||||
|
||||
| Datei | Zeile | Änderung |
|
||||
|-------|-------|----------|
|
||||
| `src/domain/class_regelbegruendung.cpp` | 25 | `strcpy(dst, src)` → `strncpy(dst, src, sizeof(dst)-1); dst[sizeof(dst)-1]='\0'` |
|
||||
| `src/domain/class_leistungwert.cpp` | 40 | `strcpy(buf, val)` → `strncpy(buf, val, sizeof(buf)-1); buf[sizeof(buf)-1]='\0'` |
|
||||
| `src/rw_actions/op_datum_selektor.hpp` | 22 | `strcpy(opdatum_, val)` → sichern |
|
||||
| `src/rw_actions/setze_alpha_extension.hpp` | 33 | `strcpy(gop, lst→gop())` → sichern |
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "class_regelbegruendung", direction: "upstream"})` für jede betroffene Klasse
|
||||
2. Jede Datei einzeln bearbeiten
|
||||
3. Vor jeder Änderung: Größe des Ziel-Puffers ermitteln (`sizeof(buf)` oder Member-Deklaration prüfen)
|
||||
4. `strcpy(dst, src)` → `strncpy(dst, src, sizeof(dst)-1); dst[sizeof(dst)-1] = '\0';`
|
||||
5. Nach jeder Datei: Build + Tests
|
||||
6. `gitnexus_detect_changes()`
|
||||
7. Commit pro Datei: `fix: replace strcpy with strncpy in <filename>`
|
||||
|
||||
**Nicht anfassen:** `src/util/std_c_compat.hpp` — nur dokumentieren, nicht ändern (wird von vielen Dateien benötigt).
|
||||
|
||||
---
|
||||
|
||||
## Phase B — Stabilität (3 Änderungen)
|
||||
|
||||
### B1. `static` → `thread_local` für Funktions-Caches
|
||||
|
||||
**Datei:** `src/core/sys_vars.cpp`
|
||||
|
||||
**3 Stellen ändern:**
|
||||
1. `diagnosenErfuellt()` — `static ScheinPtrVector sScheine` → `thread_local ScheinPtrVector sScheine`
|
||||
2. `hatFK4012Quartal()` — `static ScheinPtrVector sScheine` → `thread_local ScheinPtrVector sScheine`
|
||||
3. `aktive_bht_datum_menge()` — `static std::vector<int> s_result` → `thread_local std::vector<int> s_result`
|
||||
|
||||
**Ablauf:**
|
||||
1. `src/core/sys_vars.cpp` öffnen
|
||||
2. Drei `static` → `thread_local` ersetzen (einfaches Search & Replace)
|
||||
3. Build + Tests + Integrationstest
|
||||
4. Thread Sanitizer: `cmake -B build-tsan -G Ninja -DBUILD_TESTS=ON -DCMAKE_CXX_FLAGS="-fsanitize=thread" && cmake --build build-tsan && ./build-tsan/tests/integration_test`
|
||||
5. `gitnexus_detect_changes()`
|
||||
6. Commit: `fix: function-local static caches → thread_local in sys_vars.cpp`
|
||||
|
||||
---
|
||||
|
||||
### B2. `sRegelnAusfuehren` atomar machen
|
||||
|
||||
**Dateien:** `src/core/regelmaschine.hpp`, `src/core/regelmaschine.cpp`
|
||||
|
||||
**Ablauf:**
|
||||
1. `regelmaschine.hpp`: `#include <atomic>` hinzufügen
|
||||
2. `static bool sRegelnAusfuehren;` → `static std::atomic<bool> sRegelnAusfuehren{true};`
|
||||
3. `regelmaschine.cpp`: Alle Zugriffe auf `sRegelnAusfuehren` prüfen:
|
||||
- Lesend: `if(sRegelnAusfuehren)` → `if(sRegelnAusfuehren.load(std::memory_order_acquire))`
|
||||
- Schreibend: `sRegelnAusfuehren = val` → `sRegelnAusfuehren.store(val, std::memory_order_release)`
|
||||
4. Build + Tests
|
||||
5. `gitnexus_detect_changes()`
|
||||
6. Commit: `fix: sRegelnAusfuehren → std::atomic<bool>`
|
||||
|
||||
---
|
||||
|
||||
### B3. DLL-Interface mit Mutex schützen
|
||||
|
||||
**Datei:** `src/core/rw_dll.cpp`
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "xmlRegelWerk", direction: "upstream"})` — alle Caller
|
||||
2. `gitnexus_impact({target: "RegelWerkFree", direction: "upstream"})` — alle Caller
|
||||
3. `rw_dll.cpp` öffnen, `#include <mutex>` hinzufügen
|
||||
4. File-scope: `static std::mutex rwMutex;` hinzufügen
|
||||
5. `xmlRegelWerk()`: Erste Zeile nach Variablen-Deklarationen → `std::lock_guard<std::mutex> lock(rwMutex);`
|
||||
6. `RegelWerkFree()`: Erste Zeile → `std::lock_guard<std::mutex> lock(rwMutex);`
|
||||
7. Build + Tests + Integrationstest
|
||||
8. `gitnexus_detect_changes()`
|
||||
9. Commit: `fix: mutex guard for DLL interface functions`
|
||||
|
||||
---
|
||||
|
||||
## Phase C — Robustheit (2 Änderungen)
|
||||
|
||||
### C1. Exception-Sicherheit — `class_steuer.cpp:73`
|
||||
|
||||
**Datei:** `src/domain/class_steuer.cpp`
|
||||
|
||||
**Vorher:**
|
||||
```cpp
|
||||
catch(...) {
|
||||
Debug::logError("...");
|
||||
}
|
||||
```
|
||||
|
||||
**Nachher:**
|
||||
```cpp
|
||||
catch(const std::exception& e) {
|
||||
Debug::logError(std::string("...") + e.what());
|
||||
return false;
|
||||
}
|
||||
catch(...) {
|
||||
Debug::logError("... unknown exception");
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "class_steuer", direction: "upstream"})`
|
||||
2. `class_steuer.cpp` öffnen, `#include <exception>` prüfen/ergänzen
|
||||
3. `catch(...)` durch die differenzierte Variante ersetzen
|
||||
4. Prüfen ob `return false` bereits vorhanden ist, sonst ergänzen
|
||||
5. Build + Tests
|
||||
6. `gitnexus_detect_changes()`
|
||||
7. Commit: `fix: distinguish exception types in class_steuer.cpp`
|
||||
|
||||
---
|
||||
|
||||
### C2. `ConfigUnion` → `std::variant`
|
||||
|
||||
**Datei:** `src/core/config.hpp` (und alle Includer)
|
||||
|
||||
**Vorher:**
|
||||
```cpp
|
||||
union ConfigUnion {
|
||||
char* s;
|
||||
int i;
|
||||
char c;
|
||||
void* p;
|
||||
double d;
|
||||
};
|
||||
```
|
||||
|
||||
**Nachher:**
|
||||
```cpp
|
||||
#include <variant>
|
||||
using ConfigUnion = std::variant<char*, int, char, void*, double>;
|
||||
```
|
||||
|
||||
**Ablauf:**
|
||||
1. `gitnexus_impact({target: "ConfigUnion", direction: "upstream"})` — ALLE Zugriffsstellen finden (critical!)
|
||||
2. Alle Zugriffe auditieren: `union.member` → `std::get<T>(variant)`
|
||||
- `.s` → `std::get<char*>(val)` oder `std::get<0>(val)`
|
||||
- `.i` → `std::get<int>(val)` oder `std::get<1>(val)`
|
||||
- usw.
|
||||
3. Alle Zugriffe einzeln ersetzen
|
||||
4. Build — erwarte Compile-Fehler an Stellen mit `.member`-Zugriff, die übersehen wurden → fixen
|
||||
5. Tests
|
||||
6. `gitnexus_detect_changes()`
|
||||
7. Commit: `refactor: ConfigUnion → std::variant`
|
||||
|
||||
---
|
||||
|
||||
## Phase D — Testbarkeit (3 strategische Änderungen)
|
||||
|
||||
### D1. Testabdeckung: Prädikate Batch 2
|
||||
|
||||
**Neue Datei:** `tests/predicates_batch2_test.cpp`
|
||||
|
||||
**Struktur (Kopie von `predicates_batch1_test.cpp`):**
|
||||
```cpp
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include "catch2/catch_amalgamated.hpp"
|
||||
#include "mock_leistung.hpp"
|
||||
// Predicate-Headers includieren
|
||||
|
||||
TEST_CASE("GOP_Menge_Selector", "[predicates]") {
|
||||
// Test mit MockLeistung
|
||||
}
|
||||
```
|
||||
|
||||
**Zu testende Prädikate (10 Stück):**
|
||||
1. `gop_menge_selector.hpp` — GOP-Mengen-Prüfung
|
||||
2. `ist_element_von.hpp` — Set-Membership
|
||||
3. `nicht_disjunkt.hpp` — Nicht-Disjunktheit
|
||||
4. `pruefe_patientenalter.hpp` — Altersprüfung
|
||||
5. `ist_op_datum.hpp` — OP-Datum-Prüfung
|
||||
6. `diagnosen_erfuellt.hpp` — Diagnose-Prüfung
|
||||
7. `le_hat_berechtigung.hpp` — LE-Berechtigung
|
||||
8. `kennzeichen_ist_element_von.hpp` — Kennzeichen-Prüfung
|
||||
9. `hat_datum.hpp` — Datums-Prüfung
|
||||
10. `ist_gueltiges_datum.hpp` — Gültiges-Datum-Prüfung
|
||||
|
||||
**Ablauf:**
|
||||
1. `predicates_batch1_test.cpp` lesen — Pattern verstehen
|
||||
2. `mock_leistung.hpp` lesen — MockLeistung API verstehen
|
||||
3. Jeden Predicate-Header lesen — `operator()` Signatur + Parameter verstehen
|
||||
4. Test-Struktur: Pro Predicate mindestens 2 Test Cases (true + false)
|
||||
5. `tests/CMakeLists.txt` ergänzen: `add_rw_catch_test(predicates_batch2_test)`
|
||||
6. Build + `./build/tests/predicates_batch2_test`
|
||||
7. `gitnexus_detect_changes()`
|
||||
8. Commit: `test: predicates batch 2 — 10 standalone Prädikate`
|
||||
|
||||
---
|
||||
|
||||
### D2. Testabdeckung: Aktionen Batch 1
|
||||
|
||||
**Neue Datei:** `tests/actions_batch1_test.cpp`
|
||||
|
||||
**Zu testende Aktionen (10 Stück):**
|
||||
1. `leistung_hinzu_dahinter.hpp` — Leistung einfügen
|
||||
2. `wertaenderung.hpp` — Wertänderung
|
||||
3. `proz_wertaenderung.hpp` — Prozentuale Wertänderung
|
||||
4. `umfaerbe.hpp` — Umfärben
|
||||
5. `taetigkeit_umsetzen.hpp` — Tätigkeit umsetzen
|
||||
6. `setze_lug.hpp` — LUG setzen
|
||||
7. `setze_lglug.hpp` — LGLUG setzen
|
||||
8. `gop_hinzusetzen.hpp` — GOP hinzusetzen
|
||||
9. `gop_menge_hinzu.hpp` — GOP-Menge hinzu
|
||||
10. `setze_alpha_extension.hpp` — Alpha-Extension setzen
|
||||
|
||||
**Ablauf:**
|
||||
1. `actions_test.cpp` lesen — Pattern verstehen
|
||||
2. `mock_leistung.hpp` lesen — welche Setter/Methoden existieren für Aktionen
|
||||
3. Jeden Action-Header lesen — `operator()` Signatur verstehen
|
||||
4. Tests schreiben (pro Action: Setup → Ausführen → Assertions auf MockLeistung)
|
||||
5. `tests/CMakeLists.txt` ergänzen
|
||||
6. Build + `./build/tests/actions_batch1_test`
|
||||
7. `gitnexus_detect_changes()`
|
||||
8. Commit: `test: actions batch 1 — 10 standalone Aktionen`
|
||||
|
||||
---
|
||||
|
||||
### D3. Integrationstest für `sb_meth`-Familie
|
||||
|
||||
**Neue Datei:** `tests/sb_meth_integration_test.cpp`
|
||||
|
||||
**Ansatz:** XML-Testdaten → `Patientenfall::newFromXML()` → `regelFall()` → Ergebnis-XML → Assertions
|
||||
|
||||
**Ablauf:**
|
||||
1. `integration_test.cpp` lesen — Pattern verstehen (XML laden, Patient erstellen, Regelwerk ausführen)
|
||||
2. Test-XML-Dateien für SB20, SB34, SB46 erstellen (minimale Testszenarien)
|
||||
3. Tests schreiben: `TEST_CASE("SB20 - basic", "[integration][sb]")`
|
||||
4. Erwartete Ergebnisse im Ausgabe-XML prüfen (Leistung gestrichen, umgefärbt, etc.)
|
||||
5. `tests/CMakeLists.txt` ergänzen
|
||||
6. Build + `./build/tests/sb_meth_integration_test`
|
||||
7. `gitnexus_detect_changes()`
|
||||
8. Commit: `test: integration tests for SB methods`
|
||||
|
||||
---
|
||||
|
||||
## Phase E — Modernisierung (3 Bereiche)
|
||||
|
||||
### E1. Makros in `rw_macros.hpp` ersetzen
|
||||
|
||||
**Datei:** `src/core/rw_macros.hpp`
|
||||
|
||||
**Ersetzungen (schrittweise, je ein Commit):**
|
||||
|
||||
1. `FOR`/`REP` → `for(size_t i = s; i < n; ++i)` (direkt, kein `std::views::iota` wegen Compiler-Support)
|
||||
- `gitnexus_impact({target: "FOR", direction: "upstream"})` → alle Verwendungen finden
|
||||
- Jede Verwendung einzeln ersetzen
|
||||
- Makro am Ende entfernen
|
||||
|
||||
2. `RW_ARRAYSIZE` → `std::size`
|
||||
- `gitnexus_impact({target: "RW_ARRAYSIZE", direction: "upstream"})`
|
||||
- `RW_ARRAYSIZE(arr)` → `std::size(arr)` (benötigt `#include <iterator>`)
|
||||
- Makro entfernen
|
||||
|
||||
3. `LL` → `std::int64_t`
|
||||
- `gitnexus_impact({target: "LL", direction: "upstream"})`
|
||||
- Alle `LL`-Verwendungen durch `std::int64_t` ersetzen
|
||||
- `#include <cstdint>` wo nötig
|
||||
|
||||
4. `ALL` → direkte Iterator-Paare
|
||||
- Nicht ersetzen, sondern dokumentieren dass es deprecated ist
|
||||
- Zu viele Verwendungen für einen simplen Batch
|
||||
|
||||
**Ablauf pro Makro:**
|
||||
1. Impact-Analyse
|
||||
2. Alle Verwendungen ersetzen
|
||||
3. Build — Compile-Fehler an übersehenen Stellen fixen
|
||||
4. Tests
|
||||
5. Makro-Definition entfernen
|
||||
6. `gitnexus_detect_changes()`
|
||||
7. Commit
|
||||
|
||||
---
|
||||
|
||||
### E2. Tote Perl-Tools löschen
|
||||
|
||||
**Zu löschende Dateien:**
|
||||
```
|
||||
tools/make.pl
|
||||
tools/clean.pl
|
||||
tools/test_rw.pl
|
||||
tools/rw_mr.pl
|
||||
tools/gen2list.pl
|
||||
tools/idstring.pl
|
||||
```
|
||||
|
||||
**Ablauf:**
|
||||
1. `git rm tools/make.pl tools/clean.pl tools/test_rw.pl tools/rw_mr.pl tools/gen2list.pl tools/idstring.pl`
|
||||
2. Build — sicherstellen dass nichts fehlschlägt (diese Tools sind nicht im Build)
|
||||
3. `gitnexus_detect_changes()`
|
||||
4. Commit: `chore: remove dead Perl build tools (hpux, borland, sybase, svn era)`
|
||||
|
||||
---
|
||||
|
||||
### E3. Tote Konfigurationen und Plattform-Guards
|
||||
|
||||
**Teil 1 — `config/kvai.ini`:**
|
||||
```bash
|
||||
git rm config/kvai.ini
|
||||
```
|
||||
|
||||
**Teil 2 — `src/util/debug.cpp` `_HPUX`-Guards:**
|
||||
1. Zeilen mit `#ifdef _HPUX` / `#ifndef _HPUX` / `#endif` identifizieren (~Zeilen 20, 445)
|
||||
2. `_HPUX`-Block komplett entfernen (Code zwischen `#ifdef` und `#else`/`#endif`)
|
||||
3. Build — sicherstellen dass nichts fehlschlägt
|
||||
|
||||
**Teil 3 — `src/util/debug.cpp` `__WIN32__`-Guards:**
|
||||
1. Prüfen ob Windows noch ein Target ist (CI baut nur Linux)
|
||||
2. Wenn nicht: `__WIN32__`-Block entfernen
|
||||
3. Wenn doch: so belassen
|
||||
|
||||
**Teil 4 — `src/aktsource_dummies/` leeres Verzeichnis:**
|
||||
```bash
|
||||
rmdir src/aktsource_dummies
|
||||
```
|
||||
|
||||
**Ablauf:**
|
||||
1. Jeweils einzeln ausführen
|
||||
2. Build nach jeder Änderung
|
||||
3. `gitnexus_detect_changes()`
|
||||
4. Commits: `chore: remove dead HP-UX platform guards` etc.
|
||||
|
||||
---
|
||||
|
||||
## Phase F — Build (1 Änderung)
|
||||
|
||||
### F1. Toten `RW_DLL`-Define entfernen
|
||||
|
||||
**Dateien:** `CMakeLists.txt`, `src/core/rw_implementation.cpp`
|
||||
|
||||
**Ablauf:**
|
||||
1. `CMakeLists.txt`: `add_compile_definitions(RW_DLL)` entfernen
|
||||
2. `src/core/rw_implementation.cpp`: `#ifdef RW_DLL`-Block + Code darin prüfen — wenn DLL-spezifisch und DLL nicht mehr gebaut wird → entfernen
|
||||
3. Build — wenn Compile-Fehler durch fehlende `#ifdef RW_DLL`-Definitionen → prüfen ob Code noch gebraucht wird
|
||||
4. Tests
|
||||
5. `gitnexus_detect_changes()`
|
||||
6. Commit: `chore: remove dead RW_DLL define and guards`
|
||||
|
||||
---
|
||||
|
||||
## Verifikation nach jeder Phase
|
||||
|
||||
```bash
|
||||
# In Projekt-Root ausführen:
|
||||
|
||||
# 1. Build
|
||||
cmake -B build -G Ninja -DBUILD_TESTS=ON
|
||||
cmake --build build -j$(sysctl -n hw.logicalcpu)
|
||||
|
||||
# 2. Alle Tests
|
||||
ctest --test-dir build --output-on-failure
|
||||
|
||||
# 3. Integrationstest separat
|
||||
./build/tests/integration_test
|
||||
|
||||
# 4. Statische Analyse
|
||||
cppcheck --enable=all --inconclusive src/ 2>&1 | head -50
|
||||
|
||||
# 5. gitnexus_detect_changes()
|
||||
npx gitnexus detect-changes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checkliste pro Änderung
|
||||
|
||||
- [ ] `gitnexus_impact` — Blast Radius verstanden, Risiko akzeptabel
|
||||
- [ ] Code-Änderung — nur das Nötigste, existierenden Stil respektieren
|
||||
- [ ] Build — `cmake --build build` erfolgreich
|
||||
- [ ] Tests — `ctest --test-dir build --output-on-failure` alle grün
|
||||
- [ ] Integrationstest — `./build/tests/integration_test` erfolgreich
|
||||
- [ ] `gitnexus_detect_changes` — nur erwartete Symbole betroffen
|
||||
- [ ] Commit — ein Commit pro logischer Änderung, Sprache Deutsch
|
||||
|
||||
---
|
||||
|
||||
## Geschätzte Gesamtanzahl Commits: ~20–25
|
||||
|
||||
| Phase | Commits |
|
||||
|-------|---------|
|
||||
| A | 5 (A1=1, A2=1, A3=3) |
|
||||
| B | 3 |
|
||||
| C | 2 |
|
||||
| D | 3 |
|
||||
| E | 8 (E1=4, E2=1, E3=3) |
|
||||
| F | 1 |
|
||||
Reference in new issue
Block a user