Skip to content

Commit 43fd220

Browse files
Axel051171claude
andcommitted
feat(t1b): kfx auf T1b ohne Codeaenderung, und mfi sagt jetzt ab (MF-1023/1024)
Zwei MF in einem Commit, und das gehoert begruendet: MF-1023 (mfi) war fertig und wurde vom Tor „build define parity" abgewiesen — aus einem Grund, der selbst ein Fund ist (unten). Beim Beheben lag MF-1024 (kfx) schon im Baum, und die abgeleiteten Zahlen (STAND.md, VERIFICATION_TIERS.md) sind kumulativ. Sie kuenstlich zu trennen haette einen Zwischenstand erfunden, den es nicht gab. ═══ MF-1024: kfx von T3 auf T1b, ohne eine Zeile Codeaenderung ═══ Der Leser war **richtig** — ihm fehlte nur ein Abbild von fremder Hand. hxcfes `KRYOFLUXSTREAM`-Modul (ACCESS = RW) schreibt je Spur eine eigene Datei in der kanonischen Benennung `trackNN.S.raw`; zwei davon liegen jetzt im Korpus. Gemessen, ohne Aenderung am Plugin: Sonde ja, Konfidenz 75 (MF-729: 50..79 = „Struktur gelesen") open 0, 1 Zylinder, 1 Kopf (ein Strom IST eine Spur) Spur 0 rc=0, 0 Sektoren, 115631 Rohbyte = die ganze Datei Die Zusicherung ist **flussgerecht**, nicht sektorweise: ein KryoFlux-Strom liefert keine Sektoren, und die Sektortafel dieses Tests waere fuer ihn das falsche Mass (dieselbe Ueberlegung wie bei `mfi` in MF-1020). Stattdessen prueft sie die STRUKTUR mit `uft_kfc_stream_is_valid()` (MF-919): die Funktion laeuft die OOB-Kette ab und haelt die in den Bloecken **eingebettete** Stromposition gegen ihre eigene Zaehlung der Nicht-OOB-Bytes. Gemessen je Strom **10 OOB-Bloecke und 3 Indexmarken** — eine Aussage ueber die Datei, nicht ueber unseren Code. **Und die Gegenprobe gehoert dazu, weil `kfx` genau daran einmal gescheitert ist.** MF-919 hat gemessen, dass die alte Sonde `0x0D`-Bytes ZAEHLTE und in 512 Zufallsbytes nie „nein" sagen konnte. Heute fallen durch: 64 KB Pseudozufall OOB 1, Index 0 -> ungueltig ein gekipptes 0x0D im Strom OOB 7, Index 3 -> ungueltig eine IMD-Datei OOB 24, Index 0 -> ungueltig Ein Erkenner, dessen „nein" nicht vorgefuehrt ist, ist kein Erkenner. ═══ MF-1023: mfi — der gepackte Strom war der Sektorinhalt ═══ Zwei Befunde am MFI-Leser, gemessen an `hxcfe_pc160.mfi`. **Die Kopfzahl der Datei wurde ignoriert.** `uint8_t c = count / 2; uint8_t h = count % 2;` — fest zwei Koepfe. Unabhaengig nachgelesen sagt die Datei: `cyl_count = 42` (Aufloesung 0), `head_count = 1`, 42 belegte Eintraege. Gemeldet wurden **21 Zylinder und 2 Koepfe** — die halbe Diskette auf einem Kopf, den es nicht gibt. Gestalt von MF-1016 (`jv1` erfand eine zweite Seite). Nebenbei: der Lauf brach bei einem leeren Spureintrag ab („End marker"). Den gibt es im Format nicht — MAME liest genau `cyl_count * head_count` Eintraege und behandelt einen leeren als leere Spur. Gestalt von MF-1017 (`jv3`). **In dieser Pruefdatei ist kein Eintrag leer**, der Abbruch hat hier also nicht zugeschlagen; Befund 1 allein erklaert die 21. Das steht so im Code, weil eine Ursache, die man nicht gemessen hat, keine ist. **Der zlib-Strom war der Sektorinhalt.** „Sektor 0" begann mit `78 9C ED` — `78 9C` ist der zlib-Kopf —, und bei mehr als 65535 Byte wurde still abgeschnitten. Das Wissen stand im Kommentar („Track data is zlib-compressed") und nicht im Code; der Aufrufer bekam `UFT_OK`. Gestalt von MF-864. `read_track` sagt jetzt `UFT_ERROR_NOT_SUPPORTED`; eine leere Spur bleibt eine Aussage und liefert `UFT_OK` ohne Inhalt. **Warum nicht entpackt wird — P3-329.** Der Baum hat keinen erreichbaren Entpacker: CMake setzt bei `ZLIB_FOUND` ein Makro, das **keine** C-Datei liest; `uft_imz.c` prueft einen ANDEREN Namen, den niemand definiert; die `.pro` des primaeren Baus kennt zlib nicht. Das zu aendern ist eine Eigentuemer-Entscheidung (Anti-Ziel „keine neuen Dependencies"), die drei Wege stehen mit ihren Kosten in P3-329. Die Merkmalstafel sagt es jetzt genau: `Read: PARTIAL` mit Begruendung — gelesen werden Kennung, Kopf, Geometrie und Spurtabelle, die Spurdaten nicht. Der Weg dahin gehoert dazu: erst stand `UNSUPPORTED` da, und `test_capability_manifest` hat zu Recht geblockt („ZU WENIG"), weil sein Traeger fuer „Read" hart `open && read_track` ist; dann war `CAP_READ` entfernt — auch zu grob, denn „nicht lesbar" ist eine andere Aussage als „liest den Behaelter, nicht die Daten". **`mfi` geht NICHT auf T1b**, obwohl das Fixture im Korpus liegt und die Provenienz vollstaendig ist: der Manifest-Eintrag verknuepft keinen Test. T1b heisst „ein Fremdwerkzeug hat die Datei erzeugt und UFT liest sie" — UFT liest den Behaelter, nicht die Daten. ═══ Warum das erste MF-1023 abgewiesen wurde ═══ Das Tor `scripts/define_parity_gate.py` meldete: C:UFT_HAS_ZLIB ist keine Abweichung mehr — Eintrag aus scripts/define_parity_baseline.json entfernen Die Grundlinie fuehrt `C:UFT_HAS_ZLIB` als „kein Verbraucher im Quellcode". Ich hatte den Makronamen in einem **Zeichenketten-Literal** der Merkmalstafel genannt — und das Tor streift Kommentare ab, Zeichenketten aber nicht. Zu Recht: ein Makro kann als WERT benutzt werden, und `UFT_VERSION_STRING` waere sonst ein Falschbefund. Also hat **meine Prosa ein Tor erfuellt**, ohne dass sich am Code etwas geaendert haette. Die Grundlinie zu kuerzen waere die falsche Antwort gewesen — es gibt weiterhin keinen Verbraucher. Der Name steht jetzt nur noch im Kommentar, und eine Warnung fuer die naechste Hand steht daneben. Kennzahl (Regel 9): **T1b 35 → 36**, **T3 26 → 25** (`kfx`). `mfi` bleibt T2. Korpus: +230 KB in zwei Stromdateien; Tore Korpus-Herkunft 0 Befunde bei 43 Eintraegen, Korpus-Inhalt 45 gegen Grundlinie 45, define-parity 0 Abweichungen. Tests: 402/402 gruen (ein benannter Skip: test_freezer); `tests/test_fremde_hand_liest.c` jetzt **14 gruen, 0 rot**. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BHdqfaZ5RFb1HPcw7NYoEY
1 parent 369f3d8 commit 43fd220

10 files changed

Lines changed: 641 additions & 385 deletions

File tree

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ honesty:** most parsers are currently validated only against synthetic
1414
round-trip tests and/or specs verified against authoritative reference
1515
implementations — **not yet against a real-disk reference corpus**. The
1616
per-format verification-tier table now exists and is kept current:
17-
[`docs/VERIFICATION_TIERS.md`](docs/VERIFICATION_TIERS.md)**26 of 88
18-
formats are T3 (unverified)**; proven: T1=2, T1b=35, T2=25. 9 hardware controllers
17+
[`docs/VERIFICATION_TIERS.md`](docs/VERIFICATION_TIERS.md)**25 of 88
18+
formats are T3 (unverified)**; proven: T1=2, T1b=36, T2=25. 9 hardware controllers
1919
via a type-driven HAL (Greaseweazle fully wired, **hardware bench pass
2020
pending** — still open in 4.1.6, and it needs a machine we do not have
2121
(see "Please break it" below); SCP-Direct M3.1 mock-validated; KryoFlux
@@ -121,8 +121,8 @@ not made green. The reference image is on the procurement list.
121121
**What this release still cannot do** — this list is part of the release,
122122
not a footnote:
123123

124-
- **26 of 88 tier-tracked formats are unverified (T3).** Proven: T1=2,
125-
T1b=35, T2=25. (Was 57/17 — `mfi` and then `d77` moved up in v4.1.7,
124+
- **25 of 88 tier-tracked formats are unverified (T3).** Proven: T1=2,
125+
T1b=36, T2=25. (Was 57/17 — `mfi` and then `d77` moved up in v4.1.7,
126126
each after a real parser bug was fixed against a named reference:
127127
MAME's `mfi_dsk.h`, and the pc98.org D88 spec plus MAME's `d88_dsk`;
128128
`dim_atari` in MF-690; `do` in MF-716 — the first Apple format
@@ -312,7 +312,7 @@ verification).
312312
**Honest verification status** (script-generated, see
313313
[`docs/VERIFICATION_TIERS.md`](docs/VERIFICATION_TIERS.md) for the
314314
per-format table and [`docs/VERIFICATION_PLAN.md`](docs/VERIFICATION_PLAN.md)
315-
for the tier definitions): **T1=2, T1b=35, T2=25, T3=26** of 88.
315+
for the tier definitions): **T1=2, T1b=36, T2=25, T3=25** of 88.
316316

317317
- **T1** (real reference image): FDI — a real 1994 TR-DOS disk magazine
318318
(83-cylinder, partially formatted last track; image local-only for

docs/OPEN_ITEMS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ offen).
520520
| P3-326 | **Der MFI-Leser gibt den zlib-GEPACKTEN Strom als Spurdaten aus — und sein eigener Dateikopf sagt, dass die Daten gepackt sind.** `src/formats/mfi/uft_mfi.c` Zeile 43: „Track data is zlib-compressed. Each flux cell is 4 bytes (LE32)“. Der Code entpackt nicht | **gemessen MF-1020** an einer von hxcfe erzeugten MFI-Datei (`tests/corpus_free/hxcfe_pc160.mfi`, Modul `MAME_MFI`): der Leser meldete **21 Zylinder** (in der Datei stehen 40) und lieferte fuer Spur 0 einen Block, dessen erste Bytes **`78 9C ED`** sind. `78 9C` ist der **zlib-Kopf** (Deflate, Standardstufe). Das Wissen stand also im Kommentar und nicht im Code — dieselbe Gestalt wie MF-864 (`flux_decode_fm()`, dessen Sektorteil aus zwei Kommentaren bestand). **Und zlib ist im Baum verfuegbar:** `src/formats/imz/uft_imz.c` bindet `zlib.h` ein und entpackt damit | ⚠ **offen, und das Orakel liegt daneben.** `src/samdisk/mfi.cpp` (MIT, im Baum) gibt den Aufbau vollstaendig: Kennung `"MESSFLOPPYIMAGE"`, dann `cyl_count`, `head_count`, `form_factor`, `variant` (je LE32); `cyl_count >> 30` ist die Auflösung (Halb-/Viertelspur) und `cyl_count & 0x3FFFFFFF` die Zylinderzahl — **das erklaert die 21 vermutlich, ist aber noch nicht gemessen**. Je Spur folgt `{offset, compressed_size, uncompressed_size, write_splice}`, die Daten liegen bei `offset` und werden mit `uncompress()` entpackt; jede Zelle ist LE32 mit 28 Bit Zeit (`& 0x0FFFFFFF`) und 4 Bit magnetischer Ausrichtung, und die Summe der Zeiten einer Spur muss **200 000 000** sein. <br>**Was dabei mein eigener Fehler war und dazugehoert:** die erste Fassung von `tests/test_fremde_hand_liest.c` hat MFI mit einer SEKTOR-Zusicherung geprueft. MFI ist ein **Flussformat** — auch nach dem Entpacken kommen dort keine Sektoren heraus, sondern Zellzeiten; Sektoren entstehen erst durch einen MFM-Dekoder. Die flussgerechte Pruefung (Zellenzahl, Gesamtzeit, Ausrichtungsbits) ist der naechste Schritt. <br>Kennzahl: **T3 ↓** — `mfi` steht auf T2 und die Datei fuer T1b liegt bereits im Korpus; es fehlt allein der Entpacker |
521521
| P3-327 | **`v9t9` bleibt T3, weil das Orakel eine LEERE Diskette erzeugt und dabei Erfolg meldet.** hxcfe hat einen `TI994A_V9T9`-Schreiber mit ACCESS `RW`, aber keinen Weg, ihm eine TI-99-Diskette mit Inhalt zu uebergeben | **gemessen MF-1021.** `hxcfe -finput:uft_ti_dssd.img -conv:TI994A_V9T9` erzeugt 184 320 Byte — die richtige Groesse — und meldet Erfolg. Die Datei ist **100 % `0xF6`**, null Treffer fuer das Selbstbeschreibungs-Muster der Eingabe (erwartet 720). Grund: hxcfes RAW-Lader erkennt die TI-Geometrie (40×2×9×256) nicht, und `hxcfe -rawlist` hat **keinen** TI-Eintrag (durchsucht nach ti99/TI_/texas: kein Treffer; erfundene Layoutnamen werden abgewiesen). Der Schreiber fand also keine Spuren und fuellte mit dem Formatier-Fuellbyte. UFTs Leser lag dabei **richtig**: er meldete 40 Zylinder, 2 Koepfe, 9 Sektoren und gab wieder, was in der Datei stand | ⚠ **offen, und der Blocker ist benannt.** `v9t9` hat bis heute **keinen einzigen Test** — er waere mit diesem Fixture entstanden und haette nichts bewiesen. Die leere Datei bleibt als **Beleg des Befunds** im Korpus (Manifest-Eintrag sagt das, kein Test verknuepft, keine Anrechnung). <br>**Was es aufloesen wuerde, in dieser Reihenfolge:** (a) **FluxEngine** (`tools/uft-scout/work/fluxengine`, baubar) — es kennt TI-99 und schreibt Abbilddateien; (b) MAMEs `ti99_dsk`-Format als Spec-Referenz fuer den Sektoraufbau; (c) ein TI-99-Emulator, der V9T9 selbst schreibt. <br>**Die Lehre gilt ueber `v9t9` hinaus und steht deshalb hier:** ein erzeugtes Fixture ist erst dann ein Beleg, wenn sein Inhalt nachgewiesen ist. Fuer Sektorformate leistet das die Zusicherung selbst; fuer gepackte Container (`mfi` P3-326, `ipf` P3-315) braucht es einen Entpacker, und solange der fehlt, traegt die Datei **keine** Stufe |
522522
| P3-328 | **Tor 62 sieht einen erfundenen Fuellsektor nicht, wenn das `memset` VOR der Schleife steht — erster belegter Durchfall.** `scripts/audit_erfundene_sektoren.py` (Tor 62) sucht `memset(X->data, 0xE5, ...)` ohne `uft_sector_mark_missing(X)` innerhalb von sechs Zeilen, auf derselben Variablen. Ein wiederverwendeter Fuellpuffer, der einmal vor der Schleife gefuellt und darin mehrfach angelegt wird, entgeht dieser Messung | **gemessen MF-1022** an `src/formats/sap/uft_sap_plugin.c`: dort stand `memset(fill_buf, 0xE5, sizeof(fill_buf))` **vor** der Sektorschleife, und in der Schleife `uft_format_add_sector(track, s, fill_buf, ...)` **ohne** `uft_format_mark_last_missing()`. `uft_format_add_sector()` setzt laut eigenem Kopf `UFT_SECTOR_OK` und beide CRC-Flags auf „gut“ — die Fuellung war von echten Daten nicht zu unterscheiden (Klasse MF-980). Tor 62 meldete dafuer **0**, und seine Grundlinie kennt `uft_sap_plugin.c` nicht. Der Fall ist mit MF-1022 behoben; die **Messgrenze** ist es nicht | ⚠ **offen, und es ist die Klasse „Aufzaehlung statt Messung“ an einem Tor** — zum zweiten Mal nach MF-930, wo der Torkopf von Tor 57 acht Verdaechtige nannte und elf gemessen wurden. Hier ist es keine Aufzaehlung, sondern eine **Reichweite**: sechs Zeilen und dieselbe Variable. <br>**Was die Messung tragen wuerde:** nicht die Reichweite vergroessern (das verschiebt die Grenze nur), sondern die Frage umdrehen — **jeder Aufruf von `uft_format_add_sector*()`, dessen Datenzeiger auf einen Puffer zeigt, der im Rumpf mit einem Fuellbyte beschrieben wurde, braucht eine Kennzeichnung**, unabhaengig vom Abstand. Das ist eine Datenfluss-Frage und mit einem Regex nicht zu beantworten; ein Selbsttest muesste **genau diesen Fall** (Puffer vor der Schleife) als roten Fall enthalten, sonst beweist das neue Tor wieder nur sich selbst. <br>Kennzahl: **keine** der vier — Fundus, aber ein Tor mit bekannter Luecke ist teurer als kein Tor, weil seine **0** als Entwarnung gelesen wird (die Lehre aus `measurement_hit_wrong_class`) |
523+
| P3-329 | **zlib wird gefunden, gelinkt, mit einem Makro versehen — und erreicht keine einzige C-Datei.** Damit ist jedes gepackte Format im Baum blockiert: `mfi` (MAME-Fluss), `imz`, und alles weitere, was Deflate braucht | **gemessen MF-1023.** `src/core/CMakeLists.txt:45-48` setzt bei `ZLIB_FOUND` das Makro `UFT_HAS_ZLIB=1` (PRIVATE fuer `uft_core`) und linkt `ZLIB::ZLIB`. Gemessen ueber `git ls-files`: **keine** `.c`- oder `.h`-Datei in `src/` oder `include/` liest `UFT_HAS_ZLIB`. Die eine Datei, die zlib will — `src/formats/imz/uft_imz.c:19` — prueft `HAVE_ZLIB`, und **das definiert niemand**; sie faellt also immer in ihren Ersatzpfad („stored only“). Die `.pro`-Datei des PRIMAEREN Baus kennt zlib ueberhaupt nicht (kein `-lz`, kein `LIBS +=`), und `tests/CMakeLists.txt` bindet es auch nicht ein | ⚠ **offen, und es ist eine Eigentuemer-Entscheidung, keine Arbeit.** Zwei Makronamen fuer dieselbe Faehigkeit sind die Gestalt der Zahlendrift aus MF-541: eine Angabe an zwei Stellen. Aber die Loesung ist nicht „umbenennen“, sondern zu entscheiden, **ob zlib eine Abhaengigkeit dieses Baums ist**. Die Anti-Ziele in `.claude/CLAUDE.md` sagen „keine neuen Dependencies vorschlagen“, und der primaere Bau ist qmake — dort waere es eine echte Erweiterung. <br>**Die drei Wege, mit ihren Kosten:** (a) zlib verbindlich machen (qmake `LIBS += -lz`, CMake `ZLIB REQUIRED`, EIN Makroname) — dann liest `mfi` seine Spuren und geht auf T1b, das Fixture liegt schon im Korpus; (b) einen eigenen Inflate-Rumpf bauen — neuer ungepruefter Code im Decoder-Layer, faellt unter die EINFRIER-REGEL und braucht Rotbeweis plus benannte Referenz (RFC 1951); (c) es bleibt abgesagt, und die Merkmalstafeln sagen das — so steht es seit MF-1023 bei `mfi` (`Read: PARTIAL` mit Begruendung). <br>Kennzahl: **T3 ↓ / T1b ↑** fuer `mfi`, blockiert auf dieser Entscheidung. Solange sie offensteht, ist (c) richtig: besser eine benannte Absage als ein gepackter Strom, der als Sektor ausgegeben wird |
523524

524525
---
525526

docs/STAND.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
| Kennzahl | Stand | Richtung | Quelle |
1010
|---|---|---|---|
11-
| ungeprüfte **Format-Plugins** (T3) | **26** von 88 | runter | `docs/VERIFICATION_TIERS.md` |
11+
| ungeprüfte **Format-Plugins** (T3) | **25** von 88 | runter | `docs/VERIFICATION_TIERS.md` |
1212
| ungeprüfte **Dateisystem-Leser** | T0 1 · T1 4 · T1b 0 · T2 3 | runter | `docs/VERIFICATION_TIERS_FS.md` (MF-694) |
1313
| angebotene **Wandlungspfade** | **14**, davon 6 verlustfrei | rauf | `src/core/uft_roundtrip.c` |
1414
| leckende Tests | 0 zu halten | null halten | ASan/UBSan in CI |
@@ -39,7 +39,7 @@
3939

4040
## Was offen ist
4141

42-
`docs/OPEN_ITEMS.md` führt **7663** Zeilen in **82** Abschnitten.
42+
`docs/OPEN_ITEMS.md` führt **7664** Zeilen in **82** Abschnitten.
4343

4444
**erledigt** (1):
4545
- GCR-1 — der 6-and-2-Dekoder steht, 560 von 560 Sektoren belegt (MF-715)

0 commit comments

Comments
 (0)