Poracle

Uitleg

Hoe Poracle werkt

Poracle beantwoordt Riftbound-regelvragen. Niet door een taalmodel te laten gokken, maar door eerst de officiële bronnen binnen te halen, ze doorzoekbaar te maken op betekenis én op letter, ze aan elkaar te knopen in een kennisgraaf, en pas dán een antwoord te laten formuleren — met de bron eronder. Deze pagina legt die keten stap voor stap uit.

963 kaarten
65 geverifieerde rulings
10 ban-vermeldingen
3 wijzigingen (14 dagen)

Deze cijfers komen rechtstreeks uit de database, de ontologie-tabellen verderop rechtstreeks uit het schema in de code. De uitleg eromheen is met de hand geschreven.

In het kort

  1. We halen de officiële regels, kaarten, bans en errata automatisch op en zien meteen wát er veranderde.
  2. Alles wordt in kleine stukken geknipt en op twee manieren doorzoekbaar gemaakt: op woord en op betekenis.
  3. Een ontologie legt vast welke soorten dingen er bestaan en welke verbanden tussen welke soorten mogen lopen.
  4. Die verbanden vormen een graaf, waarin nieuwe feiten afgeleid kunnen worden die niemand heeft ingevoerd.
  5. Bij een vraag zoekt de vector het startpunt en levert de graaf de onderbouwing — met bronvermelding en een eerlijk label als iets géén officiële bron heeft.

1. Bronnen binnenhalen

Alles begint bij Riot zelf. Poracle bezoekt de officiële Rules Hub en zoekt daar elke ronde opnieuw de actuele Core Rules- en Tournament Rules-PDF's op, want die links wisselen per versie. De banlijst leest Poracle uit de tekst van de Rules Hub zelf; de errata en patch notes komen uit de officiële nieuwsartikelen per set, en de kaartgegevens uit de officiële kaartgallery. Dat gebeurt op een vaste ronde, niet met de hand.

Belangrijk detail: we bewaren niet alleen de nieuwste versie, maar ook wát er veranderde. Elke ronde wordt de nieuwe tekst vergeleken met de vorige; verschilt er iets, dan komt dat als wijziging in de feed met bron, datum en een voor/na-diff. Zo is niet alleen te zien wat de regel nú is, maar ook sinds wanneer en waarom.

Waarom dit zo strak moet. De Rules Hub geeft de artikellinks per bezoek in een andere volgorde terug. Zonder tegenmaatregel meldt de feed elke ronde een "wijziging" die er geen is. Poracle houdt daarom een hash-historie bij en onderdrukt zulke heen-en-weer-veranderingen.

2. Opdelen in stukken

Een regelboek van honderden pagina's is als geheel nutteloos voor een zoekopdracht: je wilt § 601.2.d, niet "het hoofdstuk waarin dat ergens staat". De PDF wordt daarom opgeknipt in genummerde secties. Elke sectie krijgt haar eigen adres, haar plaats in de hiërarchie (601 → 601.2 → 601.2.d) en het paginanummer waarop ze in de officiële PDF staat.

Daardoor kan elk citaat later doorlinken naar precies de juiste regelpagina én naar de bijbehorende pagina in de officiële PDF. Wie het antwoord niet vertrouwt, klikt door naar de bron — dat is het hele punt.

3. Twee manieren van zoeken

Zoeken op woorden werkt prima zolang de vraag dezelfde woorden gebruikt als de regel. Dat is zelden zo. Iemand vraagt "kan ik dat blokken?" terwijl de regel het over Deflect heeft. Letterlijk zoeken vindt dan niets. Daarom doet Poracle het op twee manieren tegelijk.

Letterlijk (full-text)

De klassieke variant: Postgres indexeert alle woorden en vindt exacte termen, kaartnamen en codes. Sterk waar precisie telt — "§ 601.2" of "Teemo" moet gewoon de juiste treffer geven.

Op betekenis (vector)

Elk tekstfragment gaat door een embedding-model (bge-m3, lokaal) dat er een rij van 1024 getallen van maakt. Teksten met een vergelijkbare betekenis krijgen rijen die dicht bij elkaar liggen. Zoeken is dan: maak van de vraag óók zo'n rij en pak wat er het dichtst bij ligt.

