fix(mentions): a name inside a link is not a person #478

Closed
coilyco-ops wants to merge 1 commit from fix/a-name-in-a-url-is-not-a-person into main
Member

closes #465

My defect, shipped within the hour, and it reached a member. Kai asked for a jobs page and got:

https://eco-app/.@Kai (@coilysiren).me/jobs

instead of https://eco-app.coilysiren.me/jobs#468.

Cause

resolveMentions matched a display name anywhere in the reply, and a URL is part of the reply. The match required a word boundary preceded by any non-word character — and / and . are both non-word characters — so a name matched inside a host or a path. A member called eco or main corrupted every link containing it.

Fix

Names resolve only outside links and outside markup that is already a mention.

The link span reuses urlSpan, the definition four reply validators already share, rather than a second answer to what a link is. Quail's comment on the issue pointed straight at it: "which maskURLs already does for four validators". I had written my own regex first.

Fixed rather than reverted

The feature was one condition short of correct. Reverting would take an approved mention behaviour back out over a bug in where I looked for names, not in whether names should resolve.

Quail's characterization test

It documented the defect and its failure message said to delete it once fixed. Deleted — and its corpus kept: the same four replies (eco, wiki, issues, main) now assert the link is left alone. The half Quail marked "must survive any fix" is untouched and still passes.

ward exec gate green: build, policy-check, vet, test, test-skips, pre-commit.

closes #465 **My defect, shipped within the hour, and it reached a member.** Kai asked for a jobs page and got: ``` https://eco-app/.@Kai (@coilysiren).me/jobs ``` instead of `https://eco-app.coilysiren.me/jobs` — https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/468. ## Cause `resolveMentions` matched a display name **anywhere** in the reply, and a URL is part of the reply. The match required a word boundary preceded by any non-word character — and `/` and `.` are both non-word characters — so a name matched inside a host or a path. A member called `eco` or `main` corrupted every link containing it. ## Fix Names resolve only outside links and outside markup that is already a mention. **The link span reuses `urlSpan`**, the definition four reply validators already share, rather than a second answer to what a link is. Quail's comment on the issue pointed straight at it: *"which maskURLs already does for four validators"*. I had written my own regex first. ## Fixed rather than reverted The feature was one condition short of correct. Reverting would take an approved mention behaviour back out over a bug in *where I looked for names*, not in whether names should resolve. ## Quail's characterization test It documented the defect and its failure message said to delete it once fixed. Deleted — and **its corpus kept**: the same four replies (`eco`, `wiki`, `issues`, `main`) now assert the link is left alone. The half Quail marked *"must survive any fix"* is untouched and still passes. `ward exec gate` green: build, policy-check, vet, test, test-skips, pre-commit.
fix(mentions): a name inside a link is not a person
All checks were successful
ci / image-build (pull_request) Successful in 20s
ci / test (pull_request) Successful in 38s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
49d4873932
Shipped an hour ago and reached a member. Kai asked for a jobs page and got
https://eco-app/.@Kai (@coilysiren).me/jobs, because resolveMentions matched a
display name anywhere in the reply and a URL is part of the reply.

The match required a word boundary preceded by any non-word character, and
both / and . are non-word characters, so a name matched inside a host or a
path. A member called eco or main corrupted every link containing it.

Names are now resolved only outside links and outside markup that is already a
mention. The link span reuses urlSpan, the definition four reply validators
already share, rather than a second answer to what a link is. Quail's comment
on the issue pointed at it.

Fixed rather than reverted. The feature was one condition short of correct and
a revert would take an approved behaviour out over a bug in where I looked.

Quail's characterization test documented the defect and its failure message
said to delete it once fixed. Deleted, and its corpus kept: the same four
replies now assert the link is left alone.

closes #465

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Author
Member

Closing: someone landed the same fix while I was writing mine — Angie (ENG, claude seat). mentionSpans is on main, splits on urlSpan, and #465 is closed. Same insight, and theirs is the better shape: splitting the reply into spans beats my index-arithmetic over match offsets.

Fifth duplicate today. This one I mind least — it was a live member-visible defect I had just shipped, and two people converging on it fast is the system working.

One thing mine covered that theirs does not, and I have demonstrated it rather than asserted it: Discord markup is not prose either, and only URLs are treated as opaque. Filing it separately with the reproduction.

**Closing: someone landed the same fix while I was writing mine — Angie (ENG, claude seat).** `mentionSpans` is on main, splits on `urlSpan`, and https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/465 is closed. Same insight, and theirs is the better shape: splitting the reply into spans beats my index-arithmetic over match offsets. Fifth duplicate today. This one I mind least — it was a live member-visible defect I had just shipped, and two people converging on it fast is the system working. **One thing mine covered that theirs does not**, and I have demonstrated it rather than asserted it: Discord markup is not prose either, and only URLs are treated as opaque. Filing it separately with the reproduction.
coilyco-ops closed this pull request 2026-08-13 14:18:28 +00:00
All checks were successful
ci / image-build (pull_request) Successful in 20s
ci / test (pull_request) Successful in 38s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped

Pull request closed

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!478
No description provided.