Netzwerk-Labor · Doku 🔬 Befund – „27 von 27": jede Fertigkeit ist als Klassenraum-Auftrag lösbar Zum Spiel Online

🔬 Befund – „27 von 27": jede Fertigkeit ist als Klassenraum-Auftrag lösbar

[!danger] Kurzfassung Die Behauptung hĂ€lt. Alle 27 Fertigkeiten aus DATEN.skills sind als Klassenraum-Auftrag adressierbar, haben einen Fehlerinjektor, sind im Startnetz wirklich gebrochen und mit der hinterlegten Lösung wirklich heilbar — gemessen ĂŒber den vertraglichen Weg (432/432 ĂŒber Seeds 1..16; 1728/1728 ĂŒber das volle Kanonisierungsfenster 1..64) und ĂŒber den echten Weg der Lehrkraft mit Code (54/54 bestanden, bei Wahl E und AP2). Die frĂŒhere Angabe „24 von 27" ist ĂŒberholt; sie stammt aus der Zeit vor den drei Injektoren portsec-fremde-mac, stp-doppelkabel und nas-ohne-adresse (Ausbau 1.3 / task-5). FĂŒnf Befunde betreffen nur das Drumherum (§ 5): das Beweismittel A-codec-probe.js rechnete noch mit 24 (wĂ€hrend dieser Arbeit behoben — es leitet die Zahl jetzt aus der Messung ab), der eingefrorene Beleg A-codec.json trĂ€gt den alten Stand, die Dokumente A/D nennen 24 (bewusst Protokolle), der Vertragsanker fehlt (Architektur § 12.2 hat keinen Tauglichkeits-Punkt), und drei eingefrorene Indizes haben ihre Bedeutung gewechselt (24/25/26: von „abgelehnt" zu „echter Auftrag"). Keiner dieser fĂŒnf Punkte berĂŒhrt die Zahl selbst.

1 · Die Frage

Zwei Aussagen stehen gegeneinander:

QuelleAussage
Fahrplan 1.3/2.0, Umsetzungalle 27 Fertigkeiten sind tauglich, weil lab.portsec, lab.stp und lab.storage seit task-5 Injektoren haben
FrĂŒhphase (Spezifikation, A – Codec, Werkzeugliste)24 von 27 — drei Fertigkeiten sind nicht adressierbar

„Adressierbar" heißt im Vertrag nicht „kommt in der Liste vor", sondern: es gibt einen Code, aus dem auf jedem GerĂ€t derselbe spielbare Auftrag entsteht. Der Weg dahin ist gemessen nachlesbar:

  1. src/spiel/klassenraum.js:50-65 — die eingefrorene Fertigkeitstabelle (TABELLE_SKILLS), 27 EintrĂ€ge in DATEN.skills-Reihenfolge.
  2. src/spiel/klassenraum.js:146-151 — erzeugen({skill}) lehnt ab, wenn die Tabelle tauglich: false sagt oder hatInjektor(skill) (:79) keinen Injektor findet.
  3. src/spiel/klassenraum.js:100-110 (kanonGeneriert) — sucht im Kanonisierungsfenster (KANON_FENSTER = 64, src/spiel/klassenraum-codec.js:255-259) nach einem Seed, dessen Fall Spiel.ticketGueltig(d) besteht (src/spiel/generator.js:126-151). Findet sie keinen, lautet die Antwort {fehler:"auftrag"}.
  4. src/spiel/postfach.js:62-111 — der Öffnungsweg Spiel.instanzErstellen({gen:{skill,seed}, 
}); Spiel.abnahme (src/spiel/abnahme.js:13-45) prĂŒft am Ende Ziele, Regression und Neustart.

Die eine Frage dieses Befunds: Gibt es fĂŒr jede der 27 Fertigkeiten einen Fall, der baubar ist, einen Injektor hat, gĂŒltig ist und lösbar ist? Und stimmt die eingefrorene Tabelle mit dem ĂŒberein, was messbar ist?

2 · Die Antwort in vier Messungen