Wat een vector-database precies doet

Het idee klinkt abstract, maar de intuïtie is eenvoudig. Stel dat elke tekst een punt op een landkaart is. Teksten die over hetzelfde gaan komen in dezelfde streek te liggen, ook als ze andere woorden gebruiken. "Blokken", "Deflect" en "aanval voorkomen" belanden bij elkaar in de buurt. Zoeken op betekenis is dan simpelweg: zet de vraag ook op die kaart en kijk wie de buren zijn.

Die "kaart" heeft in werkelijkheid 1024 dimensies in plaats van twee, en de opslag zit in Postgres met de pgvector-uitbreiding. Om niet elke keer alle punten te hoeven vergelijken ligt er over de grootste verzamelingen — regels, kaarten en community-inzichten — een HNSW-index: een gelaagd netwerk van kortere en langere sprongen, waarmee de buren gevonden worden zonder de hele verzameling af te lopen. De twee kleinere verzamelingen, spelbegrip en rulings, hebben zo'n index niet: die zijn kort genoeg om nog gewoon punt voor punt te vergelijken.

Eén model, één maat. Vectoren van verschillende modellen zijn onvergelijkbaar — hetzelfde woord komt bij een ander model ergens anders te liggen. Poracle legt daarom bij de vectoren vast welk model ze maakte, en de kolom heeft een vaste maat: een model met een andere dimensie wordt hard geweigerd in plaats van er stilletjes naast te gaan liggen. Wisselt het model, dan is opnieuw berekenen een expliciete stap: kaarten pakt de embed-job vanzelf op, de andere lagen volgen bij hun eerstvolgende herindexering of hergeneratie.

De twee lijsten samenvoegen

Beide zoekwijzen leveren een eigen ranglijst. Die worden gecombineerd met Reciprocal Rank Fusion: elk resultaat krijgt punten op basis van zijn plaats in elke lijst (1 / (60 + positie)), en de punten worden opgeteld. Het effect is dat hoge posities zwaarder wegen, maar geen enkele lijst de uitslag alleen bepaalt. Iets dat in beide lijsten redelijk scoort wint van iets dat in één lijst toevallig bovenaan staat.

Dat zoeken gebeurt over vijf gescheiden kennislagen — regels, kaarten, spelbegrip, rulings en community-inzichten — elk met een eigen verzameling vectoren. Welke laag zwaarder meetelt hangt af van het soort vraag: bij een legaliteitsvraag telt de banlijst, bij een definitievraag de regeltekst.

4. De ontologie: de afspraak over wat er bestaat

Voordat je dingen aan elkaar kunt knopen, moet vastliggen wát voor dingen het zijn. Dat is een ontologie: een expliciete lijst van soorten (klassen) en van de verbanden die tussen welke soorten mogen lopen. Zonder die afspraak groeit een graaf vanzelf scheef — dan staat "Deflect" er drie keer in als drie verschillende soorten dingen, en klopt geen enkele telling meer.

Bij Poracle staat die afspraak in code, op één plek, en is ze machine-leesbaar. Uit diezelfde bron komen de validatieregels, de afleidingsregels en de tabel hieronder. Een verband over Riftbound zelf dat hier niet staat, bestaat niet. Wat de graaf daarnaast nog vastlegt is herkomst en eigen boekhouding — welke bron een bewering staaft, uit welke ronde ze komt, welke entiteit met welke is samengevoegd — en dat valt bewust buiten de ontologie, omdat het niets over het spel beweert.

Ontologie-versie 4.0.0 — 31 klassen, 23 relaties. Live opgehaald uit de API, dus deze tabel veroudert niet.

Relaties die als directe verbinding bestaan

