BotLeadList bekommt die Stufe (WorkersPage reicht sie durch). Unterhalb von BOTLEADS_AB
(Stufe 6) ruft sie weder api.botleads noch ein JWT, zeigt keine Ladeanzeige und keinen
Fehlerzustand: Szene mit Arne, Register-Buch, Reiter und Suche stehen da, das Register ist leer
("Noch keine Bot-Leads. Hier legt Arne Betriebe ohne Website ab, die Bea nicht fuer eine Mail
ausgewaehlt hat. Die Branchen-Raeume ... suchen noch nicht."), ohne Zahl am Reiter. Reiter,
Suche, Zuklappen und Alle anzeigen bleiben bedienbar und loesen nie einen Abruf aus. Ab Stufe 6
unveraendert (Live-Daten); der Test-Laeufer startet den Keller standardmaessig mit Stufe 6.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Die Stufen-Sperre trennt jetzt zwei Dinge: KELLER_BEGEHBAR_AB = 3 (Keller-Etage als Link,
?tab=botleads gueltig, Spur-Links in den Keller) und BOTLEADS_AB = 6 (Abruf von GET /botleads).
kellerOffen/STUFE_KELLER entfallen, dafuer kellerBegehbar() und botleadsAbrufbar().
workersApi.botleads bleibt unter Stufe 6 hart gesperrt, der Text heisst nun
BOTLEADS_GESPERRT_TEXT. Die Keller-Ansicht selbst (leeres Register ohne Abruf) folgt im
naechsten Commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hustler-Pixelwelt mit Stufen-Sperre (Stufe 3 = Dienst P3) mit Website-Statistik (f9b0cbc) zusammengeführt; Konflikt in tests/unit/navLinks.test.mjs: beide Listen vereint (hustler statt leads, statistik vor serverpuls).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build.mjs setzt die Stufe über define ein (Standard 6, andere Ziffer 1 bis 9 aus der Umgebung, Ungültiges bricht ab), damit die Szenarien K (Pult P4) und L (Keller) weiter laufen;
ein Test baut den Prüfstand mit Standard, 3 und ungültigen Werten. docs/superpowers/hustler-stufe.md erklärt Stufen, Sperren und die Schritte beim Hochsetzen.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WorkersPage: ?tab=botleads (auch mit &bot=) und unbekannte Werte fallen unterhalb von Stufe 6 auf das Hochhaus zurück, BotLeadList wird nie eingehängt; die Weiterleitungen /leads und /workers bleiben.
HochhausWelt: die Keller-Etage ist dann ein Knopf wie jede andere (zoomt heran) statt eines Links; Arne bleibt klickbar, die Zahl Bot-Leads in der Kopfzeile bleibt Text.
HustlerDialog: Spur-Links in den Keller bleiben Text. workersApi.botleads ruft unterhalb von Stufe 6 nichts ab (kein JWT, keine Anfrage), sondern liefert 404 mit deutschem Satz.
Bestehende Keller-Tests laufen ausdrücklich auf Stufe 6; neue Tests prüfen Stufe 1, 3 und 5 (gesperrt) und 6 bis 9 (offen).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Unterhalb von Stufe 4 sind canReply, canPaste, canApprovePreview und canStartBuild immer false: Antwort des Kunden einfügen, Als Mensch antworten / Jetzt senden, Freigeben & senden
und Vorschau bauen verschwinden samt Feldern und Rückfragen, die Aktionsgruppe schließt sich ohne Lücke. P3-Aktionen (übernehmen, Kopieren & öffnen, als gesendet markieren, verwerfen,
erledigt, E-Mail schreiben) bleiben. Bestehende P4-Tests laufen ausdrücklich auf Stufe 6; neue Tests prüfen Stufe 3 gerendert und bedient (Reihenfolge der Knöpfe, kein Feld, Esc, Verwerfen mit Rückfrage).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Eine Quelle der Wahrheit dafür, was die Oberfläche schon zeigen darf, solange der Dienst nur P1 und P3 kann. Der Wert aus dem Bau gilt nur als Ziffer 1 bis 9,
sonst die Standardstufe; keine Überschreibung zur Laufzeit. Dazu tabErlaubt (Keller = ?tab=botleads) und linkErlaubt (Links in den Keller, auch über /workers und /leads).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Pult: laufende Anfragen je Eintrags-Id in PultList (laufRef, Brief meldet Beginn/Ende): Brief schließen und denselben Eintrag
wieder öffnen sperrt alle Aktionsknöpfe, kein zweites reply/paste/start-build (P1); spätes Ergebnis nennt den Titel (P1b);
Original und Entwurf pre-wrap (P3); Überschrift nimmt beim Einhängen den Fokus (M2); „Pult zuklappen“ mit aria-expanded (K4);
paused -> hk-steht an der Szene (R3); Brief z-index 9 (R4); Textlinks am Handy 40 px (K7).
Keller: Überschrift-Fokus (M2), Reiter-Fokusring innen (M3), Seitenzeile/Punkte/Reiterzahl in Pixelify Sans 13 px (K5), Suchfeld und
Akte-Link 40 px am Handy (K7), Ortszeile mit title (W2), paused -> hk-steht (R3), Akte z-index 9 (R4); Arne ohne Eintrag neutral (R5).
Tests: Sperre laufender Aktionen, Titel im späten Ergebnis, Fokus, aria-expanded, paused, pre-wrap, z-index, Tippflächen, Reiter-Fokus,
Schrift, Kontrast (WCAG) von .hk-zeile-alt/.hk-kl-tag auf Papier und Hover, Arne neutral (alte „Arne schläft ohne Eintrag“-Prüfung ersetzt).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Prüfstand: entry.jsx zeigt nur noch die echte Seite WorkersPage (BrowserRouter, Adresse mit ?tab= lesbar); shot.cjs neu mit den Szenarien A–M
(Hochhaus, Regie, Handy, weniger Bewegung, Notbremse, Ausfall, Detail, Etagen, Pause, Pult P3, Pult P4, Keller, Handy Pult/Keller),
harte Prüfungen und Bildern mit Szenario-Vorsilbe; Befunde an der App stehen getrennt von den Verstößen. Skript-API: Gründe der Bot-Leads
wörtlich wie im Dienst. Kopfzeile am Handy: zwei Reihen (Geld + Pause/Zahnrad, dann die fünf Kennzahlen), schmaler Panel-Rand, 40-px-Knöpfe,
Querformat unter 500 px Höhe in einer Reihe; hustlerKopf.test um die Zusicherungen dazu ergänzt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- gelöscht: components/workers/engine/* (10 Dateien), WorkersStage, WorkersBoard, WorkerCard, WorkerList, WorkersKpis,
die neun Engine-Tests samt workersSmoke (211 Tests) und die Helfer engineVm.mjs und fakeCtx.mjs (nur die Engine-Tests brauchten sie)
- workers.css (310 -> 60 Zeilen) behält nur Einstellungen-Dialog und Interessenten-Panel; @font-face für Pixelify Sans steht jetzt in hustler/schrift.css
- workersComponents: kein innerHTML und kein Kanvas rekursiv unter components/workers/**, jeder Knopf mit type, Links nur aus geprüften Feldern
(externe mit noopener), keine Anmeldung in den Bildschirmen, alte Dateien weg und nirgends mehr importiert
- workersCss: jede wk-Klasse im Code hat eine Regel, keine Regel ohne Nutzer; workersFont: Pixelify Sans genau einmal in schrift.css
- hustlerAssets: Pixelify Sans in schrift.css erlaubt; hustlerDialog: Link-Ziele nur aus safeLink, Knöpfe mit type; hustlerSeite: Laden/Fehler/bereit am selben Einhängepunkt
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
HochhausWelt.jsx baut die Welt 1:1 aus dem Markup der Zeichenfläche (Himmel, Bühne 2400x1200, Haus-, Licht- und Fensterebenen, Neon, Aufzug,
Raumschilder, Bildschirme, Radar, Schilder, Etagen, 19 Hustler, Schnee); Figuren, Zusätze, graue Raum-Ebenen samt Papier-Zettel, Briefkasten-Zähler
und Etagen-Links folgen dem Dienst-Zustand. useKamera.js ist der Hook für Rad, Ziehen, Pinch, Doppeltipp, Tasten und Gleiten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- scripts/hustler-import.mjs liest pixelwelt-v2 (+ pixelwelt-woms/haus) und schreibt src/assets/hustler, src/styles/hustler/{hochhaus,keller,pult}.css und src/lib/hustlerWelt.js; idempotent
- haus.png mit allen Räumen hell, acht graue Ebenen für die Such-Räume (GRAUE_RAEUME, .hk-raum-grau-<raum>)
- Press Start 2P lateinisch aus @fontsource/press-start-2p@5.2.7 (OFL), noch nirgends importiert
- 40 neue Tests (Assets, Geometrie, CSS-Umformung)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
N5: Der Fokus geht nach dem Blättern über restoreFocus (workersFocus.js) mit preventScroll an die Seitenzeile zurück, aber nur, wenn er
wirklich verloren ging (body, nirgends, alter Knopf ausgehängt). Hat der Nutzer inzwischen Suchfeld oder Raumfilter angesteuert, bleibt er dort.
N6: Scheitert eine Anfrage, steht unter der Meldung „Erneut versuchen“; der Knopf stellt genau diese Anfrage (Raum, Suche, Seite oder Eintrag)
noch einmal und die Seitenzeile bekommt danach den Fokus zurück. CSS: .wk-bl-retry, am Handy 40 px.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Endprüfung P6 (C5, W1, W2):
- Blätterknöpfe 36 px -> 40 px und „Alle anzeigen“ der Einzelansicht (32 px) -> 40 px über
`.wk-bl-pager .btn` und `.wk-bl-single .btn` im Handy-Block; min-height schlägt height: 32px,
keine globale .btn-Regel, kein !important.
- Gekürzte Zeilen: --text-2 statt --text-3 (Kontrast von etwa 2,9:1 auf mehr als 5:1).
- `.wk-bl .wk-bl-table td .cell-sub { overflow-wrap: break-word }` (0,3,1) schlägt das globale
`.table td .cell-sub { overflow-wrap: anywhere }` (0,2,1) („Kaiserslau-tern“ in der Einzelansicht).
- Tests: workersCss.test.mjs (Farbe, Kontrast aus den Token von global.css, Höhen, Spezifität gegen die
globale Regel); Prüfstand botleads und handy-botleads: 81 Prüfungen grün.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Endprüfung P6 (C5, W1): Beim Blättern hängt die Seitenzeile beim Laden aus, und „Alle anzeigen“
wird durch den Raumfilter ersetzt; der Fokus fiel jeweils auf <body>.
- Blättern: gemerkt wird der gedrückte Knopf; nach dem Laden bekommt er den Fokus zurück, ist er
gesperrt (erste oder letzte Seite), der andere. Raum oder Suche bedient der Nutzer inzwischen,
geschieht nichts; scheitert die Anfrage, gibt es keine Seitenzeile und nichts geschieht.
- „Alle anzeigen“: der Raumfilter bekommt den Fokus, sobald die Seite bot aus der Adresse
genommen hat. Nicht beim Einhängen (am Handy öffnete das die Auswahl) und nicht bei einem
anderen Weg zur Liste (Zurück-Taste).
- aria-current nur mit bot (single) und passender Kennung; Zeilen ohne Kennung teilen sich keinen key mehr.
- Tests: botleadList.test.mjs (Fokus-Attrappe über __fakeRef, Mutationsprobe für die Reset-Zeilen),
botleadsView.test.mjs (Quelltext-Probe); der Prüfstand prüft zusätzlich den Fokus nach „Alle anzeigen“.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Skript-API: botleads({ room, q, page, id }) antwortet wie GET /botleads des Dienstes
(items, total, pageSize 50; Telefon nie bei Heilberufen, gekürzte Stubs nur mit id).
60 sichtbare Einträge in vier Räumen (zwei Seiten), 3 gekürzte Stubs, Heilberufe mit
Altbestand-Telefon, eine http-Quelle, zwei feindliche Quellen, lange Namen und Gründe.
Schalter: faults.botleads, botleadsDelayMs, botleadsEmpty (?botleads=leer), botleadCalls.
Fetch-Weiche und entry.jsx (?bot=<Id>) um die Route und den Deep-Link ergänzt.
Szenarien: botleads (Reiter, Liste, Raumfilter, Blättern mit Fokus, Suche, Leerzustände,
Fehlertexte, Deep-Link, Quellen-Links, Telefon) und handy-botleads (390 x 844: kein
seitliches Scrollen, Knopfhöhe, Kontrast der gekürzten Zeile, Wortumbruch).
Der Pin in workersHarness.test.mjs prüft nun die neue Antwortform statt der leeren Liste.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Die zeichengleiche Inline-Kopie (FAKE_REACT und Plug-in) ist entfernt; der Baustein ist jetzt die einzige Fassung für workersPultUi.test.mjs und botleadList.test.mjs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Der Commit 1536a3b hatte den Test „reply, approve-preview und start-build warten länger als die übrigen
Pult-Aktionen“ gelöscht. Der neue Test prüft gegen den heutigen Code (ACTION_TIMEOUT_MS 65 s,
REQUEST_TIMEOUT_MS 20 s, Optionen timeoutMs / actionTimeoutMs) mit den Uhren von node:test statt echter
Wartezeit: keine Abhängigkeit von der Last, Grenzen auf die Millisekunde (eine Millisekunde vor der Frist
läuft der Abruf, mit ihr endet er). Die drei langsamen Aktionen nehmen eine Antwort zwischen kurzer und langer
Frist an, claim/sent/discard/done/paste und das Lesen enden mit der kurzen Frist (DOWN_TEXT, status 0, Signal
abgebrochen), ein hängender Abruf endet nach der langen Frist. Derselbe Ablauf mit Standard- und mit
eingespeisten Fristen; ein zweiter Test pinnt, dass auch der Wiederholungsversuch nach einer 401 die Frist
der Aktion behält.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ohne die Option springt die Seite beim Zurückgeben des Fokus zum Ziel: bei einer Zeile weit unten in
einer langen Liste zur Meldung oben, und die Person verliert ihre Stelle. restoreFocus ruft jetzt
target.focus({ preventScroll: true }); der Fokus (und damit die Ansage) wandert, die Ansicht bleibt stehen.
Die Attrappe in workersFocus.test.mjs merkt sich die Argumente, ein neuer Test pinnt genau einen Aufruf
mit dieser Option.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>