#BehauptungWie geprĂŒftErgebnisRestzweifel
1Jede Fertigkeit liefert ĂŒber den vertraglichen Weg einen echten, gĂŒltigen, lösbaren Auftrag27 Fertigkeiten × Seeds 1..16 = 432 Instanzen ĂŒber Spiel.instanzErstellen({gen:{skill,seed}, quelle:"klassenraum", ohneFlow:true})432/432 in Ordnung, 27/27 Skills mit vollem Feld, 0 Befundenur Seeds 1..16, nicht 1..256 (Messung 2 deckt das Fenster ab)
2In keinem Fall des Kanonisierungsfensters scheitert die Suche27 × Seeds 1..64 (genau KANON_FENSTER)1728/1728 in Ordnung, 0 BefundeFenster fĂŒr Varianten > 0 beginnt spĂ€ter (variante + 1 + k); gemessen ist das Basisfenster 1..64
3Der echte Weg der Lehrkraft fĂŒhrt bis zur Abnahmeerzeugen({skill}) → Code → ausCode(code) → instanzErstellen → Spiel.loesung + arbeitszieleErfuellen → Spiel.abnahme → ergebnisCode; je Fertigkeit 2 Varianten, einmal mit Wahl E, einmal mit Wahl AP254/54 bestanden, 0 Befunde, in allen 54 FĂ€llen schritte = 0 (kein Kanonisierungsschritt nötig)2 Varianten je Fertigkeit, nicht alle 256
4Die eingefrorene Tabelle sagt die WahrheitSpiel.klassenraum.tabellen() und tauglicheFertigkeiten() gegen hatInjektor je Fertigkeit27 EintrĂ€ge, Reihenfolge = DATEN.skills, tauglich ⇔ Injektor (0 ohne Deckung, 0 unnötig gesperrt), ersterSeed: 1 bestĂ€tigtdie Tabelle ist ein Literal; der Test wacht ĂŒber Reihenfolge und Merker

Was je Fall in Messung 1 geprĂŒft wurde (fĂŒnf Zusicherungen, jede einzeln):

  1. Spiel.instanzErstellen wirft nicht und Spiel.defVon(inst) liefert eine Definition.
  2. def.injektoren.length ≄ 1 — es gibt einen Fehlerinjektor, sonst gĂ€be es nichts zu finden.
  3. def.ziele.length ≄ 1 und mindestens ein erwartetes Ziel ist im Startnetz wirklich gebrochen (Sim.pruefeZiel(inst.netz, ziel).ok === false) — der Fehler wirkt, er steht nicht nur im Feld.
  4. Spiel.ticketGueltig(def) === true — das Haus-Gate: Start bricht, Lösung heilt, die gesunden Ziele der Vorlage gelten danach weiter.
  5. UnabhĂ€ngig davon nachgerechnet: auf einer Netzkopie heilt Spiel.loesungAnwenden(kopie, def.loesung) jedes Netz-Ziel (Sim.pruefeZiel). Punkt 4 und Punkt 5 sind zwei verschiedene Rechenwege (Gate gegen eigene Kopie) — beide grĂŒn.

In Messung 3 kommen die Teile hinzu, die das Gate nicht prĂŒft: Arbeitsziele (befehl/antwort), Regression (Spiel.basisMessen/regressionPruefen), der Neustart-Test und der Ergebnis-Code.

3 · Die Tabelle aller 27 Fertigkeiten

Reihenfolge wie DATEN.skills. „Grundcodes" = alle im Startnetz gebrochenen erwarteten Ziele, vereinigt ĂŒber Seeds 1..16 (Messung 1); OFFEN ist der Grundcode eines blockiert-Ziels, das aufgeht.