RelatieVanNaarAantal
ABOUTClaim, RulingCard, Mechanic, RuleSection, Concept0..*
CONTRADICTSClaimClaim, NormativeSource0..*
CORROBORATESClaimClaim, NormativeSource0..*
ERRATA_OFErratumCard, Keyword1..1
EXPLAINSConceptRuleSection0..*
FROM_SETCardSet1..1
GOVERNED_BYConcept, Card, InteractionRuleSection1..*
HAS_DOMAINCardDomain1..*
HAS_MECHANICCardMechanic0..*
HAS_ROLEInteractionCard, Mechanic2..*
HAS_STATUSObjectStatus0..*
HAS_TAGCardTag0..*
INTERACTS_WITHCardCard0..*
INVOKESKeywordMechanic1..*
PART_OFRuleSectionRuleSection0..1
RELATES_TOConcept, Card, Mechanic, RuleSection, ClaimConcept, Card, Mechanic, RuleSection, Claim0..*
REQUIRES_CONDITIONInteractionCondition0..*
SUBCLASS_OFThingThing0..*
SUPERSEDESErratumCard0..1

"Aantal" is de kardinaliteit: 1..* betekent minstens één en verder onbeperkt, 0..1 hooguit één.

Relaties die nooit een kale verbinding mogen zijn

Sommige verbanden zijn nooit onvoorwaardelijk waar. "Kaart A countert kaart B" klopt alleen binnen een bepaald tijdvenster, bij een bepaalde toestand of vanaf een bepaalde kostendrempel. Zo'n verband wordt daarom niet als losse verbinding opgeslagen maar als een eigen knoop, met de voorwaarden eraan vast. Anders zou de graaf iets beweren dat in de helft van de gevallen onwaar is.

  • COUNTERS
  • GRANTS
  • MODIFIES
  • REQUIRES

Wat niet tegelijk kan

De ontologie legt ook vast welke soorten elkaar uitsluiten. Een Spell is geen Object: hij lost op en verlaat het spel. Zulke uitsluitingen maken fouten vindbaar in plaats van onzichtbaar.

  • Keyword ⟂ Mechanic
  • Keyword ⟂ Status
  • Mechanic ⟂ Status
  • Spell ⟂ Object

Wel een ontologie, geen triplestore

Wie zich in dit onderwerp inleest komt al snel de triplestore tegen: een database die kennis opslaat als losse drieslagen — onderwerp, relatie, object. "Kaart X — heeft mechaniek — Deflect." Daar hoort een hele wereld bij (RDF, SPARQL, OWL) met één groot voordeel: het is een W3C-standaard, dus twee organisaties kunnen elkaars kennis letterlijk uitwisselen.

Poracle gebruikt die opslagvorm niet, maar wél de begrippen eruit. De graaf is een property graph: knopen en verbindingen dragen zelf eigenschappen, in plaats van dat elk feitje een aparte drieslag is. De ontologie hierboven is intussen wel degelijk in de taal van die wereld geschreven — klassen met overerving, relaties met een toegestaan domein en bereik, kardinaliteit, uitsluitingen, en eigenschappen als transitief en symmetrisch. De afleidingsregels uit paragraaf 5 zijn letterlijk OWL-achtige ketenregels, alleen uitgevoerd als graafquery in plaats van door een reasoner.

Waarom die keuze. Precies om de gekwalificeerde relaties hierboven. In een triplestore kan een drieslag zelf geen eigenschappen dragen: wil je vastleggen dat "A countert B" alleen geldt binnen een bepaald tijdvenster, dan moet je die uitspraak opsplitsen in hulpknopen. Wat bij ons een bewuste modelleerkeuze is, zou daar een verplichting worden — en juist die voorwaarden zijn de kern van een regelvraag. Daar komt bij dat de graaf een projectie is: de waarheid staat in Postgres, en dat maakt het uitwisselformaat van de graaf een implementatiedetail in plaats van een fundament.

De ontologie groeit mee

Elke set brengt nieuwe kaarten, nieuwe keywords en soms een heel nieuw soort ding. De ontologie is daarom geversioneerd, met vaste regels voor wat een versie-ophoging rechtvaardigt: nieuwe kaarten en keywords zijn gewoon nieuwe gevallen binnen het bestaande schema, een nieuw relatietype is een uitbreiding, en het splitsen van een klasse of het wijzigen van een uitsluiting is een breuk: het schema krijgt een nieuw hoofdversienummer, het teken dat alles wat al in de graaf staat opnieuw tegen dat schema getoetst moet worden. Wijzigt de structuur van het schema zonder dat de vastgelegde momentopname wordt bijgewerkt, dan faalt de build — precies zoals een databasemigratie dat doet. Bij dat bijwerken hoort de bewuste keuze welk deel van het versienummer opschuift.

