Nachlese zu #21: vier tote Stellen im Produktcode, ein Solver-Aufruf mit falscher Bedeutung – und zwei CJK-Zeichen im ausgelieferten Dokument #28

Open
opened 2026-09-04 15:46:55 +02:00 by gilli · 0 comments
Owner

Komponente: GAME (S 2800, el-Liste 2786, updateDemo 3383/3403), RENDER (poseFor 2210),
CORE (verifyContent 1555 → strategyList 1471–1489), Kommentar Zeile 1482
Betroffene Version: main @ 86a481d, index.html (3.684 Zeilen, MD5 777d18c3edbb834aa41fccc7d10a7d18)

Beschreibung

Issue #21 hat 14 Fundstellen „Flag ohne Setzer / Zustand ohne Leser“ bereinigt. Sechs weitere
Fundstellen derselben Klasse sind übrig — fünf tote Stellen und ein Aufruf, der ein Argument mit
anderer Bedeutung füttert. Dazu kommt ein Textdefekt im ausgelieferten Dokument.

Alle sieben Punkte sind ausgeführt bzw. per Skript gegen das Dokument geprüft (Schreib-/Lesezähler
über index.html, kein Verdacht ohne Zähler):

# Fundstelle Befund
1 S.shakePhase: 0 (Zeile 2800) im Objekt-Literal angelegt, im gesamten Dokument 0 Lesungen und 0 weitere Schreibungen (shakePhase kommt genau einmal vor)
2 "hudSector" in der el-Liste (Zeile 2786) Element existiert im Markup (Zeile 291, Layout-Container) — aber keine Zeile Code liest el.hudSector (gelesen werden hudSectorCap, hudSectorName, hudSectorNo, hudEndless)
3 state === "DEMO" in poseFor (Zeile 2210) kein Aufrufer übergibt je "DEMO": drawBody (3524–3545) mappt SLACK → "FALLING", Tod → "DEAD", sonst b.state; b.state nimmt nur RUNNING/JUMPING/FALLING/ROLLING/HANGING/SLACK ein
4 S.distance = before === undefined ? 0 : … in updateDemo (Zeile 3403) const before = d.body.x; (Zeile 3383) ist immer definiert; der Ternary ist dauerhaft im zweiten Zweig und before wird sonst nirgends benutzt — die Zeile tut exakt dasselbe wie S.distance = Math.max(0, (d.body.x − K.START_X) / 10)
5 strategyList(hasHooks, content.obstacles.length > 0) in verifyContent (Zeile 1555) das zweite Argument heißt dort hasGates (Zeile 1471) und entscheidet rollLeads = hasGates ? ROLL_LEADS : [110]. Ein JUMP-Muster ohne Tor sagt true und bekommt alle drei ROLL_LEADS (52/110/168) — 54 Solver-Versuche statt 18, alle mit identischem Ergebnis, weil ohne Tor niemand eine Rolle auslöst
6 Kommentar Zeile 1482: damit es auf Touch-Geräten同样 spielbar ist. zwei CJK-Ideogramme (U+540C, U+6837) mitten im deutschen Satz, ohne Leerzeichen an „Geräten“
7 Umfang des Dokuments nach Zeichen-Klassifikation sind ü ä ö ß · – — × „ “ − √ → ° ≥ ± ∞ die gesamten Nicht-Latin-Zeichen des Dokuments — mit Ausnahme der beiden Ideogramme aus Punkt 6

Zählprobe (Skript, gegen index.html)

el genutzt aber nicht gemappt: []
gemappt aber nie genutzt:      ['gameover', 'help', 'hudSector', 'menu', 'pause', 'settings']
   (fünf davon werden über el[NAME] / showOnly gelesen — nur 'hudSector' ist wirklich tot)
S-Feld im Literal, nie via S. gelesen/geschrieben: ['shakePhase']
"DEMO" im Dokument:            nur Zeile 2210 (die Bedingung selbst)
CJK im Dokument:               Zeile 1482: 同 (U+540C), 样 (U+6837)

Ursache im Code