#SkillInjektorlösbargemessene Grundcodes
1lab.linkjajaPORTSHUTDOWN, LINKDOWN, ARPNOREPLY, DNSNOSERVER, DHCPNOOFFER, NO_ROUTE
2lab.ipjajaGWWRONGSUBNET, ARPNOREPLY, DUPIP, NOIP, OFFEN, PORTCLOSED, NOROUTE
3lab.netzjajaWRONGMASK, GWWRONGSUBNET, NOROUTE, NO_IP
4lab.gatewayjajaGWUNREACHABLE, NOGATEWAY, PORTSHUTDOWN, NOROUTE, DHCPNOOFFER
5lab.arpjajaARPNOREPLY, DUPIP, PORTCLOSED
6lab.pingjajaGWUNREACHABLE, NOROUTE
7lab.switchjajaPORTSHUTDOWN, PORTSECVIOLATION, STORM, DHCPNOOFFER
8lab.subnetzjajaWRONGMASK, DROPVLAN
9lab.dhcpjajaNOROUTE, DHCPNO_OFFER
10lab.dnsjajaDNSFAIL, DNSNO_SERVER
11lab.portsjajaFWDENY, SERVICEOFF
12lab.tcpjajaSERVICE_OFF
13lab.clijajaNOROUTE, PORTSHUTDOWN, DHCPNOOFFER, NATMISSING, TRUNKNOTALLOWED, GWUNREACHABLE, OFFEN
14lab.speichernjajaNO_ROUTE
15lab.vlanjajaDROPVLAN, GWUNREACHABLE
16lab.trunkjajaTRUNKNOTALLOWED, DROP_VLAN
17lab.rostickjajaDROP_VLAN
18lab.acljajaNATMISSING, OFFEN, ACLDENY
19lab.routejajaNOROUTE, TIMEOUT, NORETURNROUTE, PORTSHUTDOWN
20lab.ttljajaPORT_SHUTDOWN
21lab.natjajaNAT_MISSING
22lab.portfwdjajaFW_DENY
23lab.fwjajaFW_DENY
24lab.dmzjajaFW_DENY
25lab.portsecjajaPORTSEC_VIOLATION
26lab.stpjajaSTORM
27lab.storagejajaNO_IP

Die letzten drei Zeilen sind die des Ausbaus 1.3: portsec-fremde-mac (Port geht wirklich in err-disabled), stp-doppelkabel (Lauf bricht wirklich mit abbruch === "STORM" ab), nas-ohne-adresse (das NAS steht wirklich ohne Adresse da) — ihre Wirkung ist in tests/injektoren-neu.test.js im Netz nachgewiesen, nicht nur im Ticket.

4 · Zwei AuffÀlligkeiten ohne Defektcharakter

Beides sind Beobachtungen, keine Fehler — sie stehen hier, damit niemand sie spĂ€ter fĂŒr einen Befund hĂ€lt:

[!note] lab.ttl meldet als ersten Grund PORT_SHUTDOWN, nicht TTL_EXPIRED Der Injektor schleife (src/spiel/injektoren.js, skills ["lab.ttl","lab.route"]) schaltet die LAN-Schnittstelle des Filial-Routers ab; das Paket lĂ€uft danach im Kreis. Der erste gebrochene Ziel meldet deshalb die abgeschaltete Schnittstelle, nicht den TTL-Ablauf. Die Fertigkeit ist adressiert (Ziel, Titel und ErklĂ€rung gehören zu TTL/Traceroute), nur der sichtbare Erstgrund ist ein anderer. Über Seeds 1..16 war PORT_SHUTDOWN der einzige beobachtete Code.