5. De kennisgraaf

Met die afspraak op zak kan alles aan elkaar. Kaarten hangen aan hun set, hun domein, hun factie en hun mechanieken; regelsecties hangen aan hun bovenliggende sectie; primer-concepten leggen secties uit; errata wijzigen kaarten; rulings gaan érgens over. Dat geheel leeft in een graafdatabase (Neo4j) en is te doorlopen op de brein-pagina.

Eén principe is daarbij hard: Postgres blijft de bron van waarheid, de graaf is een projectie. Alles in de graaf is opnieuw op te bouwen uit de relationele data. Raakt de graaf beschadigd of loopt hij achter, dan is dat een herbouw — nooit dataverlies.

Feiten die niemand heeft ingevoerd

Het aardige van een graaf met een ontologie eronder is dat er conclusies uit volgen. Een voorbeeld: draagt een kaart de mechaniek Deflect, en definieert § 809.1 wat Deflect doet, dan valt die kaart onder die regel — zonder dat iemand dat feit intypt; het volgt uit twee andere feiten. De regels die zulke ketens aflopen worden automatisch uit de ontologie gegenereerd en staan klaar, maar juist deze keten levert vandaag nog niets op: de graaf legt de tweede stap — van mechaniek naar regelsectie — nog niet vast. Wat er nu wél uit volgt is de terugweg van een verbinding die maar één kant op is vastgelegd: werkt kaart A in op kaart B, dan geldt die verbinding ook andersom. Elke afgeleide verbinding draagt een stempel: welke regel hem maakte en in welke ronde. Afgeleide kennis is nooit bron; bij een herbouw wordt ze opnieuw afgeleid.

Op dit moment worden 4 afleidingsregels automatisch uit de ontologie gegenereerd — ze staan nergens los onderhouden.

Leidt afSoortWaaruit
CONTRADICTSSymmetricClosureMaterialiseert de ontbrekende terug-edge voor de symmetrische relatie CONTRADICTS.
GOVERNED_BYPropertyChainLeidt GOVERNED_BY(Card,RuleSection) af via de keten HAS_DOMAIN → GOVERNED_BY.
GOVERNED_BYPropertyChainLeidt GOVERNED_BY(Card,RuleSection) af via de keten HAS_MECHANIC → GOVERNED_BY.
INTERACTS_WITHSymmetricClosureMaterialiseert de ontbrekende terug-edge voor de symmetrische relatie INTERACTS_WITH.

6. Vector en graaf samen

Vectoren en grafen lossen verschillende problemen op, en dat is precies waarom ze samenwerken. Een vector-zoekactie is goed in vinden: ze komt uit bij de tekst die op de vraag lijkt, zelfs als er geen woord overeenkomt. Maar ze kan niets bewijzen — "dit lijkt op elkaar" is geen redenering. Een graaf is omgekeerd: hij weet niets van formulering, maar kan wél een keten leggen van A naar B en die keten laten zien.

Vector-database

  • Vindt op betekenis, ook zonder woordovereenkomst
  • Bestand tegen andere formuleringen en typefouten
  • Levert gelijkenis, geen onderbouwing
  • Kan geen "waarom" beantwoorden

Kennisgraaf

  • Legt expliciete, benoemde verbanden vast
  • Kan een keten van A naar B tonen als bewijs
  • Leidt nieuwe feiten af uit bestaande
  • Vindt niets als je het beginpunt niet kent

De combinatie heet GraphRAG en werkt in die volgorde: de vector levert het startpunt, de graaf levert de onderbouwing. Een vraag wordt eerst gekoppeld aan concrete dingen die Poracle kent — een kaartnaam, een mechaniek, een sectie. Vanaf die ankers loopt de graaf uit over toegestane verbanden, en de gevonden knopen halen hun tekst weer op uit de kennislagen.