1.–4. sind Reste früherer Umbauten: Feld im State-Literal angelegt und nie benutzt (#21 hat genau
diese Klasse entfernt, hier nur für S.paused/S.newRecord), Element-Liste mitwachsen lassen,
Pose-Zustand für eine Demo erfunden, die später über simStepDemo/autopilot läuft (Issue #15),
und ein Ternary, dessen Null-Fall durch eine spätere Zeilen-Umstellung unerreichbar wurde.

  1. ist ein Semantikfehler im Aufruf, kein toter Code: strategyList bekommt an der einzigen
    Aufrufstelle ein Mengenmaß (obstacles.length > 0) für ein Typprädikat (hasGates).

6./7. sind ein Kippfehler beim Tippen des Kommentars zu Issue #22 — in einer Datei, die laut
AGENTS.md „kein Build, keine Tooling-Artefakte“ ist und deren sichtbare Texte Deutsch, deren
Kommentare ebenfalls Deutsch sind.

Folgeverhalten

  • Kein Laufzeitfehler — alle sieben Punkte sind harmlos. Sie kosten aber genau das, was #9/#21
    einfordern: ein Leser darf sich darauf verlassen können, dass ein Feld im State-Literal einen
    Grund hat, eine el-Liste nur Existsierendes enthält und eine Pose nur Zustände kennt, die
    jemand übergibt.
  • Punkt 5 kostet Solverzeit: 3× so viele Strategieversuche für jedes block-behaftete Muster ohne
    Tor. Der Generierungs-Aufwand ist gemessen p99 6,7 ms / Spitze 12,6 ms pro generateAhead-Aufruf
    (issues/README.md, „Bestätigt in Ordnung“) — ein Drittel dieser Versuche ist hier unnütz.
  • Punkt 6 fällt beim Durchsehen des Dokuments auf und in jeder Suchmaschine/Patch-Anzeige als
    kaputte Zeile auf; in Diff-Werkzeugen mit Narrow-Width-Annahme verrutscht die Spalte.

Nicht verletzt (bewusst abgegrenzt)

  • Kein Verhalten, kein Test, keine Zahl ändert sich — deshalb ~low und ein gemeinsamer Befund
    statt sieben.
  • Die übrigen Punkte aus #21 sind nach wie vor sauber: body.dead, o.dead, S.paused,
    S.newRecord, pit.double, ev.releaseTheta, ev.leftGround, gen.stats.attempted,
    gen.lastPitHook, hooks.onPointer kommen im Dokument 0-mal vor (tests/issue9.mjs prüft das).
  • pit.platform und INPUT.state.anyPointerDown bleiben die dokumentierten Test-APIs (#21).

Lösungsvorschlag

  • S.shakePhase streichen; S.camShake ist die einzige Kamera-Schüttel-Größe (render
    zeichnet daraus shakeX/shakeY, update zählt es herunter).
  • "hudSector" aus der el-Liste nehmen (das Markup behält die id, sie ist CSS-Anker).
  • "DEMO"-Zweig in poseFor streichen oder — wenn die Demo künftig eine eigene Pose bekommen
    soll — als dokumentierte, gebundene Möglichkeit kommentieren (wie pit.platform in #21).
  • updateDemo: S.distance = Math.max(0, (d.body.x - K.START_X) / 10); und const before = …
    entfernen.
  • verifyContent: const hasGates = content.obstacles.some(o => o.type === "GATE" || o.type === "MGATE");
    und das an strategyList übergeben — ein Prädikat, kein Mengenmaß.
  • Zeile 1482: damit es auf Touch-Geräten同样 spielbar ist. → damit es auf Touch-Geräten ebenso spielbar ist.

Erwarteter Test

  • In tests/issue9.mjs (die Suite hält bereits die Schreib-/Lesekontrolle zu #21) die Whitelist
    der gestrichenen Bezeichner erweitern: shakePhase, DEMO als Pose-Zustand, before in
    updateDemo — jeweils 0-mal im Dokument.
  • Zusätzliche, billige Text-Prüfung in tests/browser_smoke.py (liest ohnehin das
    Auslieferungsdokument): keine Zeichen außerhalb von Latin + den dokumentierten Satzzeichen
    (En-dash, Em-dash, „ “, ·, ×, −, √, →, °, ≥, ±, ∞) im Dokument. Damit ist auch jede künftige CJK-Einsprengsel rot, bevor sie
    eingecheckt wird.

Dokumentiert in issues/28-nachlese-21-tote-stellen-und-cjk-im-dokument.md (Commit 86a481d).

**Komponente:** GAME (`S` 2800, `el`-Liste 2786, `updateDemo` 3383/3403), RENDER (`poseFor` 2210), CORE (`verifyContent` 1555 → `strategyList` 1471–1489), Kommentar Zeile 1482 **Betroffene Version:** `main` @ `86a481d`, `index.html` (3.684 Zeilen, MD5 `777d18c3edbb834aa41fccc7d10a7d18`) ## Beschreibung Issue #21 hat 14 Fundstellen „Flag ohne Setzer / Zustand ohne Leser“ bereinigt. Sechs weitere Fundstellen derselben Klasse sind übrig — fünf tote Stellen und ein Aufruf, der ein Argument mit anderer Bedeutung füttert. Dazu kommt ein Textdefekt im ausgelieferten Dokument. Alle sieben Punkte sind ausgeführt bzw. per Skript gegen das Dokument geprüft (Schreib-/Lesezähler über `index.html`, kein Verdacht ohne Zähler): | # | Fundstelle | Befund | |---|---|---| | 1 | `S.shakePhase: 0` (Zeile 2800) | im Objekt-Literal angelegt, im gesamten Dokument **0 Lesungen und 0 weitere Schreibungen** (`shakePhase` kommt genau einmal vor) | | 2 | `"hudSector"` in der `el`-Liste (Zeile 2786) | Element existiert im Markup (Zeile 291, Layout-Container) — aber **keine** Zeile Code liest `el.hudSector` (gelesen werden `hudSectorCap`, `hudSectorName`, `hudSectorNo`, `hudEndless`) | | 3 | `state === "DEMO"` in `poseFor` (Zeile 2210) | kein Aufrufer übergibt je `"DEMO"`: `drawBody` (3524–3545) mappt `SLACK → "FALLING"`, Tod → `"DEAD"`, sonst `b.state`; `b.state` nimmt nur `RUNNING/JUMPING/FALLING/ROLLING/HANGING/SLACK` ein | | 4 | `S.distance = before === undefined ? 0 : …` in `updateDemo` (Zeile 3403) | `const before = d.body.x;` (Zeile 3383) ist **immer** definiert; der Ternary ist dauerhaft im zweiten Zweig und `before` wird sonst nirgends benutzt — die Zeile tut exakt dasselbe wie `S.distance = Math.max(0, (d.body.x − K.START_X) / 10)` | | 5 | `strategyList(hasHooks, content.obstacles.length > 0)` in `verifyContent` (Zeile 1555) | das zweite Argument heißt dort `hasGates` (Zeile 1471) und entscheidet `rollLeads = hasGates ? ROLL_LEADS : [110]`. Ein `JUMP`-Muster **ohne Tor** sagt `true` und bekommt alle drei `ROLL_LEADS` (52/110/168) — 54 Solver-Versuche statt 18, alle mit identischem Ergebnis, weil ohne Tor niemand eine Rolle auslöst | | 6 | Kommentar Zeile 1482: `damit es auf Touch-Geräten同样 spielbar ist.` | **zwei CJK-Ideogramme** (`U+540C`, `U+6837`) mitten im deutschen Satz, ohne Leerzeichen an „Geräten“ | | 7 | Umfang des Dokuments | nach Zeichen-Klassifikation sind `ü ä ö ß · – — × „ “ − √ → ° ≥ ± ∞` die gesamten Nicht-Latin-Zeichen des Dokuments — **mit Ausnahme** der beiden Ideogramme aus Punkt 6 | ### Zählprobe (Skript, gegen `index.html`) ``` el genutzt aber nicht gemappt: [] gemappt aber nie genutzt: ['gameover', 'help', 'hudSector', 'menu', 'pause', 'settings'] (fünf davon werden über el[NAME] / showOnly gelesen — nur 'hudSector' ist wirklich tot) S-Feld im Literal, nie via S. gelesen/geschrieben: ['shakePhase'] "DEMO" im Dokument: nur Zeile 2210 (die Bedingung selbst) CJK im Dokument: Zeile 1482: 同 (U+540C), 样 (U+6837) ``` ## Ursache im Code 1.–4. sind Reste früherer Umbauten: Feld im State-Literal angelegt und nie benutzt (#21 hat genau diese Klasse entfernt, hier nur für `S.paused`/`S.newRecord`), Element-Liste mitwachsen lassen, Pose-Zustand für eine Demo erfunden, die später über `simStepDemo`/`autopilot` läuft (Issue #15), und ein Ternary, dessen Null-Fall durch eine spätere Zeilen-Umstellung unerreichbar wurde. 5. ist ein Semantikfehler im Aufruf, kein toter Code: `strategyList` bekommt an der einzigen Aufrufstelle ein Mengenmaß (`obstacles.length > 0`) für ein Typprädikat (`hasGates`). 6./7. sind ein Kippfehler beim Tippen des Kommentars zu Issue #22 — in einer Datei, die laut AGENTS.md „kein Build, keine Tooling-Artefakte“ ist und deren sichtbare Texte Deutsch, deren Kommentare ebenfalls Deutsch sind. ## Folgeverhalten * Kein Laufzeitfehler — alle sieben Punkte sind harmlos. Sie kosten aber genau das, was #9/#21 einfordern: ein Leser darf sich darauf verlassen können, dass ein Feld im State-Literal einen Grund hat, eine `el`-Liste nur Existsierendes enthält und eine Pose nur Zustände kennt, die jemand übergibt. * Punkt 5 kostet Solverzeit: 3× so viele Strategieversuche für jedes block-behaftete Muster ohne Tor. Der Generierungs-Aufwand ist gemessen p99 6,7 ms / Spitze 12,6 ms pro `generateAhead`-Aufruf (`issues/README.md`, „Bestätigt in Ordnung“) — ein Drittel dieser Versuche ist hier unnütz. * Punkt 6 fällt beim Durchsehen des Dokuments auf und in jeder Suchmaschine/Patch-Anzeige als kaputte Zeile auf; in Diff-Werkzeugen mit Narrow-Width-Annahme verrutscht die Spalte. ## Nicht verletzt (bewusst abgegrenzt) * Kein Verhalten, kein Test, keine Zahl ändert sich — deshalb ~low und ein gemeinsamer Befund statt sieben. * Die übrigen Punkte aus #21 sind nach wie vor sauber: `body.dead`, `o.dead`, `S.paused`, `S.newRecord`, `pit.double`, `ev.releaseTheta`, `ev.leftGround`, `gen.stats.attempted`, `gen.lastPitHook`, `hooks.onPointer` kommen im Dokument 0-mal vor (`tests/issue9.mjs` prüft das). * `pit.platform` und `INPUT.state.anyPointerDown` bleiben die dokumentierten Test-APIs (#21). ## Lösungsvorschlag * `S.shakePhase` streichen; `S.camShake` ist die einzige Kamera-Schüttel-Größe (`render` zeichnet daraus `shakeX`/`shakeY`, `update` zählt es herunter). * `"hudSector"` aus der `el`-Liste nehmen (das Markup behält die `id`, sie ist CSS-Anker). * `"DEMO"`-Zweig in `poseFor` streichen oder — wenn die Demo künftig eine eigene Pose bekommen soll — als dokumentierte, gebundene Möglichkeit kommentieren (wie `pit.platform` in #21). * `updateDemo`: `S.distance = Math.max(0, (d.body.x - K.START_X) / 10);` und `const before = …` entfernen. * `verifyContent`: `const hasGates = content.obstacles.some(o => o.type === "GATE" || o.type === "MGATE");` und das an `strategyList` übergeben — ein Prädikat, kein Mengenmaß. * Zeile 1482: `damit es auf Touch-Geräten同样 spielbar ist.` → `damit es auf Touch-Geräten ebenso spielbar ist.` ## Erwarteter Test * In `tests/issue9.mjs` (die Suite hält bereits die Schreib-/Lesekontrolle zu #21) die Whitelist der gestrichenen Bezeichner erweitern: `shakePhase`, `DEMO` als Pose-Zustand, `before` in `updateDemo` — jeweils 0-mal im Dokument. * Zusätzliche, billige Text-Prüfung in `tests/browser_smoke.py` (liest ohnehin das Auslieferungsdokument): keine Zeichen außerhalb von Latin + den dokumentierten Satzzeichen (En-dash, Em-dash, „ “, ·, ×, −, √, →, °, ≥, ±, ∞) im Dokument. Damit ist auch jede künftige CJK-Einsprengsel rot, bevor sie eingecheckt wird. --- *Dokumentiert in `issues/28-nachlese-21-tote-stellen-und-cjk-im-dokument.md` (Commit `86a481d`).*
Sign in to join this conversation.
No description provided.