test(mentions): pin that a name inside a link rewrites the link #466

Merged
coilyco-ops merged 1 commit from qa/pin-the-mention-url-collision into main 2026-08-13 14:06:13 +00:00
Member

Pins #465 without reddening main.

452088d resolves a display name to a mention anywhere it appears in the reply, and a URL is part of the reply:

in : Open trades are listed at https://eco-app.coilysiren.me/trade
out: Open trades are listed at https://<@999>-app.coilysiren.me/trade

The matcher is right and its scope is not. It requires a non-word character before the name, and every URL separator is one — /, -, . satisfy both sides — so a name between two slashes matches exactly as if it were prose.

The corpus is four real reply shapes

Not invented strings. Two of them are the approved links that approved-wiki-link and approved-live-surface-link exist to require, which is what makes this member-facing rather than cosmetic: a rewritten host does not resolve, and reaching the right page is the service's job.

Those two gate cases would catch this in principle and cannot in practice — they run with no roster, so resolveMentions returns early on an empty map. The guard is on one side of a seam and the failure is on the other, which is the shape most of today's findings have had.

Characterization, not a demand

The fix is a scope change with a real offset choice in it. maskURLs at decision.go:24 already does this for four validators, but matching against masked text while rewriting the original needs the offsets mapped back, and that is an implementation decision rather than a one-liner. Asserting the desired behaviour here would redden main for a choice nobody has made.

Verified it flips — matching against maskURLs(reply) fails this test naming the colliding names:

--- FAIL: TestANameInsideALinkRewritesTheLink
    the name "eco" no longer rewrites the link it sits inside, so issue 465 is fixed
    the name "wiki" no longer rewrites the link it sits inside, so issue 465 is fixed

The half that must survive is pinned beside it

Kai still resolves and Kaitlyn still does not. A fix that fixes the URL case by narrowing too far fails this file too, which is the failure mode I would expect from a hurried scope change — and the one the four existing bounds were written to avoid.

Test-only. No production change.

Refs #465

Pins https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/465 without reddening `main`. `452088d` resolves a display name to a mention **anywhere it appears in the reply**, and a URL is part of the reply: ``` in : Open trades are listed at https://eco-app.coilysiren.me/trade out: Open trades are listed at https://<@999>-app.coilysiren.me/trade ``` The matcher is right and its **scope** is not. It requires a non-word character before the name, and every URL separator is one — `/`, `-`, `.` satisfy both sides — so a name between two slashes matches exactly as if it were prose. ## The corpus is four real reply shapes Not invented strings. **Two of them are the approved links** that `approved-wiki-link` and `approved-live-surface-link` exist to require, which is what makes this member-facing rather than cosmetic: a rewritten host does not resolve, and reaching the right page is the service's job. Those two gate cases would catch this in principle and **cannot in practice** — they run with no roster, so `resolveMentions` returns early on an empty map. The guard is on one side of a seam and the failure is on the other, which is the shape most of today's findings have had. ## Characterization, not a demand The fix is a scope change with a real offset choice in it. `maskURLs` at `decision.go:24` already does this for four validators, but matching against masked text while rewriting the original needs the offsets mapped back, and that is an implementation decision rather than a one-liner. Asserting the desired behaviour here would redden `main` for a choice nobody has made. Verified it flips — matching against `maskURLs(reply)` fails this test naming the colliding names: ``` --- FAIL: TestANameInsideALinkRewritesTheLink the name "eco" no longer rewrites the link it sits inside, so issue 465 is fixed the name "wiki" no longer rewrites the link it sits inside, so issue 465 is fixed ``` ## The half that must survive is pinned beside it `Kai` still resolves and `Kaitlyn` still does not. **A fix that fixes the URL case by narrowing too far fails this file too**, which is the failure mode I would expect from a hurried scope change — and the one the four existing bounds were written to avoid. Test-only. No production change. Refs https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/465
test(mentions): pin that a name inside a link rewrites the link
All checks were successful
ci / image-build (pull_request) Successful in 17s
ci / test (pull_request) Successful in 32s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
bfacf955fd
452088d resolves a display name to a mention anywhere it appears in the reply,
and a URL is part of the reply. A member called eco, wiki, main or issues
corrupts every link carrying that component.

  https://eco-app.coilysiren.me/trade
  https://<@999>-app.coilysiren.me/trade

The matcher is right and its scope is not. It requires a non-word character
before the name, and every URL separator is one, so a name between two slashes
matches exactly as if it were prose.

The corpus is four real reply shapes rather than invented strings. Two of them
are the approved links that approved-wiki-link and approved-live-surface-link
exist to require, which is what makes this member-facing rather than cosmetic.

Characterization, because the fix is a scope change with an offset choice in it.
maskURLs already does this for four validators, and matching against masked text
while rewriting the original is a real decision rather than a one-liner.

Verified it flips: matching against maskURLs(reply) fails this test naming the
colliding names. The half that must survive is pinned beside it, so a fix that
stops resolving plain names fails too.

Refs sirens-echo#465

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!466
No description provided.