# Beweise — die Messungen zu KONZEPT-WINDOWS.md § 3 Diese zwei Skripte sind die Grundlage für die Entscheidung, Rippy v5 in TypeScript/Node zu bauen. Sie beantworten die einzige Frage, an der das ganze Konzept hängt: > **Kann Node überhaupt alles, was Rippy am Laufwerk braucht?** Wäre die Antwort nein gewesen, wäre das Konzept wertlos gewesen. Deshalb sind sie zuerst gelaufen — vor der ersten Zeile Konzept. `AGENTS.md` Regel D: *„Externe Schnittstellen NIE aus dem Kopf."* --- ## Nachstellen ``` npm install koffi node laufwerk.js ``` Gemessen am 30.08.2026 mit Node v24.19.0, koffi 3.1.6, an einem HL-DT-ST BD-RE BU40N (USB) mit eingelegter Blu-ray. --- ## `laufwerk.js` — Win32-Laufwerkszugriff Ruft dieselben Steuercodes auf wie `src/rippy/drives/win_ioctl.py` im Docker-Zweig. **Nur lesend** — kein Auswerfen, kein Verriegeln. ``` 1. GetLogicalDrives + GetDriveTypeW -> optische Laufwerke: [ 'G' ] 2. CreateFileW \\.\G: (Zugriff 0) -> offen CreateFileW \\.\G: (GENERIC_READ) -> offen 3. IOCTL_STORAGE_QUERY_PROPERTY -> Hersteller: HL-DT-ST | Modell: BD-RE BU40N | Rev: 1.03 | Serial: 0025114C0149 4. IOCTL_STORAGE_CHECK_VERIFY2 -> Medium eingelegt 5. IOCTL_CDROM_DISK_TYPE -> Win32-Fehler 50 6. IOCTL_DISK_GET_LENGTH_INFO -> 33.759.690.752 Bytes (33,76 GB) => Blu-ray ``` **Punkt 5 ist kein Fehlschlag.** Fehler 50 ist `ERROR_NOT_SUPPORTED` — genau das, was der Python-Treiber an diesem Laufwerk auch sieht (`SAVEPOINT.md`, v4.0-rc11, Abschnitt „Das Laufwerk"). Node verhält sich identisch. Die Lehre steht im alten Code und gilt weiter: **Die Disc-Einordnung darf sich nicht auf `IOCTL_CDROM_DISK_TYPE` verlassen — die Größe ist der verlässliche Weg.** Punkt 2 zeigt die Unterscheidung, die in rc11 teuer war: `Zugriff 0` fragt das **Gerät**, `GENERIC_READ` fragt das **Medium**. Bei einer gestörten Disc scheitert das zweite und das erste geht weiter — wer nur eins probiert, hält ein antwortendes Laufwerk für tot. --- ## `leine.js` — die Prozess-Leine (Job Object) Stellt den Befund aus `SAVEPOINT.md` v4.0-rc10 nach: Windows räumt Kindprozesse **nicht** auf. Ein hart beendeter Rippy hinterlässt ein `makemkvcon`, das das Laufwerk festhält, und jeder spätere Rip scheitert. Das Skript setzt eine Arbeitsgruppe mit `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`, startet ein langlebiges Kind und lässt sich dann hart abschießen — `taskkill /F` **ohne** `/T`, also genau das, was bei einem Absturz und beim Drüber-Installieren passiert. ``` 1. CreateJobObjectW -> Arbeitsgruppe angelegt 2. SetInformationJobObject -> KILL_ON_JOB_CLOSE gesetzt 3. AssignProcessToJobObject -> dieser Prozess hängt in der Gruppe 4. Kindprozess gestartet, PID 16040 vor dem Abschuss: Eltern lebt: True Kind lebt: True taskkill /F /PID 29488 -> ERFOLGREICH danach: Eltern lebt: False Kind lebt: False ``` Nachstellen (PowerShell): ```powershell $p = Start-Process node -ArgumentList "leine.js" -PassThru -RedirectStandardOutput out.txt Start-Sleep 3 $kind = (Select-String -Path out.txt -Pattern 'KIND-PID=(\d+)').Matches[0].Groups[1].Value taskkill /F /PID $p.Id Start-Sleep 2 Get-Process -Id $kind -ErrorAction SilentlyContinue # muss LEER sein ``` --- ## Zwei weitere Messungen aus § 3, ohne eigenes Skript **`node:sqlite` ist in Node 24 eingebaut:** ``` node -e "const s=require('node:sqlite'); const db=new s.DatabaseSync(':memory:'); db.exec('CREATE TABLE t (a TEXT)'); db.prepare('INSERT INTO t VALUES (?)').run('geht'); console.log(db.prepare('SELECT a FROM t').get().a)" geht ``` ⚠️ Das ist in **Node 24.19.0** gemessen, nicht in Electron. Electron baut sein Node mit eigenen Flags — ob `node:sqlite` dort vorhanden ist, ist der erste Handgriff in Etappe W-0. **npm 11 blockiert Install-Skripte:** ``` npm warn allow-scripts koffi@3.1.6 (install: node ./cnoke.cjs -P . --prebuild --release) ``` koffi lädt trotzdem — es bringt vorgebaute Binärdateien mit. Die Warnung gehört in die Bau-Anleitung, sonst sucht eines Tages jemand an der falschen Stelle.