Skip to content

fix(symbolConverter): do not register colliding outcome slugs - #199

Open
JulienKervarrec wants to merge 4 commits into
nktkas:mainfrom
JulienKervarrec:fix/outcome-slug-collisions
Open

JulienKervarrec wants to merge 4 commits into
nktkas:mainfrom
JulienKervarrec:fix/outcome-slug-collisions

Conversation

@JulienKervarrec

@JulienKervarrec JulienKervarrec commented Sep 17, 2026 •

Copy link
Copy Markdown

Closes #196.

Problem

_processOutcomeMarkets writes every outcome side straight into _nameToAssetId:

this._nameToAssetId.set(slug, 100000000 + 10 * outcome.outcome + sideIdx);

Templated markets carry the template id as their display name (template:binaryPrice, side template:Yes) and keep the real values in description. _outcomeSlug only slugifies the question, outcome and side names, so every market built from the same template produces the same slug and each set overwrites the previous one.

The result is the worst failure mode for this kind of lookup: getAssetId("templatebinaryprice-templateyes") returns a valid id for the wrong market — whichever happened to load last — and the other markets sharing that slug cannot be reached at all. A caller has no way to tell that apart from a correct answer.

Change

Record each outcome slug as it is registered, note the ones produced more than once, and unregister those after the loop. An ambiguous slug is simply absent, so getAssetId / getSzDecimals return undefined — the same result callers already handle for an unknown symbol.

This deliberately does not try to invent a better slug. As #196 notes, doing that properly means rendering the template from outcomeTemplates into the display name, and there is no public source for what the resulting URL slug should be. Refusing to answer is the part that can be fixed correctly today; a real slug for templated markets can follow once the naming is known.

Behaviour change

A lookup on an ambiguous templated slug now returns undefined instead of an id. That id was wrong for every one of those markets except one, so nothing that was correct stops working.

Verification

Added SymbolConverter templated outcome markets to tests/utils/symbolConverter.test.ts, using the existing offline fixture transport, so it runs under deno test -A -- --offline in CI. It covers both halves: the ambiguous slug is absent, and a uniquely named market in the same payload still resolves.

I also replayed the old and the new algorithm over the existing OUTCOME_META fixture outside the SDK: both produce the same 14 entries with the same ids, so the recurring-price, sports and categorical slugs asserted by the current tests are untouched. On the templated fixture the old algorithm maps templatebinaryprice-templateyes to 100003010 — outcome 301, having silently replaced outcome 300 — while the new one leaves it unmapped.

deno fmt --check and deno lint (repository rules, without the .dev plugin) pass on both files, and deno test -A tests/utils/symbolConverter.test.ts -- --offline passes. jsr.io is unreachable from my machine, so for that run the JSR imports were mapped to local equivalents; CI remains the reference.

Note on #195

#195 changes the szDecimals value for outcome markets in this same method. This PR leaves those lines untouched, and the new test only checks that a unique slug has a numeric szDecimals, not its value, so the two PRs merge cleanly in either order. I checked both orders locally: no conflict, and the test file passes after each.

Templated outcome markets share their question, outcome and side names, so
several distinct markets slugify to the same string and the last one loaded
silently won the lookup.

Collect outcome slugs first and register only the unique ones, so getAssetId
returns undefined for an ambiguous slug instead of the wrong market.

Closes nktkas#196

Signed-off-by: Julien Kervarrec <114134889+JulienKervarrec@users.noreply.github.com>
Adds an offline fixture with two templated markets that slugify identically and
asserts that the ambiguous slug is not registered while unique ones still are.

Closes nktkas#196

Signed-off-by: Julien Kervarrec <114134889+JulienKervarrec@users.noreply.github.com>
@JulienKervarrec

Copy link
Copy Markdown
Author

Update: I've now run the offline tests for this file. deno test -A tests/utils/symbolConverter.test.ts -- --offline passes, including both new steps. With _symbolConverter.ts reverted to main, "ambiguous slugs are not registered" fails, so the test covers the fix.

jsr.io is still unreachable from my environment, so for this run the JSR imports resolved to their npm builds. CI stays the reference once the workflows are approved.

…he loop

Same behaviour as before: a slug produced by more than one outcome side is
left unregistered. Registration now stays as on main and the ambiguous slugs
are removed afterwards, so the szDecimals lines touched by nktkas#195 are left
alone and the two changes merge cleanly in either order.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Signed-off-by: Julien Kervarrec <114134889+JulienKervarrec@users.noreply.github.com>
The collision test only needs to know that a unique slug is still
registered. Checking for a numeric szDecimals instead of 5 keeps it valid
if nktkas#195 changes that value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Signed-off-by: Julien Kervarrec <114134889+JulienKervarrec@users.noreply.github.com>
@JulienKervarrec

Copy link
Copy Markdown
Author

Small rework, same behaviour: ambiguous slugs are now unregistered after the loop instead of being filtered before registration (93f025b), and the unique-slug test checks for a numeric szDecimals rather than 5 (0537cef).

The point is #195: the szDecimals lines it changes are no longer touched here, so the two PRs now merge cleanly in either order. I checked both orders locally, and the symbolConverter tests pass after each. The diff to _symbolConverter.ts is now +13/−0. Description updated accordingly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: SymbolConverter maps templated outcome markets to colliding slugs

1 participant