doku(KF-6/KF-7): zwei eigene Befunde in die Matrix, und ein Zwischenfall ins Protokoll
KF-6 Space Grotesk deklariert 500 und 700, besitzt aber nur drei Dateien:
beide Gewichte zeigen Subset fuer Subset auf dieselben Bytes. Ein
font-bold auf Displaytext waere still wirkungslos. Beim Nachpruefen
einer Agentenbehauptung gefunden; Nachtrag beauftragt, ohne Download.
KF-7 commands/process.rs traegt denselben Bauplan wie der reparierte
Sweep-Test, mit festem sleep(300ms), genau einem Scan und festem
Port 61888. Vom KF-1-Agenten gemeldet, von mir uebernommen.
KF-1 auf 'umgesetzt' nachgezogen (067a3c2b + ea91c689).
Im Changelog das verschwundene node_modules: offline aus dem npm-Cache
wiederhergestellt, aber die Messungen von vier Agenten aus diesem Fenster
sind wertlos. Mit dem eigenen Messfehler derselben Minute — exit-Status von
tail statt von cargo protokolliert.
This commit is contained in:
1 parent
ea91c68960
commit
70489a23ab
2 files changed
+40
-1
No files matched your search
+3
-1
@@ -189,11 +189,13 @@ Zwei Befunde, die in **keinem** der beiden Audits stehen. Ich habe sie beim Nach
|
||||
|
||||
| ID | Was | Fundstelle | Status | Anmerkung |
|
||||
|---|---|---|---|---|
|
||||
| KF-1 | Der Beenden-Pfad erreicht jeden Daemon außer dem Tunnel | `state.rs:462` | umgesetzt | `067a3c2b` | per Test (3 Sonden des Agenten + 3 eigene) | `RemoteServer::shutdown_tunnel()` ist jetzt der eine Eintrittspunkt; `Drop` ruft dieselbe Methode statt einer zweiten Kopie. `take()` wie jeder andere Slot — ein zweiter Schlag ginge auf eine womöglich recycelte pid, unter Windows als `taskkill /T /F` auf einen fremden Baum. **Was ich selbst gefunden habe: die Reihenfolge ist begründet, aber nicht festgenagelt.** Der Tunnel muss zuerst sterben, weil das Internet ihn hindurch weiter zu den Daemons erreicht, die der Rest der Funktion gerade abräumt. Meine Sonde: den Aufruf ans Ende verschoben → alle 774 Tests bleiben grün. Nachtrag beauftragt. |
|
||||
| KF-1 | Der Beenden-Pfad erreicht jeden Daemon außer dem Tunnel | `state.rs:462` | umgesetzt | `067a3c2b` + `ea91c689` | per Test (7 Sonden des Agenten + 4 eigene) | `RemoteServer::shutdown_tunnel()` ist jetzt der eine Eintrittspunkt; `Drop` ruft dieselbe Methode statt einer zweiten Kopie. `take()` wie jeder andere Slot — ein zweiter Schlag ginge auf eine womöglich recycelte pid, unter Windows als `taskkill /T /F` auf einen fremden Baum. **Was ich selbst gefunden habe: die Reihenfolge ist begründet, aber nicht festgenagelt.** Der Tunnel muss zuerst sterben, weil das Internet ihn hindurch weiter zu den Daemons erreicht, die der Rest der Funktion gerade abräumt. Meine Sonde: den Aufruf ans Ende verschoben → alle 774 Tests bleiben grün. **Geschlossen mit `ea91c689`:** eine Wache liest den Rumpf von `shutdown_subprocesses`, wirft Kommentarzeilen weg und prüft, dass vor dem Tunnel kein `.lock(`, kein `kill`, kein `.stop(` steht. Keine Wanduhrmessung — der Tunnel bekommt SIGTERM mit 800 ms Frist, die anderen sofort SIGKILL; ein Laufzeittest würde das Gegenteil der Eigenschaft behaupten. Im selben Nachtrag die Ursache des cloudflared-Flakes, den ich gemeldet hatte: der Stellvertreter war eine Kopie von `/bin/sh`, und **macOS killt die exec'te Kopie eines SIP-Plattform-Binaries mit SIGKILL** (15 Spawns, alle Signal 9, 95–486 ms). Deterministisch reproduziert über eine Verzögerungsreihe. **Eigene Sonde gegen den stillen Leerlauf:** die freie Funktion umbenannt — die Wache geht nicht vacuously grün durch, sie schlägt an. |
|
||||
| KF-2 | Prosa erzeugt ausgeliefertes CSS | `AUDIT-COVERAGE.md:301` → `dist/assets/index-*.css` | umgesetzt | `fcce2b54` | per Test (13 Sonden des Agenten + 2 eigene) + A/B/A-Messung an echten Builds | Tailwind 4 scannt das Projektverzeichnis als Text. **30 Klassen ohne jede Call-Site** landeten im Bundle (roh −1.863 B, gzip −339 B; 1426 → 1396 Klassen, keine kommt hinzu) — aus Markdown, aus `docs/`, aus **Rust-Kommentaren** (`gpu.rs:217` → `[vendor:device]`) und aus 20 Testdateien, wo Platzhalter zu Regeln mit buchstäblich `background-color:#...` wurden. Eine davon steht in diesem Dokument in der Beschreibung **ihrer eigenen Entfernung** (`:194` → `max-w-[760px]`). Fix ist positiv formuliert (`source(none)` + zwei `@source` + ein `not`), keine Ausschlussliste nach Endungen — dieselbe Klasse steht in Tabelle *und* Testkommentar, eine Quelle abzuschalten hätte nichts genützt. Eine Zeile wurde gemessen und **verworfen**: `@source not "./index.css"` ergab ein byte-identisches Bundle. **Die eigentliche Kur am Test:** jede Nadel wird gegen *alle* Treffer geprüft, nicht gegen den ersten. |
|
||||
| KF-3 | Sechs Befunde, die erst sichtbar wurden, als der Client aufhörte, ein String zu sein | `mobile-client/**` | **teils offen** | Herausgefallen beim T-75-Umbau, in keinem Audit: (1) `repairToolCallArgs` — der Doppel-Dekodier-Zweig ist **unerreichbar**: ein doppelt kodiertes Argument ist gültiges JSON, das erste `JSON.parse` gelingt, `typeof === 'string'`, Rückgabe `{}` — genau der Fehler, den der Kommentar zu beheben behauptet. Verhalten festgenagelt, nicht repariert (Bytes eingefroren). (2) **Codex ignoriert eine eingeschaltete Persona nicht** — der TS-Nachbau hatte ein `else`, der echte Client nicht; neun grüne Zusicherungen betrafen die Kopie. (3) `mobile-parity.test.ts` testete das **Desktop**-`isThinkingCompatible` unter der Überschrift „mobile parity". (4) `useCodex-prompt-contract` prüfte `toContain('AUTONOMY CONTRACT')` gegen die ganze Rust-Datei — grün war es an der Desktop-Kopie nebenan; der Mobil-Prompt sagt „HARD RULES". (5) eslint lief zum ersten Mal überhaupt auf diesem Code: **5 echte Fehler**. (6) `tool-description-parity` prüfte `>= 9` bei 10 Werkzeugen — ein verlorenes hätte der Parser still geschluckt. |
|
||||
| KF-4 | Die App meldete den Zug fertig, bevor er im Store lag | `useChat.ts:323/994`, `useCodex.ts:2512`, `useAgentChat.ts:2224` | umgesetzt | `4bb21590` + `dedf73c4` | **per Messung in echtem Chromium gegen echtes IndexedDB** + eigene Sonde | Vier Stellen veröffentlichten „fertig" und starteten *danach* den Schreibvorgang. Gemessen mit gepatchtem `IDBObjectStore.prototype.put` und rAF-Ticker, Profil 6,48 MB: unbelastet 0,6–4,3 ms (der Put ist oft schon **vor** dem Paint abgeschickt, −0,9 ms), bei CPU 20× gedrosselt **283–522 ms**. Der Verlust selbst reproduziert: gedrosselt **6 von 6** Läufen kamen nach `reload()` ohne die Antwort zurück. Der Fix dreht die Reihenfolge statt ein `await` davorzusetzen; nachher −225/−318/−256 ms, Vorzeichenwechsel. **Ehrlich:** der Verlust ist nicht weg — wer neu lädt, während die Antwort auf dem Schirm steht, verliert sie weiter (4/12, mit und ohne Fix). Was der Fix kauft, ist ein beobachtbares Signal. **Meine eigene Sonde fand eine Lücke, die mit `dedf73c4` geschlossen ist:** die Position des Aufrufs war nur kommentiert — verschoben blieben 1233 Tests grün. Jetzt lesen zwei Regeln alle vier `finally`-Blöcke (der Schreibvorgang startet vor jeder benannten Arbeit; vor dem Aufruf wird nichts `await`ed), plus ein dritter Test, damit die Liste nicht verrottet. **Die Wache fand beim ersten Lauf selbst etwas:** `useCodex` ließ `extractMemoriesFromPair` *vor* dem Turn-Ende laufen — die dritte Kopie war abgedriftet. Ich habe beide Richtungen nachgeprüft: meine Sonde wird rot (mit einer Meldung, die sagt, was zu tun ist), ein harmloser Store-Write darüber bleibt grün, und die vom Agenten selbst gemeldete Lücke (ein neuer, nicht gelisteter Aufruf rutscht durch) besteht tatsächlich. Der e2e-Spec ging unter identischer künstlicher Last von **3 von 12 rot** auf **24 von 24** bei gleicher Laufzeit je Lauf. |
|
||||
| KF-5 | Sechs e2e-Specs beschreiben eine Oberfläche, die es nicht mehr gibt | `e2e/*.spec.ts` | in Arbeit | **Von einem Agenten im Vorbeigehen gefunden, nicht von mir.** Ich habe jedes Paket mit `tsc`, `vitest` und `madge` geprüft — aber nicht mit e2e, und `ci.yml` fährt `npm run test:e2e` als **scharfes Gate ohne `continue-on-error`**. Gemessen am HEAD `04e22492`: **6 rot, 28 grün, 3 übersprungen.** Zwei Ursachen sind belegt und brechen die App für echte Nutzer *nicht*: (a) `builtin-ctx.spec.ts:55` sucht die Beschriftung `ctx 8K`, die D-S06 absichtlich ersetzt hat — der Füllstand *ist* jetzt das Label des Wählers; (b) `chat-delete-discoverable.spec.ts` ruft `hover()` direkt auf ein Zeilen-Icon, das seit D-S15 `pointer-events-none group-hover:pointer-events-auto` trägt — für Maus und Tastatur offen, aber Playwright verlangt vor dem Hover einen Treffer im Hit-Test. Henne und Ei. **Der dritte Fall ist womöglich ein echter Produktfehler:** ein Fehlerbericht zeigt die App auf dem Willkommensschirm stehengeblieben, ein anderer meldet, `Continue` werde gefunden, der Klick laufe aber in den Timeout — der Knopf ist nicht deaktiviert und `.lu-primary` trägt keine Animation. **Die Lehre für mein Verfahren:** ein Paket, das sichtbare Beschriftungen ändert, muss gegen die Specs laufen, die sie anklicken. `tsc` und `vitest` sehen davon nichts — die Unit-Tests dieses Projekts lesen Quelltext, keine gerenderte Oberfläche. Es ist dasselbe Muster wie überall hier, eine Ebene höher: zwei Beschreibungen derselben Oberfläche, von denen nur eine gepflegt wurde. |
|
||||
| KF-6 | Die App deklariert einen fetten Schriftschnitt, den sie nicht besitzt | `public/fonts/lu-fonts.css` | in Arbeit | | per Dateivergleich (sha256) | **Beim Nachprüfen einer Agentenbehauptung selbst gefunden.** Space Grotesk hat dort sechs `@font-face`-Blöcke, aber nur **drei physische Dateien**: Gewicht 500 und 700 zeigen Subset für Subset auf dieselben Bytes (`534357209344` 6772 B, `e911c2d94a1e` 18924 B, `a57c9413b9ba` 22320 B). Der Browser synthetisiert nicht, wenn eine `@font-face` das Gewicht behauptet — er nimmt die Datei, wie sie ist. Ein `font-bold` auf Displaytext wäre deshalb **still wirkungslos**: nicht fett und auch nicht sichtbar falsch. Das erklärt zugleich die Messung des Agenten schärfer, als er sie gedeutet hat — Grotesk 500 = 1094,18 px und 700 = 1094,34 px sind nicht zwei ähnlich bauende Schnitte, sondern dieselben Glyphen. Sein Schluss (Displaygewicht 500) bleibt richtig, aus einem stärkeren Grund. Nachtrag beauftragt: messen, dann entweder die drei 700-Blöcke entfernen (der Browser fettet dann wieder synthetisch, sichtbar statt still) oder die Lüge festhalten — **ohne Download**, und mit einer Regel statt einer Aufzählung dieser drei Fälle. |
|
||||
| KF-7 | Derselbe Bauplan wie der reparierte Sweep-Test, eine Datei weiter | `src-tauri/src/commands/process.rs` | offen | | vom KF-1-Agenten gemeldet, von mir übernommen | `comfy_adoption_tests::the_scan_finds_a_real_process_by_the_argv_lu_would_have_used` spawnt wie der cloudflared-Test einen Stellvertreter und scannt die echte Prozesstabelle — benutzt aber das **echte** `/bin/sh` und stirbt deshalb nicht am SIP-Kill. Seine Schwäche ist eine andere: ein einzelnes festes `sleep(300 ms)`, danach **genau ein** Scan ohne Wiederholung und ohne Selbstprüfung, plus ein **fester Port 61888**, den ein zweiter Prozess derselben Suite besetzen kann. Unter drei gleichzeitigen Suiten (Apparatur, kein Praxisfall) fiel er 16×. Vier weitere Fremdtests kollidieren dort auf global geteilten Ressourcen: `kill_tree_tests::the_call_does_not_block_for_the_grace_period` (14×), `workspace_listing_tests::lists_only_directory_names_sorted` (12×), `system::tests::every_screenshot_gets_its_own_temp_file` (7×). Keiner davon gehörte zum KF-1-Paket. |
|
||||
|
||||
**Wie KF-2 vier Monate unentdeckt bleiben konnte:** `fokusring-und-press.test.ts:248` trägt `describe.skipIf(builtCss === null)` und liest aus `dist/assets`. Wo kein `dist/` steht, schaltet sich der ganze Block **still** ab. Das ist der dritte Fall desselben Musters in diesem Projekt (nach `gguf.rs:264` und `bundle-size-drift.live.test.ts`) — und ich bin selbst einmal darauf hereingefallen: ein Lauf war grün gegen ein `dist/`, das aus einer früheren Sonde stammte und nicht mehr zum Quelltext passte. Seitdem gilt für mich: **vor jedem Testlauf, der gebautes CSS liest, `rm -rf dist && npx vite build`.**
|
||||
|
||||
|
||||
@@ -664,3 +664,40 @@ Zwei Dinge folgen daraus, und das zweite ist mir das wichtigere:
|
||||
Es ist übrigens dasselbe Muster wie überall sonst hier, nur eine Ebene höher:
|
||||
zwei Beschreibungen derselben Oberfläche — die Komponente und der Spec — von
|
||||
denen nur eine gepflegt wurde.
|
||||
|
||||
## Ein verschwundenes `node_modules`, und was es über Messungen sagt
|
||||
|
||||
Mitten in dieser Runde war `node_modules` im Hauptrepo vollständig weg. Kein
|
||||
`npm install` lief, nichts hatte es angekündigt. Sichtbar wurde es als
|
||||
`resource path ../dist doesn't exist` in `cargo test` — Tauri braucht das
|
||||
gebaute Frontend als Ressource, und `vite build` konnte es nicht liefern,
|
||||
weil ihm `vite` selbst fehlte.
|
||||
|
||||
Wiederhergestellt habe ich es **ohne Netz**: der npm-Cache lag mit 4,4 GB
|
||||
vollständig da, `npm ci --offline` brachte 422 Pakete zurück, der Build war
|
||||
danach in 394 ms wieder grün. Das ist der eigentliche Grund, warum es hier
|
||||
steht — die Reparatur war billig, der Schaden an den *Messungen* nicht.
|
||||
|
||||
Denn in dem Zeitfenster liefen vier Agenten. Jeder `tsc`, jeder `vitest`,
|
||||
jeder Playwright-Lauf daraus ist rot geworden, aus einem Grund, der mit dem
|
||||
geprüften Code nichts zu tun hat. Ein Agent, der so ein Rot für sein eigenes
|
||||
hält, repariert ein Phantom — und schlimmstenfalls „repariert" er dabei
|
||||
etwas, das richtig war. Ich habe deshalb beiden noch laufenden Agenten
|
||||
geschrieben, sie sollen die Ergebnisse aus diesem Fenster wegwerfen und
|
||||
wiederholen, und dem e2e-Agenten ausdrücklich, dass auch mein eigener
|
||||
Verdacht gegen seinen dritten roten Spec dadurch wertlos sein könnte.
|
||||
|
||||
Die vermutete Ursache ist ein `rm -rf …/node_modules/` **mit Schrägstrich am
|
||||
Ende** auf einen Symlink: unter macOS zeigt das auf das Ziel, nicht auf den
|
||||
Link, und löscht dessen Inhalt. Ich habe selbst so einen Link angelegt, für
|
||||
den isolierten Worktree der Paketprüfung. Wer es war, weiß ich nicht — ich
|
||||
habe beide Agenten gefragt und werde es nachtragen, wenn eine Antwort kommt.
|
||||
Die Lehre gilt unabhängig davon: **eine geteilte Abhängigkeit gehört nicht
|
||||
in eine Arbeitskopie verlinkt.** Kopieren ist teurer und kann das hier nicht.
|
||||
|
||||
Und eine zweite, unangenehmere: mein eigener Messfehler in derselben Minute.
|
||||
Ich hatte `cargo test 2>&1 | tail -25 > log; echo "exit=$?"` geschrieben und
|
||||
damit den Status von `tail` protokolliert, nicht den von `cargo`. Das Log
|
||||
sagte `exit=0`, während der Build in Wahrheit gescheitert war. Ein grünes
|
||||
Ergebnis, das gar nichts gemessen hat — genau die Form von Fehler, die ich
|
||||
in dieser Sitzung bei anderen dreimal gesucht habe.
|
||||
Reference in new issue
Block a user