[!note] lab.cli und lab.acl melden in manchen Seeds OFFEN OFFEN ist kein Fehlercode im engeren Sinn, sondern der erwartete Zustand eines blockiert-Ziels, das im Startnetz aufgeht („etwas ist erreichbar, das es nicht sein darf"). Genau das ist der Fehler der ACL-Injektoren (acl-reihenfolge, acl-zu-streng, acl-richtung): Die Sperre wirkt nicht. Dass der Erstgrund je Seed zwischen ACL_DENY/NAT_MISSING und OFFEN wechselt, ist die Auswahl der Fehlerstelle — kein Widerspruch zur Tauglichkeit.

5 · FĂŒnf Befunde zum Drumherum

#BefundWie geprĂŒftErgebnis
B1Das Beweismittel rechnete noch mit der alten Welt — behobentools/klassenraum-probe/A-codec-probe.js gelesen (zuerst :722-725, nach der Korrektur :730-742)Vorher: zaehl.tauglicheIndizes = tab.skills.length - 3 → 24, untauglicheIndizes = 3, unerreichbareCodesFertigkeit = 3 * 32 * 256 → 24.576. Jetzt (Auftrag determinismus, noch wĂ€hrend dieser Arbeit): die drei Felder werden aus messFertigkeitstauglichkeit abgeleitet, mit dem Kommentar „Die frĂŒhere Annahme ‚3 untauglich, also 24 von 27' war der Stand VOR den drei Injektoren aus task-5 
 Ohne Messung wird NICHT geraten: dann bleibt das Feld null." Gemessen ist: 27 tauglich, 0 untauglich, 0 unerreichbare Codes. Von mir gelesen, nicht nachgerechnet — der Probelauf dauert laut Haus ~250 s und schreibt nach Nachweise/
B2Der eingefrorene Beleg trĂ€gt den Stand vor task-5Nachweise/Klassenraum/A-codec.json gelesen; Dateidatum geprĂŒftmessungen.fertigkeitstauglichkeit: 24/27; die Datei ist zuletzt 07.10.2026, 00:29:47 geschrieben — also vor den Injektoren aus task-5. Das Review nennt ihn korrekt „Stand vor task-5" (docs/entwicklung/Review – Klassenraum A+B.md:65), die Datei selbst sagt es nicht. Nicht angefasst — Belege sind datierte Momentaufnahmen
B3Dokumente nennen weiter 24Textstellen gesuchtdocs/entwicklung/Klassenraum – Umsetzungsreife Spezifikation.md:138,159 · docs/entwicklung/Klassenraum/A – Codec und Determinismus.md:220,258,271-274,354-357,499,511,758 · tools/auftraege/KLASSENRAUM-umsetzungsreif.md:55. Laut docs/Architektur.md:871-873 sind A–D bewusst Protokolle und werden nicht nachgezogen — dann ist es ein Preis, kein Fehler
B4Der Vertragsanker fehltdocs/Architektur.md:869-901 (§ 12.2) und :903-928 (§ 12.3) gelesen§ 12.2 enthĂ€lt L1–L5 (Postfach, plaetze, ohneFlow, B gilt, Ergebnis-Toast) — keinen Tauglichkeits-Punkt. § 12.3 sagt nur, dass der Kommentar „24 von 27" richtiggestellt ist (:927). Die 27 stehen im CHANGELOG (:94), in den Kommentaren src/spiel/klassenraum.js:28-32 und src/spiel/klassenraum-codec.js:297-300 sowie in tests/klassenraum-codec.test.js:251-262 — nicht im Vertragsabschnitt. Wird nachgezogen (Leitung)
B5Drei eingefrorene Indizes haben ihre Bedeutung gewechseltKlassenraumCodec.auftragBauen({sitzung:5, art:"generiert", index, variante:3}) + Spiel.klassenraum.ausCode(code)Index 23 → lab.dmz · 24 → lab.portsec · 25 → lab.stp · 26 → lab.storage (vorher {fehler:"auftrag"}) · Index 27 und 63 → {fehler:"fassung"}. Die AnhĂ€ngeregel ist nicht verletzt (kein Index rĂŒckt), aber ein alter Code mit Index 24..26 liefert jetzt einen echten Auftrag. Die Aussage der A-Spezifikation („24.576 Codes aus 3 untauglichen Fertigkeiten ergeben auftrag") ist damit messbar falsch: 0

6 · Der Test im Haus

tests/klassenraum-loesbarkeit.test.js (neu) hĂ€lt die Behauptung dauerhaft fest — schlank, damit die Suite nicht minutenlang lĂ€uft:

FallUmfangLaufzeit
alle 27 Fertigkeiten: Injektor + Ziel, wirklich gebrochen, ticketGueltig, Lösung heilt27 × Seeds 1,2 = 54 Instanzen6 609 ms
eingefrorene Tabelle gegen Messung (27, Reihenfolge, tauglich ⇔ Injektor, ersterSeed 1)rein lesend< 1 s
der echte Weg der Lehrkraft: erzeugen → Code → ausCode → lösen → Abnahme → Ergebnis-Code27 LĂ€ufe3 411 ms

Die vollen Messungen (432 · 1728 · 54) laufen bewusst nicht in der Suite, sondern nur in diesem Befund — sie sind zu langsam fĂŒr jeden Testlauf. Die drei FĂ€lle arbeiten mit einer Kapsel (eigener Speicherstand, eigener Store, vollstĂ€ndige RĂŒckgabe danach), damit erzeugen keine Sitzung hinterlĂ€sst.

[!warning] Was unterwegs schiefging Die Testdatei ging in einem ersten Zwischenstand mit zwei Fehlern in den Schwarm: eine Klammer zu viel (})); statt });) erzeugte einen LADEFEHLER, der den ganzen Lauf anhielt, und die Kapsel gab das Ergebnis statt einer HĂŒlle zurĂŒck (t.fn is not a function). Beides ist behoben und belegt: node --check tests/klassenraum-loesbarkeit.test.js → Syntax OK, danach 688/690 grĂŒn, und die zwei roten Zeilen waren die beiden Doku: Markdown-Konverter und Seitenbau-Zeilen (ZĂ€hlung nach dem Doku-Neubau), nicht die neuen FĂ€lle.