Welke vorm dat uitlopen krijgt hangt af van de vraag. Een scherpe interactievraag over twee kaarten vraagt om een korte, gerichte uitbreiding rond die twee. Een brede vraag ("hoe werkt de gevechtsfase in het algemeen?") heeft juist samenvattende concepten nodig in plaats van losse knopen. Een "waarom"-vraag vraagt om een pad tussen twee punten. En een ban-vraag heeft helemaal geen graaf nodig: de banlijst opzoeken is exacter.

De kortste keten, met de stevigheid erbij. Als de graaf een keten als onderbouwing levert, zoekt hij de kortste verbinding tussen twee ankers en toont die stap voor stap. Bij elke stap legt Poracle vast hoe zwaar de betrokken kennislaag weegt en hoe zeker de verbinding is, zodat zichtbaar blijft waar een keten op zwak bewijs leunt — en zodat die weging meetelt in de vraag of een antwoord genoeg officiële dekking heeft. Het pad kiezen op die stevigheid in plaats van op lengte — elke stap kost dan 1 / (betrouwbaarheid × zekerheid) — is uitgewerkt en getest, maar staat nog niet aan.

De graafverrijking van de vraagbaak is een schakelaar in beheer. Staat hij uit, dan beantwoordt Poracle de vraag met de gelaagde zoekactie uit stap 3 — nooit met een fout.

7. Wat een antwoord mag dragen

Niet alle kennis is gelijk. De officiële regels zijn iets anders dan een goed beargumenteerde forumpost, en dat verschil mag nooit wegvallen in de opmaak van een antwoord. Poracle labelt daarom elk opgehaald feit met zijn laag, en die volgorde is bindend.

LaagWat het isGewicht
OfficieelRegels, kaartgegevens, toernooiregels1,00
Geverifieerde rulingRuling of erratum, automatisch tegen de bron getoetst; twijfelgevallen eerst langs de beheerder0,85
SpelbegripUit de regels gedestilleerde uitleg0,65
CommunityInterpretatie van spelers, met bron en bijval0,45
MetaTactiek en deckgebruik; veroudert het snelst0,25

Dat gewicht is geen weegschaal waarop community-kennis wordt weggedrukt — het bepaalt de route. Is er officiële dekking voor de vraag, dan draagt die het antwoord en mag community-kennis hooguit kleuren, altijd zichtbaar gelabeld. Is die dekking er niet, dan mag een goed onderbouwde community-lezing het antwoord dragen, mét de eerlijke melding dat er geen officiële bron voor is. En is er ook dat niet, dan zegt Poracle dat het het niet weet. Dat laatste is een functie, geen tekortkoming: een verzonnen regel is schadelijker dan geen antwoord.

Community-uitspraken worden bovendien niet één-op-één overgenomen. Ze worden geparafraseerd, voorzien van hun bron met citaat, getoetst aan de officiële tekst, en gewogen op hoeveel onafhankelijke bronnen hetzelfde zeggen. Eén losse post is een signaal; vijf bronnen die elkaar bevestigen is iets anders.

8. Het antwoord

Pas als al het bovenstaande klaar is, komt het taalmodel in beeld — en dan met een strakke opdracht: schrijf uitsluitend op wat in de aangeleverde context staat, in de vorm die een scheidsrechter zou gebruiken.

  • Oordeel — het antwoord in één zin
  • Zekerheid — Bevestigd, Afgeleid, Community-consensus of Onzeker, met toelichting
  • Uitleg — de redenering, met [1], [2] op de plek waar ze op een fragment leunt
  • Let op — de randgevallen die het omdraaien

De regelsecties zelf staan niet in het antwoord maar in de citatielijst eronder — bewust op één plek. Citaties zijn uitklapbaar en tonen naast de geciteerde sectie ook de bovenliggende regel, want een sectie los gelezen betekent vaak iets anders. Genoemde kaarten en regels verschijnen als aanklikbare blokken in plaats van kale tekst. En achter de schermen legt Poracle per vraag vast welke lagen meededen en hoe lang elke stap duurde — zichtbaar in beheer, zodat een slecht antwoord terug te herleiden is tot de stap waar het misging.

