Graph: gemeinsamer Porttyp auch über mehrere Nodes hinweg #210

Closed
opened 2026-09-23 07:05:34 +02:00 by meleki · 2 comments
Owner

Aus #207, Antwort 2: „lassen wir es einfach vorerst - über mehrere nodes => extra issue anlegen“.

Befund

  • Seit #207 kann ein NodeDef eine Gruppe mit gemeinsamem Typ tragen (sharedType). Der Ausgang erbt den Typ, auf den sich die verbundenen Eingänge einigen (agreedType, src/core/graph/portTypes.ts).
  • Bewusst nicht gebaut: Ketten. Hängt vor einem solchen Node ein weiterer Node derselben Art, meldet der Vorgänger das any, mit dem er registriert ist (shapedDef(…, inherit: false), src/core/graph/nested.ts:124 ff.). Zwei First not empty hintereinander typisieren sich deshalb nicht durch, obwohl vorn eine Animation hineingeht.
  • Der Grund war der Schutz vor Rückkopplung: Ein Datenzyklus aus solchen Nodes würde sich beim Auflösen endlos im Kreis fragen.

Zu bauen (Vorschlag)

  • Die Frage „was speist diesen Eingang“ darf durch Nodes mit sharedType hindurch weiterfragen, mit einer Menge der schon besuchten Nodes. Wird ein Node zum zweiten Mal erreicht, zählt er als any. Damit endet jeder Zyklus, und eine Kette ohne Zyklus typisiert sich durch.
  • Weiter gilt Variante A aus #207: Nur Ausgänge erben, Eingänge bleiben any.
  • Eine Kante, die dadurch weiter hinten ungültig wird, wird rot wie heute (#207, Antwort 3).
  • Tests: Kette aus zwei und aus drei Nodes typisiert durch. Ein Zyklus aus zwei Nodes endet mit any, ohne Stack-Überlauf. Ein gemischter Eingang irgendwo in der Kette macht alles dahinter any. Undo einer Kante vorne bringt die Kette zurück auf any.

Offen (mit Vorschlag)

  1. Kosten: Das Auflösen läuft bei jedem Redraw. Vorschlag: messen mit 50 Nodes in einer Kette, erst bei Bedarf cachen.
  2. Farbige Eingangs-Pins (paintType, Nachtrag in #207): Folgen sie dem durchgereichten Typ mit? Vorschlag: ja, sie nehmen schon heute den aufgelösten Ausgangstyp des Nachbarn, das fällt automatisch ab.
Aus #207, Antwort 2: „lassen wir es einfach vorerst - über mehrere nodes => extra issue anlegen“. ## Befund - Seit #207 kann ein `NodeDef` eine Gruppe mit gemeinsamem Typ tragen (`sharedType`). Der Ausgang erbt den Typ, auf den sich die verbundenen Eingänge einigen (`agreedType`, `src/core/graph/portTypes.ts`). - **Bewusst nicht gebaut: Ketten.** Hängt vor einem solchen Node ein weiterer Node derselben Art, meldet der Vorgänger das `any`, mit dem er registriert ist (`shapedDef(…, inherit: false)`, `src/core/graph/nested.ts:124` ff.). Zwei `First not empty` hintereinander typisieren sich deshalb nicht durch, obwohl vorn eine Animation hineingeht. - Der Grund war der Schutz vor Rückkopplung: Ein Datenzyklus aus solchen Nodes würde sich beim Auflösen endlos im Kreis fragen. ## Zu bauen (Vorschlag) - Die Frage „was speist diesen Eingang“ darf durch Nodes mit `sharedType` hindurch weiterfragen, mit einer Menge der schon besuchten Nodes. Wird ein Node zum zweiten Mal erreicht, zählt er als `any`. Damit endet jeder Zyklus, und eine Kette ohne Zyklus typisiert sich durch. - Weiter gilt Variante A aus #207: Nur Ausgänge erben, Eingänge bleiben `any`. - Eine Kante, die dadurch weiter hinten ungültig wird, wird rot wie heute (#207, Antwort 3). - Tests: Kette aus zwei und aus drei Nodes typisiert durch. Ein Zyklus aus zwei Nodes endet mit `any`, ohne Stack-Überlauf. Ein gemischter Eingang irgendwo in der Kette macht alles dahinter `any`. Undo einer Kante vorne bringt die Kette zurück auf `any`. ## Offen (mit Vorschlag) 1. **Kosten:** Das Auflösen läuft bei jedem Redraw. Vorschlag: messen mit 50 Nodes in einer Kette, erst bei Bedarf cachen. 2. **Farbige Eingangs-Pins** (`paintType`, Nachtrag in #207): Folgen sie dem durchgereichten Typ mit? Vorschlag: ja, sie nehmen schon heute den aufgelösten Ausgangstyp des Nachbarn, das fällt automatisch ab.
meleki added the new label 2026-09-23 07:05:34 +02:00
admin added low-priorityquestion and removed new labels 2026-09-23 07:06:51 +02:00
admin added this to the Development project 2026-09-23 07:14:42 +02:00
admin moved this to Next in Development on 2026-10-02 10:19:27 +02:00
  1. vorschlag passt, über 50 nodes, cache brauchen wir vorerst nicht
  2. passt
1. vorschlag passt, über 50 nodes, cache brauchen wir vorerst nicht 2. passt
admin removed the question label 2026-10-02 10:34:06 +02:00
Author
Owner

Umgesetzt und live (Build auf stein2).

Was sich ändert

  • Der gemeinsame Typ wandert durch Ketten. Hängt hinter einem First not empty oder Select ein weiterer solcher Node, übernimmt er den Typ, auf den sich der vordere geeinigt hat. Das gilt auch gemischt, etwa Select hinter zwei First not empty.
  • Ein gemischter oder offener Eingang irgendwo in der Kette macht alles dahinter wieder any. Davor bleibt der Typ stehen.
  • Ein Kreis aus solchen Nodes endet mit any, statt endlos zu fragen. Das gilt auch für einen Node, der sich selbst speist.
  • Eingänge bleiben any, nur Ausgänge erben (Variante A aus #207). Eine Kante, die weiter hinten ungültig wird, bleibt liegen und wird rot.
  • Die farbigen Eingangs-Pins folgen mit (Antwort 2).

Kosten (Antwort 1)

  • Kein Cache, wie entschieden.
  • Eine Kette aus 50 Nodes löst sich in rund 10 ms auf, vorher waren es 2 ms. Die Zahl stammt aus einer Messung früher in dieser Runde, für den Endstand habe ich sie nicht neu gemessen. Ein Unit-Test hält fest, dass die 50er-Kette innerhalb eines Frames bleibt.
  • Speist ein Node beide Eingänge des nächsten, wird er je Frage nur einmal gefragt. Ohne das würde sich der Aufwand mit jedem Glied verdoppeln. Das ist kein Cache zwischen zwei Änderungen, die Antworten gelten nur für die eine Frage.

Under the hood

  • shapedDef in src/core/graph/nested.ts bekommt statt des Schalters inherit einen Trail mit zwei Teilen:
    • open: die Nodes, die gerade gefragt werden. Wird einer zum zweiten Mal erreicht, meldet er das any, mit dem er registriert ist.
    • done: die Antworten dieser einen Frage.
  • ownShape ist der abgespaltene Teil von shapedDef, der die Ports baut, bevor die Gruppe mitredet. Inhaltlich ist er unverändert.
  • paintedInputs benutzt einen Trail für alle Pins eines Nodes.

Tests (auf melektaus-atx)

Gate        → 211 Files, 3240 Tests, CHECK EXIT 0   (3227 + 13)
e2e 1-6     → ALL PASSED – 298 checks   (6: +2 für die Kette)
e2e 4,6,18,19,20,23,24,26,28,31,36,43,53 → ALL PASSED – 558 checks
  • 14 neue Unit-Tests in tests/core/shared-port-type.test.ts: Kette aus zwei und drei, gemischte Arten, gemischter und offener Eingang, Undo vorne, Kreis aus zwei, Selbstspeisung, hinter einem Kreis, ungültige Kante weiter hinten, die 40er-Kette (jeder Node einmal gefragt), die 50er-Kette, zwei für die Pins. Der alte Test „reicht den Typ nicht durch einen zweiten Node“ ist gestrichen, daher netto 13.
  • Zwei neue e2e-Checks in Modul 06: Der zweite Node übernimmt number, und ein Text vorne öffnet die ganze Kette wieder.
  • Alle vier Unit-Gegenproben greifen.
  • Die Browser-Gegenprobe greift: Mit dem alten Verhalten fällt genau der Ketten-Check, die übrigen 297 bleiben grün.
  • Die e2e-Summe 1673 ist gerechnet (1671 + 2). 1671 hat CI für c88f57c gemessen. Volle Suite und Smokes liefen für diesen Stand nicht, das macht der CI-Lauf zu diesem Commit.
  • Nicht im Browser geprüft: der Kreis und die Kette aus drei Nodes, dafür gibt es nur Unit-Tests. Nach dem Build habe ich nichts mehr angesehen.

Wiki: Behaviors (Absatz zum gemeinsamen Typ) und Development (Summe).

Umgesetzt und live (Build auf stein2). ## Was sich ändert - **Der gemeinsame Typ wandert durch Ketten.** Hängt hinter einem `First not empty` oder `Select` ein weiterer solcher Node, übernimmt er den Typ, auf den sich der vordere geeinigt hat. Das gilt auch gemischt, etwa `Select` hinter zwei `First not empty`. - **Ein gemischter oder offener Eingang** irgendwo in der Kette macht alles dahinter wieder `any`. Davor bleibt der Typ stehen. - **Ein Kreis aus solchen Nodes** endet mit `any`, statt endlos zu fragen. Das gilt auch für einen Node, der sich selbst speist. - **Eingänge bleiben `any`**, nur Ausgänge erben (Variante A aus #207). Eine Kante, die weiter hinten ungültig wird, bleibt liegen und wird rot. - **Die farbigen Eingangs-Pins folgen mit** (Antwort 2). ## Kosten (Antwort 1) - **Kein Cache**, wie entschieden. - **Eine Kette aus 50 Nodes** löst sich in rund 10 ms auf, vorher waren es 2 ms. Die Zahl stammt aus einer Messung früher in dieser Runde, für den Endstand habe ich sie nicht neu gemessen. Ein Unit-Test hält fest, dass die 50er-Kette innerhalb eines Frames bleibt. - **Speist ein Node beide Eingänge des nächsten**, wird er je Frage nur einmal gefragt. Ohne das würde sich der Aufwand mit jedem Glied verdoppeln. Das ist kein Cache zwischen zwei Änderungen, die Antworten gelten nur für die eine Frage. ## Under the hood - `shapedDef` in `src/core/graph/nested.ts` bekommt statt des Schalters `inherit` einen `Trail` mit zwei Teilen: - `open`: die Nodes, die gerade gefragt werden. Wird einer zum zweiten Mal erreicht, meldet er das `any`, mit dem er registriert ist. - `done`: die Antworten dieser einen Frage. - `ownShape` ist der abgespaltene Teil von `shapedDef`, der die Ports baut, bevor die Gruppe mitredet. Inhaltlich ist er unverändert. - `paintedInputs` benutzt einen `Trail` für alle Pins eines Nodes. ## Tests (auf `melektaus-atx`) ``` Gate → 211 Files, 3240 Tests, CHECK EXIT 0 (3227 + 13) e2e 1-6 → ALL PASSED – 298 checks (6: +2 für die Kette) e2e 4,6,18,19,20,23,24,26,28,31,36,43,53 → ALL PASSED – 558 checks ``` - **14 neue Unit-Tests** in `tests/core/shared-port-type.test.ts`: Kette aus zwei und drei, gemischte Arten, gemischter und offener Eingang, Undo vorne, Kreis aus zwei, Selbstspeisung, hinter einem Kreis, ungültige Kante weiter hinten, die 40er-Kette (jeder Node einmal gefragt), die 50er-Kette, zwei für die Pins. Der alte Test „reicht den Typ nicht durch einen zweiten Node“ ist gestrichen, daher netto 13. - **Zwei neue e2e-Checks** in Modul 06: Der zweite Node übernimmt `number`, und ein Text vorne öffnet die ganze Kette wieder. - **Alle vier Unit-Gegenproben greifen.** - **Die Browser-Gegenprobe greift:** Mit dem alten Verhalten fällt genau der Ketten-Check, die übrigen 297 bleiben grün. - Die e2e-Summe **1673** ist gerechnet (1671 + 2). 1671 hat CI für `c88f57c` gemessen. Volle Suite und Smokes liefen für diesen Stand nicht, das macht der CI-Lauf zu diesem Commit. - **Nicht im Browser geprüft:** der Kreis und die Kette aus drei Nodes, dafür gibt es nur Unit-Tests. Nach dem Build habe ich nichts mehr angesehen. Wiki: *Behaviors* (Absatz zum gemeinsamen Typ) und *Development* (Summe).
admin moved this to Done in Development on 2026-10-02 14:46:05 +02:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#210