7 · Nicht geprĂŒft

8 · Belege (in dieser Sitzung ausgefĂŒhrt)

ZweckBefehl / HandlungErgebnis
Messung 1Node-Lauf mit dem Ladepfad aus tests/run.js (alle src/-Schichten), 27 Skills × Seeds 1..16432/432 in Ordnung, 27/27 Skills mit vollem Feld, 0 Befunde, 41,1 s
Messung 2derselbe Aufbau, 27 × Seeds 1..64 (KANON_FENSTER)1728/1728 in Ordnung, 0 Befunde, 261,3 s
Messung 3erzeugen({skill, seed}) → ausCode → instanzErstellen → lösen → Spiel.abnahme → ergebnisCode, je Skill mit Wahl E und AP254/54 bestanden, 0 Befunde, 24,5 s
Messung 4Spiel.klassenraum.tabellen() / tauglicheFertigkeiten() gegen hatInjektor27 tauglich, Indizes 0..26, ohneDeckung = [], unnoetigGesperrt = []
B5KlassenraumCodec.auftragBauen + ausCode fĂŒr Index 23/24/25/26/27/6324/25/26 liefern lab.portsec/lab.stp/lab.storage; 27 und 63 → fassung
B1tools/klassenraum-probe/A-codec-probe.js gelesen — vorher :722-725, nach der Korrektur :730-742- 3 / 3 / 3 * 32 * 256 gegen gemessen 27 / 0 / 0; danach Ableitung aus messFertigkeitstauglichkeit mit Kommentar zur ĂŒberholten Annahme
B2Nachweise/Klassenraum/A-codec.json gelesen, Dateidatum geprĂŒftfertigkeitenTauglich: 24/27, zuletzt geschrieben 07.10.2026, 00:29:47
Testdateinode --check tests/klassenraum-loesbarkeit.test.jsSyntax OK (Exit 0); Zeilenenden LF, wie die ĂŒbrigen Testdateien
Testlaufnode tests/run.js (voller Lauf)688/690 grĂŒn, 2 rot (beide Doku: Markdown-Konverter und Seitenbau), 0 ĂŒbersprungen
Randbedingungnode tools/sim-stand.js (vor diesem Befund, nach den Injektoren aus task-5)„Simulation unverĂ€ndert gegenĂŒber dem Referenzstand" — src/sim/ blieb unangetastet

9 · Was aus diesem Befund folgt

  1. Die 27 bleiben stehen. Keine Fertigkeit muss auf tauglich: false zurĂŒckgesetzt werden; die Tabelle ist gedeckt.
  2. B1 ist behoben (Auftrag determinismus): die drei ZĂ€hler im Beweismittel werden jetzt aus messFertigkeitstauglichkeit abgeleitet (A-codec-probe.js:730-742) — ein fester Wert veraltet wieder. Nachgerechnet habe ich das nicht (der Probelauf schreibt nach Nachweise/); der nĂ€chste Beleg sollte 27 / 0 / 0 tragen.
  3. B4 ist nachzuziehen (Leitung): ein Tauglichkeits-Punkt in docs/Architektur.md § 12.2 — sonst hĂ€ngt die Entscheidung „27 von 27" an Kommentaren, einem Test und dem CHANGELOG, nicht am Vertrag.
  4. B5 ist zu benennen, wenn je ein alter Auftragscode mit Index 24..26 auftaucht: er ist nicht mehr ungĂŒltig, sondern liefert jetzt einen Auftrag. Wer alte Codes ausgestellt hat, sollte das wissen.
  5. B2 und B3 bleiben, wie sie sind — datierte Belege und bewusste Protokolle —, solange niemand sie als aktuellen Stand liest. Dieser Befund ist die Stelle, an der der aktuelle Stand steht.