Loopt er iets mis in een antwoord, dan is dat te melden. Zo'n melding komt in een reviewwachtrij; wordt ze goedgekeurd, dan wordt de ruling onderdeel van de kennisbank en doet ze mee bij volgende vragen. Het systeem leert dus van correcties in plaats van dezelfde fout te herhalen.

9. Grafen aan elkaar knopen

Poracle's graaf is niet de enige denkbare graaf over Riftbound. Er kan er een bestaan over toernooien en uitslagen, een over decks en meta, een over kaartprijzen. De vraag is dan: hoe koppel je die aan elkaar zonder dat het één grote bak wordt waarin niemand meer weet wat waar vandaan komt?

Voorwaarde 1: stabiele identiteiten

Elk ding in Poracle heeft één vaste tekstuele naam, in dezelfde vorm in de vector-opslag, in de graaf en in de API — card:ogn-011-298, mechanic:Deflect, section:core-rules-pdf/101.2. Zonder zo'n stabiele verwijzing is koppelen onbegonnen werk: dan match je op namen, en namen veranderen, verschillen per taal en zijn niet uniek.

Daar komt bij dat één kaart meerdere drukken kan hebben: alternatieve art, een herdruk in een latere set. Dat zijn geen verschillende kaarten. Poracle kiest per kaartnaam één canonieke druk en hangt de afgeleide kennis — mechanieken, rulings, relaties, ban-historie — daaraan. Een ban op één druk geldt daardoor voor álle drukken van dezelfde kaart.

Voorwaarde 2: gelijkheid als gewogen bewering

Twee grafen koppelen betekent zeggen: "dit ding hier is hetzelfde als dat ding daar." Zo'n uitspraak hoort zelf een feit te zijn, met een zekerheid en een herkomst — geen stille samensmelting. Blijkt de koppeling later fout, dan haal je één bewering weg in plaats van twee vervlochten datasets uit elkaar te pulken.

Twee manieren, met een duidelijke afweging

Bevragen waar het staat

De andere graaf blijft van de ander; je stelt hem een vraag op het moment dat je het antwoord nodig hebt. Altijd actueel, geen kopie die veroudert — maar je bent afhankelijk van zijn beschikbaarheid en snelheid.

Binnenhalen en bijhouden

Je haalt de feiten op en slaat ze zelf op, gelabeld met hun herkomst. Snel en altijd beschikbaar — maar het is een kopie, en kopieën lopen achter tenzij je ze actief ververst.

De keuze hangt af van hoe snel de kennis veroudert. Regelteksten wijzigen zelden en lenen zich voor binnenhalen; toernooiuitslagen en prijzen veranderen doorlopend en kun je beter bevragen. Wat in beide gevallen geldt: het label van herkomst gaat mee. Kennis uit een externe graaf komt binnen op de laag die bij die bron past, niet als officiële regel.

Voorwaarde 3: één gedeelde begrippenlijst

De diepste voorwaarde is de saaiste: als de andere graaf "unit" gebruikt waar Poracle "Unit" bedoelt, of "kaart" voor iets dat hier "druk" heet, dan levert koppelen rommel op. Daarom is de ontologie uit stap 4 geen bureaucratie maar de aansluiting: ze maakt expliciet wat een term betekent, zodat een andere partij erop kan aansluiten of zijn eigen begrippen erop kan afbeelden. Dat is ook precies waarom ze publiek opvraagbaar is — de tabel op deze pagina komt uit diezelfde API.

Waar het niet voor is

  • Geen officiële bron. Poracle is een onofficiële referentie en geen onderdeel van Riot Games. Bij twijfel geldt de officiële tekst, en daar linkt elk antwoord naartoe.
  • Geen vervanging van een scheidsrechter. Op een toernooi beslist de aanwezige scheidsrechter. Poracle helpt bij voorbereiden en nazoeken.
  • Geen orakel. Waar geen dekking is, zegt het systeem dat het het niet weet. Dat is de bedoeling.

Nieuwsgierig hoe dat er in de praktijk uitziet? Verken het brein of stel een vraag.